@agentuity/cli 0.0.56 → 0.0.58
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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +41 -2
- package/dist/cli.js.map +1 -1
- package/dist/cmd/build/ast.d.ts +4 -10
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +9 -10
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/bundler.d.ts +25 -2
- package/dist/cmd/build/bundler.d.ts.map +1 -1
- package/dist/cmd/build/bundler.js +138 -47
- package/dist/cmd/build/bundler.js.map +1 -1
- package/dist/cmd/build/plugin.js +7 -7
- package/dist/cmd/build/plugin.js.map +1 -1
- package/dist/cmd/build/workbench-templates.d.ts +4 -0
- package/dist/cmd/build/workbench-templates.d.ts.map +1 -0
- package/dist/cmd/build/workbench-templates.js +49 -0
- package/dist/cmd/build/workbench-templates.js.map +1 -0
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +11 -3
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/deployment/show.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/show.js +73 -20
- package/dist/cmd/cloud/deployment/show.js.map +1 -1
- package/dist/cmd/cloud/session/get.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +102 -54
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/index.d.ts.map +1 -1
- package/dist/cmd/index.js +2 -0
- package/dist/cmd/index.js.map +1 -1
- package/dist/schema-generator.d.ts +1 -1
- package/dist/schema-generator.d.ts.map +1 -1
- package/dist/schema-parser.d.ts +2 -1
- package/dist/schema-parser.d.ts.map +1 -1
- package/dist/schema-parser.js +18 -2
- package/dist/schema-parser.js.map +1 -1
- package/dist/steps.d.ts +2 -1
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +26 -3
- package/dist/steps.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +9 -10
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/cli.ts +49 -2
- package/src/cmd/build/ast.ts +15 -27
- package/src/cmd/build/bundler.ts +157 -45
- package/src/cmd/build/plugin.ts +8 -8
- package/src/cmd/build/workbench-templates.ts +52 -0
- package/src/cmd/cloud/deploy.ts +11 -3
- package/src/cmd/cloud/deployment/show.ts +60 -17
- package/src/cmd/cloud/session/get.ts +5 -5
- package/src/cmd/dev/index.ts +113 -58
- package/src/cmd/index.ts +2 -0
- package/src/schema-generator.ts +1 -1
- package/src/schema-parser.ts +19 -4
- package/src/steps.ts +27 -4
- package/src/tui.ts +11 -12
package/src/cmd/cloud/deploy.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
import { join, resolve } from 'node:path';
|
|
2
3
|
import { createPublicKey } from 'node:crypto';
|
|
3
4
|
import { createReadStream, createWriteStream } from 'node:fs';
|
|
@@ -26,9 +27,9 @@ import {
|
|
|
26
27
|
} from '../../env-util';
|
|
27
28
|
import { zipDir } from '../../utils/zip';
|
|
28
29
|
import { encryptFIPSKEMDEMStream } from '../../crypto/box';
|
|
29
|
-
import {
|
|
30
|
+
import { DeployOptionsSchema } from '../build/bundler';
|
|
30
31
|
import { getCommand } from '../../command-prefix';
|
|
31
|
-
import {
|
|
32
|
+
import { checkCustomDomainForDNS } from './domain';
|
|
32
33
|
|
|
33
34
|
const DeployResponseSchema = z.object({
|
|
34
35
|
success: z.boolean().describe('Whether deployment succeeded'),
|
|
@@ -58,17 +59,19 @@ export const deploySubcommand = createSubcommand({
|
|
|
58
59
|
examples: [
|
|
59
60
|
`${getCommand('cloud deploy')} # Deploy current project`,
|
|
60
61
|
`${getCommand('cloud deploy')} --log-level=debug # Deploy with verbose output`,
|
|
62
|
+
`${getCommand('cloud deploy')} --tag a --tag b # Deploy with specific tags`,
|
|
61
63
|
],
|
|
62
64
|
toplevel: true,
|
|
63
65
|
idempotent: false,
|
|
64
66
|
requires: { auth: true, project: true, apiClient: true },
|
|
65
67
|
prerequisites: ['auth login'],
|
|
66
68
|
schema: {
|
|
69
|
+
options: DeployOptionsSchema,
|
|
67
70
|
response: DeployResponseSchema,
|
|
68
71
|
},
|
|
69
72
|
|
|
70
73
|
async handler(ctx) {
|
|
71
|
-
const { project, apiClient, projectDir, config, options } = ctx;
|
|
74
|
+
const { project, apiClient, projectDir, config, options, opts } = ctx;
|
|
72
75
|
|
|
73
76
|
let deployment: Deployment | undefined;
|
|
74
77
|
let build: BuildMetadata | undefined;
|
|
@@ -171,6 +174,11 @@ export const deploySubcommand = createSubcommand({
|
|
|
171
174
|
orgId: deployment.orgId,
|
|
172
175
|
projectId: project.projectId,
|
|
173
176
|
project,
|
|
177
|
+
commitUrl: opts?.commitUrl,
|
|
178
|
+
logsUrl: opts?.logsUrl,
|
|
179
|
+
provider: opts?.provider,
|
|
180
|
+
trigger: opts?.trigger,
|
|
181
|
+
tag: opts?.tag,
|
|
174
182
|
});
|
|
175
183
|
build = await loadBuildMetadata(join(projectDir, '.agentuity'));
|
|
176
184
|
instructions = await projectDeploymentUpdate(
|
|
@@ -15,7 +15,39 @@ const DeploymentShowResponseSchema = z.object({
|
|
|
15
15
|
tags: z.array(z.string()).describe('Deployment tags'),
|
|
16
16
|
customDomains: z.array(z.string()).optional().describe('Custom domains'),
|
|
17
17
|
cloudRegion: z.string().optional().describe('Cloud region'),
|
|
18
|
-
metadata: z
|
|
18
|
+
metadata: z
|
|
19
|
+
.object({
|
|
20
|
+
git: z
|
|
21
|
+
.object({
|
|
22
|
+
repo: z.string().optional(),
|
|
23
|
+
commit: z.string().optional(),
|
|
24
|
+
message: z.string().optional(),
|
|
25
|
+
branch: z.string().optional(),
|
|
26
|
+
url: z.string().optional(),
|
|
27
|
+
trigger: z.string().optional(),
|
|
28
|
+
provider: z.string().optional(),
|
|
29
|
+
event: z.string().optional(),
|
|
30
|
+
buildUrl: z.string().optional(),
|
|
31
|
+
pull_request: z
|
|
32
|
+
.object({
|
|
33
|
+
number: z.number(),
|
|
34
|
+
url: z.string().optional(),
|
|
35
|
+
commentId: z.string().optional(),
|
|
36
|
+
})
|
|
37
|
+
.optional(),
|
|
38
|
+
})
|
|
39
|
+
.optional(),
|
|
40
|
+
build: z
|
|
41
|
+
.object({
|
|
42
|
+
agentuity: z.string().optional(),
|
|
43
|
+
bun: z.string().optional(),
|
|
44
|
+
platform: z.string().optional(),
|
|
45
|
+
arch: z.string().optional(),
|
|
46
|
+
})
|
|
47
|
+
.optional(),
|
|
48
|
+
})
|
|
49
|
+
.optional()
|
|
50
|
+
.describe('Deployment metadata'),
|
|
19
51
|
});
|
|
20
52
|
|
|
21
53
|
export const showSubcommand = createSubcommand({
|
|
@@ -49,8 +81,6 @@ export const showSubcommand = createSubcommand({
|
|
|
49
81
|
|
|
50
82
|
// Skip TUI output in JSON mode
|
|
51
83
|
if (!options.json) {
|
|
52
|
-
tui.banner(`Deployment ${deployment.id}`, `State: ${deployment.state || 'unknown'}`);
|
|
53
|
-
|
|
54
84
|
console.log(tui.bold('ID: ') + deployment.id);
|
|
55
85
|
console.log(tui.bold('Project: ') + projectId);
|
|
56
86
|
console.log(tui.bold('State: ') + (deployment.state || 'unknown'));
|
|
@@ -74,22 +104,35 @@ export const showSubcommand = createSubcommand({
|
|
|
74
104
|
console.log(tui.bold('Region: ') + deployment.cloudRegion);
|
|
75
105
|
}
|
|
76
106
|
|
|
77
|
-
//
|
|
78
|
-
const
|
|
79
|
-
if (
|
|
107
|
+
// Git metadata
|
|
108
|
+
const git = deployment.metadata?.git;
|
|
109
|
+
if (git) {
|
|
80
110
|
tui.newline();
|
|
81
|
-
tui.info('
|
|
82
|
-
if (
|
|
83
|
-
if (
|
|
84
|
-
if (
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
111
|
+
tui.info('Git Information');
|
|
112
|
+
if (git.repo) console.log(` Repo: ${git.repo}`);
|
|
113
|
+
if (git.branch) console.log(` Branch: ${git.branch}`);
|
|
114
|
+
if (git.commit) console.log(` Commit: ${git.commit}`);
|
|
115
|
+
if (git.message) console.log(` Message: ${git.message}`);
|
|
116
|
+
if (git.url) console.log(` URL: ${git.url}`);
|
|
117
|
+
if (git.trigger) console.log(` Trigger: ${git.trigger}`);
|
|
118
|
+
if (git.provider) console.log(` Provider: ${git.provider}`);
|
|
119
|
+
if (git.event) console.log(` Event: ${git.event}`);
|
|
120
|
+
if (git.pull_request) {
|
|
121
|
+
console.log(` PR: #${git.pull_request.number}`);
|
|
122
|
+
if (git.pull_request.url) console.log(` PR URL: ${git.pull_request.url}`);
|
|
92
123
|
}
|
|
124
|
+
if (git.buildUrl) console.log(` Build: ${git.buildUrl}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Build metadata
|
|
128
|
+
const build = deployment.metadata?.build;
|
|
129
|
+
if (build) {
|
|
130
|
+
tui.newline();
|
|
131
|
+
tui.info('Build Information');
|
|
132
|
+
if (build.agentuity) console.log(` Agentuity: ${build.agentuity}`);
|
|
133
|
+
if (build.bun) console.log(` Bun: ${build.bun}`);
|
|
134
|
+
if (build.platform) console.log(` Platform: ${build.platform}`);
|
|
135
|
+
if (build.arch) console.log(` Arch: ${build.arch}`);
|
|
93
136
|
}
|
|
94
137
|
}
|
|
95
138
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createSubcommand } from '../../../types';
|
|
3
3
|
import * as tui from '../../../tui';
|
|
4
|
-
import { sessionGet, type SpanNode } from '@agentuity/server';
|
|
4
|
+
import { sessionGet, type SpanNode, type EvalRun, type AgentInfo } from '@agentuity/server';
|
|
5
5
|
import { getCommand } from '../../../command-prefix';
|
|
6
6
|
import { ErrorCode } from '../../../errors';
|
|
7
7
|
import { getCatalystAPIClient } from '../../../config';
|
|
@@ -95,7 +95,7 @@ function printTimeline(node: SpanNode, prefix: string, isLast = true): void {
|
|
|
95
95
|
|
|
96
96
|
const childPrefix = prefix + (isLast ? ' ' : '│ ');
|
|
97
97
|
const children = node.children ?? [];
|
|
98
|
-
children.forEach((child, index) => {
|
|
98
|
+
children.forEach((child: SpanNode, index: number) => {
|
|
99
99
|
printTimeline(child, childPrefix, index === children.length - 1);
|
|
100
100
|
});
|
|
101
101
|
}
|
|
@@ -142,7 +142,7 @@ export const getSubcommand = createSubcommand({
|
|
|
142
142
|
route_id: session.route_id,
|
|
143
143
|
thread_id: session.thread_id,
|
|
144
144
|
agents: enriched.agents,
|
|
145
|
-
eval_runs: enriched.evalRuns.map((run) => ({
|
|
145
|
+
eval_runs: enriched.evalRuns.map((run: EvalRun) => ({
|
|
146
146
|
id: run.id,
|
|
147
147
|
eval_id: run.eval_id,
|
|
148
148
|
created_at: run.created_at,
|
|
@@ -189,7 +189,7 @@ export const getSubcommand = createSubcommand({
|
|
|
189
189
|
}
|
|
190
190
|
if (enriched.agents.length > 0) {
|
|
191
191
|
const agentDisplay = enriched.agents
|
|
192
|
-
.map((agent) => `${agent.name} ${tui.muted(`(${agent.identifier})`)}`)
|
|
192
|
+
.map((agent: AgentInfo) => `${agent.name} ${tui.muted(`(${agent.identifier})`)}`)
|
|
193
193
|
.join(', ');
|
|
194
194
|
console.log(tui.bold('Agents: ') + agentDisplay);
|
|
195
195
|
}
|
|
@@ -206,7 +206,7 @@ export const getSubcommand = createSubcommand({
|
|
|
206
206
|
if (enriched.evalRuns.length > 0) {
|
|
207
207
|
console.log('');
|
|
208
208
|
console.log(tui.bold('Eval Runs:'));
|
|
209
|
-
const evalTableData = enriched.evalRuns.map((run) => ({
|
|
209
|
+
const evalTableData = enriched.evalRuns.map((run: EvalRun) => ({
|
|
210
210
|
ID: run.id,
|
|
211
211
|
'Eval ID': run.eval_id,
|
|
212
212
|
Success: run.success ? tui.colorSuccess('✓') : tui.colorError('✗'),
|
package/src/cmd/dev/index.ts
CHANGED
|
@@ -238,48 +238,52 @@ export const command = createCommand({
|
|
|
238
238
|
let gravityClient: Bun.Subprocess | undefined;
|
|
239
239
|
let initialStartupComplete = false;
|
|
240
240
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
logger.error(
|
|
278
|
-
'Failed to spawn gravity client: %s',
|
|
279
|
-
err instanceof Error ? err.message : String(err)
|
|
280
|
-
);
|
|
241
|
+
const sdkKey = await loadProjectSDKKey(rootDir);
|
|
242
|
+
if (!sdkKey) {
|
|
243
|
+
tui.warning(`Couldn't find the AGENTUITY_SDK_KEY in ${rootDir} .env file`);
|
|
244
|
+
}
|
|
245
|
+
const gravityBinExists = gravityBin ? await Bun.file(gravityBin).exists() : undefined;
|
|
246
|
+
if (!gravityBinExists) {
|
|
247
|
+
logger.error(`Gravity binary not found at ${gravityBin}, skipping gravity client startup`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async function restartGravityClient() {
|
|
251
|
+
if (gravityClient) {
|
|
252
|
+
gravityClient.kill('SIGINT');
|
|
253
|
+
gravityClient.kill();
|
|
254
|
+
}
|
|
255
|
+
if (!devmode) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
gravityClient = Bun.spawn(
|
|
260
|
+
[
|
|
261
|
+
gravityBin!,
|
|
262
|
+
'--endpoint-id',
|
|
263
|
+
devmode.id,
|
|
264
|
+
'--port',
|
|
265
|
+
env.PORT!,
|
|
266
|
+
'--url',
|
|
267
|
+
config?.overrides?.gravity_url ?? 'grpc://devmode.agentuity.com',
|
|
268
|
+
'--log-level',
|
|
269
|
+
process.env.AGENTUITY_GRAVITY_LOG_LEVEL ?? 'error',
|
|
270
|
+
],
|
|
271
|
+
{
|
|
272
|
+
cwd: rootDir,
|
|
273
|
+
stdout: 'inherit',
|
|
274
|
+
stderr: 'inherit',
|
|
275
|
+
stdin: 'ignore',
|
|
276
|
+
env: { ...env, AGENTUITY_SDK_KEY: sdkKey },
|
|
281
277
|
}
|
|
282
|
-
|
|
278
|
+
);
|
|
279
|
+
gravityClient.exited.then(() => {
|
|
280
|
+
logger.debug('gravity client exited');
|
|
281
|
+
});
|
|
282
|
+
} catch (err) {
|
|
283
|
+
logger.error(
|
|
284
|
+
'Failed to spawn gravity client: %s',
|
|
285
|
+
err instanceof Error ? err.message : String(err)
|
|
286
|
+
);
|
|
283
287
|
}
|
|
284
288
|
}
|
|
285
289
|
|
|
@@ -307,14 +311,42 @@ export const command = createCommand({
|
|
|
307
311
|
}
|
|
308
312
|
}
|
|
309
313
|
|
|
314
|
+
let lastErrorLineCount = 0;
|
|
315
|
+
let showedRestartMessage = false;
|
|
316
|
+
|
|
317
|
+
function clearRestartMessage() {
|
|
318
|
+
if (showedRestartMessage) {
|
|
319
|
+
process.stdout.write('\x1b[1A\x1b[2K');
|
|
320
|
+
showedRestartMessage = false;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
310
324
|
function failure(msg: string) {
|
|
311
325
|
failed = true;
|
|
312
326
|
failures++;
|
|
327
|
+
// Exit immediately on initial startup failure
|
|
328
|
+
if (!initialStartupComplete) {
|
|
329
|
+
tui.fatal(msg);
|
|
330
|
+
}
|
|
331
|
+
// During hot reload, show error but don't exit unless too many failures
|
|
313
332
|
if (failures >= 5) {
|
|
314
333
|
tui.error(msg);
|
|
315
334
|
tui.fatal('too many failures, exiting');
|
|
316
335
|
} else {
|
|
317
|
-
|
|
336
|
+
// Ensure we're on a new line before printing error
|
|
337
|
+
tui.error(msg);
|
|
338
|
+
// Track lines: 1 for "✗ Building..." + 1 for error message
|
|
339
|
+
lastErrorLineCount = 2;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function clearLastError() {
|
|
344
|
+
if (lastErrorLineCount > 0) {
|
|
345
|
+
// Move cursor up and clear each line
|
|
346
|
+
for (let i = 0; i < lastErrorLineCount; i++) {
|
|
347
|
+
process.stdout.write('\x1b[1A\x1b[2K');
|
|
348
|
+
}
|
|
349
|
+
lastErrorLineCount = 0;
|
|
318
350
|
}
|
|
319
351
|
}
|
|
320
352
|
|
|
@@ -406,6 +438,7 @@ export const command = createCommand({
|
|
|
406
438
|
logger.trace('Server is running, killing before restart');
|
|
407
439
|
checkRestartThrottle();
|
|
408
440
|
tui.info('Restarting on file change');
|
|
441
|
+
showedRestartMessage = true;
|
|
409
442
|
await kill();
|
|
410
443
|
logger.trace('Server killed, continuing with restart');
|
|
411
444
|
// Continue with restart after kill completes
|
|
@@ -413,11 +446,16 @@ export const command = createCommand({
|
|
|
413
446
|
logger.trace('Initial server start');
|
|
414
447
|
}
|
|
415
448
|
logger.trace('Starting typecheck and build...');
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
449
|
+
|
|
450
|
+
// Clear any previous error before starting new build
|
|
451
|
+
clearLastError();
|
|
452
|
+
clearRestartMessage();
|
|
453
|
+
|
|
454
|
+
try {
|
|
455
|
+
await tui.spinner({
|
|
456
|
+
message: 'Building...',
|
|
457
|
+
clearOnSuccess: true,
|
|
458
|
+
callback: async () => {
|
|
421
459
|
logger.trace('Bundle starting...');
|
|
422
460
|
building = true;
|
|
423
461
|
await bundle({
|
|
@@ -431,7 +469,7 @@ export const command = createCommand({
|
|
|
431
469
|
buildCompletedAt = Date.now();
|
|
432
470
|
logger.trace('Bundle completed successfully');
|
|
433
471
|
logger.trace('tsc starting...');
|
|
434
|
-
await tui.runCommand({
|
|
472
|
+
const tscExitCode = await tui.runCommand({
|
|
435
473
|
command: 'tsc',
|
|
436
474
|
cmd: ['bunx', 'tsc', '--noEmit'],
|
|
437
475
|
cwd: rootDir,
|
|
@@ -440,15 +478,32 @@ export const command = createCommand({
|
|
|
440
478
|
maxLinesOutput: 2,
|
|
441
479
|
maxLinesOnFailure: 15,
|
|
442
480
|
});
|
|
481
|
+
if (tscExitCode !== 0) {
|
|
482
|
+
logger.trace('tsc failed with exit code %d', tscExitCode);
|
|
483
|
+
failure('Type check failed');
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
443
486
|
logger.trace('tsc completed successfully');
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
487
|
+
await restartGravityClient();
|
|
488
|
+
},
|
|
489
|
+
});
|
|
490
|
+
} catch (error) {
|
|
491
|
+
building = false;
|
|
492
|
+
const e = error as Error;
|
|
493
|
+
if (e.constructor.name === 'AggregateError') {
|
|
494
|
+
const ex = e as AggregateError;
|
|
495
|
+
for (const err of ex.errors) {
|
|
496
|
+
if (err) {
|
|
497
|
+
failure(err);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
449
500
|
}
|
|
450
|
-
|
|
451
|
-
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
504
|
+
failure(errorMsg);
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
452
507
|
|
|
453
508
|
logger.trace('Typecheck and build completed');
|
|
454
509
|
|
|
@@ -457,6 +512,9 @@ export const command = createCommand({
|
|
|
457
512
|
return;
|
|
458
513
|
}
|
|
459
514
|
|
|
515
|
+
// Reset failure counter on successful build
|
|
516
|
+
failures = 0;
|
|
517
|
+
|
|
460
518
|
logger.trace('Checking if app file exists: %s', appPath);
|
|
461
519
|
if (!existsSync(appPath)) {
|
|
462
520
|
logger.trace('App file not found: %s', appPath);
|
|
@@ -548,9 +606,6 @@ export const command = createCommand({
|
|
|
548
606
|
|
|
549
607
|
if (showInitialReadyMessage) {
|
|
550
608
|
showInitialReadyMessage = false;
|
|
551
|
-
// Clear any lingering spinner/command output - clear everything below cursor
|
|
552
|
-
process.stderr.write('\x1B[J'); // Clear from cursor to end of screen
|
|
553
|
-
process.stdout.write('\x1B[J'); // Clear from cursor to end of screen
|
|
554
609
|
logger.info('DevMode ready 🚀');
|
|
555
610
|
logger.trace('Initial ready message logged');
|
|
556
611
|
// Mark initial startup complete immediately to prevent watcher restarts
|
package/src/cmd/index.ts
CHANGED
|
@@ -38,6 +38,8 @@ export async function discoverCommands(): Promise<CommandDefinition[]> {
|
|
|
38
38
|
prerequisites: (subcommand as any).prerequisites,
|
|
39
39
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
40
40
|
tags: (subcommand as any).tags,
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
examples: (subcommand as any).examples,
|
|
41
43
|
};
|
|
42
44
|
commands.push(alias as CommandDefinition);
|
|
43
45
|
}
|
package/src/schema-generator.ts
CHANGED
package/src/schema-parser.ts
CHANGED
|
@@ -13,9 +13,10 @@ export interface ParsedArgs {
|
|
|
13
13
|
export interface ParsedOption {
|
|
14
14
|
name: string;
|
|
15
15
|
description?: string;
|
|
16
|
-
type: 'string' | 'number' | 'boolean';
|
|
16
|
+
type: 'string' | 'number' | 'boolean' | 'array';
|
|
17
17
|
hasDefault?: boolean;
|
|
18
18
|
defaultValue?: unknown;
|
|
19
|
+
enumValues?: string[];
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
interface ZodTypeDef {
|
|
@@ -167,11 +168,21 @@ export function parseOptionsSchema(schema: ZodType): ParsedOption[] {
|
|
|
167
168
|
? (defaultInfo.defaultValue as () => unknown)()
|
|
168
169
|
: defaultInfo.defaultValue;
|
|
169
170
|
|
|
170
|
-
let type: 'string' | 'number' | 'boolean' = 'string';
|
|
171
|
+
let type: 'string' | 'number' | 'boolean' | 'array' = 'string';
|
|
172
|
+
let enumValues: string[] | undefined;
|
|
171
173
|
if (typeId === 'ZodNumber' || typeId === 'number') {
|
|
172
174
|
type = 'number';
|
|
173
175
|
} else if (typeId === 'ZodBoolean' || typeId === 'boolean') {
|
|
174
176
|
type = 'boolean';
|
|
177
|
+
} else if (typeId === 'ZodArray' || typeId === 'array') {
|
|
178
|
+
type = 'array';
|
|
179
|
+
} else if (typeId === 'ZodEnum' || typeId === 'enum') {
|
|
180
|
+
// Extract enum values from Zod 4's def.entries
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
182
|
+
const def = (unwrapped as any)?._def;
|
|
183
|
+
if (def?.entries && typeof def.entries === 'object') {
|
|
184
|
+
enumValues = Object.values(def.entries as Record<string, string>);
|
|
185
|
+
}
|
|
175
186
|
}
|
|
176
187
|
|
|
177
188
|
options.push({
|
|
@@ -180,6 +191,7 @@ export function parseOptionsSchema(schema: ZodType): ParsedOption[] {
|
|
|
180
191
|
description,
|
|
181
192
|
hasDefault: defaultInfo.hasDefault,
|
|
182
193
|
defaultValue,
|
|
194
|
+
enumValues,
|
|
183
195
|
});
|
|
184
196
|
}
|
|
185
197
|
|
|
@@ -203,8 +215,11 @@ export function buildValidationInput(
|
|
|
203
215
|
if (schemas.options) {
|
|
204
216
|
const parsed = parseOptionsSchema(schemas.options);
|
|
205
217
|
for (const opt of parsed) {
|
|
206
|
-
//
|
|
207
|
-
|
|
218
|
+
// Only include the option if it has a value - omitting undefined allows Zod to apply defaults
|
|
219
|
+
const value = rawOptions[opt.name];
|
|
220
|
+
if (value !== undefined) {
|
|
221
|
+
result.options[opt.name] = value;
|
|
222
|
+
}
|
|
208
223
|
}
|
|
209
224
|
}
|
|
210
225
|
|
package/src/steps.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import type { ColorScheme } from './terminal';
|
|
9
9
|
import type { LogLevel } from './types';
|
|
10
|
+
import { ValidationError } from '@agentuity/server';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Get the appropriate exit function (Bun.exit or process.exit)
|
|
@@ -108,14 +109,18 @@ function getColor(colorKey: keyof typeof COLORS): string {
|
|
|
108
109
|
export type StepOutcome =
|
|
109
110
|
| { status: 'success' }
|
|
110
111
|
| { status: 'skipped'; reason?: string }
|
|
111
|
-
| { status: 'error'; message: string };
|
|
112
|
+
| { status: 'error'; message: string; cause?: Error };
|
|
112
113
|
|
|
113
114
|
/**
|
|
114
115
|
* Helper functions for creating step outcomes
|
|
115
116
|
*/
|
|
116
117
|
export const stepSuccess = (): StepOutcome => ({ status: 'success' });
|
|
117
118
|
export const stepSkipped = (reason?: string): StepOutcome => ({ status: 'skipped', reason });
|
|
118
|
-
export const stepError = (message: string): StepOutcome => ({
|
|
119
|
+
export const stepError = (message: string, cause?: Error): StepOutcome => ({
|
|
120
|
+
status: 'error',
|
|
121
|
+
message,
|
|
122
|
+
cause,
|
|
123
|
+
});
|
|
119
124
|
|
|
120
125
|
/**
|
|
121
126
|
* Progress callback function
|
|
@@ -260,6 +265,7 @@ async function runStepsTUI(state: StepState[]): Promise<void> {
|
|
|
260
265
|
step.outcome = {
|
|
261
266
|
status: 'error',
|
|
262
267
|
message: err instanceof Error ? err.message : String(err),
|
|
268
|
+
cause: err instanceof Error ? err : undefined,
|
|
263
269
|
};
|
|
264
270
|
}
|
|
265
271
|
|
|
@@ -276,7 +282,15 @@ async function runStepsTUI(state: StepState[]): Promise<void> {
|
|
|
276
282
|
// If error, show error message and exit
|
|
277
283
|
if (step.outcome?.status === 'error') {
|
|
278
284
|
const errorColor = getColor('red');
|
|
279
|
-
console.error(`\n${errorColor}Error: ${step.outcome.message}${COLORS.reset}
|
|
285
|
+
console.error(`\n${errorColor}Error: ${step.outcome.message}${COLORS.reset}`);
|
|
286
|
+
if (step.outcome.cause instanceof ValidationError) {
|
|
287
|
+
console.error(`${errorColor}Validation details:${COLORS.reset}`);
|
|
288
|
+
for (const issue of step.outcome.cause.issues) {
|
|
289
|
+
const path = issue.path.length > 0 ? issue.path.join('.') : '(root)';
|
|
290
|
+
console.error(` ${path}: ${issue.message}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
console.error('');
|
|
280
294
|
process.stdout.write('\x1B[?25h'); // Show cursor
|
|
281
295
|
process.exit(1);
|
|
282
296
|
}
|
|
@@ -312,6 +326,7 @@ async function runStepsPlain(state: StepState[]): Promise<void> {
|
|
|
312
326
|
step.outcome = {
|
|
313
327
|
status: 'error',
|
|
314
328
|
message: err instanceof Error ? err.message : String(err),
|
|
329
|
+
cause: err instanceof Error ? err : undefined,
|
|
315
330
|
};
|
|
316
331
|
}
|
|
317
332
|
|
|
@@ -326,7 +341,15 @@ async function runStepsPlain(state: StepState[]): Promise<void> {
|
|
|
326
341
|
} else if (step.outcome?.status === 'error') {
|
|
327
342
|
console.log(`${redColor}${ICONS.error}${COLORS.reset} ${step.label}`);
|
|
328
343
|
const errorColor = getColor('red');
|
|
329
|
-
console.error(`\n${errorColor}Error: ${step.outcome.message}${COLORS.reset}
|
|
344
|
+
console.error(`\n${errorColor}Error: ${step.outcome.message}${COLORS.reset}`);
|
|
345
|
+
if (step.outcome.cause instanceof ValidationError) {
|
|
346
|
+
console.error(`${errorColor}Validation details:${COLORS.reset}`);
|
|
347
|
+
for (const issue of step.outcome.cause.issues) {
|
|
348
|
+
const path = issue.path.length > 0 ? issue.path.join('.') : '(root)';
|
|
349
|
+
console.error(` ${path}: ${issue.message}`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
console.error('');
|
|
330
353
|
process.exit(1);
|
|
331
354
|
}
|
|
332
355
|
}
|
package/src/tui.ts
CHANGED
|
@@ -859,8 +859,8 @@ export async function spinner<T>(
|
|
|
859
859
|
let frameIndex = 0;
|
|
860
860
|
let currentProgress: number | undefined;
|
|
861
861
|
|
|
862
|
-
//
|
|
863
|
-
process.stderr.write('\x1B[?25l');
|
|
862
|
+
// Save cursor position and hide cursor
|
|
863
|
+
process.stderr.write('\x1B[s\x1B[?25l');
|
|
864
864
|
|
|
865
865
|
// Start animation
|
|
866
866
|
const interval = setInterval(() => {
|
|
@@ -893,9 +893,12 @@ export async function spinner<T>(
|
|
|
893
893
|
? await options.callback()
|
|
894
894
|
: await options.callback;
|
|
895
895
|
|
|
896
|
-
//
|
|
896
|
+
// Stop animation first
|
|
897
897
|
clearInterval(interval);
|
|
898
|
-
|
|
898
|
+
|
|
899
|
+
// Restore cursor position, clear to end of screen, show cursor
|
|
900
|
+
// This removes spinner and any partial output that happened during animation
|
|
901
|
+
process.stderr.write('\x1B[u\x1B[J\x1B[?25h');
|
|
899
902
|
|
|
900
903
|
// If clearOnSuccess is false, show success message
|
|
901
904
|
if (!options.clearOnSuccess) {
|
|
@@ -904,22 +907,18 @@ export async function spinner<T>(
|
|
|
904
907
|
console.error(`${successColor}${ICONS.success} ${message}${reset}`);
|
|
905
908
|
}
|
|
906
909
|
|
|
907
|
-
// Show cursor
|
|
908
|
-
process.stderr.write('\x1B[?25h');
|
|
909
|
-
|
|
910
910
|
return result;
|
|
911
911
|
} catch (err) {
|
|
912
|
-
//
|
|
912
|
+
// Stop animation first
|
|
913
913
|
clearInterval(interval);
|
|
914
|
-
|
|
914
|
+
|
|
915
|
+
// Restore cursor position, clear to end of screen, show cursor
|
|
916
|
+
process.stderr.write('\x1B[u\x1B[J\x1B[?25h');
|
|
915
917
|
|
|
916
918
|
// Show error
|
|
917
919
|
const errorColor = getColor('error');
|
|
918
920
|
console.error(`${errorColor}${ICONS.error} ${message}${reset}`);
|
|
919
921
|
|
|
920
|
-
// Show cursor
|
|
921
|
-
process.stderr.write('\x1B[?25h');
|
|
922
|
-
|
|
923
922
|
throw err;
|
|
924
923
|
}
|
|
925
924
|
}
|