@agentuity/cli 1.0.44 → 1.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.ts +189 -143
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +45 -2
- package/dist/cli.js.map +1 -1
- package/dist/cmd/cloud/sandbox/cp.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/cp.js +69 -13
- package/dist/cmd/cloud/sandbox/cp.js.map +1 -1
- package/dist/cmd/cloud/sandbox/events.d.ts +3 -0
- package/dist/cmd/cloud/sandbox/events.d.ts.map +1 -0
- package/dist/cmd/cloud/sandbox/events.js +92 -0
- package/dist/cmd/cloud/sandbox/events.js.map +1 -0
- package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/exec.js +22 -0
- package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
- package/dist/cmd/cloud/sandbox/execution/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/execution/get.js +5 -0
- package/dist/cmd/cloud/sandbox/execution/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/execution/list.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/execution/list.js +12 -7
- package/dist/cmd/cloud/sandbox/execution/list.js.map +1 -1
- package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/get.js +1 -0
- package/dist/cmd/cloud/sandbox/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/index.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/index.js +2 -0
- package/dist/cmd/cloud/sandbox/index.js.map +1 -1
- package/dist/cmd/cloud/sandbox/util.js +1 -1
- package/dist/cmd/cloud/sandbox/util.js.map +1 -1
- package/package.json +6 -6
- package/src/cli.ts +56 -2
- package/src/cmd/cloud/sandbox/cp.ts +89 -14
- package/src/cmd/cloud/sandbox/events.ts +108 -0
- package/src/cmd/cloud/sandbox/exec.ts +27 -0
- package/src/cmd/cloud/sandbox/execution/get.ts +5 -0
- package/src/cmd/cloud/sandbox/execution/list.ts +13 -14
- package/src/cmd/cloud/sandbox/get.ts +1 -0
- package/src/cmd/cloud/sandbox/index.ts +2 -0
- package/src/cmd/cloud/sandbox/util.ts +1 -1
package/bin/cli.ts
CHANGED
|
@@ -22,7 +22,7 @@ import type { CommandContext, LogLevel } from '../src/types';
|
|
|
22
22
|
import { generateCLISchema } from '../src/schema-generator';
|
|
23
23
|
import { generateAIHelp } from '../src/ai-help';
|
|
24
24
|
import { setOutputOptions } from '../src/output';
|
|
25
|
-
import type { GlobalOptions } from '../src/types';
|
|
25
|
+
import type { Config, GlobalOptions } from '../src/types';
|
|
26
26
|
import { ensureBunOnPath } from '../src/bun-path';
|
|
27
27
|
import { checkForUpdates } from '../src/version-check';
|
|
28
28
|
import { closeDatabase } from '../src/cache';
|
|
@@ -154,151 +154,165 @@ if (!hasHelp) {
|
|
|
154
154
|
}
|
|
155
155
|
const earlyOpts = program.opts();
|
|
156
156
|
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
157
|
+
// Set JSON error format early, BEFORE any code that might throw,
|
|
158
|
+
// so that startup failures also use the JSON error formatter.
|
|
159
|
+
// Note: --error-format defaults to 'text', so we must check !== 'json'
|
|
160
|
+
// rather than !earlyOpts.errorFormat (which would always be false).
|
|
161
|
+
if (earlyOpts.json && earlyOpts.errorFormat !== 'json') {
|
|
162
|
+
earlyOpts.errorFormat = 'json';
|
|
164
163
|
}
|
|
165
|
-
|
|
164
|
+
setOutputOptions(earlyOpts as GlobalOptions);
|
|
166
165
|
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
// Variables that may or may not be initialized by the time an error occurs.
|
|
167
|
+
// Hoisted here so the centralized error handler can reference them.
|
|
168
|
+
let config: Config | null | undefined;
|
|
169
|
+
let logger: ReturnType<typeof createCompositeLogger> | undefined;
|
|
171
170
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
// For help mode, parsedOperands is empty so we fall back to extracting from preprocessedArgs.
|
|
187
|
-
const commandArgs = hasHelp
|
|
188
|
-
? preprocessedArgs.filter((arg) => !arg.startsWith('-'))
|
|
189
|
-
: parsedOperands;
|
|
190
|
-
|
|
191
|
-
// Check if we should skip internal logging based on command or help flags
|
|
192
|
-
// We need to check the commands first to see if skipInternalLogging is set
|
|
193
|
-
const earlyCommandName = commandArgs[0];
|
|
194
|
-
const earlySubcommandName = commandArgs[1];
|
|
195
|
-
const commands = await discoverCommands();
|
|
196
|
-
const earlyCommandDef = commands.find((cmd) => cmd.name === earlyCommandName);
|
|
197
|
-
const earlySubcommandDef = earlySubcommandName
|
|
198
|
-
? earlyCommandDef?.subcommands?.find((sub) => sub.name === earlySubcommandName)
|
|
199
|
-
: undefined;
|
|
200
|
-
|
|
201
|
-
// Skip internal logging if:
|
|
202
|
-
// 1. Help flag is present
|
|
203
|
-
// 2. No command provided (shows help)
|
|
204
|
-
// 3. Command has skipInternalLogging set
|
|
205
|
-
// 4. Subcommand has skipInternalLogging set
|
|
206
|
-
const shouldSkipInternalLogging =
|
|
207
|
-
hasHelp ||
|
|
208
|
-
commandArgs.length === 0 ||
|
|
209
|
-
earlyCommandDef?.skipInternalLogging ||
|
|
210
|
-
earlySubcommandDef?.skipInternalLogging;
|
|
211
|
-
|
|
212
|
-
// Create internal logger for trace/debug logging (always at trace level)
|
|
213
|
-
const internalLogger = createInternalLogger(version, getPackageName());
|
|
214
|
-
|
|
215
|
-
// Disable or initialize the internal logger based on command flags
|
|
216
|
-
if (shouldSkipInternalLogging) {
|
|
217
|
-
internalLogger.disable();
|
|
218
|
-
} else {
|
|
219
|
-
const command = commandArgs.length > 0 ? commandArgs.join(' ') : 'help';
|
|
220
|
-
// Extract --dir from argv if present (for project context in logs)
|
|
221
|
-
const projectDirArg = getProjectDirFromArgs();
|
|
222
|
-
// Filter out command/subcommand names from args by position, not by value.
|
|
223
|
-
// The first N entries of preprocessedArgs that are not flags are the command tokens.
|
|
224
|
-
// Skip the leading command tokens to get only the actual arguments.
|
|
225
|
-
let commandTokensToSkip = commandArgs.length;
|
|
226
|
-
const filteredArgs: string[] = [];
|
|
227
|
-
for (const arg of preprocessedArgs) {
|
|
228
|
-
if (commandTokensToSkip > 0 && !arg.startsWith('-') && commandArgs.includes(arg)) {
|
|
229
|
-
commandTokensToSkip--;
|
|
230
|
-
} else {
|
|
231
|
-
filteredArgs.push(arg);
|
|
171
|
+
/**
|
|
172
|
+
* Main startup and command execution.
|
|
173
|
+
*
|
|
174
|
+
* Wrapped in a function so that the entire boot sequence (config loading,
|
|
175
|
+
* command discovery, update checks, command registration, and execution)
|
|
176
|
+
* is enclosed in a single try/catch whose error handler respects --json.
|
|
177
|
+
*/
|
|
178
|
+
async function main() {
|
|
179
|
+
// Detect or override terminal color scheme
|
|
180
|
+
let colorScheme = await detectColorScheme();
|
|
181
|
+
if (earlyOpts.colorScheme === 'light' || earlyOpts.colorScheme === 'dark') {
|
|
182
|
+
colorScheme = earlyOpts.colorScheme;
|
|
183
|
+
if (process.env.DEBUG_COLORS) {
|
|
184
|
+
console.log(`[DEBUG] Using --color-scheme=${colorScheme} flag`);
|
|
232
185
|
}
|
|
233
186
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
// Set session ID in environment so forked child processes can share the same log file
|
|
237
|
-
process.env.AGENTUITY_INTERNAL_SESSION_ID = internalLogger.getSessionId();
|
|
187
|
+
setColorScheme(colorScheme);
|
|
238
188
|
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
internalLogger.setDetectedAgent(detectedAgent);
|
|
189
|
+
// Debug: show detected color scheme
|
|
190
|
+
if (process.env.DEBUG_COLORS) {
|
|
191
|
+
console.log(`[DEBUG] Color scheme: ${colorScheme}`);
|
|
243
192
|
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Create composite logger that writes to both console and internal log
|
|
247
|
-
const logger = createCompositeLogger(consoleLogger, internalLogger);
|
|
248
193
|
|
|
249
|
-
//
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
194
|
+
// Create logger instance with global options
|
|
195
|
+
// In quiet or JSON mode, suppress most logging
|
|
196
|
+
const effectiveLogLevel =
|
|
197
|
+
earlyOpts.quiet || earlyOpts.json ? 'error' : (earlyOpts.logLevel as LogLevel) || 'info';
|
|
198
|
+
const consoleLogger = new ConsoleLogger(
|
|
199
|
+
effectiveLogLevel,
|
|
200
|
+
earlyOpts.logTimestamp || false,
|
|
201
|
+
colorScheme
|
|
202
|
+
);
|
|
203
|
+
consoleLogger.setShowPrefix(earlyOpts.logPrefix !== false);
|
|
204
|
+
|
|
205
|
+
// Use the parsed operands from Commander.js parseOptions() which correctly
|
|
206
|
+
// separates command names from option values. parsedOperands contains only
|
|
207
|
+
// positional arguments (command/subcommand names), not flag values.
|
|
208
|
+
// For help mode, parsedOperands is empty so we fall back to extracting from preprocessedArgs.
|
|
209
|
+
const commandArgs = hasHelp
|
|
210
|
+
? preprocessedArgs.filter((arg) => !arg.startsWith('-'))
|
|
211
|
+
: parsedOperands;
|
|
212
|
+
|
|
213
|
+
// Check if we should skip internal logging based on command or help flags
|
|
214
|
+
// We need to check the commands first to see if skipInternalLogging is set
|
|
215
|
+
const earlyCommandName = commandArgs[0];
|
|
216
|
+
const earlySubcommandName = commandArgs[1];
|
|
217
|
+
const commands = await discoverCommands();
|
|
218
|
+
const earlyCommandDef = commands.find((cmd) => cmd.name === earlyCommandName);
|
|
219
|
+
const earlySubcommandDef = earlySubcommandName
|
|
220
|
+
? earlyCommandDef?.subcommands?.find((sub) => sub.name === earlySubcommandName)
|
|
221
|
+
: undefined;
|
|
222
|
+
|
|
223
|
+
// Skip internal logging if:
|
|
224
|
+
// 1. Help flag is present
|
|
225
|
+
// 2. No command provided (shows help)
|
|
226
|
+
// 3. Command has skipInternalLogging set
|
|
227
|
+
// 4. Subcommand has skipInternalLogging set
|
|
228
|
+
const shouldSkipInternalLogging =
|
|
229
|
+
hasHelp ||
|
|
230
|
+
commandArgs.length === 0 ||
|
|
231
|
+
earlyCommandDef?.skipInternalLogging ||
|
|
232
|
+
earlySubcommandDef?.skipInternalLogging;
|
|
233
|
+
|
|
234
|
+
// Create internal logger for trace/debug logging (always at trace level)
|
|
235
|
+
const internalLogger = createInternalLogger(version, getPackageName());
|
|
236
|
+
|
|
237
|
+
// Disable or initialize the internal logger based on command flags
|
|
238
|
+
if (shouldSkipInternalLogging) {
|
|
239
|
+
internalLogger.disable();
|
|
240
|
+
} else {
|
|
241
|
+
const command = commandArgs.length > 0 ? commandArgs.join(' ') : 'help';
|
|
242
|
+
// Extract --dir from argv if present (for project context in logs)
|
|
243
|
+
const projectDirArg = getProjectDirFromArgs();
|
|
244
|
+
// Filter out command/subcommand names from args by position, not by value.
|
|
245
|
+
// The first N entries of preprocessedArgs that are not flags are the command tokens.
|
|
246
|
+
// Skip the leading command tokens to get only the actual arguments.
|
|
247
|
+
let commandTokensToSkip = commandArgs.length;
|
|
248
|
+
const filteredArgs: string[] = [];
|
|
249
|
+
for (const arg of preprocessedArgs) {
|
|
250
|
+
if (commandTokensToSkip > 0 && !arg.startsWith('-') && commandArgs.includes(arg)) {
|
|
251
|
+
commandTokensToSkip--;
|
|
252
|
+
} else {
|
|
253
|
+
filteredArgs.push(arg);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
internalLogger.init(command, filteredArgs, undefined, projectDirArg);
|
|
253
257
|
|
|
254
|
-
|
|
258
|
+
// Set session ID in environment so forked child processes can share the same log file
|
|
259
|
+
process.env.AGENTUITY_INTERNAL_SESSION_ID = internalLogger.getSessionId();
|
|
255
260
|
|
|
256
|
-
//
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
+
// Set detected agent in session logs
|
|
262
|
+
const detectedAgent = getExecutingAgent();
|
|
263
|
+
if (detectedAgent) {
|
|
264
|
+
internalLogger.setDetectedAgent(detectedAgent);
|
|
265
|
+
}
|
|
261
266
|
}
|
|
262
|
-
} catch {
|
|
263
|
-
// Ignore auth errors - user might not be logged in
|
|
264
|
-
}
|
|
265
267
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
logger,
|
|
269
|
-
options: earlyOpts,
|
|
270
|
-
getExecutingAgent,
|
|
271
|
-
};
|
|
268
|
+
// Create composite logger that writes to both console and internal log
|
|
269
|
+
logger = createCompositeLogger(consoleLogger, internalLogger);
|
|
272
270
|
|
|
273
|
-
// Set
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
setOutputOptions(earlyOpts as GlobalOptions);
|
|
271
|
+
// Set version check skip flag from CLI option
|
|
272
|
+
if (earlyOpts.skipVersionCheck) {
|
|
273
|
+
process.env.AGENTUITY_SKIP_VERSION_CHECK = '1';
|
|
274
|
+
}
|
|
279
275
|
|
|
280
|
-
|
|
281
|
-
// Find the command being run to check if it opts out of upgrade check
|
|
282
|
-
// Use parsedOperands from Commander's parseOptions which correctly separates
|
|
283
|
-
// command names from option values (e.g., "--file myfile" won't treat "myfile" as a command)
|
|
284
|
-
// Also find the subcommand if present (e.g., "auth whoami" -> command="auth", subcommand="whoami")
|
|
285
|
-
const commandName = parsedOperands[0];
|
|
286
|
-
const subcommandName = parsedOperands[1];
|
|
287
|
-
const commandDef = commands.find((cmd) => cmd.name === commandName);
|
|
288
|
-
const subcommandDef = subcommandName
|
|
289
|
-
? commandDef?.subcommands?.find((sub) => sub.name === subcommandName)
|
|
290
|
-
: undefined;
|
|
276
|
+
config = await loadConfig(earlyOpts.config, false, earlyOpts.profile);
|
|
291
277
|
|
|
292
|
-
|
|
278
|
+
// Update internal logger with userId if available from auth (keychain or config)
|
|
279
|
+
try {
|
|
280
|
+
const auth = await getAuth();
|
|
281
|
+
if (auth?.userId) {
|
|
282
|
+
internalLogger.setUserId(auth.userId);
|
|
283
|
+
}
|
|
284
|
+
} catch {
|
|
285
|
+
// Ignore auth errors - user might not be logged in
|
|
286
|
+
}
|
|
293
287
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
288
|
+
const ctx = {
|
|
289
|
+
config,
|
|
290
|
+
logger,
|
|
291
|
+
options: earlyOpts,
|
|
292
|
+
getExecutingAgent,
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// Check for updates before running commands (may upgrade and re-exec)
|
|
296
|
+
// Find the command being run to check if it opts out of upgrade check
|
|
297
|
+
// Use parsedOperands from Commander's parseOptions which correctly separates
|
|
298
|
+
// command names from option values (e.g., "--file myfile" won't treat "myfile" as a command)
|
|
299
|
+
// Also find the subcommand if present (e.g., "auth whoami" -> command="auth", subcommand="whoami")
|
|
300
|
+
const commandName = parsedOperands[0];
|
|
301
|
+
const subcommandName = parsedOperands[1];
|
|
302
|
+
const commandDef = commands.find((cmd) => cmd.name === commandName);
|
|
303
|
+
const subcommandDef = subcommandName
|
|
304
|
+
? commandDef?.subcommands?.find((sub) => sub.name === subcommandName)
|
|
305
|
+
: undefined;
|
|
306
|
+
|
|
307
|
+
await checkForUpdates(config, logger, earlyOpts, commandDef, subcommandDef, preprocessedArgs);
|
|
308
|
+
|
|
309
|
+
// Generate and store CLI schema globally for the schema command
|
|
310
|
+
const cliSchema = generateCLISchema(program, commands, version);
|
|
311
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
312
|
+
(global as any).__CLI_SCHEMA__ = cliSchema;
|
|
298
313
|
|
|
299
|
-
await registerCommands(program, commands, ctx as unknown as CommandContext);
|
|
314
|
+
await registerCommands(program, commands, ctx as unknown as CommandContext);
|
|
300
315
|
|
|
301
|
-
try {
|
|
302
316
|
await program.parseAsync(process.argv);
|
|
303
317
|
// Ensure clean exit after successful command execution.
|
|
304
318
|
// In TTY environments, process.stdin may keep the event loop alive
|
|
@@ -308,6 +322,10 @@ try {
|
|
|
308
322
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
309
323
|
const exit = (globalThis as any).AGENTUITY_PROCESS_EXIT || process.exit;
|
|
310
324
|
exit(0);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
try {
|
|
328
|
+
await main();
|
|
311
329
|
} catch (error) {
|
|
312
330
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
313
331
|
const exit = (globalThis as any).AGENTUITY_PROCESS_EXIT || process.exit;
|
|
@@ -369,19 +387,40 @@ try {
|
|
|
369
387
|
}
|
|
370
388
|
|
|
371
389
|
if (earlyOpts.errorFormat === 'json') {
|
|
372
|
-
|
|
373
|
-
|
|
390
|
+
let message = errorWithMessage?.message ?? String(error);
|
|
391
|
+
// Classify the error: treat as API_ERROR if it's a structured error
|
|
392
|
+
// OR if the error carries a numeric status/statusCode (e.g. ServiceException)
|
|
393
|
+
const hasStatus =
|
|
394
|
+
typeof error === 'object' &&
|
|
395
|
+
error !== null &&
|
|
396
|
+
(('status' in error && typeof (error as any).status === 'number') ||
|
|
397
|
+
('statusCode' in error && typeof (error as any).statusCode === 'number'));
|
|
398
|
+
const code =
|
|
399
|
+
isStructuredError(error) || hasStatus ? ErrorCode.API_ERROR : ErrorCode.INTERNAL_ERROR;
|
|
374
400
|
const details: Record<string, unknown> = {};
|
|
375
401
|
if (isStructuredError(error) && errorWithMessage._tag) {
|
|
376
402
|
details.tag = errorWithMessage._tag;
|
|
377
403
|
}
|
|
378
|
-
if (
|
|
379
|
-
|
|
380
|
-
error
|
|
381
|
-
|
|
382
|
-
typeof (error as any).
|
|
383
|
-
|
|
384
|
-
|
|
404
|
+
if (typeof error === 'object' && error !== null) {
|
|
405
|
+
// Support both error.status (APIErrorResponse) and error.statusCode (ServiceException)
|
|
406
|
+
if ('status' in error && typeof (error as any).status === 'number') {
|
|
407
|
+
details.status = (error as any).status;
|
|
408
|
+
} else if ('statusCode' in error && typeof (error as any).statusCode === 'number') {
|
|
409
|
+
details.status = (error as any).statusCode;
|
|
410
|
+
}
|
|
411
|
+
if ('sessionId' in error && (error as any).sessionId) {
|
|
412
|
+
details.sessionId = (error as any).sessionId;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
// Try to parse embedded JSON in API error messages
|
|
416
|
+
// API errors often have messages like: '{"success":false,"message":"not found: ..."}'
|
|
417
|
+
try {
|
|
418
|
+
const parsed = JSON.parse(message);
|
|
419
|
+
if (parsed && typeof parsed === 'object' && typeof parsed.message === 'string') {
|
|
420
|
+
message = parsed.message;
|
|
421
|
+
}
|
|
422
|
+
} catch {
|
|
423
|
+
// Not JSON, use message as-is
|
|
385
424
|
}
|
|
386
425
|
console.error(
|
|
387
426
|
formatErrorJSON(
|
|
@@ -389,13 +428,20 @@ try {
|
|
|
389
428
|
)
|
|
390
429
|
);
|
|
391
430
|
} else if (isStructuredError(error)) {
|
|
392
|
-
logger.error
|
|
431
|
+
// Use the composite logger if available; fall back to console.error
|
|
432
|
+
// if the error occurred before logger initialization completed
|
|
433
|
+
if (logger) {
|
|
434
|
+
logger.error(error);
|
|
435
|
+
} else {
|
|
436
|
+
console.error(String(error));
|
|
437
|
+
}
|
|
393
438
|
} else {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
439
|
+
const msg = errorWithMessage?.message ? errorWithMessage.message : String(error);
|
|
440
|
+
if (logger) {
|
|
441
|
+
logger.error('CLI error: %s %s', msg, error);
|
|
442
|
+
} else {
|
|
443
|
+
console.error(`CLI error: ${msg}`);
|
|
444
|
+
}
|
|
399
445
|
}
|
|
400
446
|
closeDatabase();
|
|
401
447
|
exit(1);
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EACX,iBAAiB,EAEjB,cAAc,EAEd,MAAM,EAGN,MAAM,EAGN,MAAM,SAAS,CAAC;AAWjB,OAAO,EAAE,KAAK,UAAU,EAAyB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EACX,iBAAiB,EAEjB,cAAc,EAEd,MAAM,EAGN,MAAM,EAGN,MAAM,SAAS,CAAC;AAWjB,OAAO,EAAE,KAAK,UAAU,EAAyB,MAAM,mBAAmB,CAAC;AA0d3E,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqSjE;AAkFD,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,CAAC;CAC3C;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAyJ3F;AAirCD,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,OAAO,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC,CA6Of"}
|
package/dist/cli.js
CHANGED
|
@@ -11,9 +11,9 @@ import * as tui from './tui';
|
|
|
11
11
|
import { parseArgsSchema, parseOptionsSchema, buildValidationInputAsync } from './schema-parser';
|
|
12
12
|
import { defaultProfileName, loadProjectConfig, saveProjectId, saveRegion } from './config';
|
|
13
13
|
import { APIClient, getAPIBaseURL, getAppBaseURL } from './api';
|
|
14
|
-
import { ErrorCode, ExitCode, createError, exitWithError } from './errors';
|
|
14
|
+
import { ErrorCode, ExitCode, createError, exitWithError, formatErrorJSON } from './errors';
|
|
15
15
|
import { getCommand } from './command-prefix';
|
|
16
|
-
import { isValidateMode, outputValidation } from './output';
|
|
16
|
+
import { getOutputOptions, isValidateMode, outputValidation, } from './output';
|
|
17
17
|
import { StructuredError } from '@agentuity/core';
|
|
18
18
|
import { setProgram } from './program-ref';
|
|
19
19
|
import { generateIntroPrompt } from './cmd/ai/intro';
|
|
@@ -413,6 +413,12 @@ export async function createCLI(version) {
|
|
|
413
413
|
// Handle unknown commands
|
|
414
414
|
program.on('command:*', (operands) => {
|
|
415
415
|
const unknownCommand = operands[0];
|
|
416
|
+
const opts = getOutputOptions();
|
|
417
|
+
if (opts?.json || opts?.errorFormat === 'json') {
|
|
418
|
+
console.error(formatErrorJSON(createError(ErrorCode.UNKNOWN_COMMAND, `unknown command '${unknownCommand}'`)));
|
|
419
|
+
process.exit(1);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
416
422
|
console.error(`error: unknown command '${unknownCommand}'`);
|
|
417
423
|
console.error();
|
|
418
424
|
const availableCommands = program.commands.map((cmd) => cmd.name());
|
|
@@ -426,13 +432,50 @@ export async function createCLI(version) {
|
|
|
426
432
|
console.error(`Run '${getCommand('--help')}' for usage information.`);
|
|
427
433
|
process.exit(1);
|
|
428
434
|
});
|
|
435
|
+
// Track whether a JSON error was already emitted by outputError
|
|
436
|
+
// so we can suppress Commander's help-after-error text in JSON mode
|
|
437
|
+
let jsonErrorEmitted = false;
|
|
429
438
|
// Custom error handling for argument/command parsing errors
|
|
430
439
|
program.configureOutput({
|
|
440
|
+
writeErr: (str) => {
|
|
441
|
+
// In JSON mode, suppress Commander's help-after-error text
|
|
442
|
+
// (we already emitted a structured JSON error in outputError)
|
|
443
|
+
const opts = getOutputOptions();
|
|
444
|
+
if (jsonErrorEmitted && (opts?.json || opts?.errorFormat === 'json')) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
process.stderr.write(str);
|
|
448
|
+
},
|
|
431
449
|
outputError: (str, write) => {
|
|
432
450
|
// Suppress "unknown option '--help'" error since we handle help flags specially
|
|
433
451
|
if (str.includes("unknown option '--help'")) {
|
|
434
452
|
return;
|
|
435
453
|
}
|
|
454
|
+
// In JSON mode, output structured JSON errors for all Commander parsing errors
|
|
455
|
+
const opts = getOutputOptions();
|
|
456
|
+
if (opts?.json || opts?.errorFormat === 'json') {
|
|
457
|
+
// Strip "error: " prefix and trailing newline for clean message
|
|
458
|
+
let message = str.replace(/^error:\s*/, '').replace(/\n$/, '');
|
|
459
|
+
let code = ErrorCode.INVALID_OPTION;
|
|
460
|
+
if (str.includes('unknown command') || str.includes('too many arguments')) {
|
|
461
|
+
code = ErrorCode.UNKNOWN_COMMAND;
|
|
462
|
+
}
|
|
463
|
+
else if (str.includes('missing required argument')) {
|
|
464
|
+
code = ErrorCode.MISSING_ARGUMENT;
|
|
465
|
+
}
|
|
466
|
+
// Extract Commander's "Did you mean" suggestion into a separate field
|
|
467
|
+
let suggestions;
|
|
468
|
+
const suggestionMatch = message.match(/\n\(Did you mean (.+)\?\)/);
|
|
469
|
+
if (suggestionMatch?.[1] != null) {
|
|
470
|
+
suggestions = [suggestionMatch[1]];
|
|
471
|
+
message = message.replace(/\n\(Did you mean .+\?\)/, '');
|
|
472
|
+
}
|
|
473
|
+
// Write directly to stderr (not via write/writeErr) to avoid
|
|
474
|
+
// self-suppression — writeErr suppresses output when jsonErrorEmitted is true
|
|
475
|
+
jsonErrorEmitted = true;
|
|
476
|
+
process.stderr.write(formatErrorJSON(createError(code, message, undefined, suggestions)) + '\n');
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
436
479
|
// Intercept commander.js error messages
|
|
437
480
|
if (str.includes('too many arguments') || str.includes('unknown command')) {
|
|
438
481
|
// Extract potential command name from error context
|