mirror of https://github.com/buster-so/buster.git
udpate imports
This commit is contained in:
parent
b778192148
commit
01130b9d7d
|
@ -1,18 +1,82 @@
|
|||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||
"extends": ["../../biome.json"],
|
||||
"$schema": "https://biomejs.dev/schemas/2.2.3/schema.json",
|
||||
"files": {
|
||||
"ignoreUnknown": false,
|
||||
"includes": [
|
||||
"src/**/*",
|
||||
".vscode/**/*",
|
||||
"index.html",
|
||||
"vite.config.ts",
|
||||
"vitest.config.ts",
|
||||
"vitest.setup.ts",
|
||||
"!**/node_modules",
|
||||
"!**/dist",
|
||||
"!**/build",
|
||||
"!**/coverage"
|
||||
]
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"suspicious": {
|
||||
"noConsoleLog": "off",
|
||||
"noConsole": "off"
|
||||
"recommended": true,
|
||||
"correctness": {
|
||||
"noUnusedVariables": "off",
|
||||
"useExhaustiveDependencies": "off"
|
||||
},
|
||||
"style": {
|
||||
"useImportType": "off"
|
||||
"noNonNullAssertion": "error",
|
||||
"useImportType": "warn",
|
||||
"useNodejsImportProtocol": "error",
|
||||
"useConsistentArrayType": "error",
|
||||
"noUnusedTemplateLiteral": "off"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "error",
|
||||
"noConsole": "off"
|
||||
},
|
||||
"complexity": {
|
||||
"noExcessiveCognitiveComplexity": "off",
|
||||
"noForEach": "off"
|
||||
},
|
||||
"performance": {
|
||||
"noDelete": "error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"include": ["src/**/*", "scripts/**/*"]
|
||||
"overrides": [
|
||||
{
|
||||
"includes": ["**/*.test.ts", "**/*.test.tsx", "**/*.stories.tsx"],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"suspicious": {
|
||||
"noExplicitAny": "off"
|
||||
},
|
||||
"style": {
|
||||
"noNonNullAssertion": "off"
|
||||
},
|
||||
"correctness": {
|
||||
"noUnusedFunctionParameters": "off",
|
||||
"noUnusedVariables": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 100,
|
||||
"lineEnding": "lf"
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "single",
|
||||
"jsxQuoteStyle": "double",
|
||||
"trailingCommas": "es5",
|
||||
"semicolons": "always",
|
||||
"arrowParentheses": "always"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,35 +25,32 @@
|
|||
"dependencies": {
|
||||
"@buster/sdk": "workspace:*",
|
||||
"@buster/server-shared": "workspace:*",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.1.0",
|
||||
"chalk": "^5.6.0",
|
||||
"commander": "^14.0.0",
|
||||
"fast-glob": "^3.3.3",
|
||||
"ink": "^5.0.1",
|
||||
"ink": "^6.2.3",
|
||||
"ink-big-text": "^2.0.0",
|
||||
"ink-gradient": "^3.0.0",
|
||||
"ink-spinner": "^5.0.0",
|
||||
"ink-text-input": "^6.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"micromatch": "^4.0.8",
|
||||
"react": "^18.3.1",
|
||||
"zod": "^3.24.1"
|
||||
"react": "^19.1.1",
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@biomejs/biome": "^2.2.3",
|
||||
"@buster/env-utils": "workspace:*",
|
||||
"@buster/typescript-config": "workspace:*",
|
||||
"@buster/vitest-config": "workspace:*",
|
||||
"@types/bun": "^1.1.14",
|
||||
"@types/bun": "^1.2.21",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/node": "^22.10.5",
|
||||
"@types/react": "^18.3.17",
|
||||
"@vitest/coverage-v8": "^2.1.8",
|
||||
"@types/react": "^19.1.12",
|
||||
"ink-testing-library": "^4.0.0",
|
||||
"react-devtools-core": "^6.1.5",
|
||||
"tsx": "^4.19.2",
|
||||
"typescript": "^5.7.3",
|
||||
"vitest": "^2.1.8"
|
||||
"tsx": "catalog:"
|
||||
},
|
||||
"engines": {
|
||||
"bun": ">=1.0.0"
|
||||
|
|
|
@ -2,7 +2,7 @@ import { createBusterSDK } from '@buster/sdk';
|
|||
import { Box, Text, useApp, useInput } from 'ink';
|
||||
import Spinner from 'ink-spinner';
|
||||
import TextInput from 'ink-text-input';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
type Credentials,
|
||||
deleteCredentials,
|
||||
|
@ -205,10 +205,10 @@ export function Auth({ apiKey, host, local, cloud, clear, noSave, show }: AuthPr
|
|||
|
||||
if (step === 'host') {
|
||||
return (
|
||||
<Box flexDirection='column'>
|
||||
<Box flexDirection="column">
|
||||
{_existingCreds && (
|
||||
<Box marginBottom={1}>
|
||||
<Text color='yellow'>⚠️ Existing credentials found. They will be overwritten.</Text>
|
||||
<Text color="yellow">⚠️ Existing credentials found. They will be overwritten.</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
|
@ -227,17 +227,17 @@ export function Auth({ apiKey, host, local, cloud, clear, noSave, show }: AuthPr
|
|||
if (step === 'apikey') {
|
||||
const displayHost = (hostInput || DEFAULT_HOST).replace(/^https?:\/\//, '');
|
||||
return (
|
||||
<Box flexDirection='column'>
|
||||
<Box flexDirection="column">
|
||||
{_error && (
|
||||
<Box marginBottom={1}>
|
||||
<Text color='red'>❌ {_error}</Text>
|
||||
<Text color="red">❌ {_error}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Box>
|
||||
<Text>Enter your API key: </Text>
|
||||
</Box>
|
||||
<TextInput value={apiKeyInput} onChange={setApiKeyInput} mask='*' />
|
||||
<TextInput value={apiKeyInput} onChange={setApiKeyInput} mask="*" />
|
||||
|
||||
<Box marginTop={1}>
|
||||
<Text dimColor>Find your API key at https://{displayHost}/app/settings/api-keys</Text>
|
||||
|
@ -254,7 +254,7 @@ export function Auth({ apiKey, host, local, cloud, clear, noSave, show }: AuthPr
|
|||
return (
|
||||
<Box>
|
||||
<Text>
|
||||
<Spinner type='dots' /> Validating API key...
|
||||
<Spinner type="dots" /> Validating API key...
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
|
@ -264,7 +264,7 @@ export function Auth({ apiKey, host, local, cloud, clear, noSave, show }: AuthPr
|
|||
return (
|
||||
<Box>
|
||||
<Text>
|
||||
<Spinner type='dots' /> Saving credentials...
|
||||
<Spinner type="dots" /> Saving credentials...
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
|
|
|
@ -25,9 +25,9 @@ export function DeployProgress({
|
|||
const percentage = total > 0 ? Math.round((current / total) * 100) : 0;
|
||||
|
||||
return (
|
||||
<Box flexDirection='column' marginY={1}>
|
||||
<Box flexDirection="column" marginY={1}>
|
||||
<Box>
|
||||
{!isComplete && <Spinner type='dots' />}
|
||||
{!isComplete && <Spinner type="dots" />}
|
||||
<Text color={isComplete ? 'green' : 'cyan'}>
|
||||
{' '}
|
||||
[{current}/{total}] {status}
|
||||
|
@ -36,14 +36,14 @@ export function DeployProgress({
|
|||
|
||||
{currentFile && (
|
||||
<Box marginLeft={2}>
|
||||
<Text color='dim'>File: {currentFile}</Text>
|
||||
<Text color="dim">File: {currentFile}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{currentModel && (
|
||||
<Box marginLeft={2}>
|
||||
<Text color='dim'>Model: </Text>
|
||||
<Text color='magenta'>{currentModel}</Text>
|
||||
<Text color="dim">Model: </Text>
|
||||
<Text color="magenta">{currentModel}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
|
@ -64,9 +64,9 @@ function ProgressBar({ percentage, width }: { percentage: number; width: number
|
|||
|
||||
return (
|
||||
<Box>
|
||||
<Text color='green'>{'█'.repeat(filled)}</Text>
|
||||
<Text color='dim'>{'░'.repeat(empty)}</Text>
|
||||
<Text color='cyan'> {percentage}%</Text>
|
||||
<Text color="green">{'█'.repeat(filled)}</Text>
|
||||
<Text color="dim">{'░'.repeat(empty)}</Text>
|
||||
<Text color="cyan"> {percentage}%</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -14,80 +14,80 @@ export function DeploySummary({ result }: DeploySummaryProps) {
|
|||
const hasFailures = result.failures.length > 0;
|
||||
|
||||
return (
|
||||
<Box flexDirection='column' marginY={1}>
|
||||
<Text bold color='cyan'>
|
||||
<Box flexDirection="column" marginY={1}>
|
||||
<Text bold color="cyan">
|
||||
📊 Deployment Summary
|
||||
</Text>
|
||||
<Text color='dim'>{'='.repeat(40)}</Text>
|
||||
<Text color="dim">{'='.repeat(40)}</Text>
|
||||
|
||||
{/* Success metrics */}
|
||||
<Box flexDirection='column' marginY={1}>
|
||||
<Text color='green'>✅ Successfully deployed: {totalDeployed} models</Text>
|
||||
<Box flexDirection="column" marginY={1}>
|
||||
<Text color="green">✅ Successfully deployed: {totalDeployed} models</Text>
|
||||
|
||||
{result.success.length > 0 && (
|
||||
<Box marginLeft={2}>
|
||||
<Text color='green'>✨ New models: {result.success.length}</Text>
|
||||
<Text color="green">✨ New models: {result.success.length}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{result.updated.length > 0 && (
|
||||
<Box marginLeft={2}>
|
||||
<Text color='cyan'>🔄 Updated models: {result.updated.length}</Text>
|
||||
<Text color="cyan">🔄 Updated models: {result.updated.length}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{result.noChange.length > 0 && (
|
||||
<Box marginLeft={2}>
|
||||
<Text color='dim'>➖ No changes: {result.noChange.length}</Text>
|
||||
<Text color="dim">➖ No changes: {result.noChange.length}</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{/* Exclusions */}
|
||||
{result.excluded.length > 0 && (
|
||||
<Text color='yellow'>⛔ Excluded: {result.excluded.length} files</Text>
|
||||
<Text color="yellow">⛔ Excluded: {result.excluded.length} files</Text>
|
||||
)}
|
||||
|
||||
{/* Failures */}
|
||||
{hasFailures && (
|
||||
<Box flexDirection='column' marginTop={1}>
|
||||
<Text color='red'>❌ Failed: {result.failures.length} models</Text>
|
||||
<Text color='dim'>{'-'.repeat(40)}</Text>
|
||||
<Box flexDirection="column" marginTop={1}>
|
||||
<Text color="red">❌ Failed: {result.failures.length} models</Text>
|
||||
<Text color="dim">{'-'.repeat(40)}</Text>
|
||||
|
||||
{result.failures.slice(0, 5).map((failure) => (
|
||||
<Box
|
||||
key={`${failure.file}-${failure.modelName}`}
|
||||
flexDirection='column'
|
||||
flexDirection="column"
|
||||
marginLeft={2}
|
||||
marginY={0.5}
|
||||
>
|
||||
<Text color='yellow'>File: {failure.file}</Text>
|
||||
<Text color='magenta'>Model: {failure.modelName}</Text>
|
||||
<Text color="yellow">File: {failure.file}</Text>
|
||||
<Text color="magenta">Model: {failure.modelName}</Text>
|
||||
{failure.errors.map((error: string) => (
|
||||
<Box key={error} marginLeft={2}>
|
||||
<Text color='red'>• {error}</Text>
|
||||
<Text color="red">• {error}</Text>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
{result.failures.length > 5 && (
|
||||
<Text color='dim' italic>
|
||||
<Text color="dim" italic>
|
||||
...and {result.failures.length - 5} more failures
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Text color='dim'>{'='.repeat(40)}</Text>
|
||||
<Text color="dim">{'='.repeat(40)}</Text>
|
||||
|
||||
{/* Final status */}
|
||||
{hasFailures ? (
|
||||
<Text color='yellow' bold>
|
||||
<Text color="yellow" bold>
|
||||
⚠️ Some models failed to deploy. Please check the errors above.
|
||||
</Text>
|
||||
) : (
|
||||
<Text color='green' bold>
|
||||
<Text color="green" bold>
|
||||
🎉 All models processed successfully!
|
||||
</Text>
|
||||
)}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { existsSync } from 'node:fs';
|
||||
import { readFile, readdir, stat } from 'node:fs/promises';
|
||||
import { readdir, readFile, stat } from 'node:fs/promises';
|
||||
import { join, relative, resolve } from 'node:path';
|
||||
import yaml from 'js-yaml';
|
||||
import {
|
||||
|
|
|
@ -7,9 +7,9 @@ import {
|
|||
processDeploymentResponse,
|
||||
} from './deployment/results';
|
||||
import {
|
||||
type DeployFunction,
|
||||
createAuthenticatedDeployer,
|
||||
createDryRunDeployer,
|
||||
type DeployFunction,
|
||||
} from './deployment/strategies';
|
||||
import {
|
||||
createModelFileMap,
|
||||
|
|
|
@ -65,7 +65,7 @@ export function DeployCommand(props: DeployCommandProps) {
|
|||
|
||||
// Always show the banner at the top
|
||||
return (
|
||||
<Box flexDirection='column'>
|
||||
<Box flexDirection="column">
|
||||
<BusterBanner showSubtitle={false} />
|
||||
|
||||
{/* Error state */}
|
||||
|
@ -74,16 +74,16 @@ export function DeployCommand(props: DeployCommandProps) {
|
|||
{/* Check if it's a buster.yml not found error */}
|
||||
{error?.includes('No buster.yml found') ? (
|
||||
<Box paddingX={2}>
|
||||
<Text color='red'>No buster.yml found</Text>
|
||||
<Text color="red">No buster.yml found</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<Box flexDirection='column' paddingX={2}>
|
||||
<Text color='red' bold>
|
||||
<Box flexDirection="column" paddingX={2}>
|
||||
<Text color="red" bold>
|
||||
❌ Deployment Error
|
||||
</Text>
|
||||
<Text color='red'>{error}</Text>
|
||||
<Text color="red">{error}</Text>
|
||||
<Box marginTop={1}>
|
||||
<Text color='dim'>Please check your configuration and try again.</Text>
|
||||
<Text color="dim">Please check your configuration and try again.</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
@ -108,7 +108,7 @@ export function DeployCommand(props: DeployCommandProps) {
|
|||
{/* Initializing state - show spinner */}
|
||||
{status === 'initializing' && (
|
||||
<Box paddingX={2}>
|
||||
<Spinner label='Loading configuration...' />
|
||||
<Spinner label="Loading configuration..." />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { relative } from 'node:path';
|
||||
import type { CLIDeploymentResult, DeployResponse, DeploymentExcluded, Model } from '../schemas';
|
||||
import type { CLIDeploymentResult, DeploymentExcluded, DeployResponse, Model } from '../schemas';
|
||||
|
||||
/**
|
||||
* Pure function to merge multiple deployment results into one
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { type BusterSDK, createBusterSDK } from '@buster/sdk';
|
||||
import { loadCredentials } from '../../../utils/credentials';
|
||||
import type { DeployRequest, DeployResponse, DeploymentFailure, DeploymentItem } from '../schemas';
|
||||
import type { DeploymentFailure, DeploymentItem, DeployRequest, DeployResponse } from '../schemas';
|
||||
|
||||
/**
|
||||
* Type definition for a deployment function
|
||||
|
|
|
@ -5,11 +5,11 @@ import yaml from 'js-yaml';
|
|||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
import type { Model } from '../schemas';
|
||||
import {
|
||||
ModelParsingError,
|
||||
fileContainsTodo,
|
||||
findTodoMarkers,
|
||||
formatZodIssues,
|
||||
generateDefaultSQL,
|
||||
ModelParsingError,
|
||||
parseModelFile,
|
||||
parseModelFileStrict,
|
||||
resolveModelConfig,
|
||||
|
|
|
@ -9,14 +9,14 @@ import {
|
|||
DeployColumnSchema,
|
||||
type DeployModel,
|
||||
DeployModelSchema,
|
||||
type DeployRequest,
|
||||
DeployRequestSchema,
|
||||
type DeployResponse,
|
||||
DeployResponseSchema,
|
||||
type DeploymentFailure,
|
||||
DeploymentFailureSchema,
|
||||
type DeploymentItem,
|
||||
DeploymentItemSchema,
|
||||
type DeployRequest,
|
||||
DeployRequestSchema,
|
||||
type DeployResponse,
|
||||
DeployResponseSchema,
|
||||
type Dimension,
|
||||
DimensionSchema,
|
||||
type Filter,
|
||||
|
|
|
@ -5,20 +5,20 @@ import { HelloCommand } from './hello';
|
|||
|
||||
describe('HelloCommand', () => {
|
||||
it('should render greeting with default name', () => {
|
||||
const { lastFrame } = render(<HelloCommand name='World' />);
|
||||
const { lastFrame } = render(<HelloCommand name="World" />);
|
||||
|
||||
expect(lastFrame()).toContain('Hello, World!');
|
||||
expect(lastFrame()).toContain('Buster CLI');
|
||||
});
|
||||
|
||||
it('should render greeting in uppercase when flag is set', () => {
|
||||
const { lastFrame } = render(<HelloCommand name='Claude' uppercase={true} />);
|
||||
const { lastFrame } = render(<HelloCommand name="Claude" uppercase={true} />);
|
||||
|
||||
expect(lastFrame()).toContain('HELLO, CLAUDE!');
|
||||
});
|
||||
|
||||
it('should render greeting in normal case when uppercase flag is false', () => {
|
||||
const { lastFrame } = render(<HelloCommand name='Claude' uppercase={false} />);
|
||||
const { lastFrame } = render(<HelloCommand name="Claude" uppercase={false} />);
|
||||
|
||||
expect(lastFrame()).toContain('Hello, Claude!');
|
||||
expect(lastFrame()).not.toContain('HELLO, CLAUDE!');
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import chalk from 'chalk';
|
||||
import { Box, Text } from 'ink';
|
||||
import React, { useEffect } from 'react';
|
||||
import type React from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
interface HelloCommandProps {
|
||||
name: string;
|
||||
|
@ -19,8 +20,8 @@ export const HelloCommand: React.FC<HelloCommandProps> = ({ name, uppercase }) =
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<Box flexDirection='column'>
|
||||
<Text color='green'>{chalk.bold('🚀 Buster CLI')}</Text>
|
||||
<Box flexDirection="column">
|
||||
<Text color="green">{chalk.bold('🚀 Buster CLI')}</Text>
|
||||
<Text>{displayText}</Text>
|
||||
</Box>
|
||||
);
|
||||
|
|
|
@ -4,7 +4,7 @@ import { createBusterSDK } from '@buster/sdk';
|
|||
import { Box, Text, useApp, useInput } from 'ink';
|
||||
import Spinner from 'ink-spinner';
|
||||
import TextInput from 'ink-text-input';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { BusterBanner } from '../components/banner.js';
|
||||
import { type Credentials, getCredentials, saveCredentials } from '../utils/credentials.js';
|
||||
|
||||
|
@ -436,26 +436,26 @@ export function InitCommand({ apiKey, host, local, path: providedPath }: InitPro
|
|||
|
||||
// Always show the banner at the top
|
||||
return (
|
||||
<Box flexDirection='column'>
|
||||
<Box flexDirection="column">
|
||||
<BusterBanner />
|
||||
|
||||
{step === 'check' && (
|
||||
<Box paddingX={2}>
|
||||
<Text>
|
||||
<Spinner type='dots' /> Checking configuration...
|
||||
<Spinner type="dots" /> Checking configuration...
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{step === 'prompt-auth' && (
|
||||
<Box flexDirection='column' paddingX={2}>
|
||||
<Box flexDirection="column" paddingX={2}>
|
||||
<Box marginBottom={1}>
|
||||
<Text>Let's get you connected to Buster.</Text>
|
||||
</Box>
|
||||
|
||||
{error && (
|
||||
<Box marginBottom={1}>
|
||||
<Text color='red'>❌ {error}</Text>
|
||||
<Text color="red">❌ {error}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
|
@ -470,7 +470,7 @@ export function InitCommand({ apiKey, host, local, path: providedPath }: InitPro
|
|||
<Text>Enter your API key: </Text>
|
||||
</Box>
|
||||
|
||||
<TextInput value={apiKeyInput} onChange={setApiKeyInput} mask='*' placeholder='sk_...' />
|
||||
<TextInput value={apiKeyInput} onChange={setApiKeyInput} mask="*" placeholder="sk_..." />
|
||||
|
||||
<Box marginTop={1}>
|
||||
<Text dimColor>Find your API key at {hostInput}/app/settings/api-keys</Text>
|
||||
|
@ -485,7 +485,7 @@ export function InitCommand({ apiKey, host, local, path: providedPath }: InitPro
|
|||
{step === 'validate' && (
|
||||
<Box paddingX={2}>
|
||||
<Text>
|
||||
<Spinner type='dots' /> Validating your API key...
|
||||
<Spinner type="dots" /> Validating your API key...
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
@ -493,20 +493,20 @@ export function InitCommand({ apiKey, host, local, path: providedPath }: InitPro
|
|||
{step === 'save' && (
|
||||
<Box paddingX={2}>
|
||||
<Text>
|
||||
<Spinner type='dots' /> Saving your configuration...
|
||||
<Spinner type="dots" /> Saving your configuration...
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{step === 'prompt-location' && (
|
||||
<Box flexDirection='column' paddingX={2}>
|
||||
<Box flexDirection="column" paddingX={2}>
|
||||
<Box marginBottom={1}>
|
||||
<Text>Where would you like to create your Buster project?</Text>
|
||||
</Box>
|
||||
|
||||
{error && (
|
||||
<Box marginBottom={1}>
|
||||
<Text color='red'>❌ {error}</Text>
|
||||
<Text color="red">❌ {error}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
|
@ -514,8 +514,8 @@ export function InitCommand({ apiKey, host, local, path: providedPath }: InitPro
|
|||
<Text>Project location: </Text>
|
||||
</Box>
|
||||
|
||||
<Box borderStyle='single' borderColor='#7C3AED' paddingX={1}>
|
||||
<TextInput value={projectPath} onChange={setProjectPath} placeholder='./' />
|
||||
<Box borderStyle="single" borderColor="#7C3AED" paddingX={1}>
|
||||
<TextInput value={projectPath} onChange={setProjectPath} placeholder="./" />
|
||||
</Box>
|
||||
|
||||
<Box marginTop={1}>
|
||||
|
@ -531,22 +531,22 @@ export function InitCommand({ apiKey, host, local, path: providedPath }: InitPro
|
|||
{step === 'creating' && (
|
||||
<Box paddingX={2}>
|
||||
<Text>
|
||||
<Spinner type='dots' /> Creating project structure...
|
||||
<Spinner type="dots" /> Creating project structure...
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{step === 'done' && (
|
||||
<Box flexDirection='column' paddingX={2}>
|
||||
<Box flexDirection="column" paddingX={2}>
|
||||
<Box marginBottom={1}>
|
||||
<Text color='green'>✅ Created example project</Text>
|
||||
<Text color="green">✅ Created example project</Text>
|
||||
</Box>
|
||||
|
||||
<Box marginBottom={1}>
|
||||
<Text>Project structure:</Text>
|
||||
</Box>
|
||||
|
||||
<Box flexDirection='column' marginLeft={2}>
|
||||
<Box flexDirection="column" marginLeft={2}>
|
||||
<Text>📁 {join(resolve(projectPath), 'buster')}/</Text>
|
||||
<Text>├── 📄 buster.yml</Text>
|
||||
<Text>└── 📁 docs/</Text>
|
||||
|
@ -562,7 +562,7 @@ export function InitCommand({ apiKey, host, local, path: providedPath }: InitPro
|
|||
<Text bold>📚 Next steps:</Text>
|
||||
</Box>
|
||||
|
||||
<Box flexDirection='column' marginLeft={2}>
|
||||
<Box flexDirection="column" marginLeft={2}>
|
||||
<Text>1. cd {join(resolve(projectPath), 'buster')}</Text>
|
||||
<Text>2. Configure buster.yml for your data source</Text>
|
||||
<Text>3. Populate docs/ with your documentation files</Text>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import chalk from 'chalk';
|
||||
import { Box, Text, useApp, useInput } from 'ink';
|
||||
import React, { useState } from 'react';
|
||||
import type React from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
export const InteractiveCommand: React.FC = () => {
|
||||
const [selectedOption, setSelectedOption] = useState(0);
|
||||
|
@ -27,15 +28,15 @@ export const InteractiveCommand: React.FC = () => {
|
|||
});
|
||||
|
||||
return (
|
||||
<Box flexDirection='column'>
|
||||
<Box flexDirection="column">
|
||||
<Box marginBottom={1}>
|
||||
<Text color='cyan' bold>
|
||||
<Text color="cyan" bold>
|
||||
🚀 Buster CLI - Interactive Mode
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Text dimColor>Use arrow keys to navigate, Enter to select, Q to quit</Text>
|
||||
<Box marginTop={1} flexDirection='column'>
|
||||
<Box marginTop={1} flexDirection="column">
|
||||
{options.map((option, index) => (
|
||||
<Box key={option}>
|
||||
<Text {...(selectedOption === index ? { color: 'green' } : {})}>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { createBusterSDK } from '@buster/sdk';
|
||||
import { Box, Text, useApp, useInput } from 'ink';
|
||||
import { render } from 'ink';
|
||||
import { Box, render, Text, useApp, useInput } from 'ink';
|
||||
import Spinner from 'ink-spinner';
|
||||
import TextInput from 'ink-text-input';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { BusterBanner } from '../components/banner.js';
|
||||
import {
|
||||
type Credentials,
|
||||
|
@ -21,11 +20,11 @@ const _LOCAL_HOST = 'http://localhost:3001';
|
|||
// Component for the welcome screen header with additional help text
|
||||
function WelcomeHeader() {
|
||||
return (
|
||||
<Box paddingY={2} paddingX={2} alignItems='center'>
|
||||
<Box paddingY={2} paddingX={2} alignItems="center">
|
||||
<Box marginRight={4}>
|
||||
<BusterBanner showSubtitle={false} inline={true} />
|
||||
</Box>
|
||||
<Box flexDirection='column' justifyContent='center'>
|
||||
<Box flexDirection="column" justifyContent="center">
|
||||
<Text bold>Welcome to Buster</Text>
|
||||
<Box marginTop={1}>
|
||||
<Text dimColor>Type / to use slash commands</Text>
|
||||
|
@ -40,7 +39,7 @@ function WelcomeHeader() {
|
|||
<Text dimColor>/help for more</Text>
|
||||
</Box>
|
||||
<Box marginTop={2}>
|
||||
<Text color='#7C3AED'>"Run `buster` and fix all the errors"</Text>
|
||||
<Text color="#7C3AED">"Run `buster` and fix all the errors"</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -115,21 +114,21 @@ function CommandInput({ onSubmit }: { onSubmit: (input: string) => void }) {
|
|||
});
|
||||
|
||||
return (
|
||||
<Box flexDirection='column' paddingX={2} paddingBottom={1}>
|
||||
<Box borderStyle='single' borderColor='#7C3AED' paddingX={1} width='100%'>
|
||||
<Text color='#7C3AED'>❯ </Text>
|
||||
<Box flexDirection="column" paddingX={2} paddingBottom={1}>
|
||||
<Box borderStyle="single" borderColor="#7C3AED" paddingX={1} width="100%">
|
||||
<Text color="#7C3AED">❯ </Text>
|
||||
<TextInput
|
||||
value={input}
|
||||
onChange={handleChange}
|
||||
onSubmit={handleSubmit}
|
||||
placeholder='Enter a command or question...'
|
||||
placeholder="Enter a command or question..."
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Show command suggestions */}
|
||||
{showSuggestions && filteredCommands.length > 0 && (
|
||||
<Box flexDirection='column' marginTop={1} paddingX={1}>
|
||||
<Text color='#7C3AED' bold>
|
||||
<Box flexDirection="column" marginTop={1} paddingX={1}>
|
||||
<Text color="#7C3AED" bold>
|
||||
Available Commands:
|
||||
</Text>
|
||||
{filteredCommands.map((cmd, index) => (
|
||||
|
@ -194,21 +193,21 @@ function AuthPrompt({ onAuth }: { onAuth: (creds: Credentials) => void }) {
|
|||
return (
|
||||
<Box paddingX={2}>
|
||||
<Text>
|
||||
<Spinner type='dots' /> Validating your API key...
|
||||
<Spinner type="dots" /> Validating your API key...
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box flexDirection='column' paddingX={2}>
|
||||
<Box flexDirection="column" paddingX={2}>
|
||||
<Box marginBottom={1}>
|
||||
<Text>Let's get you connected to Buster.</Text>
|
||||
</Box>
|
||||
|
||||
{error && (
|
||||
<Box marginBottom={1}>
|
||||
<Text color='red'>❌ {error}</Text>
|
||||
<Text color="red">❌ {error}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
|
@ -216,13 +215,13 @@ function AuthPrompt({ onAuth }: { onAuth: (creds: Credentials) => void }) {
|
|||
<Text>Enter your API key: </Text>
|
||||
</Box>
|
||||
|
||||
<Box borderStyle='single' borderColor='#7C3AED' paddingX={1}>
|
||||
<Box borderStyle="single" borderColor="#7C3AED" paddingX={1}>
|
||||
<TextInput
|
||||
value={apiKey}
|
||||
onChange={setApiKey}
|
||||
onSubmit={handleSubmit}
|
||||
mask='*'
|
||||
placeholder='sk_...'
|
||||
mask="*"
|
||||
placeholder="sk_..."
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
@ -334,11 +333,11 @@ export function Main() {
|
|||
|
||||
if (checkingAuth) {
|
||||
return (
|
||||
<Box flexDirection='column'>
|
||||
<Box flexDirection="column">
|
||||
<WelcomeHeader />
|
||||
<Box paddingX={2}>
|
||||
<Text>
|
||||
<Spinner type='dots' /> Checking configuration...
|
||||
<Spinner type="dots" /> Checking configuration...
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -346,12 +345,12 @@ export function Main() {
|
|||
}
|
||||
|
||||
return (
|
||||
<Box flexDirection='column'>
|
||||
<Box flexDirection="column">
|
||||
<WelcomeHeader />
|
||||
|
||||
{/* Show command history if authenticated */}
|
||||
{isAuthenticated && commandHistory.length > 0 && (
|
||||
<Box flexDirection='column' paddingX={2} marginBottom={1}>
|
||||
<Box flexDirection="column" paddingX={2} marginBottom={1}>
|
||||
{commandHistory.slice(-5).map((cmd, idx) => (
|
||||
<Box key={`cmd-${idx}-${cmd}`}>
|
||||
<Text dimColor>❯ {cmd}</Text>
|
||||
|
|
|
@ -17,9 +17,9 @@ export function Welcome() {
|
|||
return (
|
||||
<Box paddingY={2} paddingX={2}>
|
||||
<Box marginRight={4}>
|
||||
<AnimatedLogo color='#7C3AED' />
|
||||
<AnimatedLogo color="#7C3AED" />
|
||||
</Box>
|
||||
<Box flexDirection='column' justifyContent='center'>
|
||||
<Box flexDirection="column" justifyContent="center">
|
||||
<Text bold>Welcome to Buster</Text>
|
||||
<Box marginTop={1}>
|
||||
<Text dimColor>Type / to use slash commands</Text>
|
||||
|
@ -34,7 +34,7 @@ export function Welcome() {
|
|||
<Text dimColor>/help for more</Text>
|
||||
</Box>
|
||||
<Box marginTop={2}>
|
||||
<Text color='#7C3AED'>"Run `buster` and fix all the errors"</Text>
|
||||
<Text color="#7C3AED">"Run `buster` and fix all the errors"</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Box, Text } from 'ink';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
// ASCII art for the Buster "b" logo - compact version
|
||||
const BUSTER_LOGO_FRAMES = [
|
||||
|
@ -84,7 +84,7 @@ export function AnimatedLogo({ color = '#7C3AED' }: AnimatedLogoProps) {
|
|||
const currentFrame = BUSTER_LOGO_FRAMES[opacity];
|
||||
|
||||
return (
|
||||
<Box flexDirection='column' alignItems='center'>
|
||||
<Box flexDirection="column" alignItems="center">
|
||||
<Text color={color}>{currentFrame}</Text>
|
||||
</Box>
|
||||
);
|
||||
|
|
|
@ -14,8 +14,8 @@ export function BusterBanner({ showSubtitle = true, inline = false }: BannerProp
|
|||
const content = (
|
||||
<>
|
||||
<Box>
|
||||
<Text color='#7C3AED'>
|
||||
<BigText text='BUSTER' font='block' />
|
||||
<Text color="#7C3AED">
|
||||
<BigText text="BUSTER" font="block" />
|
||||
</Text>
|
||||
</Box>
|
||||
{showSubtitle && (
|
||||
|
@ -28,12 +28,12 @@ export function BusterBanner({ showSubtitle = true, inline = false }: BannerProp
|
|||
|
||||
// For inline mode (root command), don't add padding
|
||||
if (inline) {
|
||||
return <Box flexDirection='column'>{content}</Box>;
|
||||
return <Box flexDirection="column">{content}</Box>;
|
||||
}
|
||||
|
||||
// For centered mode (init, deploy commands), add padding and center
|
||||
return (
|
||||
<Box paddingY={2} paddingX={2} flexDirection='column' alignItems='center'>
|
||||
<Box paddingY={2} paddingX={2} flexDirection="column" alignItems="center">
|
||||
{content}
|
||||
</Box>
|
||||
);
|
||||
|
|
|
@ -37,7 +37,7 @@ export function Spinner({ label = 'Loading', type = 'dots' }: SpinnerProps) {
|
|||
}, [spinner]);
|
||||
|
||||
return (
|
||||
<Text color='cyan'>
|
||||
<Text color="cyan">
|
||||
{spinner.frames[frame]} {label}
|
||||
</Text>
|
||||
);
|
||||
|
|
7789
pnpm-lock.yaml
7789
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue