@agentuity/cli 0.0.56 → 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/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 +130 -38
- 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/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/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 +149 -37
- 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/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/cmd/build/ast.ts
CHANGED
|
@@ -3,6 +3,11 @@ import { basename, dirname, relative } from 'node:path';
|
|
|
3
3
|
import { generate } from 'astring';
|
|
4
4
|
import type { BuildMetadata } from '../../types';
|
|
5
5
|
import { createLogger } from '@agentuity/server';
|
|
6
|
+
import * as ts from 'typescript';
|
|
7
|
+
import type { WorkbenchConfig } from '@agentuity/core';
|
|
8
|
+
import type { LogLevel } from '../../types';
|
|
9
|
+
|
|
10
|
+
const logger = createLogger((process.env.AGENTUITY_LOG_LEVEL || 'info') as LogLevel);
|
|
6
11
|
|
|
7
12
|
interface ASTNode {
|
|
8
13
|
type: string;
|
|
@@ -925,14 +930,6 @@ export async function parseRoute(
|
|
|
925
930
|
return routes;
|
|
926
931
|
}
|
|
927
932
|
|
|
928
|
-
/**
|
|
929
|
-
* Configuration extracted from createWorkbench call
|
|
930
|
-
*/
|
|
931
|
-
export interface WorkbenchConfig {
|
|
932
|
-
route: string;
|
|
933
|
-
headers?: Record<string, string>;
|
|
934
|
-
}
|
|
935
|
-
|
|
936
933
|
/**
|
|
937
934
|
* Result of workbench analysis
|
|
938
935
|
*/
|
|
@@ -949,15 +946,14 @@ export interface WorkbenchAnalysis {
|
|
|
949
946
|
* @param functionName - The function name to check for (e.g., 'createWorkbench')
|
|
950
947
|
* @returns true if the function is both imported and called
|
|
951
948
|
*/
|
|
952
|
-
export
|
|
949
|
+
export function checkFunctionUsage(content: string, functionName: string): boolean {
|
|
953
950
|
try {
|
|
954
|
-
const ts = await import('typescript');
|
|
955
951
|
const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
|
|
956
952
|
|
|
957
953
|
let hasImport = false;
|
|
958
954
|
let hasUsage = false;
|
|
959
955
|
|
|
960
|
-
function visitNode(node:
|
|
956
|
+
function visitNode(node: ts.Node): void {
|
|
961
957
|
// Check for import declarations with the function
|
|
962
958
|
if (ts.isImportDeclaration(node) && node.importClause?.namedBindings) {
|
|
963
959
|
if (ts.isNamedImports(node.importClause.namedBindings)) {
|
|
@@ -983,7 +979,7 @@ export async function checkFunctionUsage(content: string, functionName: string):
|
|
|
983
979
|
return hasImport && hasUsage;
|
|
984
980
|
} catch (error) {
|
|
985
981
|
// Fallback to string check if AST parsing fails
|
|
986
|
-
|
|
982
|
+
logger.warn(`AST parsing failed for ${functionName}, falling back to string check:`, error);
|
|
987
983
|
return content.includes(functionName);
|
|
988
984
|
}
|
|
989
985
|
}
|
|
@@ -991,17 +987,13 @@ export async function checkFunctionUsage(content: string, functionName: string):
|
|
|
991
987
|
/**
|
|
992
988
|
* Check if app.ts contains conflicting routes for a given endpoint
|
|
993
989
|
*/
|
|
994
|
-
export
|
|
995
|
-
content: string,
|
|
996
|
-
workbenchEndpoint: string
|
|
997
|
-
): Promise<boolean> {
|
|
990
|
+
export function checkRouteConflicts(content: string, workbenchEndpoint: string): boolean {
|
|
998
991
|
try {
|
|
999
|
-
const ts = await import('typescript');
|
|
1000
992
|
const sourceFile = ts.createSourceFile('app.ts', content, ts.ScriptTarget.Latest, true);
|
|
1001
993
|
|
|
1002
994
|
let hasConflict = false;
|
|
1003
995
|
|
|
1004
|
-
function visitNode(node:
|
|
996
|
+
function visitNode(node: ts.Node): void {
|
|
1005
997
|
// Check for router.get calls
|
|
1006
998
|
if (
|
|
1007
999
|
ts.isCallExpression(node) &&
|
|
@@ -1033,16 +1025,15 @@ export async function checkRouteConflicts(
|
|
|
1033
1025
|
* @param content - The TypeScript source code
|
|
1034
1026
|
* @returns workbench analysis including usage and config
|
|
1035
1027
|
*/
|
|
1036
|
-
export
|
|
1028
|
+
export function analyzeWorkbench(content: string): WorkbenchAnalysis {
|
|
1037
1029
|
try {
|
|
1038
|
-
const ts = await import('typescript');
|
|
1039
1030
|
const sourceFile = ts.createSourceFile('app.ts', content, ts.ScriptTarget.Latest, true);
|
|
1040
1031
|
|
|
1041
1032
|
let hasImport = false;
|
|
1042
1033
|
let hasUsage = false;
|
|
1043
1034
|
let config: WorkbenchConfig | null = null;
|
|
1044
1035
|
|
|
1045
|
-
function visitNode(node:
|
|
1036
|
+
function visitNode(node: ts.Node): void {
|
|
1046
1037
|
// Check for import declarations with createWorkbench
|
|
1047
1038
|
if (ts.isImportDeclaration(node) && node.importClause?.namedBindings) {
|
|
1048
1039
|
if (ts.isNamedImports(node.importClause.namedBindings)) {
|
|
@@ -1062,7 +1053,7 @@ export async function analyzeWorkbench(content: string): Promise<WorkbenchAnalys
|
|
|
1062
1053
|
// Extract configuration from the first argument (if any)
|
|
1063
1054
|
if (node.arguments.length > 0) {
|
|
1064
1055
|
const configArg = node.arguments[0];
|
|
1065
|
-
config = parseConfigObject(configArg
|
|
1056
|
+
config = parseConfigObject(configArg);
|
|
1066
1057
|
} else {
|
|
1067
1058
|
// Default config if no arguments provided
|
|
1068
1059
|
config = { route: '/workbench' };
|
|
@@ -1087,7 +1078,7 @@ export async function analyzeWorkbench(content: string): Promise<WorkbenchAnalys
|
|
|
1087
1078
|
};
|
|
1088
1079
|
} catch (error) {
|
|
1089
1080
|
// Fallback to simple check if AST parsing fails
|
|
1090
|
-
|
|
1081
|
+
logger.warn('Workbench AST parsing failed, falling back to string check:', error);
|
|
1091
1082
|
const hasWorkbench = content.includes('createWorkbench');
|
|
1092
1083
|
return {
|
|
1093
1084
|
hasWorkbench,
|
|
@@ -1099,10 +1090,7 @@ export async function analyzeWorkbench(content: string): Promise<WorkbenchAnalys
|
|
|
1099
1090
|
/**
|
|
1100
1091
|
* Parse a TypeScript object literal to extract configuration
|
|
1101
1092
|
*/
|
|
1102
|
-
function parseConfigObject(
|
|
1103
|
-
node: import('typescript').Node,
|
|
1104
|
-
ts: typeof import('typescript')
|
|
1105
|
-
): WorkbenchConfig | null {
|
|
1093
|
+
function parseConfigObject(node: ts.Node): WorkbenchConfig | null {
|
|
1106
1094
|
if (!ts.isObjectLiteralExpression(node)) {
|
|
1107
1095
|
return { route: '/workbench' }; // Default config
|
|
1108
1096
|
}
|
package/src/cmd/build/bundler.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $ } from 'bun';
|
|
2
|
+
import { z } from 'zod';
|
|
2
3
|
import { join, relative, resolve, dirname } from 'node:path';
|
|
3
|
-
import { createRequire } from 'node:module';
|
|
4
4
|
import { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs';
|
|
5
5
|
import gitParseUrl from 'git-url-parse';
|
|
6
6
|
import AgentuityBundler, { getBuildMetadata } from './plugin';
|
|
@@ -10,8 +10,37 @@ import type { Project } from '../../types';
|
|
|
10
10
|
import { fixDuplicateExportsInDirectory } from './fix-duplicate-exports';
|
|
11
11
|
import { createLogger } from '@agentuity/server';
|
|
12
12
|
import type { LogLevel } from '../../types';
|
|
13
|
+
import { generateWorkbenchMainTsx, generateWorkbenchIndexHtml } from './workbench-templates';
|
|
14
|
+
import { analyzeWorkbench } from './ast';
|
|
15
|
+
import { encodeWorkbenchConfig } from '@agentuity/core';
|
|
13
16
|
|
|
14
|
-
export
|
|
17
|
+
export const DeployOptionsSchema = z.object({
|
|
18
|
+
tag: z
|
|
19
|
+
.array(z.string())
|
|
20
|
+
.default(['latest'])
|
|
21
|
+
.optional()
|
|
22
|
+
.describe('One or more tags to add to the deployment'),
|
|
23
|
+
logsUrl: z.url().optional().describe('The url to the CI build logs'),
|
|
24
|
+
trigger: z
|
|
25
|
+
.enum(['cli', 'workflow', 'webhook'])
|
|
26
|
+
.default('cli')
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('The trigger that caused the build'),
|
|
29
|
+
commitUrl: z.url().optional().describe('The url to the CI commit'),
|
|
30
|
+
provider: z.string().optional().describe('The CI provider name (attempts to autodetect)'),
|
|
31
|
+
event: z
|
|
32
|
+
.enum(['pull_request', 'push', 'manual', 'workflow'])
|
|
33
|
+
.default('manual')
|
|
34
|
+
.optional()
|
|
35
|
+
.describe('The event that triggered the deployment'),
|
|
36
|
+
pullRequestNumber: z.number().optional().describe('the pull request number'),
|
|
37
|
+
pullRequestCommentId: z.string().optional().describe('the pull request comment id'),
|
|
38
|
+
pullRequestURL: z.url().optional().describe('the pull request url'),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
type DeployOptions = z.infer<typeof DeployOptionsSchema>;
|
|
42
|
+
|
|
43
|
+
export interface BundleOptions extends DeployOptions {
|
|
15
44
|
rootDir: string;
|
|
16
45
|
dev?: boolean;
|
|
17
46
|
env?: Map<string, string>;
|
|
@@ -30,6 +59,15 @@ export async function bundle({
|
|
|
30
59
|
rootDir,
|
|
31
60
|
project,
|
|
32
61
|
port,
|
|
62
|
+
tag,
|
|
63
|
+
logsUrl,
|
|
64
|
+
commitUrl,
|
|
65
|
+
provider,
|
|
66
|
+
trigger,
|
|
67
|
+
event,
|
|
68
|
+
pullRequestNumber,
|
|
69
|
+
pullRequestCommentId,
|
|
70
|
+
pullRequestURL,
|
|
33
71
|
}: BundleOptions) {
|
|
34
72
|
const appFile = join(rootDir, 'app.ts');
|
|
35
73
|
if (!existsSync(appFile)) {
|
|
@@ -254,14 +292,12 @@ export async function bundle({
|
|
|
254
292
|
}
|
|
255
293
|
|
|
256
294
|
// Bundle workbench app if detected via setupWorkbench
|
|
257
|
-
const { analyzeWorkbench } = await import('./ast');
|
|
258
295
|
if (existsSync(appFile)) {
|
|
259
296
|
const appContent = await Bun.file(appFile).text();
|
|
260
|
-
const analysis =
|
|
297
|
+
const analysis = analyzeWorkbench(appContent);
|
|
261
298
|
|
|
262
299
|
if (analysis.hasWorkbench) {
|
|
263
300
|
// Encode workbench config for environment variable
|
|
264
|
-
const { encodeWorkbenchConfig } = await import('@agentuity/core');
|
|
265
301
|
const config = analysis.config || { route: '/workbench', headers: {} };
|
|
266
302
|
// Add port to config (defaults to 3500 if not provided)
|
|
267
303
|
const configWithPort = { ...config, port: port || 3500 };
|
|
@@ -272,41 +308,55 @@ export async function bundle({
|
|
|
272
308
|
};
|
|
273
309
|
const logger = createLogger((process.env.AGENTUITY_LOG_LEVEL as LogLevel) || 'info');
|
|
274
310
|
try {
|
|
275
|
-
|
|
276
|
-
const
|
|
277
|
-
|
|
311
|
+
// Generate workbench files on the fly instead of using files from package
|
|
312
|
+
const tempWorkbenchDir = join(outDir, 'temp-workbench');
|
|
313
|
+
mkdirSync(tempWorkbenchDir, { recursive: true });
|
|
278
314
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const workbenchBuildConfig: Bun.BuildConfig = {
|
|
284
|
-
entrypoints: [workbenchIndexFile],
|
|
285
|
-
root: workbenchAppDir,
|
|
286
|
-
outdir: join(outDir, 'workbench'),
|
|
287
|
-
define: workbenchDefine,
|
|
288
|
-
sourcemap: dev ? 'inline' : 'linked',
|
|
289
|
-
plugins: [AgentuityBundler],
|
|
290
|
-
target: 'browser',
|
|
291
|
-
format: 'esm',
|
|
292
|
-
banner: `// Generated file. DO NOT EDIT`,
|
|
293
|
-
minify: true,
|
|
294
|
-
splitting: true,
|
|
295
|
-
packages: 'bundle',
|
|
296
|
-
naming: {
|
|
297
|
-
entry: '[dir]/[name].[ext]',
|
|
298
|
-
chunk: 'workbench/chunk/[name]-[hash].[ext]',
|
|
299
|
-
asset: 'workbench/asset/[name]-[hash].[ext]',
|
|
300
|
-
},
|
|
301
|
-
};
|
|
315
|
+
// Generate files using templates
|
|
316
|
+
await Bun.write(join(tempWorkbenchDir, 'main.tsx'), generateWorkbenchMainTsx(config));
|
|
317
|
+
const workbenchIndexFile = join(tempWorkbenchDir, 'index.html');
|
|
318
|
+
await Bun.write(workbenchIndexFile, generateWorkbenchIndexHtml());
|
|
302
319
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
320
|
+
// Bundle workbench using generated files
|
|
321
|
+
const workbenchBuildConfig: Bun.BuildConfig = {
|
|
322
|
+
entrypoints: [workbenchIndexFile],
|
|
323
|
+
root: tempWorkbenchDir,
|
|
324
|
+
outdir: join(outDir, 'workbench'),
|
|
325
|
+
define: workbenchDefine,
|
|
326
|
+
sourcemap: dev ? 'inline' : 'linked',
|
|
327
|
+
plugins: [AgentuityBundler],
|
|
328
|
+
target: 'browser',
|
|
329
|
+
format: 'esm',
|
|
330
|
+
banner: `// Generated file. DO NOT EDIT`,
|
|
331
|
+
minify: true,
|
|
332
|
+
splitting: true,
|
|
333
|
+
packages: 'bundle',
|
|
334
|
+
naming: {
|
|
335
|
+
entry: '[dir]/[name].[ext]',
|
|
336
|
+
chunk: 'workbench/chunk/[name]-[hash].[ext]',
|
|
337
|
+
asset: 'workbench/asset/[name]-[hash].[ext]',
|
|
338
|
+
},
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const workbenchResult = await Bun.build(workbenchBuildConfig);
|
|
342
|
+
if (workbenchResult.success) {
|
|
343
|
+
logger.debug('Workbench bundled successfully');
|
|
344
|
+
// Clean up temp directory
|
|
345
|
+
rmSync(tempWorkbenchDir, { recursive: true, force: true });
|
|
346
|
+
} else {
|
|
347
|
+
logger.error('Workbench bundling failed. Logs:', workbenchResult.logs);
|
|
348
|
+
if (workbenchResult.logs.length === 0) {
|
|
349
|
+
logger.error('No build logs available. Checking generated files...');
|
|
350
|
+
logger.error('Temp dir exists:', await Bun.file(tempWorkbenchDir).exists());
|
|
351
|
+
logger.error('Index file exists:', await Bun.file(workbenchIndexFile).exists());
|
|
352
|
+
logger.error(
|
|
353
|
+
'Main.tsx exists:',
|
|
354
|
+
await Bun.file(join(tempWorkbenchDir, 'main.tsx')).exists()
|
|
355
|
+
);
|
|
309
356
|
}
|
|
357
|
+
// Clean up temp directory even on failure
|
|
358
|
+
rmSync(tempWorkbenchDir, { recursive: true, force: true });
|
|
359
|
+
process.exit(1);
|
|
310
360
|
}
|
|
311
361
|
} catch (error) {
|
|
312
362
|
logger.error('Failed to bundle workbench:', error);
|
|
@@ -339,7 +389,14 @@ export async function bundle({
|
|
|
339
389
|
repo: process.env.GITHUB_REPOSITORY
|
|
340
390
|
? gitParseUrl(process.env.GITHUB_REPOSITORY).toString('https')
|
|
341
391
|
: '',
|
|
392
|
+
provider: 'git',
|
|
342
393
|
};
|
|
394
|
+
if (process.env.GITHUB_REPOSITORY) {
|
|
395
|
+
buildmetadata.deployment.git.provider = 'github';
|
|
396
|
+
}
|
|
397
|
+
if (process.env.CI && !trigger) {
|
|
398
|
+
buildmetadata.deployment.git.trigger = 'ci';
|
|
399
|
+
}
|
|
343
400
|
// pull out the git information if we have it
|
|
344
401
|
try {
|
|
345
402
|
let gitDir = join(rootDir, '.git');
|
|
@@ -396,6 +453,61 @@ export async function bundle({
|
|
|
396
453
|
}
|
|
397
454
|
}
|
|
398
455
|
|
|
456
|
+
// if in gitlab CI, set defaults before user overrides
|
|
457
|
+
if (process.env.GITLAB_CI && buildmetadata?.deployment) {
|
|
458
|
+
buildmetadata.deployment.git ??= {};
|
|
459
|
+
buildmetadata.deployment.git.provider ??= 'gitlab';
|
|
460
|
+
buildmetadata.deployment.git.branch ??= process.env.CI_COMMIT_REF_NAME;
|
|
461
|
+
buildmetadata.deployment.git.commit ??= process.env.CI_COMMIT_SHA;
|
|
462
|
+
buildmetadata.deployment.git.buildUrl ??=
|
|
463
|
+
process.env.CI_JOB_URL ?? process.env.CI_PIPELINE_URL;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// configure any overrides or any that aren't detected automatically
|
|
467
|
+
if (buildmetadata?.deployment) {
|
|
468
|
+
buildmetadata.deployment.git ??= {};
|
|
469
|
+
|
|
470
|
+
// build tags: start with existing discovered tags, add defaults, then merge explicit tags
|
|
471
|
+
const tags = new Set(buildmetadata.deployment.git.tags ?? []);
|
|
472
|
+
tags.add('latest');
|
|
473
|
+
if (buildmetadata.deployment.git.branch) {
|
|
474
|
+
tags.add(buildmetadata.deployment.git.branch);
|
|
475
|
+
}
|
|
476
|
+
if (buildmetadata.deployment.git.commit) {
|
|
477
|
+
tags.add(buildmetadata.deployment.git.commit.substring(0, 7));
|
|
478
|
+
}
|
|
479
|
+
if (tag?.length && !(tag.length === 1 && tag[0] === 'latest')) {
|
|
480
|
+
for (const t of tag) {
|
|
481
|
+
tags.add(t);
|
|
482
|
+
}
|
|
483
|
+
tags.delete('latest'); // if you specify explicit tags we remove latest
|
|
484
|
+
}
|
|
485
|
+
buildmetadata.deployment.git.tags = Array.from(tags);
|
|
486
|
+
|
|
487
|
+
if (provider) {
|
|
488
|
+
buildmetadata.deployment.git.provider = provider;
|
|
489
|
+
}
|
|
490
|
+
if (logsUrl) {
|
|
491
|
+
buildmetadata.deployment.git.buildUrl = logsUrl;
|
|
492
|
+
}
|
|
493
|
+
if (commitUrl) {
|
|
494
|
+
buildmetadata.deployment.git.url = commitUrl;
|
|
495
|
+
}
|
|
496
|
+
if (trigger) {
|
|
497
|
+
buildmetadata.deployment.git.trigger = trigger;
|
|
498
|
+
}
|
|
499
|
+
if (event) {
|
|
500
|
+
buildmetadata.deployment.git.event = event;
|
|
501
|
+
}
|
|
502
|
+
if (pullRequestNumber) {
|
|
503
|
+
buildmetadata.deployment.git.pull_request = {
|
|
504
|
+
number: pullRequestNumber,
|
|
505
|
+
url: pullRequestURL,
|
|
506
|
+
commentId: pullRequestCommentId,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
399
511
|
await Bun.write(
|
|
400
512
|
`${outDir}/package.json`,
|
|
401
513
|
JSON.stringify({ name: pkgContents.name, version: pkgContents.version }, null, 2)
|
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`);
|
|
@@ -573,8 +573,8 @@ const AgentuityBundler: BunPlugin = {
|
|
|
573
573
|
// Use the workbench config determined at build time
|
|
574
574
|
const route = ${JSON.stringify(workbenchConfig?.route || '/workbench')};
|
|
575
575
|
|
|
576
|
-
// If using custom route, update HTML to point to absolute /workbench/ paths
|
|
577
|
-
if (route !== '/workbench') {
|
|
576
|
+
// If using custom route, update HTML to point to absolute /workbench/ paths
|
|
577
|
+
if (route !== '/workbench') {
|
|
578
578
|
workbenchIndex = workbenchIndex.replace(new RegExp('src="\\\\.\\\\/workbench\\\\/', 'g'), 'src="/workbench/');
|
|
579
579
|
}
|
|
580
580
|
|
|
@@ -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
|
|
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