@agentuity/cli 0.0.110 → 0.0.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.ts +4 -0
- package/dist/agents-docs.d.ts +5 -4
- package/dist/agents-docs.d.ts.map +1 -1
- package/dist/agents-docs.js +28 -8
- package/dist/agents-docs.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +19 -4
- package/dist/cli.js.map +1 -1
- package/dist/cmd/auth/apikey.d.ts +2 -0
- package/dist/cmd/auth/apikey.d.ts.map +1 -0
- package/dist/cmd/auth/apikey.js +31 -0
- package/dist/cmd/auth/apikey.js.map +1 -0
- package/dist/cmd/auth/index.d.ts.map +1 -1
- package/dist/cmd/auth/index.js +9 -1
- package/dist/cmd/auth/index.js.map +1 -1
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +103 -2
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/entry-generator.d.ts +2 -1
- package/dist/cmd/build/entry-generator.d.ts.map +1 -1
- package/dist/cmd/build/entry-generator.js +152 -9
- package/dist/cmd/build/entry-generator.js.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.d.ts +1 -1
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +7 -6
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
- package/dist/cmd/build/vite/index.d.ts.map +1 -1
- package/dist/cmd/build/vite/index.js +3 -2
- package/dist/cmd/build/vite/index.js.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.js +1 -1
- package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
- package/dist/cmd/build/vite/registry-generator.d.ts +1 -1
- package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/registry-generator.js +115 -23
- package/dist/cmd/build/vite/registry-generator.js.map +1 -1
- package/dist/cmd/build/vite/route-discovery.d.ts +6 -0
- package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/route-discovery.js +19 -0
- package/dist/cmd/build/vite/route-discovery.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +3 -2
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/cloud/deploy-fork.d.ts +32 -0
- package/dist/cmd/cloud/deploy-fork.d.ts.map +1 -0
- package/dist/cmd/cloud/deploy-fork.js +258 -0
- package/dist/cmd/cloud/deploy-fork.js.map +1 -0
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +125 -4
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/create.js +18 -0
- package/dist/cmd/cloud/sandbox/create.js.map +1 -1
- package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/delete.js +2 -6
- package/dist/cmd/cloud/sandbox/delete.js.map +1 -1
- package/dist/cmd/cloud/sandbox/download.d.ts +3 -0
- package/dist/cmd/cloud/sandbox/download.d.ts.map +1 -0
- package/dist/cmd/cloud/sandbox/download.js +89 -0
- package/dist/cmd/cloud/sandbox/download.js.map +1 -0
- package/dist/cmd/cloud/sandbox/env.d.ts +3 -0
- package/dist/cmd/cloud/sandbox/env.d.ts.map +1 -0
- package/dist/cmd/cloud/sandbox/env.js +90 -0
- package/dist/cmd/cloud/sandbox/env.js.map +1 -0
- package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/get.js +24 -0
- package/dist/cmd/cloud/sandbox/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/index.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/index.js +14 -0
- package/dist/cmd/cloud/sandbox/index.js.map +1 -1
- package/dist/cmd/cloud/sandbox/ls.d.ts +3 -0
- package/dist/cmd/cloud/sandbox/ls.d.ts.map +1 -0
- package/dist/cmd/cloud/sandbox/ls.js +119 -0
- package/dist/cmd/cloud/sandbox/ls.js.map +1 -0
- package/dist/cmd/cloud/sandbox/mkdir.d.ts +3 -0
- package/dist/cmd/cloud/sandbox/mkdir.d.ts.map +1 -0
- package/dist/cmd/cloud/sandbox/mkdir.js +59 -0
- package/dist/cmd/cloud/sandbox/mkdir.js.map +1 -0
- package/dist/cmd/cloud/sandbox/rm.d.ts +3 -0
- package/dist/cmd/cloud/sandbox/rm.d.ts.map +1 -0
- package/dist/cmd/cloud/sandbox/rm.js +45 -0
- package/dist/cmd/cloud/sandbox/rm.js.map +1 -0
- package/dist/cmd/cloud/sandbox/rmdir.d.ts +3 -0
- package/dist/cmd/cloud/sandbox/rmdir.d.ts.map +1 -0
- package/dist/cmd/cloud/sandbox/rmdir.js +59 -0
- package/dist/cmd/cloud/sandbox/rmdir.js.map +1 -0
- package/dist/cmd/cloud/sandbox/snapshot/create.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/create.js +0 -2
- package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/get.js +0 -2
- package/dist/cmd/cloud/sandbox/snapshot/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/list.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/list.js +0 -3
- package/dist/cmd/cloud/sandbox/snapshot/list.js.map +1 -1
- package/dist/cmd/cloud/sandbox/upload.d.ts +3 -0
- package/dist/cmd/cloud/sandbox/upload.d.ts.map +1 -0
- package/dist/cmd/cloud/sandbox/upload.js +77 -0
- package/dist/cmd/cloud/sandbox/upload.js.map +1 -0
- package/dist/cmd/cloud/ssh.d.ts.map +1 -1
- package/dist/cmd/cloud/ssh.js +9 -3
- package/dist/cmd/cloud/ssh.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +34 -19
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/sync.d.ts.map +1 -1
- package/dist/cmd/dev/sync.js +8 -14
- package/dist/cmd/dev/sync.js.map +1 -1
- package/dist/cmd/git/account/add.d.ts +17 -0
- package/dist/cmd/git/account/add.d.ts.map +1 -0
- package/dist/cmd/git/account/add.js +244 -0
- package/dist/cmd/git/account/add.js.map +1 -0
- package/dist/cmd/git/account/index.d.ts +3 -0
- package/dist/cmd/git/account/index.d.ts.map +1 -0
- package/dist/cmd/git/account/index.js +11 -0
- package/dist/cmd/git/account/index.js.map +1 -0
- package/dist/cmd/git/account/list.d.ts +2 -0
- package/dist/cmd/git/account/list.d.ts.map +1 -0
- package/dist/cmd/git/account/list.js +111 -0
- package/dist/cmd/git/account/list.js.map +1 -0
- package/dist/cmd/git/account/remove.d.ts +2 -0
- package/dist/cmd/git/account/remove.d.ts.map +1 -0
- package/dist/cmd/git/account/remove.js +171 -0
- package/dist/cmd/git/account/remove.js.map +1 -0
- package/dist/cmd/git/index.d.ts +3 -0
- package/dist/cmd/git/index.d.ts.map +1 -0
- package/dist/cmd/git/index.js +19 -0
- package/dist/cmd/git/index.js.map +1 -0
- package/dist/cmd/git/link.d.ts +32 -0
- package/dist/cmd/git/link.d.ts.map +1 -0
- package/dist/cmd/git/link.js +357 -0
- package/dist/cmd/git/link.js.map +1 -0
- package/dist/cmd/git/list.d.ts +2 -0
- package/dist/cmd/git/list.d.ts.map +1 -0
- package/dist/cmd/git/list.js +137 -0
- package/dist/cmd/git/list.js.map +1 -0
- package/dist/cmd/git/status.d.ts +2 -0
- package/dist/cmd/git/status.d.ts.map +1 -0
- package/dist/cmd/git/status.js +119 -0
- package/dist/cmd/git/status.js.map +1 -0
- package/dist/cmd/git/unlink.d.ts +2 -0
- package/dist/cmd/git/unlink.d.ts.map +1 -0
- package/dist/cmd/git/unlink.js +98 -0
- package/dist/cmd/git/unlink.js.map +1 -0
- 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/integration/api.d.ts +61 -0
- package/dist/cmd/integration/api.d.ts.map +1 -0
- package/dist/cmd/integration/api.js +176 -0
- package/dist/cmd/integration/api.js.map +1 -0
- package/dist/cmd/integration/github/connect.d.ts +2 -0
- package/dist/cmd/integration/github/connect.d.ts.map +1 -0
- package/dist/cmd/integration/github/connect.js +197 -0
- package/dist/cmd/integration/github/connect.js.map +1 -0
- package/dist/cmd/integration/github/disconnect.d.ts +2 -0
- package/dist/cmd/integration/github/disconnect.d.ts.map +1 -0
- package/dist/cmd/integration/github/disconnect.js +121 -0
- package/dist/cmd/integration/github/disconnect.js.map +1 -0
- package/dist/cmd/integration/github/index.d.ts +2 -0
- package/dist/cmd/integration/github/index.d.ts.map +1 -0
- package/dist/cmd/integration/github/index.js +21 -0
- package/dist/cmd/integration/github/index.js.map +1 -0
- package/dist/cmd/integration/index.d.ts +2 -0
- package/dist/cmd/integration/index.d.ts.map +1 -0
- package/dist/cmd/integration/index.js +16 -0
- package/dist/cmd/integration/index.js.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +25 -1
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +2 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +5 -0
- package/dist/errors.js.map +1 -1
- package/dist/log-collector.d.ts +30 -0
- package/dist/log-collector.d.ts.map +1 -0
- package/dist/log-collector.js +74 -0
- package/dist/log-collector.js.map +1 -0
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +2 -1
- package/dist/output.js.map +1 -1
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +48 -3
- package/dist/steps.js.map +1 -1
- package/dist/tui/box.d.ts.map +1 -1
- package/dist/tui/box.js +1 -6
- package/dist/tui/box.js.map +1 -1
- package/dist/tui/symbols.d.ts.map +1 -1
- package/dist/tui/symbols.js +4 -0
- package/dist/tui/symbols.js.map +1 -1
- package/dist/tui.d.ts +21 -12
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +74 -25
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +73 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -1
- package/dist/typescript-errors.d.ts.map +1 -1
- package/dist/typescript-errors.js +2 -2
- package/dist/typescript-errors.js.map +1 -1
- package/package.json +6 -6
- package/src/agents-docs.ts +42 -8
- package/src/cli.ts +20 -4
- package/src/cmd/auth/apikey.ts +36 -0
- package/src/cmd/auth/index.ts +9 -1
- package/src/cmd/build/ast.ts +120 -2
- package/src/cmd/build/entry-generator.ts +157 -10
- package/src/cmd/build/vite/agent-discovery.ts +8 -5
- package/src/cmd/build/vite/index.ts +3 -2
- package/src/cmd/build/vite/metadata-generator.ts +1 -1
- package/src/cmd/build/vite/registry-generator.ts +125 -24
- package/src/cmd/build/vite/route-discovery.ts +20 -0
- package/src/cmd/build/vite/vite-builder.ts +3 -2
- package/src/cmd/cloud/deploy-fork.ts +296 -0
- package/src/cmd/cloud/deploy.ts +148 -4
- package/src/cmd/cloud/sandbox/create.ts +22 -0
- package/src/cmd/cloud/sandbox/delete.ts +2 -6
- package/src/cmd/cloud/sandbox/download.ts +96 -0
- package/src/cmd/cloud/sandbox/env.ts +104 -0
- package/src/cmd/cloud/sandbox/get.ts +22 -0
- package/src/cmd/cloud/sandbox/index.ts +14 -0
- package/src/cmd/cloud/sandbox/ls.ts +126 -0
- package/src/cmd/cloud/sandbox/mkdir.ts +65 -0
- package/src/cmd/cloud/sandbox/rm.ts +51 -0
- package/src/cmd/cloud/sandbox/rmdir.ts +65 -0
- package/src/cmd/cloud/sandbox/snapshot/create.ts +0 -2
- package/src/cmd/cloud/sandbox/snapshot/get.ts +0 -2
- package/src/cmd/cloud/sandbox/snapshot/list.ts +0 -3
- package/src/cmd/cloud/sandbox/upload.ts +83 -0
- package/src/cmd/cloud/ssh.ts +13 -3
- package/src/cmd/dev/index.ts +49 -31
- package/src/cmd/dev/sync.ts +26 -30
- package/src/cmd/git/account/add.ts +317 -0
- package/src/cmd/git/account/index.ts +12 -0
- package/src/cmd/git/account/list.ts +139 -0
- package/src/cmd/git/account/remove.ts +212 -0
- package/src/cmd/git/index.ts +20 -0
- package/src/cmd/git/link.ts +468 -0
- package/src/cmd/git/list.ts +161 -0
- package/src/cmd/git/status.ts +144 -0
- package/src/cmd/git/unlink.ts +117 -0
- package/src/cmd/index.ts +2 -0
- package/src/cmd/integration/api.ts +379 -0
- package/src/cmd/integration/github/connect.ts +242 -0
- package/src/cmd/integration/github/disconnect.ts +149 -0
- package/src/cmd/integration/github/index.ts +21 -0
- package/src/cmd/integration/index.ts +16 -0
- package/src/config.ts +35 -1
- package/src/errors.ts +7 -0
- package/src/log-collector.ts +77 -0
- package/src/output.ts +2 -1
- package/src/steps.ts +52 -4
- package/src/tui/box.ts +1 -7
- package/src/tui/symbols.ts +5 -0
- package/src/tui.ts +77 -25
- package/src/types.ts +89 -0
- package/src/typescript-errors.ts +2 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { join } from 'node:path';
|
|
7
|
-
import type { Logger, WorkbenchConfig } from '../../types';
|
|
7
|
+
import type { Logger, WorkbenchConfig, AnalyticsConfig } from '../../types';
|
|
8
8
|
import { discoverRoutes } from './vite/route-discovery';
|
|
9
9
|
|
|
10
10
|
interface GenerateEntryOptions {
|
|
@@ -14,6 +14,7 @@ interface GenerateEntryOptions {
|
|
|
14
14
|
logger: Logger;
|
|
15
15
|
mode: 'dev' | 'prod';
|
|
16
16
|
workbench?: WorkbenchConfig;
|
|
17
|
+
analytics?: boolean | AnalyticsConfig;
|
|
17
18
|
vitePort?: number; // Port of Vite asset server (dev mode only)
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -21,7 +22,8 @@ interface GenerateEntryOptions {
|
|
|
21
22
|
* Generate entry file with clean Vite-native architecture
|
|
22
23
|
*/
|
|
23
24
|
export async function generateEntryFile(options: GenerateEntryOptions): Promise<void> {
|
|
24
|
-
const { rootDir, projectId, deploymentId, logger, mode, workbench, vitePort } =
|
|
25
|
+
const { rootDir, projectId, deploymentId, logger, mode, workbench, analytics, vitePort } =
|
|
26
|
+
options;
|
|
25
27
|
|
|
26
28
|
const srcDir = join(rootDir, 'src');
|
|
27
29
|
const generatedDir = join(srcDir, 'generated');
|
|
@@ -70,7 +72,11 @@ export async function generateEntryFile(options: GenerateEntryOptions): Promise<
|
|
|
70
72
|
` loadBuildMetadata,`,
|
|
71
73
|
` createWorkbenchRouter,`,
|
|
72
74
|
` bootstrapRuntimeEnv,`,
|
|
73
|
-
`
|
|
75
|
+
` patchBunS3ForStorageDev,`,
|
|
76
|
+
` getOrganizationId,`,
|
|
77
|
+
` getProjectId,`,
|
|
78
|
+
` isDevMode as runtimeIsDevMode,`,
|
|
79
|
+
` createWebSessionMiddleware,`,
|
|
74
80
|
];
|
|
75
81
|
|
|
76
82
|
const imports = [
|
|
@@ -200,6 +206,126 @@ if (isDevelopment() && process.env.VITE_PORT) {
|
|
|
200
206
|
// See: https://github.com/oven-sh/bun/issues/20183
|
|
201
207
|
const getEnv = (key: string) => process.env[key];
|
|
202
208
|
const isDevelopment = () => getEnv('NODE' + '_' + 'ENV') !== 'production';
|
|
209
|
+
`;
|
|
210
|
+
|
|
211
|
+
// Generate analytics config and injection helper
|
|
212
|
+
const analyticsEnabled = analytics !== false;
|
|
213
|
+
const analyticsConfig: AnalyticsConfig = typeof analytics === 'object' ? analytics : {};
|
|
214
|
+
|
|
215
|
+
const analyticsHelper = analyticsEnabled
|
|
216
|
+
? `
|
|
217
|
+
// Analytics configuration - edit agentuity.config.ts to configure
|
|
218
|
+
const analyticsConfig = {
|
|
219
|
+
enabled: ${analyticsConfig.enabled !== false},
|
|
220
|
+
requireConsent: ${analyticsConfig.requireConsent ?? false},
|
|
221
|
+
trackClicks: ${analyticsConfig.trackClicks ?? true},
|
|
222
|
+
trackScroll: ${analyticsConfig.trackScroll ?? true},
|
|
223
|
+
trackOutboundLinks: ${analyticsConfig.trackOutboundLinks ?? true},
|
|
224
|
+
trackForms: ${analyticsConfig.trackForms ?? false},
|
|
225
|
+
trackWebVitals: ${analyticsConfig.trackWebVitals ?? true},
|
|
226
|
+
trackErrors: ${analyticsConfig.trackErrors ?? true},
|
|
227
|
+
trackSPANavigation: ${analyticsConfig.trackSPANavigation ?? true},
|
|
228
|
+
sampleRate: ${analyticsConfig.sampleRate ?? 1},
|
|
229
|
+
excludePatterns: ${JSON.stringify(analyticsConfig.excludePatterns ?? [])},
|
|
230
|
+
globalProperties: ${JSON.stringify(analyticsConfig.globalProperties ?? {})},
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
// Inject analytics config and script into HTML
|
|
234
|
+
// Note: Only static config is injected (org, project, devmode, tracking options)
|
|
235
|
+
// Session and thread IDs are read from cookies by the beacon script
|
|
236
|
+
function injectAnalytics(html: string): string {
|
|
237
|
+
if (!analyticsConfig.enabled) return html;
|
|
238
|
+
|
|
239
|
+
const orgId = getOrganizationId() || '';
|
|
240
|
+
const projectId = getProjectId() || '';
|
|
241
|
+
const isDevmode = runtimeIsDevMode();
|
|
242
|
+
|
|
243
|
+
// Only include static config - session/thread come from cookies
|
|
244
|
+
const pageConfig = {
|
|
245
|
+
...analyticsConfig,
|
|
246
|
+
orgId,
|
|
247
|
+
projectId,
|
|
248
|
+
isDevmode,
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const configScript = \`<script>window.__AGENTUITY_ANALYTICS__=\${JSON.stringify(pageConfig)};</script>\`;
|
|
252
|
+
// Session script sets cookies and window.__AGENTUITY_SESSION__ (dynamic, not cached)
|
|
253
|
+
const sessionScript = '<script src="/_agentuity/webanalytics/session.js" async></script>';
|
|
254
|
+
// Beacon script reads from __AGENTUITY_SESSION__ and sends events (static, cached)
|
|
255
|
+
const beaconScript = '<script src="/_agentuity/webanalytics/analytics.js" async></script>';
|
|
256
|
+
const injection = configScript + sessionScript + beaconScript;
|
|
257
|
+
|
|
258
|
+
// Inject before </head> or at start of <body>
|
|
259
|
+
if (html.includes('</head>')) {
|
|
260
|
+
return html.replace('</head>', injection + '</head>');
|
|
261
|
+
}
|
|
262
|
+
if (html.includes('<body')) {
|
|
263
|
+
return html.replace(/<body([^>]*)>/, \`<body$1>\${injection}\`);
|
|
264
|
+
}
|
|
265
|
+
return injection + html;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Serve analytics routes
|
|
269
|
+
function registerAnalyticsRoutes(app: ReturnType<typeof createRouter>): void {
|
|
270
|
+
// Dynamic session config script - sets cookies and returns session/thread IDs
|
|
271
|
+
// This endpoint is NOT cached - it generates unique session data per request
|
|
272
|
+
app.get('/_agentuity/webanalytics/session.js', createWebSessionMiddleware(), async (c: Context) => {
|
|
273
|
+
const sessionId = c.get('sessionId') || '';
|
|
274
|
+
const thread = c.get('thread');
|
|
275
|
+
const threadId = thread?.id || '';
|
|
276
|
+
|
|
277
|
+
const sessionScript = \`window.__AGENTUITY_SESSION__={sessionId:"\${sessionId}",threadId:"\${threadId}"};\`;
|
|
278
|
+
|
|
279
|
+
return new Response(sessionScript, {
|
|
280
|
+
headers: {
|
|
281
|
+
'Content-Type': 'application/javascript; charset=utf-8',
|
|
282
|
+
'Cache-Control': 'no-store, no-cache, must-revalidate',
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Static beacon script - can be cached
|
|
288
|
+
app.get('/_agentuity/webanalytics/analytics.js', async (c: Context) => {
|
|
289
|
+
// Beacon waits for window.__AGENTUITY_SESSION__ before sending events
|
|
290
|
+
const beaconScript = \`(function(){
|
|
291
|
+
var w=window,d=document,c=w.__AGENTUITY_ANALYTICS__;
|
|
292
|
+
if(!c||!c.enabled)return;
|
|
293
|
+
var q=[],t=null,sr=false,E='/_agentuity/webanalytics/collect',geo=null;
|
|
294
|
+
function id(){return crypto.randomUUID?crypto.randomUUID():Date.now()+'-'+Math.random().toString(36).substr(2,9)}
|
|
295
|
+
function base(type){var e={id:id(),timestamp:Date.now(),timezone_offset:new Date().getTimezoneOffset(),event_type:type,url:location.href,path:location.pathname,referrer:d.referrer||'',title:d.title||'',screen_width:screen.width||0,screen_height:screen.height||0,viewport_width:innerWidth||0,viewport_height:innerHeight||0,device_pixel_ratio:devicePixelRatio||1,user_agent:navigator.userAgent||'',language:navigator.language||''};if(geo){e.country=geo.country||'';e.region=geo.region||'';e.city=geo.city||'';e.timezone=geo.timezone||''}return e}
|
|
296
|
+
fetch('https://agentuity.sh/location').then(function(r){return r.json()}).then(function(g){geo=g;try{sessionStorage.setItem('agentuity_geo',JSON.stringify(g))}catch(e){}}).catch(function(){try{var cached=sessionStorage.getItem('agentuity_geo');if(cached)geo=JSON.parse(cached)}catch(e){}});try{var cached=sessionStorage.getItem('agentuity_geo');if(cached)geo=JSON.parse(cached)}catch(e){}
|
|
297
|
+
function getSession(){return w.__AGENTUITY_SESSION__}
|
|
298
|
+
function waitForSession(cb){var s=getSession();if(s){cb(s);return}var attempts=0,maxAttempts=50;var iv=setInterval(function(){s=getSession();if(s||++attempts>=maxAttempts){clearInterval(iv);cb(s)}},100)}
|
|
299
|
+
function doFlush(s){if(!q.length)return;var events=q.splice(0);if(c.isDevmode){console.debug('[Agentuity Analytics]',events);return}var sid=s?s.sessionId:'',tid=s?s.threadId:'';var p={org_id:c.orgId,project_id:c.projectId,session_id:sid,thread_id:tid,visitor_id:localStorage.getItem('agentuity_vid')||'vid_'+id(),events:events};try{localStorage.setItem('agentuity_vid',p.visitor_id)}catch(e){}navigator.sendBeacon?navigator.sendBeacon(E,JSON.stringify(p)):fetch(E,{method:'POST',body:JSON.stringify(p),keepalive:true}).catch(function(){})}
|
|
300
|
+
function flush(){if(sr){doFlush(getSession())}else{waitForSession(function(s){sr=true;doFlush(s)})}}
|
|
301
|
+
function queue(e){if(c.sampleRate<1&&Math.random()>c.sampleRate)return;q.push(e);q.length>=10?flush():t||(t=setTimeout(function(){t=null;flush()},5000))}
|
|
302
|
+
function pv(){var e=base('pageview');if(performance.getEntriesByType){var n=performance.getEntriesByType('navigation')[0];if(n){e.load_time=Math.round(n.loadEventEnd-n.startTime);e.dom_ready=Math.round(n.domContentLoadedEventEnd-n.startTime);e.ttfb=Math.round(n.responseStart-n.requestStart)}}queue(e)}
|
|
303
|
+
w.addEventListener('visibilitychange',function(){d.visibilityState==='hidden'&&flush()});
|
|
304
|
+
w.addEventListener('pagehide',flush);
|
|
305
|
+
if(c.trackSPANavigation){var op=history.pushState,or=history.replaceState,cp=location.pathname;function ch(){var np=location.pathname;np!==cp&&(cp=np,pv())}history.pushState=function(){op.apply(this,arguments);ch()};history.replaceState=function(){or.apply(this,arguments);ch()};w.addEventListener('popstate',ch)}
|
|
306
|
+
if(c.trackErrors){w.addEventListener('error',function(e){var ev=base('error');ev.event_name='js_error';ev.event_data={message:e.message||'Unknown',filename:e.filename||'',lineno:e.lineno||0};queue(ev)});w.addEventListener('unhandledrejection',function(e){var ev=base('error');ev.event_name='unhandled_rejection';ev.event_data={message:e.reason instanceof Error?e.reason.message:String(e.reason)};queue(ev)})}
|
|
307
|
+
if(c.trackClicks){d.addEventListener('click',function(e){var t=e.target;if(!t)return;var a=t.closest('[data-analytics]');if(!a)return;var ev=base('click');ev.event_name=a.getAttribute('data-analytics');queue(ev)},true)}
|
|
308
|
+
if(c.trackScroll){var ms=new Set(),mx=0;function gs(){var st=w.scrollY||d.documentElement.scrollTop,sh=d.documentElement.scrollHeight-d.documentElement.clientHeight;return sh<=0?100:Math.min(100,Math.round(st/sh*100))}w.addEventListener('scroll',function(){var dp=gs();if(dp>mx)mx=dp;[25,50,75,100].forEach(function(m){if(dp>=m&&!ms.has(m)){ms.add(m);var ev=base('scroll');ev.event_name='scroll_'+m;ev.scroll_depth=m;queue(ev)}})},{passive:true})}
|
|
309
|
+
if(c.trackWebVitals!==false&&typeof PerformanceObserver!=='undefined'){var wvLcp=0,wvCls=0,wvInp=0,wvPath=location.pathname,wvSent={};function wvReset(){wvLcp=0;wvCls=0;wvInp=0;wvSent={}}function wvSend(){var p=wvPath;if(wvLcp>0&&!wvSent.lcp){wvSent.lcp=1;var ev=base('web_vital');ev.event_name='lcp';ev.lcp=Math.round(wvLcp);ev.path=p;queue(ev)}if(!wvSent.cls){wvSent.cls=1;var ev=base('web_vital');ev.event_name='cls';ev.cls=Math.round(wvCls*1000)/1000;ev.path=p;queue(ev)}if(wvInp>0&&!wvSent.inp){wvSent.inp=1;var ev=base('web_vital');ev.event_name='inp';ev.inp=Math.round(wvInp);ev.path=p;queue(ev)}flush()}try{var fcpObs=new PerformanceObserver(function(l){l.getEntries().forEach(function(e){if(e.name==='first-contentful-paint'){var ev=base('web_vital');ev.event_name='fcp';ev.fcp=Math.round(e.startTime);queue(ev);flush();fcpObs.disconnect()}})});fcpObs.observe({type:'paint',buffered:true})}catch(e){}try{new PerformanceObserver(function(l){var entries=l.getEntries();if(entries.length)wvLcp=entries[entries.length-1].startTime}).observe({type:'largest-contentful-paint',buffered:true})}catch(e){}try{new PerformanceObserver(function(l){l.getEntries().forEach(function(e){if(!e.hadRecentInput&&e.value)wvCls+=e.value})}).observe({type:'layout-shift',buffered:true})}catch(e){}try{new PerformanceObserver(function(l){l.getEntries().forEach(function(e){if(e.duration&&e.duration>wvInp)wvInp=e.duration})}).observe({type:'event',buffered:true})}catch(e){}d.addEventListener('visibilitychange',function(){if(d.visibilityState==='hidden')wvSend()});w.addEventListener('pagehide',wvSend);if(c.trackSPANavigation){var wvOp=history.pushState,wvOr=history.replaceState;function wvNav(){var np=location.pathname;if(np!==wvPath){wvSend();wvPath=np;wvReset()}}history.pushState=function(){wvOp.apply(this,arguments);wvNav()};history.replaceState=function(){wvOr.apply(this,arguments);wvNav()};w.addEventListener('popstate',wvNav)}}
|
|
310
|
+
d.readyState==='complete'?pv():w.addEventListener('load',pv);
|
|
311
|
+
w.agentuityAnalytics={track:function(n,p){var e=base('custom');e.event_name=n;if(p)e.event_data=p;queue(e)},flush:flush};
|
|
312
|
+
})();\`;
|
|
313
|
+
|
|
314
|
+
return new Response(beaconScript, {
|
|
315
|
+
headers: {
|
|
316
|
+
'Content-Type': 'application/javascript; charset=utf-8',
|
|
317
|
+
'Cache-Control': 'public, max-age=3600',
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
`
|
|
323
|
+
: `
|
|
324
|
+
// Analytics disabled
|
|
325
|
+
function injectAnalytics(html: string): string {
|
|
326
|
+
return html;
|
|
327
|
+
}
|
|
328
|
+
function registerAnalyticsRoutes(_app: ReturnType<typeof createRouter>): void {}
|
|
203
329
|
`;
|
|
204
330
|
|
|
205
331
|
// Web routes (runtime mode detection)
|
|
@@ -207,6 +333,9 @@ const isDevelopment = () => getEnv('NODE' + '_' + 'ENV') !== 'production';
|
|
|
207
333
|
if (hasWebFrontend) {
|
|
208
334
|
webRoutes = `
|
|
209
335
|
// Web routes - Runtime mode detection (dev proxies to Vite, prod serves static)
|
|
336
|
+
// Note: Session/thread cookies are set by /_agentuity/webanalytics/session.js (loaded via script tag)
|
|
337
|
+
// This keeps the HTML response static and cacheable
|
|
338
|
+
|
|
210
339
|
if (isDevelopment()) {
|
|
211
340
|
// Development mode: Proxy HTML from Vite to enable React Fast Refresh
|
|
212
341
|
const VITE_ASSET_PORT = parseInt(process.env.VITE_PORT || '${vitePort || 5173}', 10);
|
|
@@ -219,12 +348,15 @@ if (isDevelopment()) {
|
|
|
219
348
|
const res = await fetch(viteUrl, { signal: AbortSignal.timeout(10000) });
|
|
220
349
|
|
|
221
350
|
// Get HTML text and transform relative paths to absolute
|
|
222
|
-
|
|
223
|
-
|
|
351
|
+
let html = await res.text();
|
|
352
|
+
html = html
|
|
224
353
|
.replace(/src="\\.\\//g, 'src="/src/web/')
|
|
225
354
|
.replace(/href="\\.\\//g, 'href="/src/web/');
|
|
226
355
|
|
|
227
|
-
|
|
356
|
+
// Inject analytics config and script (session/thread read from cookies by beacon)
|
|
357
|
+
html = injectAnalytics(html);
|
|
358
|
+
|
|
359
|
+
return new Response(html, {
|
|
228
360
|
status: res.status,
|
|
229
361
|
headers: res.headers,
|
|
230
362
|
});
|
|
@@ -255,15 +387,24 @@ if (isDevelopment()) {
|
|
|
255
387
|
} else {
|
|
256
388
|
// Production mode: Serve static files from bundled output
|
|
257
389
|
const indexHtmlPath = import.meta.dir + '/client/index.html';
|
|
258
|
-
const
|
|
390
|
+
const baseIndexHtml = existsSync(indexHtmlPath)
|
|
259
391
|
? readFileSync(indexHtmlPath, 'utf-8')
|
|
260
392
|
: '';
|
|
261
393
|
|
|
262
|
-
if (!
|
|
394
|
+
if (!baseIndexHtml) {
|
|
263
395
|
otel.logger.warn('Production HTML not found at %s', indexHtmlPath);
|
|
264
396
|
}
|
|
397
|
+
|
|
398
|
+
const prodHtmlHandler = (c: Context) => {
|
|
399
|
+
if (!baseIndexHtml) {
|
|
400
|
+
return c.text('Production build incomplete', 500);
|
|
401
|
+
}
|
|
402
|
+
// Inject analytics config and script (session/thread loaded via session.js)
|
|
403
|
+
const html = injectAnalytics(baseIndexHtml);
|
|
404
|
+
return c.html(html);
|
|
405
|
+
};
|
|
265
406
|
|
|
266
|
-
app.get('/',
|
|
407
|
+
app.get('/', prodHtmlHandler);
|
|
267
408
|
|
|
268
409
|
// Serve static assets from /assets/* (Vite bundled output)
|
|
269
410
|
app.use('/assets/*', serveStatic({ root: import.meta.dir + '/client' }));
|
|
@@ -285,7 +426,7 @@ if (isDevelopment()) {
|
|
|
285
426
|
if (/\\.[a-zA-Z0-9]+$/.test(path)) {
|
|
286
427
|
return c.notFound();
|
|
287
428
|
}
|
|
288
|
-
return c
|
|
429
|
+
return prodHtmlHandler(c);
|
|
289
430
|
});
|
|
290
431
|
}
|
|
291
432
|
`;
|
|
@@ -412,6 +553,8 @@ ${imports.join('\n')}
|
|
|
412
553
|
|
|
413
554
|
${modeDetection}
|
|
414
555
|
|
|
556
|
+
${analyticsHelper}
|
|
557
|
+
|
|
415
558
|
// Step 0: Bootstrap runtime environment (load profile-specific .env files)
|
|
416
559
|
// Only in development - production env vars are injected by platform
|
|
417
560
|
// This must happen BEFORE any imports that depend on environment variables
|
|
@@ -482,6 +625,10 @@ await sessionProvider.initialize(appState);
|
|
|
482
625
|
// Step 6: Mount routes (AFTER middleware is applied)
|
|
483
626
|
|
|
484
627
|
${healthRoutes}
|
|
628
|
+
|
|
629
|
+
// Register analytics routes (if enabled)
|
|
630
|
+
registerAnalyticsRoutes(app);
|
|
631
|
+
|
|
485
632
|
${assetProxyRoutes}
|
|
486
633
|
${apiMount}
|
|
487
634
|
${workbenchApiMount}
|
|
@@ -65,7 +65,7 @@ export interface AgentMetadata {
|
|
|
65
65
|
|
|
66
66
|
export interface EvalMetadata {
|
|
67
67
|
id: string;
|
|
68
|
-
|
|
68
|
+
identifier: string;
|
|
69
69
|
name: string;
|
|
70
70
|
filename: string;
|
|
71
71
|
version: string;
|
|
@@ -311,6 +311,7 @@ function extractAgentMetadata(
|
|
|
311
311
|
*/
|
|
312
312
|
async function extractEvalMetadata(
|
|
313
313
|
evalsPath: string,
|
|
314
|
+
relativeEvalsPath: string,
|
|
314
315
|
agentId: string,
|
|
315
316
|
projectId: string,
|
|
316
317
|
deploymentId: string,
|
|
@@ -325,7 +326,7 @@ async function extractEvalMetadata(
|
|
|
325
326
|
const evalsSource = await evalsFile.text();
|
|
326
327
|
return extractEvalsFromSource(
|
|
327
328
|
evalsSource,
|
|
328
|
-
|
|
329
|
+
relativeEvalsPath,
|
|
329
330
|
agentId,
|
|
330
331
|
projectId,
|
|
331
332
|
deploymentId,
|
|
@@ -459,13 +460,13 @@ function extractEvalsFromSource(
|
|
|
459
460
|
|
|
460
461
|
if (evalName) {
|
|
461
462
|
const id = getEvalId(projectId, deploymentId, filename, evalName, version);
|
|
462
|
-
const
|
|
463
|
+
const identifier = generateStableEvalId(projectId, agentId, evalName);
|
|
463
464
|
|
|
464
|
-
logger.trace(`Found eval '${evalName}' in ${filename} (
|
|
465
|
+
logger.trace(`Found eval '${evalName}' in ${filename} (identifier: ${identifier})`);
|
|
465
466
|
|
|
466
467
|
evals.push({
|
|
467
468
|
id,
|
|
468
|
-
|
|
469
|
+
identifier,
|
|
469
470
|
name: evalName,
|
|
470
471
|
filename,
|
|
471
472
|
version,
|
|
@@ -569,8 +570,10 @@ export async function discoverAgents(
|
|
|
569
570
|
// 2. Check for evals in separate eval.ts file in same directory
|
|
570
571
|
const agentDir = dirname(filePath);
|
|
571
572
|
const evalsPath = join(agentDir, 'eval.ts');
|
|
573
|
+
const relativeEvalsPath = relative(rootDir, evalsPath);
|
|
572
574
|
const evalsInSeparateFile = await extractEvalMetadata(
|
|
573
575
|
evalsPath,
|
|
576
|
+
relativeEvalsPath,
|
|
574
577
|
agentMetadata.agentId,
|
|
575
578
|
projectId,
|
|
576
579
|
deploymentId,
|
|
@@ -87,7 +87,7 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
if (routeInfoList.length > 0) {
|
|
90
|
-
generateRouteRegistry(srcDir, routeInfoList, agents);
|
|
90
|
+
await generateRouteRegistry(srcDir, routeInfoList, agents);
|
|
91
91
|
logger.trace('Generated route registry with %d route(s)', routeInfoList.length);
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -96,7 +96,7 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
|
|
|
96
96
|
const lifecycleResult = await generateLifecycleTypes(rootDir, srcDir, logger);
|
|
97
97
|
logger.debug(`[vite-plugin] generateLifecycleTypes returned: ${lifecycleResult}`);
|
|
98
98
|
|
|
99
|
-
// Generate entry file (pass workbench
|
|
99
|
+
// Generate entry file (pass workbench and analytics config)
|
|
100
100
|
await generateEntryFile({
|
|
101
101
|
rootDir,
|
|
102
102
|
projectId,
|
|
@@ -104,6 +104,7 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
|
|
|
104
104
|
logger,
|
|
105
105
|
mode: dev ? 'dev' : 'prod',
|
|
106
106
|
workbench: workbenchConfig.enabled ? workbenchConfig : undefined,
|
|
107
|
+
analytics: config?.analytics,
|
|
107
108
|
});
|
|
108
109
|
|
|
109
110
|
logger.trace('buildStart: Discovery complete');
|
|
@@ -443,7 +443,7 @@ export async function generateMetadata(options: MetadataGeneratorOptions): Promi
|
|
|
443
443
|
evals: agent.evals?.map((evalItem) => ({
|
|
444
444
|
filename: evalItem.filename,
|
|
445
445
|
id: evalItem.id,
|
|
446
|
-
|
|
446
|
+
identifier: evalItem.identifier,
|
|
447
447
|
name: evalItem.name,
|
|
448
448
|
version: evalItem.version,
|
|
449
449
|
description: evalItem.description,
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { join } from 'node:path';
|
|
8
8
|
import { writeFileSync, mkdirSync, existsSync, unlinkSync, readFileSync } from 'node:fs';
|
|
9
|
+
import { stat } from 'node:fs/promises';
|
|
9
10
|
import { StructuredError } from '@agentuity/core';
|
|
10
11
|
import { toCamelCase, toPascalCase } from '../../../utils/string';
|
|
11
12
|
import type { AgentMetadata } from './agent-discovery';
|
|
@@ -29,6 +30,28 @@ function sanitizePathSegment(segment: string): string {
|
|
|
29
30
|
return toCamelCase(segment.replace(ROUTE_PARAM_CHARS, ''));
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Generate TypeScript type for path parameters.
|
|
35
|
+
* Returns 'never' if no path params, or '{ param1: string; param2: string }' format.
|
|
36
|
+
*/
|
|
37
|
+
function generatePathParamsType(pathParams?: string[]): string {
|
|
38
|
+
if (!pathParams || pathParams.length === 0) {
|
|
39
|
+
return 'never';
|
|
40
|
+
}
|
|
41
|
+
return `{ ${pathParams.map((p) => `${p}: string`).join('; ')} }`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generate TypeScript tuple type for path parameters (for positional args).
|
|
46
|
+
* Returns '[]' if no path params, or '[string, string]' format.
|
|
47
|
+
*/
|
|
48
|
+
function generatePathParamsTupleType(pathParams?: string[]): string {
|
|
49
|
+
if (!pathParams || pathParams.length === 0) {
|
|
50
|
+
return '[]';
|
|
51
|
+
}
|
|
52
|
+
return `[${pathParams.map(() => 'string').join(', ')}]`;
|
|
53
|
+
}
|
|
54
|
+
|
|
32
55
|
/**
|
|
33
56
|
* Generate src/generated/registry.ts with agent registry and types
|
|
34
57
|
*/
|
|
@@ -61,6 +84,43 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
|
|
|
61
84
|
});
|
|
62
85
|
}
|
|
63
86
|
|
|
87
|
+
// Collect eval files that need to be imported for createEval calls to run
|
|
88
|
+
// These are eval.ts files in the same directory as agents that have evals
|
|
89
|
+
const evalImports: string[] = [];
|
|
90
|
+
const seenEvalPaths = new Set<string>();
|
|
91
|
+
|
|
92
|
+
for (const agent of sortedAgents) {
|
|
93
|
+
if (agent.evals && agent.evals.length > 0) {
|
|
94
|
+
// Check if any eval comes from a separate eval.ts file (not the agent file itself)
|
|
95
|
+
for (const evalMeta of agent.evals) {
|
|
96
|
+
// Skip if eval is defined in the agent file itself
|
|
97
|
+
if (evalMeta.filename === agent.filename) continue;
|
|
98
|
+
|
|
99
|
+
// Build the relative path for the eval file
|
|
100
|
+
let evalRelativePath = evalMeta.filename;
|
|
101
|
+
if (evalRelativePath.startsWith('./agent/')) {
|
|
102
|
+
evalRelativePath = evalRelativePath
|
|
103
|
+
.replace(/^\.\/agent\//, '../agent/')
|
|
104
|
+
.replace(/\.tsx?$/, '.js');
|
|
105
|
+
} else if (evalRelativePath.startsWith('src/agent/')) {
|
|
106
|
+
evalRelativePath = evalRelativePath
|
|
107
|
+
.replace(/^src\/agent\//, '../agent/')
|
|
108
|
+
.replace(/\.tsx?$/, '.js');
|
|
109
|
+
} else if (evalRelativePath.includes('/src/agent/')) {
|
|
110
|
+
// Handle absolute paths by extracting the relative part
|
|
111
|
+
evalRelativePath = evalRelativePath
|
|
112
|
+
.replace(/^.*\/src\/agent\//, '../agent/')
|
|
113
|
+
.replace(/\.tsx?$/, '.js');
|
|
114
|
+
}
|
|
115
|
+
// Avoid duplicate imports
|
|
116
|
+
if (!seenEvalPaths.has(evalRelativePath)) {
|
|
117
|
+
seenEvalPaths.add(evalRelativePath);
|
|
118
|
+
evalImports.push(`import '${evalRelativePath}';`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
64
124
|
// Generate imports for all agents
|
|
65
125
|
const imports = sortedAgents
|
|
66
126
|
.map(({ name, filename }) => {
|
|
@@ -149,11 +209,21 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
|
|
|
149
209
|
})
|
|
150
210
|
.join('\n');
|
|
151
211
|
|
|
212
|
+
// Build eval imports section (side-effect imports for createEval registration)
|
|
213
|
+
const evalImportsSection =
|
|
214
|
+
evalImports.length > 0
|
|
215
|
+
? `
|
|
216
|
+
// Eval file imports (side-effect imports to register evals via createEval)
|
|
217
|
+
${evalImports.join('\n')}
|
|
218
|
+
`
|
|
219
|
+
: '';
|
|
220
|
+
|
|
152
221
|
const generatedContent = `// @generated
|
|
153
222
|
// Auto-generated by Agentuity - DO NOT EDIT
|
|
154
223
|
${imports}
|
|
155
224
|
import type { AgentRunner } from '@agentuity/runtime';
|
|
156
225
|
import type { InferInput, InferOutput } from '@agentuity/core';
|
|
226
|
+
${evalImportsSection}
|
|
157
227
|
|
|
158
228
|
// ============================================================================
|
|
159
229
|
// Schema Type Exports
|
|
@@ -362,8 +432,10 @@ function generateRPCRegistryType(
|
|
|
362
432
|
jsdoc.push(`${indent} */`);
|
|
363
433
|
lines.push(...jsdoc);
|
|
364
434
|
|
|
435
|
+
const pathParamsType = generatePathParamsType(routeInfo.pathParams);
|
|
436
|
+
const pathParamsTupleType = generatePathParamsTupleType(routeInfo.pathParams);
|
|
365
437
|
lines.push(
|
|
366
|
-
`${indent}${key}: { input: ${value.input}; output: ${value.output}; type: ${value.type} };`
|
|
438
|
+
`${indent}${key}: { input: ${value.input}; output: ${value.output}; type: ${value.type}; params: ${pathParamsType}; paramsTuple: ${pathParamsTupleType} };`
|
|
367
439
|
);
|
|
368
440
|
} else {
|
|
369
441
|
// Nested node
|
|
@@ -393,7 +465,7 @@ function generateRPCRuntimeMetadata(
|
|
|
393
465
|
sseRoutes: RouteInfo[]
|
|
394
466
|
): string {
|
|
395
467
|
interface MetadataNode {
|
|
396
|
-
[key: string]: MetadataNode | { type: string };
|
|
468
|
+
[key: string]: MetadataNode | { type: string; path: string; pathParams?: string[] };
|
|
397
469
|
}
|
|
398
470
|
|
|
399
471
|
const tree: MetadataNode = {};
|
|
@@ -431,7 +503,14 @@ function generateRPCRuntimeMetadata(
|
|
|
431
503
|
? 'stream'
|
|
432
504
|
: route.method.toLowerCase();
|
|
433
505
|
|
|
434
|
-
|
|
506
|
+
const metadata: { type: string; path: string; pathParams?: string[] } = {
|
|
507
|
+
type: routeType,
|
|
508
|
+
path: route.path,
|
|
509
|
+
};
|
|
510
|
+
if (route.pathParams && route.pathParams.length > 0) {
|
|
511
|
+
metadata.pathParams = route.pathParams;
|
|
512
|
+
}
|
|
513
|
+
current[terminalMethod] = metadata;
|
|
435
514
|
};
|
|
436
515
|
|
|
437
516
|
apiRoutes.forEach((r) => addRoute(r, r.routeType === 'stream' ? 'stream' : 'api'));
|
|
@@ -461,15 +540,15 @@ function generateRPCRuntimeMetadata(
|
|
|
461
540
|
* Creates a module augmentation for @agentuity/react that provides
|
|
462
541
|
* strongly-typed route keys with input/output schema information.
|
|
463
542
|
*/
|
|
464
|
-
export function generateRouteRegistry(
|
|
543
|
+
export async function generateRouteRegistry(
|
|
465
544
|
srcDir: string,
|
|
466
545
|
routes: RouteInfo[],
|
|
467
546
|
agents: AgentMetadata[] = []
|
|
468
|
-
): void {
|
|
469
|
-
// Check if project uses @agentuity/react
|
|
547
|
+
): Promise<void> {
|
|
470
548
|
const projectRoot = join(srcDir, '..');
|
|
471
549
|
const packageJsonPath = join(projectRoot, 'package.json');
|
|
472
550
|
let hasReactDependency = false;
|
|
551
|
+
let hasFrontendDependency = false;
|
|
473
552
|
|
|
474
553
|
try {
|
|
475
554
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
@@ -477,10 +556,25 @@ export function generateRouteRegistry(
|
|
|
477
556
|
packageJson.dependencies?.['@agentuity/react'] ||
|
|
478
557
|
packageJson.devDependencies?.['@agentuity/react']
|
|
479
558
|
);
|
|
559
|
+
hasFrontendDependency = !!(
|
|
560
|
+
packageJson.dependencies?.['@agentuity/frontend'] ||
|
|
561
|
+
packageJson.devDependencies?.['@agentuity/frontend']
|
|
562
|
+
);
|
|
563
|
+
} catch {
|
|
564
|
+
// If we can't read package.json, assume no frontend dependencies
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const webDir = join(srcDir, 'web');
|
|
568
|
+
let hasWebDirectory = false;
|
|
569
|
+
try {
|
|
570
|
+
const webDirStat = await stat(webDir);
|
|
571
|
+
hasWebDirectory = webDirStat.isDirectory();
|
|
480
572
|
} catch {
|
|
481
|
-
//
|
|
573
|
+
// Directory doesn't exist
|
|
482
574
|
}
|
|
483
575
|
|
|
576
|
+
const shouldEmitFrontendClient = hasFrontendDependency && !hasReactDependency && hasWebDirectory;
|
|
577
|
+
|
|
484
578
|
// Filter routes by type and sort by path for deterministic output
|
|
485
579
|
const sortByPath = (a: RouteInfo, b: RouteInfo) => a.path.localeCompare(b.path);
|
|
486
580
|
const apiRoutes = routes
|
|
@@ -769,13 +863,18 @@ export function generateRouteRegistry(
|
|
|
769
863
|
// because only 'json' validators extract input schemas
|
|
770
864
|
// Also check if agentVariable exists but import wasn't added (missing agentImportPath)
|
|
771
865
|
const hasValidAgentImport = route.agentVariable ? !!importName : false;
|
|
866
|
+
|
|
867
|
+
// Generate pathParams type
|
|
868
|
+
const pathParamsType = generatePathParamsType(route.pathParams);
|
|
869
|
+
|
|
772
870
|
if (!route.inputSchemaVariable && !route.outputSchemaVariable && !hasValidAgentImport) {
|
|
773
871
|
const streamValue = route.stream === true ? 'true' : 'false';
|
|
774
872
|
return `\t'${routeKey}': {
|
|
775
|
-
\t\tinputSchema: never;
|
|
776
|
-
\t\toutputSchema: never;
|
|
777
|
-
\t\tstream: ${streamValue};
|
|
778
|
-
\t}
|
|
873
|
+
\t\tinputSchema: never;
|
|
874
|
+
\t\toutputSchema: never;
|
|
875
|
+
\t\tstream: ${streamValue};
|
|
876
|
+
\t\tparams: ${pathParamsType};
|
|
877
|
+
\t};`;
|
|
779
878
|
}
|
|
780
879
|
const streamValue = importName
|
|
781
880
|
? `typeof ${importName} extends { stream?: infer S } ? S : false`
|
|
@@ -784,10 +883,11 @@ export function generateRouteRegistry(
|
|
|
784
883
|
: 'false';
|
|
785
884
|
|
|
786
885
|
return `\t'${routeKey}': {
|
|
787
|
-
\t\tinputSchema: ${pascalName}InputSchema;
|
|
788
|
-
\t\toutputSchema: ${pascalName}OutputSchema;
|
|
789
|
-
\t\tstream: ${streamValue};
|
|
790
|
-
\t}
|
|
886
|
+
\t\tinputSchema: ${pascalName}InputSchema;
|
|
887
|
+
\t\toutputSchema: ${pascalName}OutputSchema;
|
|
888
|
+
\t\tstream: ${streamValue};
|
|
889
|
+
\t\tparams: ${pathParamsType};
|
|
890
|
+
\t};`;
|
|
791
891
|
};
|
|
792
892
|
|
|
793
893
|
// Generate route entries with METHOD prefix for API routes
|
|
@@ -817,7 +917,7 @@ export function generateRouteRegistry(
|
|
|
817
917
|
const generatedContent = `// @generated
|
|
818
918
|
// Auto-generated by Agentuity - DO NOT EDIT
|
|
819
919
|
${importsStr}${typeImports}${
|
|
820
|
-
|
|
920
|
+
shouldEmitFrontendClient
|
|
821
921
|
? `
|
|
822
922
|
import { createClient } from '@agentuity/frontend';`
|
|
823
923
|
: ''
|
|
@@ -842,7 +942,7 @@ ${routeSchemaTypes}
|
|
|
842
942
|
* Individual route Input/Output types are exported above for direct usage.
|
|
843
943
|
*/
|
|
844
944
|
${
|
|
845
|
-
|
|
945
|
+
shouldEmitFrontendClient
|
|
846
946
|
? `
|
|
847
947
|
/**
|
|
848
948
|
* RPC Route Registry
|
|
@@ -907,13 +1007,14 @@ if (typeof globalThis !== 'undefined') {
|
|
|
907
1007
|
(globalThis as Record<string, unknown>).__rpcRouteMetadata = _rpcRouteMetadata;
|
|
908
1008
|
}
|
|
909
1009
|
${
|
|
910
|
-
|
|
1010
|
+
shouldEmitFrontendClient
|
|
911
1011
|
? `
|
|
912
1012
|
/**
|
|
913
1013
|
* Create a type-safe API client with optional configuration.
|
|
914
1014
|
*
|
|
915
|
-
* This function is only generated when @agentuity/
|
|
916
|
-
*
|
|
1015
|
+
* This function is only generated when @agentuity/frontend is installed
|
|
1016
|
+
* but @agentuity/react is not. For React apps, import createAPIClient
|
|
1017
|
+
* from '@agentuity/react' instead.
|
|
917
1018
|
*
|
|
918
1019
|
* @example
|
|
919
1020
|
* \`\`\`typescript
|
|
@@ -932,7 +1033,8 @@ export function createAPIClient(options?: Parameters<typeof createClient>[0]): i
|
|
|
932
1033
|
return createClient(options || {}, _rpcRouteMetadata) as import('@agentuity/frontend').Client<RPCRouteRegistry>;
|
|
933
1034
|
}
|
|
934
1035
|
`
|
|
935
|
-
:
|
|
1036
|
+
: hasReactDependency
|
|
1037
|
+
? `
|
|
936
1038
|
/**
|
|
937
1039
|
* Type-safe API client is available from @agentuity/react
|
|
938
1040
|
*
|
|
@@ -945,6 +1047,7 @@ export function createAPIClient(options?: Parameters<typeof createClient>[0]): i
|
|
|
945
1047
|
* \`\`\`
|
|
946
1048
|
*/
|
|
947
1049
|
`
|
|
1050
|
+
: ''
|
|
948
1051
|
}
|
|
949
1052
|
|
|
950
1053
|
// FOUND AN ERROR IN THIS FILE?
|
|
@@ -955,9 +1058,7 @@ export function createAPIClient(options?: Parameters<typeof createClient>[0]): i
|
|
|
955
1058
|
const generatedDir = join(srcDir, 'generated');
|
|
956
1059
|
const registryPath = join(generatedDir, 'routes.ts');
|
|
957
1060
|
|
|
958
|
-
|
|
959
|
-
mkdirSync(generatedDir, { recursive: true });
|
|
960
|
-
}
|
|
1061
|
+
mkdirSync(generatedDir, { recursive: true });
|
|
961
1062
|
|
|
962
1063
|
// Collapse 2+ consecutive empty lines into 1 empty line (3+ \n becomes 2 \n)
|
|
963
1064
|
const cleanedContent = generatedContent.replace(/\n{3,}/g, '\n\n');
|
|
@@ -40,6 +40,24 @@ export interface RouteInfo {
|
|
|
40
40
|
inputSchemaCode?: string;
|
|
41
41
|
outputSchemaCode?: string;
|
|
42
42
|
stream?: boolean;
|
|
43
|
+
pathParams?: string[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Extract path parameters from a route path.
|
|
48
|
+
* Matches patterns like :id, :userId, :id?, *path, etc.
|
|
49
|
+
*/
|
|
50
|
+
export function extractPathParams(path: string): string[] {
|
|
51
|
+
const params: string[] = [];
|
|
52
|
+
const parts = path.split('/');
|
|
53
|
+
for (const part of parts) {
|
|
54
|
+
if (part.startsWith(':')) {
|
|
55
|
+
params.push(part.replace(/^:|[?+*]$/g, ''));
|
|
56
|
+
} else if (part.startsWith('*') && part.length > 1) {
|
|
57
|
+
params.push(part.substring(1).replace(/[?+*]$/g, ''));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return params;
|
|
43
61
|
}
|
|
44
62
|
|
|
45
63
|
/**
|
|
@@ -90,6 +108,7 @@ export async function discoverRoutes(
|
|
|
90
108
|
|
|
91
109
|
// Convert to RouteInfo for registry
|
|
92
110
|
for (const route of parsedRoutes) {
|
|
111
|
+
const pathParams = extractPathParams(route.path);
|
|
93
112
|
routeInfoList.push({
|
|
94
113
|
method: route.method.toUpperCase(),
|
|
95
114
|
path: route.path,
|
|
@@ -106,6 +125,7 @@ export async function discoverRoutes(
|
|
|
106
125
|
: route.type === 'stream'
|
|
107
126
|
? true
|
|
108
127
|
: undefined,
|
|
128
|
+
pathParams: pathParams.length > 0 ? pathParams : undefined,
|
|
109
129
|
});
|
|
110
130
|
}
|
|
111
131
|
}
|