@agentuity/cli
Advanced tools
+43
-2
@@ -11,4 +11,24 @@ #!/usr/bin/env bun | ||
| import { checkLegacyCLI } from '../src/legacy-check'; | ||
| import type { LogLevel } from '../src/types'; | ||
| import type { CommandContext, LogLevel } from '../src/types'; | ||
| // Cleanup TTY state before exit | ||
| function cleanupAndExit() { | ||
| if (process.stdin.isTTY) { | ||
| process.stdin.setRawMode(false); | ||
| process.stdout.write('\x1B[?25h'); // Restore cursor | ||
| } | ||
| process.exitCode = 0; | ||
| process.exit(0); | ||
| } | ||
| // Handle Ctrl+C gracefully | ||
| process.once('SIGINT', () => { | ||
| console.log('\n'); | ||
| cleanupAndExit(); | ||
| }); | ||
| process.once('SIGTERM', () => { | ||
| cleanupAndExit(); | ||
| }); | ||
| validateRuntime(); | ||
@@ -65,3 +85,3 @@ | ||
| const commands = await discoverCommands(); | ||
| await registerCommands(program, commands, ctx); | ||
| await registerCommands(program, commands, ctx as unknown as CommandContext); | ||
@@ -71,4 +91,25 @@ try { | ||
| } catch (error) { | ||
| // Don't log error if it's from Ctrl+C, user cancellation, or signal termination | ||
| if (error instanceof Error) { | ||
| const msg = error.message.toLowerCase(); | ||
| if ( | ||
| msg.includes('sigint') || | ||
| msg.includes('sigterm') || | ||
| msg.includes('user force closed') || | ||
| msg.includes('cancelled') || // UK | ||
| msg.includes('canceled') || // US | ||
| msg === '' | ||
| ) { | ||
| process.exit(0); | ||
| } | ||
| if ('name' in error && error.name === 'AbortError') { | ||
| process.exit(0); | ||
| } | ||
| } | ||
| // Also exit cleanly if error is empty/undefined (user cancellation) | ||
| if (!error) { | ||
| process.exit(0); | ||
| } | ||
| logger.error('CLI error:', error); | ||
| process.exit(1); | ||
| } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmd/dev/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,OAAO,qCA2ElB,CAAC"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmd/dev/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,OAAO,qCAyElB,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/cmd/project/create.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,uBAAuB,wCA8ClC,CAAC"} | ||
| {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/cmd/project/create.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,uBAAuB,wCA+ClC,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../../src/cmd/project/download.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,UAAU,eAAe;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,YAAY;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA6E9E;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA8CvE"} | ||
| {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../../src/cmd/project/download.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,UAAU,eAAe;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,YAAY;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CACf;AAsBD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD9E;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCvE"} |
| import type { Logger } from '@/logger'; | ||
| interface CreateFlowOptions { | ||
| projectName?: string; | ||
| dir?: string; | ||
| template?: string; | ||
@@ -5,0 +6,0 @@ templateDir?: string; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"template-flow.d.ts","sourceRoot":"","sources":["../../../src/cmd/project/template-flow.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAKvC,UAAU,iBAAiB;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+I7E"} | ||
| {"version":3,"file":"template-flow.d.ts","sourceRoot":"","sources":["../../../src/cmd/project/template-flow.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAMvC,UAAU,iBAAiB;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0J7E"} |
+1
-1
@@ -1,2 +0,2 @@ | ||
| export declare function playSound(): Promise<void>; | ||
| export declare function playSound(): void; | ||
| //# sourceMappingURL=sound.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"sound.d.ts","sourceRoot":"","sources":["../src/sound.ts"],"names":[],"mappings":"AAEA,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAsB/C"} | ||
| {"version":3,"file":"sound.d.ts","sourceRoot":"","sources":["../src/sound.ts"],"names":[],"mappings":"AAEA,wBAAgB,SAAS,IAAI,IAAI,CAoChC"} |
+1
-1
@@ -20,3 +20,3 @@ /** | ||
| */ | ||
| export declare function warning(message: string): void; | ||
| export declare function warning(message: string, asError?: boolean): void; | ||
| /** | ||
@@ -23,0 +23,0 @@ * Print an info message with a cyan info icon |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"} |
+1
-1
| { | ||
| "name": "@agentuity/cli", | ||
| "version": "0.0.11", | ||
| "version": "0.0.12", | ||
| "type": "module", | ||
@@ -5,0 +5,0 @@ "main": "./src/index.ts", |
@@ -38,5 +38,3 @@ import { createCommand } from '@/types'; | ||
| tui.newline(); | ||
| tui.info('Starting development server...'); | ||
| tui.newline(); | ||
@@ -43,0 +41,0 @@ // Use shell to run in a process group for proper cleanup |
@@ -9,7 +9,7 @@ import type { SubcommandDefinition } from '../../types'; | ||
| async handler() { | ||
| handler() { | ||
| tui.info('Playing completion sound...'); | ||
| await playSound(); | ||
| playSound(); | ||
| tui.success('Sound played!'); | ||
| }, | ||
| }; |
@@ -42,2 +42,3 @@ import { createSubcommand } from '@/types'; | ||
| projectName: opts.name, | ||
| dir: opts.dir, | ||
| template: opts.template, | ||
@@ -44,0 +45,0 @@ templateDir: opts.templateDir, |
@@ -1,6 +0,7 @@ | ||
| import { join } from 'node:path'; | ||
| import { join, resolve } from 'node:path'; | ||
| import { existsSync, mkdirSync, renameSync, readdirSync, cpSync, rmSync } from 'node:fs'; | ||
| import { homedir } from 'node:os'; | ||
| import { pipeline } from 'node:stream/promises'; | ||
| import { createGunzip } from 'node:zlib'; | ||
| import { extract } from 'tar-fs'; | ||
| import { extract, type Headers } from 'tar-fs'; | ||
| import type { Logger } from '@/logger'; | ||
@@ -30,2 +31,22 @@ import * as tui from '@/tui'; | ||
| async function cleanup(sourceDir: string, dest: string) { | ||
| if (!existsSync(sourceDir)) { | ||
| throw new Error(`Template directory not found: ${sourceDir}`); | ||
| } | ||
| tui.spinner(`📦 Copying template from ${sourceDir}...`, async () => { | ||
| // Copy all files from source to dest | ||
| const files = readdirSync(sourceDir); | ||
| for (const file of files) { | ||
| cpSync(join(sourceDir, file), join(dest, file), { recursive: true }); | ||
| } | ||
| // Rename gitignore -> .gitignore | ||
| const gi = join(dest, 'gitignore'); | ||
| if (existsSync(gi)) { | ||
| renameSync(gi, join(dest, '.gitignore')); | ||
| } | ||
| }); | ||
| } | ||
| export async function downloadTemplate(options: DownloadOptions): Promise<void> { | ||
@@ -38,3 +59,2 @@ const { dest, template, templateDir, templateBranch } = options; | ||
| if (templateDir) { | ||
| const { resolve } = await import('node:path'); | ||
| const sourceDir = resolve(join(templateDir, template.directory)); | ||
@@ -46,17 +66,3 @@ | ||
| tui.info(`📦 Copying template from ${sourceDir}...`); | ||
| // Copy all files from source to dest | ||
| const files = readdirSync(sourceDir); | ||
| for (const file of files) { | ||
| cpSync(join(sourceDir, file), join(dest, file), { recursive: true }); | ||
| } | ||
| // Rename gitignore -> .gitignore | ||
| const gi = join(dest, 'gitignore'); | ||
| if (existsSync(gi)) { | ||
| renameSync(gi, join(dest, '.gitignore')); | ||
| } | ||
| return; | ||
| return cleanup(sourceDir, dest); | ||
| } | ||
@@ -80,2 +86,3 @@ | ||
| // Extract only the template directory from tarball | ||
| const prefix = `sdk-${branch}/${templatePath}/`; | ||
| await pipeline( | ||
@@ -85,10 +92,6 @@ stream, | ||
| extract(tempDir, { | ||
| map: (header) => { | ||
| const prefix = `sdk-${branch}/${templatePath}/`; | ||
| if (header.name.startsWith(prefix)) { | ||
| header.name = header.name.substring(prefix.length); | ||
| return header; | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| return null as any; | ||
| filter: (name: string) => name.startsWith(prefix), | ||
| map: (header: Headers) => { | ||
| header.name = header.name.substring(prefix.length); | ||
| return header; | ||
| }, | ||
@@ -100,14 +103,10 @@ }) | ||
| // Move files from temp to dest | ||
| const files = readdirSync(tempDir); | ||
| for (const file of files) { | ||
| cpSync(join(tempDir, file), join(dest, file), { recursive: true }); | ||
| await cleanup(tempDir, dest); | ||
| // Extra safety: refuse to delete root or home directories | ||
| const home = homedir(); | ||
| if (tempDir === '/' || tempDir === home) { | ||
| throw new Error(`Refusing to delete protected path: ${tempDir}`); | ||
| } | ||
| rmSync(tempDir, { recursive: true, force: true }); | ||
| // Rename gitignore -> .gitignore | ||
| const gi = join(dest, 'gitignore'); | ||
| if (existsSync(gi)) { | ||
| renameSync(gi, join(dest, '.gitignore')); | ||
| } | ||
| } | ||
@@ -118,4 +117,2 @@ | ||
| process.chdir(dest); | ||
| // Replace {{PROJECT_NAME}} in files | ||
@@ -125,16 +122,2 @@ tui.info(`🔧 Setting up ${projectName}...`); | ||
| // Run setup.ts if it exists (legacy) | ||
| if (await Bun.file('./setup.ts').exists()) { | ||
| await tui.spinner({ | ||
| message: 'Running setup script...', | ||
| callback: async () => { | ||
| const proc = Bun.spawn(['bun', './setup.ts'], { stdio: ['pipe', 'pipe', 'pipe'] }); | ||
| const exitCode = await proc.exited; | ||
| if (exitCode !== 0) { | ||
| logger.error('Setup script failed'); | ||
| } | ||
| }, | ||
| }); | ||
| } | ||
| // Install dependencies | ||
@@ -144,2 +127,3 @@ if (!noInstall) { | ||
| command: 'bun install', | ||
| cwd: dest, | ||
| cmd: ['bun', 'install'], | ||
@@ -157,2 +141,3 @@ clearOnSuccess: true, | ||
| command: 'bun run build', | ||
| cwd: dest, | ||
| cmd: ['bun', 'run', 'build'], | ||
@@ -159,0 +144,0 @@ clearOnSuccess: true, |
| import { basename, resolve } from 'node:path'; | ||
| import { existsSync, readdirSync, rmSync } from 'node:fs'; | ||
| import { cwd } from 'node:process'; | ||
| import { homedir } from 'node:os'; | ||
| import enquirer from 'enquirer'; | ||
| import type { Logger } from '@/logger'; | ||
| import * as tui from '@/tui'; | ||
| import { playSound } from '@/sound'; | ||
| import { fetchTemplates, type TemplateInfo } from './templates'; | ||
@@ -11,2 +14,3 @@ import { downloadTemplate, setupProject } from './download'; | ||
| projectName?: string; | ||
| dir?: string; | ||
| template?: string; | ||
@@ -24,2 +28,3 @@ templateDir?: string; | ||
| projectName: initialProjectName, | ||
| dir: targetDir, | ||
| template: initialTemplate, | ||
@@ -69,3 +74,9 @@ templateDir, | ||
| // Step 4: Determine destination directory | ||
| const dest = dirName === '.' ? process.cwd() : resolve(process.cwd(), dirName); | ||
| // Expand ~ to home directory | ||
| let expandedTargetDir = targetDir; | ||
| if (expandedTargetDir && expandedTargetDir.startsWith('~')) { | ||
| expandedTargetDir = expandedTargetDir.replace(/^~/, homedir()); | ||
| } | ||
| const baseDir = expandedTargetDir ? resolve(expandedTargetDir) : process.cwd(); | ||
| const dest = dirName === '.' ? baseDir : resolve(baseDir, dirName); | ||
| const destExists = existsSync(dest); | ||
@@ -77,3 +88,3 @@ const destEmpty = destExists ? readdirSync(dest).length === 0 : true; | ||
| if (process.stdin.isTTY && !skipPrompts) { | ||
| tui.warning(`Directory ${dirName} already exists and is not empty.\n`); | ||
| tui.warning(`Directory ${dest} already exists and is not empty.`, true); | ||
| const response = await enquirer.prompt<{ overwrite: boolean }>({ | ||
@@ -91,7 +102,12 @@ type: 'confirm', | ||
| // Delete the existing directory | ||
| // Extra safety: refuse to delete root or home directories | ||
| const home = homedir(); | ||
| if (dest === '/' || dest === home) { | ||
| logger.fatal(`Refusing to delete protected path: ${dest}`); | ||
| return; | ||
| } | ||
| rmSync(dest, { recursive: true, force: true }); | ||
| tui.success(`Deleted ${dirName}\n`); | ||
| tui.success(`Deleted ${dest}\n`); | ||
| } else { | ||
| logger.fatal(`Directory ${dirName} already exists and is not empty.`); | ||
| logger.fatal(`Directory ${dest} already exists and is not empty.`, true); | ||
| } | ||
@@ -102,5 +118,4 @@ } | ||
| if (!skipPrompts) { | ||
| const displayPath = dirName === '.' ? basename(dest) : dirName; | ||
| tui.info(`📁 Project: ${tui.bold(projectName)}`); | ||
| tui.info(`📂 Directory: ${tui.bold(displayPath)}\n`); | ||
| tui.info(`📂 Directory: ${tui.bold(dest)}\n`); | ||
| } | ||
@@ -161,10 +176,10 @@ | ||
| if (dirName !== '.') { | ||
| const dirDisplay = cwd() == targetDir ? basename(dirName) : dest; | ||
| tui.newline(); | ||
| console.log(` 1. ${tui.bold(`cd ${dirName}`)}`); | ||
| console.log(` 1. ${tui.bold(`cd ${dirDisplay}`)}`); | ||
| console.log(` 2. ${tui.bold('bun run dev')}`); | ||
| } else { | ||
| console.log(` 1. ${tui.bold('bun run dev')}`); | ||
| console.log(` ${tui.bold('bun run dev')}`); | ||
| } | ||
| tui.newline(); | ||
| console.log(`Your agents will be running at ${tui.link('http://localhost:3000')}`); | ||
| playSound(); | ||
| } | ||
@@ -171,0 +186,0 @@ |
+2
-2
@@ -1,2 +0,2 @@ | ||
| import { Transform } from 'node:stream'; | ||
| import { Transform, Readable } from 'node:stream'; | ||
| import * as tui from './tui'; | ||
@@ -51,3 +51,3 @@ | ||
| // Pipe the response through the progress tracker | ||
| const responseStream = response.body as unknown as NodeJS.ReadableStream; | ||
| const responseStream = Readable.fromWeb(response.body as unknown as ReadableStream); | ||
| responseStream.pipe(progressStream); | ||
@@ -54,0 +54,0 @@ |
+27
-13
@@ -1,25 +0,39 @@ | ||
| import { $ } from 'bun'; | ||
| import { join } from 'node:path'; | ||
| export async function playSound(): Promise<void> { | ||
| export function playSound(): void { | ||
| const platform = process.platform; | ||
| let result; | ||
| let command: string[]; | ||
| switch (platform) { | ||
| case 'darwin': | ||
| result = await $`afplay /System/Library/Sounds/Glass.aiff`.quiet().nothrow(); | ||
| case 'darwin': { | ||
| const items = [ | ||
| 'Blow.aiff', | ||
| 'Bottle.aiff', | ||
| 'Frog.aiff', | ||
| 'Funk.aiff', | ||
| 'Glass.aiff', | ||
| 'Hero.aiff', | ||
| 'Morse.aiff', | ||
| 'Ping.aiff', | ||
| 'Pop.aiff', | ||
| 'Purr.aiff', | ||
| 'Sosumi.aiff', | ||
| ] as const; | ||
| const file = items[Math.floor(Math.random() * items.length)]; | ||
| command = ['afplay', join('/System/Library/Sounds', file)]; | ||
| break; | ||
| } | ||
| case 'linux': | ||
| result = await $`paplay /usr/share/sounds/freedesktop/stereo/complete.oga` | ||
| .quiet() | ||
| .nothrow(); | ||
| command = ['paplay', '/usr/share/sounds/freedesktop/stereo/complete.oga']; | ||
| break; | ||
| case 'win32': | ||
| result = await $`rundll32 user32.dll,MessageBeep 0x00000040`.quiet().nothrow(); | ||
| command = ['rundll32', 'user32.dll,MessageBeep', '0x00000040']; | ||
| break; | ||
| default: | ||
| return; | ||
| } | ||
| // Fallback to terminal bell if command failed or platform unsupported | ||
| if (!result || result.exitCode !== 0) { | ||
| process.stdout.write('\u0007'); | ||
| } | ||
| Bun.spawn(command, { | ||
| stdio: ['ignore', 'ignore', 'ignore'], | ||
| }).unref(); | ||
| } |
+5
-3
@@ -88,4 +88,4 @@ /** | ||
| */ | ||
| export function warning(message: string): void { | ||
| const color = getColor('warning'); | ||
| export function warning(message: string, asError = false): void { | ||
| const color = asError ? getColor('error') : getColor('warning'); | ||
| const reset = COLORS.reset; | ||
@@ -809,3 +809,5 @@ console.log(`${color}${ICONS.warning} ${message}${reset}`); | ||
| // Show compact success: ✓ command | ||
| process.stdout.write(`\r\x1b[K${green}${ICONS.success}${reset} ${cmdColor}${displayCmd}${reset}\n`); | ||
| process.stdout.write( | ||
| `\r\x1b[K${green}${ICONS.success}${reset} ${cmdColor}${displayCmd}${reset}\n` | ||
| ); | ||
| } else { | ||
@@ -812,0 +814,0 @@ // Determine how many lines to show in final output |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 16 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 16 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
222578
0.65%5254
1.08%