@agentuity/cli 0.0.55 → 0.0.57
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/ai/schema/generate.d.ts +3 -0
- package/dist/cmd/ai/schema/generate.d.ts.map +1 -0
- package/dist/cmd/ai/schema/generate.js +50 -0
- package/dist/cmd/ai/schema/generate.js.map +1 -0
- package/dist/cmd/ai/schema/index.d.ts.map +1 -1
- package/dist/cmd/ai/schema/index.js +2 -1
- package/dist/cmd/ai/schema/index.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 +110 -91
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/ast.test.js +135 -370
- package/dist/cmd/build/ast.test.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 -43
- package/dist/cmd/build/bundler.js.map +1 -1
- package/dist/cmd/build/plugin.d.ts.map +1 -1
- package/dist/cmd/build/plugin.js +16 -8
- 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.d.ts.map +1 -1
- package/dist/cmd/cloud/session/get.js +77 -17
- package/dist/cmd/cloud/session/get.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/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +1 -0
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/config.d.ts +27 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +31 -3
- package/dist/config.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/types.d.ts +39 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -75
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
- package/src/cli.ts +49 -2
- package/src/cmd/ai/schema/generate.ts +64 -0
- package/src/cmd/ai/schema/index.ts +2 -1
- package/src/cmd/build/ast.test.ts +157 -549
- package/src/cmd/build/ast.ts +130 -116
- package/src/cmd/build/bundler.ts +157 -42
- package/src/cmd/build/plugin.ts +18 -9
- 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 +91 -19
- package/src/cmd/index.ts +2 -0
- package/src/cmd/project/template-flow.ts +1 -0
- package/src/config.ts +44 -5
- package/src/schema-generator.ts +1 -1
- package/src/schema-parser.ts +19 -4
- package/src/steps.ts +27 -4
- package/src/types.ts +5 -84
package/src/cmd/build/plugin.ts
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
parseEvalMetadata,
|
|
9
9
|
analyzeWorkbench,
|
|
10
10
|
checkRouteConflicts,
|
|
11
|
-
type WorkbenchConfig,
|
|
12
11
|
} from './ast';
|
|
12
|
+
import type { WorkbenchConfig } from '@agentuity/core';
|
|
13
13
|
import { applyPatch, generatePatches } from './patch';
|
|
14
14
|
import { detectSubagent } from '../../utils/detectSubagent';
|
|
15
15
|
import { createLogger } from '@agentuity/server';
|
|
@@ -35,18 +35,18 @@ async function setupWorkbench(srcDir: string): Promise<WorkbenchConfig | null> {
|
|
|
35
35
|
const srcAppFile = join(srcDir, 'app.ts');
|
|
36
36
|
|
|
37
37
|
let appFile = '';
|
|
38
|
-
if (
|
|
38
|
+
if (await Bun.file(rootAppFile).exists()) {
|
|
39
39
|
appFile = rootAppFile;
|
|
40
|
-
} else if (
|
|
40
|
+
} else if (await Bun.file(srcAppFile).exists()) {
|
|
41
41
|
appFile = srcAppFile;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
if (!appFile || !
|
|
44
|
+
if (!appFile || !(await Bun.file(appFile).exists())) {
|
|
45
45
|
return null;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
const appContent = await Bun.file(appFile).text();
|
|
49
|
-
const analysis =
|
|
49
|
+
const analysis = analyzeWorkbench(appContent);
|
|
50
50
|
|
|
51
51
|
if (!analysis.hasWorkbench) {
|
|
52
52
|
return null;
|
|
@@ -56,7 +56,7 @@ async function setupWorkbench(srcDir: string): Promise<WorkbenchConfig | null> {
|
|
|
56
56
|
|
|
57
57
|
// Check for route conflicts if workbench is being used
|
|
58
58
|
if (workbenchConfig?.route) {
|
|
59
|
-
const hasConflict =
|
|
59
|
+
const hasConflict = checkRouteConflicts(appContent, workbenchConfig.route);
|
|
60
60
|
if (hasConflict) {
|
|
61
61
|
const logger = createLogger((process.env.AGENTUITY_LOG_LEVEL as LogLevel) || 'info');
|
|
62
62
|
logger.error(`🚨 Route conflict detected!\n`);
|
|
@@ -493,7 +493,6 @@ const AgentuityBundler: BunPlugin = {
|
|
|
493
493
|
projectId,
|
|
494
494
|
deploymentId
|
|
495
495
|
);
|
|
496
|
-
routeDefinitions = [...routeDefinitions, ...definitions];
|
|
497
496
|
|
|
498
497
|
let agentDetail: Record<string, string> = {};
|
|
499
498
|
|
|
@@ -504,6 +503,7 @@ const AgentuityBundler: BunPlugin = {
|
|
|
504
503
|
}
|
|
505
504
|
agentDetail = {
|
|
506
505
|
name,
|
|
506
|
+
id: md.get('id')!,
|
|
507
507
|
path: `.${agent}`,
|
|
508
508
|
filename: md.get('filename')!,
|
|
509
509
|
identifier: md.get('identifier')!,
|
|
@@ -514,8 +514,14 @@ const AgentuityBundler: BunPlugin = {
|
|
|
514
514
|
agentDetail.parent = parentName;
|
|
515
515
|
}
|
|
516
516
|
agentInfo.push(agentDetail);
|
|
517
|
+
for (const def of definitions) {
|
|
518
|
+
def.agentIds = [agentDetail.agentId, agentDetail.id];
|
|
519
|
+
}
|
|
517
520
|
}
|
|
518
521
|
|
|
522
|
+
// do this after handling the agent association (if any)
|
|
523
|
+
routeDefinitions = [...routeDefinitions, ...definitions];
|
|
524
|
+
|
|
519
525
|
let buffer = `await (async() => {
|
|
520
526
|
const { createAgentMiddleware, getRouter, registerAgent } = await import('@agentuity/runtime');
|
|
521
527
|
const router = getRouter()!;
|
|
@@ -567,8 +573,8 @@ const AgentuityBundler: BunPlugin = {
|
|
|
567
573
|
// Use the workbench config determined at build time
|
|
568
574
|
const route = ${JSON.stringify(workbenchConfig?.route || '/workbench')};
|
|
569
575
|
|
|
570
|
-
// If using custom route, update HTML to point to absolute /workbench/ paths
|
|
571
|
-
if (route !== '/workbench') {
|
|
576
|
+
// If using custom route, update HTML to point to absolute /workbench/ paths
|
|
577
|
+
if (route !== '/workbench') {
|
|
572
578
|
workbenchIndex = workbenchIndex.replace(new RegExp('src="\\\\.\\\\/workbench\\\\/', 'g'), 'src="/workbench/');
|
|
573
579
|
}
|
|
574
580
|
|
|
@@ -657,6 +663,9 @@ if (route !== '/workbench') {
|
|
|
657
663
|
if (!v.has('name')) {
|
|
658
664
|
throw new Error('agent metadata is missing expected name property');
|
|
659
665
|
}
|
|
666
|
+
if (!v.has('agentId')) {
|
|
667
|
+
throw new Error('agent metadata is missing expected agentId property');
|
|
668
|
+
}
|
|
660
669
|
|
|
661
670
|
const parentName = v.get('parent');
|
|
662
671
|
if (parentName) {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { WorkbenchConfig } from '@agentuity/core';
|
|
2
|
+
|
|
3
|
+
export function generateWorkbenchMainTsx(config: WorkbenchConfig): string {
|
|
4
|
+
const configString = JSON.stringify(config);
|
|
5
|
+
|
|
6
|
+
return `// Generated workbench entry point
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { createRoot } from 'react-dom/client';
|
|
9
|
+
import { AgentuityProvider } from '@agentuity/react';
|
|
10
|
+
import { createWorkbench, Workbench } from '@agentuity/workbench';
|
|
11
|
+
import '@agentuity/workbench/styles';
|
|
12
|
+
|
|
13
|
+
// Root element
|
|
14
|
+
const rootElement = document.getElementById('root');
|
|
15
|
+
if (!rootElement) {
|
|
16
|
+
throw new Error('Root element not found');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Create workbench instance with config from bundler
|
|
20
|
+
const workbenchConfig = ${configString};
|
|
21
|
+
const workbench = createWorkbench(workbenchConfig);
|
|
22
|
+
|
|
23
|
+
function App() {
|
|
24
|
+
return (
|
|
25
|
+
<AgentuityProvider baseUrl={window.location.origin}>
|
|
26
|
+
<div className="min-h-screen bg-background text-foreground">
|
|
27
|
+
<Workbench workbench={workbench} />
|
|
28
|
+
</div>
|
|
29
|
+
</AgentuityProvider>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Render the app
|
|
34
|
+
const root = createRoot(rootElement);
|
|
35
|
+
root.render(<App />);
|
|
36
|
+
`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function generateWorkbenchIndexHtml(): string {
|
|
40
|
+
return `<!DOCTYPE html>
|
|
41
|
+
<html lang="en">
|
|
42
|
+
<head>
|
|
43
|
+
<meta charset="UTF-8">
|
|
44
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
45
|
+
<title>Agentuity Workbench</title>
|
|
46
|
+
</head>
|
|
47
|
+
<body>
|
|
48
|
+
<div id="root"></div>
|
|
49
|
+
<script type="module" src="./main.tsx"></script>
|
|
50
|
+
</body>
|
|
51
|
+
</html>`;
|
|
52
|
+
}
|
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,11 +1,29 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createSubcommand } from '../../../types';
|
|
3
3
|
import * as tui from '../../../tui';
|
|
4
|
-
import { sessionGet } from '@agentuity/server';
|
|
4
|
+
import { sessionGet, type SpanNode } from '@agentuity/server';
|
|
5
5
|
import { getCommand } from '../../../command-prefix';
|
|
6
6
|
import { ErrorCode } from '../../../errors';
|
|
7
7
|
import { getCatalystAPIClient } from '../../../config';
|
|
8
8
|
|
|
9
|
+
const SpanNodeSchema: z.ZodType<SpanNode> = z.lazy(() =>
|
|
10
|
+
z.object({
|
|
11
|
+
id: z.string().describe('Span ID'),
|
|
12
|
+
duration: z.number().describe('Duration in milliseconds'),
|
|
13
|
+
operation: z.string().describe('Operation name'),
|
|
14
|
+
attributes: z.record(z.string(), z.unknown()).describe('Span attributes'),
|
|
15
|
+
children: z.array(SpanNodeSchema).optional().describe('Child spans'),
|
|
16
|
+
})
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const RouteInfoSchema = z
|
|
20
|
+
.object({
|
|
21
|
+
id: z.string().describe('Route ID'),
|
|
22
|
+
method: z.string().describe('HTTP method'),
|
|
23
|
+
path: z.string().describe('Route path'),
|
|
24
|
+
})
|
|
25
|
+
.nullable();
|
|
26
|
+
|
|
9
27
|
const SessionGetResponseSchema = z.object({
|
|
10
28
|
id: z.string().describe('Session ID'),
|
|
11
29
|
created_at: z.string().describe('Creation timestamp'),
|
|
@@ -26,8 +44,15 @@ const SessionGetResponseSchema = z.object({
|
|
|
26
44
|
url: z.string().describe('Request URL'),
|
|
27
45
|
route_id: z.string().describe('Route ID'),
|
|
28
46
|
thread_id: z.string().describe('Thread ID'),
|
|
29
|
-
|
|
30
|
-
|
|
47
|
+
agents: z
|
|
48
|
+
.array(
|
|
49
|
+
z.object({
|
|
50
|
+
name: z.string(),
|
|
51
|
+
identifier: z.string(),
|
|
52
|
+
})
|
|
53
|
+
)
|
|
54
|
+
.describe('Agents'),
|
|
55
|
+
eval_runs: z
|
|
31
56
|
.array(
|
|
32
57
|
z.object({
|
|
33
58
|
id: z.string(),
|
|
@@ -40,8 +65,41 @@ const SessionGetResponseSchema = z.object({
|
|
|
40
65
|
})
|
|
41
66
|
)
|
|
42
67
|
.describe('Eval runs'),
|
|
68
|
+
timeline: SpanNodeSchema.nullable().optional().describe('Session timeline'),
|
|
69
|
+
route: RouteInfoSchema.optional().describe('Route information'),
|
|
43
70
|
});
|
|
44
71
|
|
|
72
|
+
function formatDuration(ms: number): string {
|
|
73
|
+
if (ms < 1) {
|
|
74
|
+
return `${(ms * 1000).toFixed(0)}µs`;
|
|
75
|
+
}
|
|
76
|
+
if (ms < 1000) {
|
|
77
|
+
return `${ms.toFixed(1)}ms`;
|
|
78
|
+
}
|
|
79
|
+
return `${(ms / 1000).toFixed(2)}s`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function printTimeline(node: SpanNode, prefix: string, isLast = true): void {
|
|
83
|
+
const connector = isLast ? '└── ' : '├── ';
|
|
84
|
+
const duration = tui.muted(`(${formatDuration(node.duration)})`);
|
|
85
|
+
let extra = '';
|
|
86
|
+
if (node.operation.startsWith('agentuity.')) {
|
|
87
|
+
if ('name' in node.attributes && 'key' in node.attributes) {
|
|
88
|
+
extra = tui.colorSuccess(`${node.attributes.name} ${node.attributes.key}`) + ' ';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (node.operation.startsWith('HTTP ') && 'http.url' in node.attributes) {
|
|
92
|
+
extra = `${tui.colorSuccess(node.attributes['http.url'] as string)} `;
|
|
93
|
+
}
|
|
94
|
+
console.log(`${prefix}${connector}${node.operation} ${extra}${duration}`);
|
|
95
|
+
|
|
96
|
+
const childPrefix = prefix + (isLast ? ' ' : '│ ');
|
|
97
|
+
const children = node.children ?? [];
|
|
98
|
+
children.forEach((child, index) => {
|
|
99
|
+
printTimeline(child, childPrefix, index === children.length - 1);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
45
103
|
export const getSubcommand = createSubcommand({
|
|
46
104
|
name: 'get',
|
|
47
105
|
description: 'Get details about a specific session',
|
|
@@ -83,8 +141,8 @@ export const getSubcommand = createSubcommand({
|
|
|
83
141
|
url: session.url,
|
|
84
142
|
route_id: session.route_id,
|
|
85
143
|
thread_id: session.thread_id,
|
|
86
|
-
|
|
87
|
-
|
|
144
|
+
agents: enriched.agents,
|
|
145
|
+
eval_runs: enriched.evalRuns.map((run) => ({
|
|
88
146
|
id: run.id,
|
|
89
147
|
eval_id: run.eval_id,
|
|
90
148
|
created_at: run.created_at,
|
|
@@ -93,6 +151,8 @@ export const getSubcommand = createSubcommand({
|
|
|
93
151
|
error: run.error,
|
|
94
152
|
result: run.result,
|
|
95
153
|
})),
|
|
154
|
+
timeline: enriched.timeline,
|
|
155
|
+
route: enriched.route,
|
|
96
156
|
};
|
|
97
157
|
|
|
98
158
|
if (options.json) {
|
|
@@ -100,17 +160,14 @@ export const getSubcommand = createSubcommand({
|
|
|
100
160
|
return result;
|
|
101
161
|
}
|
|
102
162
|
|
|
103
|
-
tui.banner(`Session ${session.id}`, `Status: ${session.success ? 'Success' : 'Failed'}`);
|
|
104
|
-
|
|
105
163
|
console.log(tui.bold('ID: ') + session.id);
|
|
106
164
|
console.log(tui.bold('Project: ') + session.project_id);
|
|
107
165
|
console.log(tui.bold('Deployment: ') + (session.deployment_id || '-'));
|
|
108
|
-
console.log(tui.bold('Created: ') + new Date(session.created_at).toLocaleString());
|
|
109
166
|
console.log(tui.bold('Start: ') + new Date(session.start_time).toLocaleString());
|
|
110
167
|
if (session.end_time) {
|
|
111
168
|
console.log(tui.bold('End: ') + new Date(session.end_time).toLocaleString());
|
|
112
169
|
}
|
|
113
|
-
if (session.duration) {
|
|
170
|
+
if (session.duration && session.end_time) {
|
|
114
171
|
console.log(
|
|
115
172
|
tui.bold('Duration: ') + `${(session.duration / 1_000_000).toFixed(0)}ms`
|
|
116
173
|
);
|
|
@@ -118,23 +175,32 @@ export const getSubcommand = createSubcommand({
|
|
|
118
175
|
console.log(tui.bold('Method: ') + session.method);
|
|
119
176
|
console.log(tui.bold('URL: ') + tui.link(session.url, session.url));
|
|
120
177
|
console.log(tui.bold('Trigger: ') + session.trigger);
|
|
121
|
-
|
|
178
|
+
if (session.env !== 'production') {
|
|
179
|
+
console.log(tui.bold('Environment: ') + session.env);
|
|
180
|
+
}
|
|
122
181
|
console.log(tui.bold('Dev Mode: ') + (session.devmode ? 'Yes' : 'No'));
|
|
123
|
-
console.log(
|
|
182
|
+
console.log(
|
|
183
|
+
tui.bold('Success: ') +
|
|
184
|
+
(session.success ? tui.colorSuccess('✓') : tui.colorError('✗'))
|
|
185
|
+
);
|
|
124
186
|
console.log(tui.bold('Pending: ') + (session.pending ? 'Yes' : 'No'));
|
|
125
187
|
if (session.error) {
|
|
126
188
|
console.log(tui.bold('Error: ') + tui.error(session.error));
|
|
127
189
|
}
|
|
128
|
-
if (enriched.
|
|
129
|
-
const agentDisplay = enriched.
|
|
130
|
-
.map((
|
|
131
|
-
const agentId = session.agent_ids[idx];
|
|
132
|
-
return `${name} ${tui.muted(`(${agentId})`)}`;
|
|
133
|
-
})
|
|
190
|
+
if (enriched.agents.length > 0) {
|
|
191
|
+
const agentDisplay = enriched.agents
|
|
192
|
+
.map((agent) => `${agent.name} ${tui.muted(`(${agent.identifier})`)}`)
|
|
134
193
|
.join(', ');
|
|
135
194
|
console.log(tui.bold('Agents: ') + agentDisplay);
|
|
136
195
|
}
|
|
137
|
-
|
|
196
|
+
if (enriched.route) {
|
|
197
|
+
console.log(
|
|
198
|
+
tui.bold('Route: ') +
|
|
199
|
+
`${enriched.route.method.toUpperCase()} ${enriched.route.path} ${tui.muted(`(${enriched.route.id})`)}`
|
|
200
|
+
);
|
|
201
|
+
} else {
|
|
202
|
+
console.log(tui.bold('Route ID: ') + session.route_id);
|
|
203
|
+
}
|
|
138
204
|
console.log(tui.bold('Thread ID: ') + session.thread_id);
|
|
139
205
|
|
|
140
206
|
if (enriched.evalRuns.length > 0) {
|
|
@@ -143,7 +209,7 @@ export const getSubcommand = createSubcommand({
|
|
|
143
209
|
const evalTableData = enriched.evalRuns.map((run) => ({
|
|
144
210
|
ID: run.id,
|
|
145
211
|
'Eval ID': run.eval_id,
|
|
146
|
-
Success: run.success ? '✓' : '✗',
|
|
212
|
+
Success: run.success ? tui.colorSuccess('✓') : tui.colorError('✗'),
|
|
147
213
|
Pending: run.pending ? '⏳' : '✓',
|
|
148
214
|
Error: run.error || 'No',
|
|
149
215
|
Created: new Date(run.created_at).toLocaleString(),
|
|
@@ -159,6 +225,12 @@ export const getSubcommand = createSubcommand({
|
|
|
159
225
|
]);
|
|
160
226
|
}
|
|
161
227
|
|
|
228
|
+
if (result.timeline) {
|
|
229
|
+
console.log('');
|
|
230
|
+
console.log(tui.bold('Timeline:'));
|
|
231
|
+
printTimeline(result.timeline, '');
|
|
232
|
+
}
|
|
233
|
+
|
|
162
234
|
return result;
|
|
163
235
|
} catch (ex) {
|
|
164
236
|
tui.fatal(
|
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/config.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
2
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
3
3
|
import type { Logger } from '@agentuity/core';
|
|
4
4
|
import {
|
|
5
5
|
BuildMetadataSchema,
|
|
@@ -486,6 +486,7 @@ class ProjectConfigNotFoundExpection extends Error {
|
|
|
486
486
|
type ProjectConfig = z.infer<typeof ProjectSchema>;
|
|
487
487
|
|
|
488
488
|
function generateJSON5WithComments(
|
|
489
|
+
jsonSchema: string,
|
|
489
490
|
schema: z.ZodObject<z.ZodRawShape>,
|
|
490
491
|
data: Record<string, unknown>
|
|
491
492
|
): string {
|
|
@@ -493,6 +494,8 @@ function generateJSON5WithComments(
|
|
|
493
494
|
const shape = schema.shape;
|
|
494
495
|
const keys = Object.keys(shape);
|
|
495
496
|
|
|
497
|
+
lines.push(` "$schema": "${jsonSchema}",`);
|
|
498
|
+
|
|
496
499
|
for (let i = 0; i < keys.length; i++) {
|
|
497
500
|
const key = keys[i];
|
|
498
501
|
const fieldSchema = shape[key] as z.ZodTypeAny;
|
|
@@ -551,23 +554,59 @@ export async function loadProjectConfig(
|
|
|
551
554
|
return result.data;
|
|
552
555
|
}
|
|
553
556
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
+
export const InitialProjectConfigSchema = z.intersection(
|
|
558
|
+
ProjectSchema,
|
|
559
|
+
z.object({
|
|
560
|
+
sdkKey: z.string().describe('the project specific SDK key'),
|
|
561
|
+
$schema: z.string().optional(),
|
|
562
|
+
})
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
type InitialProjectConfig = z.infer<typeof InitialProjectConfigSchema>;
|
|
557
566
|
|
|
558
567
|
export async function createProjectConfig(dir: string, config: InitialProjectConfig) {
|
|
559
568
|
const { sdkKey, ...sanitizedConfig } = config;
|
|
560
569
|
|
|
570
|
+
// generate the project config
|
|
561
571
|
const configPath = join(dir, 'agentuity.json');
|
|
562
|
-
const json5Content = generateJSON5WithComments(
|
|
572
|
+
const json5Content = generateJSON5WithComments(
|
|
573
|
+
'https://agentuity.dev/schema/cli/v1/agentuity.json',
|
|
574
|
+
ProjectSchema,
|
|
575
|
+
sanitizedConfig
|
|
576
|
+
);
|
|
563
577
|
await Bun.write(configPath, json5Content + '\n');
|
|
564
578
|
|
|
579
|
+
// generate the .env file with initial secret
|
|
565
580
|
const envPath = join(dir, '.env');
|
|
566
581
|
const comment =
|
|
567
582
|
'# AGENTUITY_SDK_KEY is a sensitive value and should not be committed to version control.';
|
|
568
583
|
const content = `${comment}\nAGENTUITY_SDK_KEY=${sdkKey}\n`;
|
|
569
584
|
await Bun.write(envPath, content);
|
|
570
585
|
await chmod(envPath, 0o600);
|
|
586
|
+
|
|
587
|
+
// generate the vscode settings
|
|
588
|
+
const vscodeDir = join(dir, '.vscode');
|
|
589
|
+
mkdirSync(vscodeDir);
|
|
590
|
+
|
|
591
|
+
const settings = {
|
|
592
|
+
'files.associations': {
|
|
593
|
+
'agentuity.json': 'jsonc',
|
|
594
|
+
},
|
|
595
|
+
'search.exclude': {
|
|
596
|
+
'**/.git/**': true,
|
|
597
|
+
'**/node_modules/**': true,
|
|
598
|
+
'**/bun.lock': true,
|
|
599
|
+
'**/.agentuity/**': true,
|
|
600
|
+
},
|
|
601
|
+
'json.schemas': [
|
|
602
|
+
{
|
|
603
|
+
fileMatch: ['agentuity.json'],
|
|
604
|
+
url: 'https://agentuity.dev/schema/cli/v1/agentuity.json',
|
|
605
|
+
},
|
|
606
|
+
],
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
await Bun.write(join(vscodeDir, 'settings.json'), JSON.stringify(settings, null, 2));
|
|
571
610
|
}
|
|
572
611
|
|
|
573
612
|
export async function loadBuildMetadata(dir: string): Promise<BuildMetadata> {
|
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
|
|