@agentuity/cli 0.1.6 → 0.1.8
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 +64 -4
- package/dist/cli.js.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +159 -16
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
- package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/docs-generator.js +8 -4
- package/dist/cmd/build/vite/docs-generator.js.map +1 -1
- package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/registry-generator.js +27 -4
- package/dist/cmd/build/vite/registry-generator.js.map +1 -1
- package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -1
- package/dist/cmd/build/vite/server-bundler.js +3 -1
- package/dist/cmd/build/vite/server-bundler.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js +5 -2
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
- package/dist/cmd/canary/index.d.ts.map +1 -0
- package/dist/cmd/canary/index.js +186 -0
- package/dist/cmd/canary/index.js.map +1 -0
- package/dist/cmd/cloud/deploy.js +1 -1
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/git/account/add.js +1 -1
- package/dist/cmd/git/account/add.js.map +1 -1
- package/dist/cmd/git/account/list.js +1 -1
- package/dist/cmd/git/account/list.js.map +1 -1
- package/dist/cmd/git/account/remove.js +1 -1
- package/dist/cmd/git/account/remove.js.map +1 -1
- package/dist/cmd/git/api.d.ts.map +1 -0
- package/dist/cmd/git/api.js.map +1 -0
- package/dist/cmd/git/link.js +1 -1
- package/dist/cmd/git/link.js.map +1 -1
- package/dist/cmd/git/list.js +1 -1
- package/dist/cmd/git/list.js.map +1 -1
- package/dist/cmd/git/status.js +1 -1
- package/dist/cmd/git/status.js.map +1 -1
- package/dist/cmd/git/unlink.js +1 -1
- package/dist/cmd/git/unlink.js.map +1 -1
- package/dist/cmd/index.js +1 -1
- package/dist/cmd/index.js.map +1 -1
- package/dist/cmd/project/auth/generate.js.map +1 -1
- package/dist/cmd/project/auth/init.js.map +1 -1
- package/dist/cmd/project/auth/shared.d.ts.map +1 -1
- package/dist/cmd/project/auth/shared.js +1 -2
- package/dist/cmd/project/auth/shared.js.map +1 -1
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/dependency-checker.d.ts.map +1 -1
- package/dist/utils/dependency-checker.js +5 -1
- package/dist/utils/dependency-checker.js.map +1 -1
- package/package.json +6 -6
- package/src/cli.ts +73 -4
- package/src/cmd/build/vite/agent-discovery.ts +209 -16
- package/src/cmd/build/vite/docs-generator.ts +8 -4
- package/src/cmd/build/vite/registry-generator.ts +29 -4
- package/src/cmd/build/vite/server-bundler.ts +4 -5
- package/src/cmd/build/vite/vite-asset-server-config.ts +5 -2
- package/src/cmd/canary/index.ts +214 -0
- package/src/cmd/cloud/deploy.ts +1 -1
- package/src/cmd/git/account/add.ts +1 -1
- package/src/cmd/git/account/list.ts +1 -1
- package/src/cmd/git/account/remove.ts +1 -1
- package/src/cmd/git/link.ts +1 -1
- package/src/cmd/git/list.ts +1 -1
- package/src/cmd/git/status.ts +1 -1
- package/src/cmd/git/unlink.ts +1 -1
- package/src/cmd/index.ts +1 -1
- package/src/cmd/project/auth/generate.ts +4 -4
- package/src/cmd/project/auth/init.ts +2 -2
- package/src/cmd/project/auth/shared.ts +3 -4
- package/src/cmd/project/template-flow.ts +3 -3
- package/src/types.ts +3 -0
- package/src/utils/dependency-checker.ts +6 -2
- package/dist/cmd/integration/api.d.ts.map +0 -1
- package/dist/cmd/integration/api.js.map +0 -1
- package/dist/cmd/integration/github/connect.d.ts +0 -2
- package/dist/cmd/integration/github/connect.d.ts.map +0 -1
- package/dist/cmd/integration/github/connect.js +0 -197
- package/dist/cmd/integration/github/connect.js.map +0 -1
- package/dist/cmd/integration/github/disconnect.d.ts +0 -2
- package/dist/cmd/integration/github/disconnect.d.ts.map +0 -1
- package/dist/cmd/integration/github/disconnect.js +0 -121
- package/dist/cmd/integration/github/disconnect.js.map +0 -1
- package/dist/cmd/integration/github/index.d.ts +0 -2
- package/dist/cmd/integration/github/index.d.ts.map +0 -1
- package/dist/cmd/integration/github/index.js +0 -21
- package/dist/cmd/integration/github/index.js.map +0 -1
- package/dist/cmd/integration/index.d.ts.map +0 -1
- package/dist/cmd/integration/index.js +0 -16
- package/dist/cmd/integration/index.js.map +0 -1
- package/src/cmd/integration/github/connect.ts +0 -242
- package/src/cmd/integration/github/disconnect.ts +0 -149
- package/src/cmd/integration/github/index.ts +0 -21
- package/src/cmd/integration/index.ts +0 -16
- /package/dist/cmd/{integration → canary}/index.d.ts +0 -0
- /package/dist/cmd/{integration → git}/api.d.ts +0 -0
- /package/dist/cmd/{integration → git}/api.js +0 -0
- /package/src/cmd/{integration → git}/api.ts +0 -0
|
@@ -46,11 +46,146 @@ interface ASTCallExpression extends ASTNode {
|
|
|
46
46
|
callee: ASTNode;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
interface ASTMemberExpression extends ASTNode {
|
|
50
|
+
object: ASTNode;
|
|
51
|
+
property: ASTNode;
|
|
52
|
+
computed?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
49
55
|
interface ASTVariableDeclarator extends ASTNode {
|
|
50
56
|
id: ASTNode;
|
|
51
57
|
init?: ASTNode;
|
|
52
58
|
}
|
|
53
59
|
|
|
60
|
+
interface ASTVariableDeclaration extends ASTNode {
|
|
61
|
+
declarations: ASTVariableDeclarator[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface ASTExportNamedDeclaration extends ASTNode {
|
|
65
|
+
declaration?: ASTNode;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface ASTProgram {
|
|
69
|
+
type: string;
|
|
70
|
+
body: ASTNode[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Type for identifier resolver function
|
|
75
|
+
*/
|
|
76
|
+
type IdentifierResolver = (name: string) => ASTNode | undefined;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Build a file-local identifier resolver that maps top-level variable names
|
|
80
|
+
* to their initializer AST nodes. This allows resolving schema variable references.
|
|
81
|
+
*/
|
|
82
|
+
function buildIdentifierResolver(program: ASTProgram): IdentifierResolver {
|
|
83
|
+
const initMap = new Map<string, ASTNode>();
|
|
84
|
+
|
|
85
|
+
for (const node of program.body) {
|
|
86
|
+
// const x = ... or let x = ... or var x = ...
|
|
87
|
+
if (node.type === 'VariableDeclaration') {
|
|
88
|
+
const decl = node as unknown as ASTVariableDeclaration;
|
|
89
|
+
for (const d of decl.declarations) {
|
|
90
|
+
if (d.id.type === 'Identifier' && d.init) {
|
|
91
|
+
const id = d.id as ASTNodeIdentifier;
|
|
92
|
+
initMap.set(id.name, d.init);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// export const x = ...
|
|
98
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
99
|
+
const exp = node as unknown as ASTExportNamedDeclaration;
|
|
100
|
+
if (exp.declaration && exp.declaration.type === 'VariableDeclaration') {
|
|
101
|
+
const decl = exp.declaration as unknown as ASTVariableDeclaration;
|
|
102
|
+
for (const d of decl.declarations) {
|
|
103
|
+
if (d.id.type === 'Identifier' && d.init) {
|
|
104
|
+
const id = d.id as ASTNodeIdentifier;
|
|
105
|
+
initMap.set(id.name, d.init);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return (name: string) => initMap.get(name);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get the property name from an AST node (Identifier or Literal).
|
|
117
|
+
*/
|
|
118
|
+
function getPropertyName(node: ASTNode): string | undefined {
|
|
119
|
+
if (node.type === 'Identifier') {
|
|
120
|
+
return (node as ASTNodeIdentifier).name;
|
|
121
|
+
}
|
|
122
|
+
if (node.type === 'Literal') {
|
|
123
|
+
const lit = node as ASTLiteral;
|
|
124
|
+
return typeof lit.value === 'string' ? lit.value : undefined;
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Resolve an expression by following identifier references and member access chains.
|
|
131
|
+
* Applies a recursion limit to prevent infinite loops from cyclic references.
|
|
132
|
+
*
|
|
133
|
+
* Supported patterns:
|
|
134
|
+
* - Identifiers: `AgentInput` -> resolves to variable definition
|
|
135
|
+
* - Member access: `configs.agent1.schema` -> traverses object literals
|
|
136
|
+
*/
|
|
137
|
+
function resolveExpression(
|
|
138
|
+
node: ASTNode,
|
|
139
|
+
resolveIdentifier: IdentifierResolver,
|
|
140
|
+
depth = 0
|
|
141
|
+
): ASTNode {
|
|
142
|
+
if (!node) return node;
|
|
143
|
+
if (depth > 8) return node; // Prevent cycles / deep alias chains
|
|
144
|
+
|
|
145
|
+
// Follow identifiers to their definitions
|
|
146
|
+
if (node.type === 'Identifier') {
|
|
147
|
+
const id = node as ASTNodeIdentifier;
|
|
148
|
+
const resolved = resolveIdentifier(id.name);
|
|
149
|
+
if (resolved) {
|
|
150
|
+
return resolveExpression(resolved, resolveIdentifier, depth + 1);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Follow member expressions: configs.agent1.schema, baseSchemas.shared
|
|
155
|
+
if (node.type === 'MemberExpression') {
|
|
156
|
+
const memberExpr = node as unknown as ASTMemberExpression;
|
|
157
|
+
|
|
158
|
+
// Skip computed properties like configs[agentName]
|
|
159
|
+
if (memberExpr.computed) return node;
|
|
160
|
+
|
|
161
|
+
const propName = getPropertyName(memberExpr.property);
|
|
162
|
+
if (!propName) return node;
|
|
163
|
+
|
|
164
|
+
// First resolve the object side (e.g., configs -> { agent1: {...} })
|
|
165
|
+
const resolvedObj = resolveExpression(memberExpr.object, resolveIdentifier, depth + 1);
|
|
166
|
+
|
|
167
|
+
// If we got an object literal, look up the property
|
|
168
|
+
if (resolvedObj.type === 'ObjectExpression') {
|
|
169
|
+
const obj = resolvedObj as ASTObjectExpression;
|
|
170
|
+
for (const prop of obj.properties) {
|
|
171
|
+
// Skip spread elements
|
|
172
|
+
if (!prop || !('key' in prop) || !prop.key) continue;
|
|
173
|
+
|
|
174
|
+
const keyName = getPropertyName(prop.key);
|
|
175
|
+
if (keyName === propName && prop.value) {
|
|
176
|
+
// Recurse into the property value
|
|
177
|
+
return resolveExpression(prop.value as ASTNode, resolveIdentifier, depth + 1);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Couldn't resolve - return original node
|
|
183
|
+
return node;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return node;
|
|
187
|
+
}
|
|
188
|
+
|
|
54
189
|
export interface AgentMetadata {
|
|
55
190
|
filename: string;
|
|
56
191
|
name: string;
|
|
@@ -117,9 +252,43 @@ function generateStableEvalId(projectId: string, agentId: string, name: string):
|
|
|
117
252
|
}
|
|
118
253
|
|
|
119
254
|
/**
|
|
120
|
-
*
|
|
255
|
+
* Check if a property key matches a given name.
|
|
256
|
+
* Handles both Identifier keys (schema) and Literal keys ('schema').
|
|
121
257
|
*/
|
|
122
|
-
function
|
|
258
|
+
function isKeyNamed(prop: ASTPropertyNode, name: 'schema' | 'input' | 'output'): boolean {
|
|
259
|
+
if (!prop || !prop.key) return false;
|
|
260
|
+
|
|
261
|
+
if (prop.key.type === 'Identifier') {
|
|
262
|
+
return (prop.key as ASTNodeIdentifier).name === name;
|
|
263
|
+
}
|
|
264
|
+
if (prop.key.type === 'Literal') {
|
|
265
|
+
const lit = prop.key as unknown as ASTLiteral;
|
|
266
|
+
return typeof lit.value === 'string' && lit.value === name;
|
|
267
|
+
}
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Extract schema code from createAgent call arguments.
|
|
273
|
+
* Resolves variable references to their actual definitions when possible.
|
|
274
|
+
*
|
|
275
|
+
* Supported patterns:
|
|
276
|
+
* - Inline schema: `schema: { input: s.object({...}), output: s.object({...}) }`
|
|
277
|
+
* - Variable reference: `schema: { input: AgentInput, output: AgentOutput }`
|
|
278
|
+
* - Schema object variable: `schema: schemaVar` where schemaVar is a top-level const
|
|
279
|
+
* - Shorthand: `schema: { input, output }` where input/output are top-level consts
|
|
280
|
+
*
|
|
281
|
+
* Unsupported patterns (returns empty or partial result):
|
|
282
|
+
* - Config alias: `createAgent('x', configVar)` - config must be inline object
|
|
283
|
+
* - Schema from member access: `schema: configs.agent1.schema`
|
|
284
|
+
* - Schema from function call: `schema: getSchema()`
|
|
285
|
+
* - Destructured variables: `const { schema } = config`
|
|
286
|
+
* - Cross-file imports (falls back to identifier name)
|
|
287
|
+
*/
|
|
288
|
+
function extractSchemaCode(
|
|
289
|
+
callargexp: ASTObjectExpression,
|
|
290
|
+
resolveIdentifier: IdentifierResolver
|
|
291
|
+
): {
|
|
123
292
|
inputSchemaCode?: string;
|
|
124
293
|
outputSchemaCode?: string;
|
|
125
294
|
} {
|
|
@@ -127,9 +296,16 @@ function extractSchemaCode(callargexp: ASTObjectExpression): {
|
|
|
127
296
|
|
|
128
297
|
// Find the schema property
|
|
129
298
|
for (const prop of callargexp.properties) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
299
|
+
// Skip spread elements or any non-Property nodes
|
|
300
|
+
if (!prop || !('key' in prop) || !prop.key) continue;
|
|
301
|
+
|
|
302
|
+
if (isKeyNamed(prop, 'schema')) {
|
|
303
|
+
// Resolve the schema value if it's an identifier (e.g., schema: schemaVar)
|
|
304
|
+
let valueNode = prop.value as ASTNode;
|
|
305
|
+
valueNode = resolveExpression(valueNode, resolveIdentifier);
|
|
306
|
+
|
|
307
|
+
if (valueNode.type === 'ObjectExpression') {
|
|
308
|
+
schemaObj = valueNode as ASTObjectExpression;
|
|
133
309
|
break;
|
|
134
310
|
}
|
|
135
311
|
}
|
|
@@ -144,12 +320,17 @@ function extractSchemaCode(callargexp: ASTObjectExpression): {
|
|
|
144
320
|
|
|
145
321
|
// Extract input and output schema code
|
|
146
322
|
for (const prop of schemaObj.properties) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
323
|
+
// Skip spread elements or any non-Property nodes
|
|
324
|
+
if (!prop || !('key' in prop) || !prop.key) continue;
|
|
325
|
+
|
|
326
|
+
if (isKeyNamed(prop, 'input') && prop.value) {
|
|
327
|
+
// Resolve variable reference if the value is an identifier
|
|
328
|
+
const resolvedValue = resolveExpression(prop.value as ASTNode, resolveIdentifier);
|
|
329
|
+
inputSchemaCode = formatSchemaCode(generate(resolvedValue));
|
|
330
|
+
} else if (isKeyNamed(prop, 'output') && prop.value) {
|
|
331
|
+
// Resolve variable reference if the value is an identifier
|
|
332
|
+
const resolvedValue = resolveExpression(prop.value as ASTNode, resolveIdentifier);
|
|
333
|
+
outputSchemaCode = formatSchemaCode(generate(resolvedValue));
|
|
153
334
|
}
|
|
154
335
|
}
|
|
155
336
|
|
|
@@ -179,13 +360,19 @@ function extractAgentMetadata(
|
|
|
179
360
|
projectId: string,
|
|
180
361
|
deploymentId: string
|
|
181
362
|
): AgentMetadata | null {
|
|
182
|
-
const ast = acornLoose.parse(code, {
|
|
363
|
+
const ast = acornLoose.parse(code, {
|
|
364
|
+
ecmaVersion: 'latest',
|
|
365
|
+
sourceType: 'module',
|
|
366
|
+
}) as ASTProgram;
|
|
367
|
+
|
|
368
|
+
// Build identifier resolver for resolving schema variable references
|
|
369
|
+
const resolveIdentifier = buildIdentifierResolver(ast);
|
|
183
370
|
|
|
184
371
|
// Calculate file version (hash of contents)
|
|
185
372
|
const version = hash(code);
|
|
186
373
|
|
|
187
374
|
// Find createAgent calls
|
|
188
|
-
for (const node of
|
|
375
|
+
for (const node of ast.body) {
|
|
189
376
|
if (node.type === 'ExportDefaultDeclaration') {
|
|
190
377
|
const declaration = (node as unknown as { declaration: ASTNode }).declaration;
|
|
191
378
|
|
|
@@ -204,8 +391,11 @@ function extractAgentMetadata(
|
|
|
204
391
|
// Second arg is config object
|
|
205
392
|
const callargexp = callExpr.arguments[1] as ASTObjectExpression;
|
|
206
393
|
|
|
207
|
-
// Extract schemas
|
|
208
|
-
const { inputSchemaCode, outputSchemaCode } = extractSchemaCode(
|
|
394
|
+
// Extract schemas (with variable resolution)
|
|
395
|
+
const { inputSchemaCode, outputSchemaCode } = extractSchemaCode(
|
|
396
|
+
callargexp,
|
|
397
|
+
resolveIdentifier
|
|
398
|
+
);
|
|
209
399
|
|
|
210
400
|
// Extract description from either direct property or metadata object
|
|
211
401
|
let description: string | undefined;
|
|
@@ -262,7 +452,10 @@ function extractAgentMetadata(
|
|
|
262
452
|
const name = String(nameArg.value);
|
|
263
453
|
|
|
264
454
|
const callargexp = callExpr.arguments[1] as ASTObjectExpression;
|
|
265
|
-
const { inputSchemaCode, outputSchemaCode } = extractSchemaCode(
|
|
455
|
+
const { inputSchemaCode, outputSchemaCode } = extractSchemaCode(
|
|
456
|
+
callargexp,
|
|
457
|
+
resolveIdentifier
|
|
458
|
+
);
|
|
266
459
|
|
|
267
460
|
let description: string | undefined;
|
|
268
461
|
for (const prop of callargexp.properties) {
|
|
@@ -20,8 +20,10 @@ This directory contains auto-generated TypeScript files created by the Agentuity
|
|
|
20
20
|
- \`registry.ts\` - Agent registry from \`src/agent/**\`
|
|
21
21
|
- \`routes.ts\` - Route registry from \`src/api/**\`
|
|
22
22
|
- \`app.ts\` - Application entry point
|
|
23
|
-
- \`
|
|
24
|
-
- \`
|
|
23
|
+
- \`analytics-config.ts\` - Web analytics configuration from \`agentuity.json\`
|
|
24
|
+
- \`webanalytics.ts\` - Web analytics injection and route registration
|
|
25
|
+
- \`state.ts\` - App state type (only generated when \`setup()\` returns state in \`app.ts\`)
|
|
26
|
+
- \`router.ts\` - Runtime wrapper with type augmentation (only generated when \`setup()\` returns state in \`app.ts\`)
|
|
25
27
|
|
|
26
28
|
## For Developers
|
|
27
29
|
|
|
@@ -50,8 +52,10 @@ const AGENTS_MD_CONTENT = `# AI Agent Instructions
|
|
|
50
52
|
- \`registry.ts\` - Built from agent discovery in \`src/agent/\`
|
|
51
53
|
- \`routes.ts\` - Built from route discovery in \`src/api/\`
|
|
52
54
|
- \`app.ts\` - Entry point assembled from project configuration
|
|
53
|
-
- \`
|
|
54
|
-
- \`
|
|
55
|
+
- \`analytics-config.ts\` - Web analytics configuration from \`agentuity.json\`
|
|
56
|
+
- \`webanalytics.ts\` - Web analytics injection and route registration
|
|
57
|
+
- \`state.ts\` - App state type (only generated when \`setup()\` returns state in \`app.ts\`)
|
|
58
|
+
- \`router.ts\` - Runtime wrapper with type augmentation (only generated when \`setup()\` returns state)
|
|
55
59
|
|
|
56
60
|
These files are regenerated on every \`bun run build\` or \`bun run dev\`.
|
|
57
61
|
`;
|
|
@@ -935,11 +935,15 @@ ${routeSchemaTypes}
|
|
|
935
935
|
* Route Definitions
|
|
936
936
|
*
|
|
937
937
|
* Type-safe route registry for all API routes, WebSocket connections, and SSE endpoints.
|
|
938
|
-
* Used by @agentuity/react for client-side type-safe routing.
|
|
938
|
+
* Used by @agentuity/react and @agentuity/frontend for client-side type-safe routing.
|
|
939
939
|
*
|
|
940
940
|
* @remarks
|
|
941
941
|
* This module augmentation is auto-generated from your route files during build.
|
|
942
942
|
* Individual route Input/Output types are exported above for direct usage.
|
|
943
|
+
*
|
|
944
|
+
* The augmentation targets @agentuity/frontend (the canonical source of registry types).
|
|
945
|
+
* Since @agentuity/react re-exports these types, the augmentation is visible when
|
|
946
|
+
* importing from either package.
|
|
943
947
|
*/
|
|
944
948
|
${
|
|
945
949
|
shouldEmitFrontendClient
|
|
@@ -956,7 +960,7 @@ ${rpcRegistryType}
|
|
|
956
960
|
`
|
|
957
961
|
: ''
|
|
958
962
|
}
|
|
959
|
-
declare module '@agentuity/
|
|
963
|
+
declare module '@agentuity/frontend' {
|
|
960
964
|
\t/**
|
|
961
965
|
\t * API Route Registry
|
|
962
966
|
\t *
|
|
@@ -988,13 +992,34 @@ ${sseRouteEntries}
|
|
|
988
992
|
\t * RPC Route Registry
|
|
989
993
|
\t *
|
|
990
994
|
\t * Nested structure for RPC-style client access (e.g., client.hello.post())
|
|
991
|
-
\t * Used by createClient() from @agentuity/
|
|
995
|
+
\t * Used by createClient() from @agentuity/frontend for type-safe RPC calls.
|
|
992
996
|
\t */
|
|
993
997
|
\texport interface RPCRouteRegistry {
|
|
994
998
|
${rpcRegistryType}
|
|
995
999
|
\t}
|
|
996
1000
|
}
|
|
997
|
-
|
|
1001
|
+
${
|
|
1002
|
+
hasReactDependency
|
|
1003
|
+
? `
|
|
1004
|
+
// Backward compatibility: also augment @agentuity/react for older versions
|
|
1005
|
+
// that define RouteRegistry locally instead of re-exporting from @agentuity/frontend
|
|
1006
|
+
declare module '@agentuity/react' {
|
|
1007
|
+
\texport interface RouteRegistry {
|
|
1008
|
+
${apiRouteEntries}
|
|
1009
|
+
\t}
|
|
1010
|
+
\texport interface WebSocketRouteRegistry {
|
|
1011
|
+
${websocketRouteEntries}
|
|
1012
|
+
\t}
|
|
1013
|
+
\texport interface SSERouteRegistry {
|
|
1014
|
+
${sseRouteEntries}
|
|
1015
|
+
\t}
|
|
1016
|
+
\texport interface RPCRouteRegistry {
|
|
1017
|
+
${rpcRegistryType}
|
|
1018
|
+
\t}
|
|
1019
|
+
}
|
|
1020
|
+
`
|
|
1021
|
+
: ''
|
|
1022
|
+
}
|
|
998
1023
|
/**
|
|
999
1024
|
* Runtime metadata for RPC routes.
|
|
1000
1025
|
* Contains route type information for client routing decisions.
|
|
@@ -66,7 +66,9 @@ export async function installExternalsAndBuild(options: ServerBundleOptions): Pr
|
|
|
66
66
|
|
|
67
67
|
// Build tool externals: packages that should be external but NOT installed
|
|
68
68
|
// These are devDependencies that may exist in node_modules but aren't needed at runtime
|
|
69
|
-
|
|
69
|
+
// NOTE: @babel/* is NOT externalized because some runtime deps (e.g., puppeteer → cosmiconfig → parse-json)
|
|
70
|
+
// require @babel/code-frame at runtime. Babel packages are pure JS and bundle fine.
|
|
71
|
+
const buildToolExternals = ['lightningcss', '@vitejs/*', 'vite', 'esbuild'];
|
|
70
72
|
|
|
71
73
|
// Load custom externals and define from agentuity.config.ts if it exists
|
|
72
74
|
const customExternals: string[] = [];
|
|
@@ -194,10 +196,7 @@ export async function installExternalsAndBuild(options: ServerBundleOptions): Pr
|
|
|
194
196
|
// Use npm with --force for cross-platform installs since Bun's --target flag
|
|
195
197
|
// doesn't correctly handle optional dependencies for other platforms
|
|
196
198
|
const allPackagesToInstall = [...externalInstalls, ...platformOptionalDeps];
|
|
197
|
-
logger.debug(
|
|
198
|
-
'Installing with npm (cross-platform): %s',
|
|
199
|
-
allPackagesToInstall.join(', ')
|
|
200
|
-
);
|
|
199
|
+
logger.debug('Installing with npm (cross-platform): %s', allPackagesToInstall.join(', '));
|
|
201
200
|
|
|
202
201
|
const proc = Bun.spawn(
|
|
203
202
|
[
|
|
@@ -70,9 +70,12 @@ export async function generateAssetServerConfig(
|
|
|
70
70
|
dedupe: ['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime'],
|
|
71
71
|
},
|
|
72
72
|
|
|
73
|
-
// Pre-bundle
|
|
73
|
+
// Pre-bundle dependencies to avoid React preamble issues with pre-built JSX
|
|
74
|
+
// Only include @agentuity/workbench if workbench is enabled
|
|
74
75
|
optimizeDeps: {
|
|
75
|
-
include:
|
|
76
|
+
include: workbenchPath
|
|
77
|
+
? ['@agentuity/workbench', '@agentuity/core', '@agentuity/react']
|
|
78
|
+
: ['@agentuity/core', '@agentuity/react'],
|
|
76
79
|
},
|
|
77
80
|
|
|
78
81
|
// Only allow frontend env vars (server uses process.env)
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { createCommand } from '../../types';
|
|
2
|
+
import { getPlatformInfo } from '../upgrade';
|
|
3
|
+
import { downloadWithProgress } from '../../download';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { $ } from 'bun';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
import { readdir, rm, mkdir, stat } from 'node:fs/promises';
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
import * as tui from '../../tui';
|
|
11
|
+
|
|
12
|
+
const CANARY_CACHE_DIR = join(homedir(), '.agentuity', 'canary');
|
|
13
|
+
const CANARY_BASE_URL = 'https://agentuity-sdk-objects.t3.storage.dev/binary';
|
|
14
|
+
const CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
15
|
+
|
|
16
|
+
const CanaryArgsSchema = z.object({
|
|
17
|
+
args: z
|
|
18
|
+
.array(z.string())
|
|
19
|
+
.describe('Version/URL followed by commands to run (e.g., 0.1.6-abc1234 deploy --force)'),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const CanaryResponseSchema = z.object({
|
|
23
|
+
executed: z.boolean().describe('Whether the canary was executed'),
|
|
24
|
+
version: z.string().describe('The canary version'),
|
|
25
|
+
message: z.string().describe('Status message'),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function isUrl(str: string): boolean {
|
|
29
|
+
return str.startsWith('http://') || str.startsWith('https://');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getBinaryFilename(platform: { os: string; arch: string }): string {
|
|
33
|
+
return `agentuity-${platform.os}-${platform.arch}.gz`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getCachePath(version: string): string {
|
|
37
|
+
return join(CANARY_CACHE_DIR, version, 'agentuity');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function hashUrl(url: string): string {
|
|
41
|
+
return createHash('sha256').update(url).digest('hex').slice(0, 12);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function cleanupOldCanaries(): Promise<void> {
|
|
45
|
+
try {
|
|
46
|
+
await mkdir(CANARY_CACHE_DIR, { recursive: true });
|
|
47
|
+
const entries = await readdir(CANARY_CACHE_DIR);
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
const entryPath = join(CANARY_CACHE_DIR, entry);
|
|
52
|
+
try {
|
|
53
|
+
const stats = await stat(entryPath);
|
|
54
|
+
if (now - stats.mtimeMs > CACHE_MAX_AGE_MS) {
|
|
55
|
+
await rm(entryPath, { recursive: true, force: true });
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
// Ignore errors for individual entries
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// Ignore cleanup errors
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function downloadCanary(url: string, destPath: string): Promise<void> {
|
|
67
|
+
const destDir = join(destPath, '..');
|
|
68
|
+
await mkdir(destDir, { recursive: true });
|
|
69
|
+
|
|
70
|
+
const gzPath = `${destPath}.gz`;
|
|
71
|
+
|
|
72
|
+
const stream = await downloadWithProgress({
|
|
73
|
+
url,
|
|
74
|
+
message: 'Downloading canary...',
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const writer = Bun.file(gzPath).writer();
|
|
78
|
+
for await (const chunk of stream) {
|
|
79
|
+
writer.write(chunk);
|
|
80
|
+
}
|
|
81
|
+
await writer.end();
|
|
82
|
+
|
|
83
|
+
if (!(await Bun.file(gzPath).exists())) {
|
|
84
|
+
throw new Error('Download failed - file not created');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
await $`gunzip ${gzPath}`.quiet();
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (await Bun.file(gzPath).exists()) {
|
|
91
|
+
await $`rm ${gzPath}`.quiet();
|
|
92
|
+
}
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Decompression failed: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!(await Bun.file(destPath).exists())) {
|
|
99
|
+
throw new Error('Decompression failed - file not found');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
await $`chmod 755 ${destPath}`.quiet();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const command = createCommand({
|
|
106
|
+
name: 'canary',
|
|
107
|
+
description: 'Run a canary version of the CLI',
|
|
108
|
+
hidden: true,
|
|
109
|
+
skipUpgradeCheck: true,
|
|
110
|
+
passThroughArgs: true,
|
|
111
|
+
schema: {
|
|
112
|
+
args: CanaryArgsSchema,
|
|
113
|
+
response: CanaryResponseSchema,
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
async handler(ctx) {
|
|
117
|
+
const { args } = ctx;
|
|
118
|
+
|
|
119
|
+
// Get raw args from process.argv to capture ALL args after 'canary <version>'
|
|
120
|
+
// This ensures we forward everything including flags like --json, --force, etc.
|
|
121
|
+
const argv = process.argv;
|
|
122
|
+
const canaryIndex = argv.indexOf('canary');
|
|
123
|
+
|
|
124
|
+
if (args.args.length === 0) {
|
|
125
|
+
tui.error('Usage: agentuity canary <version|url> [commands...]');
|
|
126
|
+
tui.newline();
|
|
127
|
+
tui.info('Examples:');
|
|
128
|
+
tui.info(' agentuity canary 0.1.6-abc1234');
|
|
129
|
+
tui.info(' agentuity canary 0.1.6-abc1234 deploy --log-level trace');
|
|
130
|
+
tui.info(
|
|
131
|
+
' agentuity canary https://agentuity-sdk-objects.t3.storage.dev/binary/0.1.6-abc1234/agentuity-darwin-arm64.gz'
|
|
132
|
+
);
|
|
133
|
+
return {
|
|
134
|
+
executed: false,
|
|
135
|
+
version: '',
|
|
136
|
+
message: 'No target specified',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Get target from parsed args, but get forward args from raw argv
|
|
141
|
+
// This captures ALL args after the version including any flags
|
|
142
|
+
const target = args.args[0];
|
|
143
|
+
const targetIndex = canaryIndex >= 0 ? argv.indexOf(target, canaryIndex) : -1;
|
|
144
|
+
const forwardArgs = targetIndex >= 0 ? argv.slice(targetIndex + 1) : args.args.slice(1);
|
|
145
|
+
|
|
146
|
+
// Clean up old canaries in background
|
|
147
|
+
cleanupOldCanaries().catch(() => {});
|
|
148
|
+
|
|
149
|
+
const platform = getPlatformInfo();
|
|
150
|
+
let version: string;
|
|
151
|
+
let downloadUrl: string;
|
|
152
|
+
let cachePath: string;
|
|
153
|
+
|
|
154
|
+
if (isUrl(target)) {
|
|
155
|
+
// Extract version from URL, or create a unique hash for custom URLs
|
|
156
|
+
const match = target.match(/\/binary\/([^/]+)\//);
|
|
157
|
+
version = match ? match[1] : `custom-${hashUrl(target)}`;
|
|
158
|
+
downloadUrl = target;
|
|
159
|
+
cachePath = getCachePath(version);
|
|
160
|
+
} else {
|
|
161
|
+
// Treat as version string
|
|
162
|
+
version = target;
|
|
163
|
+
const filename = getBinaryFilename(platform);
|
|
164
|
+
downloadUrl = `${CANARY_BASE_URL}/${version}/${filename}`;
|
|
165
|
+
cachePath = getCachePath(version);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Check cache
|
|
169
|
+
if (await Bun.file(cachePath).exists()) {
|
|
170
|
+
tui.info(`Using cached canary ${version}`);
|
|
171
|
+
} else {
|
|
172
|
+
tui.info(`Downloading canary ${version}...`);
|
|
173
|
+
try {
|
|
174
|
+
await downloadCanary(downloadUrl, cachePath);
|
|
175
|
+
tui.success(`Downloaded canary ${version}`);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
tui.error(
|
|
178
|
+
`Failed to download canary: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
179
|
+
);
|
|
180
|
+
return {
|
|
181
|
+
executed: false,
|
|
182
|
+
version,
|
|
183
|
+
message: `Failed to download: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Update access time
|
|
189
|
+
try {
|
|
190
|
+
await $`touch -a -m ${cachePath}`.quiet();
|
|
191
|
+
} catch {
|
|
192
|
+
// Ignore touch errors
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
tui.newline();
|
|
196
|
+
tui.info(`Running canary ${version}...`);
|
|
197
|
+
tui.newline();
|
|
198
|
+
|
|
199
|
+
// Execute the canary binary with forwarded args
|
|
200
|
+
// Skip version check in the canary binary to avoid upgrade prompts
|
|
201
|
+
const proc = Bun.spawn([cachePath, ...forwardArgs], {
|
|
202
|
+
stdin: 'inherit',
|
|
203
|
+
stdout: 'inherit',
|
|
204
|
+
stderr: 'inherit',
|
|
205
|
+
env: {
|
|
206
|
+
...process.env,
|
|
207
|
+
AGENTUITY_SKIP_VERSION_CHECK: '1',
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const exitCode = await proc.exited;
|
|
212
|
+
process.exit(exitCode);
|
|
213
|
+
},
|
|
214
|
+
});
|
package/src/cmd/cloud/deploy.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
loadProjectSDKKey,
|
|
15
15
|
updateProjectConfig,
|
|
16
16
|
} from '../../config';
|
|
17
|
-
import { getProjectGithubStatus } from '../
|
|
17
|
+
import { getProjectGithubStatus } from '../git/api';
|
|
18
18
|
import { runGitLink } from '../git/link';
|
|
19
19
|
import {
|
|
20
20
|
runSteps,
|
|
@@ -3,7 +3,7 @@ import * as tui from '../../../tui';
|
|
|
3
3
|
import { getCommand } from '../../../command-prefix';
|
|
4
4
|
import { ErrorCode } from '../../../errors';
|
|
5
5
|
import { listOrganizations } from '@agentuity/server';
|
|
6
|
-
import { getGithubIntegrationStatus } from '
|
|
6
|
+
import { getGithubIntegrationStatus } from '../api';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
|
|
9
9
|
const ListResponseSchema = z.array(
|
package/src/cmd/git/link.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
linkProjectToRepo,
|
|
11
11
|
getProjectGithubStatus,
|
|
12
12
|
type GithubRepo,
|
|
13
|
-
} from '
|
|
13
|
+
} from './api';
|
|
14
14
|
import type { APIClient } from '../../api';
|
|
15
15
|
import type { Logger } from '@agentuity/core';
|
|
16
16
|
import { runGitAccountConnect } from './account/add';
|
package/src/cmd/git/list.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as tui from '../../tui';
|
|
|
3
3
|
import { getCommand } from '../../command-prefix';
|
|
4
4
|
import enquirer from 'enquirer';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
-
import { getGithubIntegrationStatus, listGithubRepos } from '
|
|
6
|
+
import { getGithubIntegrationStatus, listGithubRepos } from './api';
|
|
7
7
|
import { ErrorCode } from '../../errors';
|
|
8
8
|
import { listOrganizations } from '@agentuity/server';
|
|
9
9
|
|