@agentuity/cli 0.0.111 → 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/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.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +4 -3
- 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 +2 -1
- package/dist/cmd/build/vite/index.js.map +1 -1
- package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/registry-generator.js +45 -0
- package/dist/cmd/build/vite/registry-generator.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +2 -1
- 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 +62 -3
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/get.js +19 -0
- package/dist/cmd/cloud/sandbox/get.js.map +1 -1
- 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 +18 -12
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.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 +71 -0
- package/dist/types.d.ts.map +1 -1
- 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 +5 -5
- package/src/agents-docs.ts +42 -8
- 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 +4 -1
- package/src/cmd/build/vite/index.ts +2 -1
- package/src/cmd/build/vite/registry-generator.ts +47 -0
- package/src/cmd/build/vite/vite-builder.ts +2 -1
- package/src/cmd/cloud/deploy-fork.ts +296 -0
- package/src/cmd/cloud/deploy.ts +70 -3
- package/src/cmd/cloud/sandbox/get.ts +17 -0
- package/src/cmd/cloud/ssh.ts +13 -3
- package/src/cmd/dev/index.ts +18 -13
- package/src/config.ts +1 -1
- 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 +85 -0
- package/src/typescript-errors.ts +2 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createSubcommand } from '../../types';
|
|
2
|
+
import { getCommand } from '../../command-prefix';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
const ApikeyResponseSchema = z.object({
|
|
6
|
+
apiKey: z.string().describe('The API key for the authenticated user'),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const apikeyCommand = createSubcommand({
|
|
10
|
+
name: 'apikey',
|
|
11
|
+
description: 'Display the API key for the currently authenticated user',
|
|
12
|
+
tags: ['read-only', 'fast', 'requires-auth'],
|
|
13
|
+
requires: { auth: true },
|
|
14
|
+
idempotent: true,
|
|
15
|
+
schema: {
|
|
16
|
+
response: ApikeyResponseSchema,
|
|
17
|
+
},
|
|
18
|
+
examples: [
|
|
19
|
+
{ command: getCommand('auth apikey'), description: 'Print the API key' },
|
|
20
|
+
{ command: getCommand('--json auth apikey'), description: 'Output API key in JSON format' },
|
|
21
|
+
],
|
|
22
|
+
|
|
23
|
+
async handler(ctx) {
|
|
24
|
+
const { auth, options } = ctx;
|
|
25
|
+
|
|
26
|
+
const result = {
|
|
27
|
+
apiKey: auth.apiKey,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
if (!options.json) {
|
|
31
|
+
console.log(result.apiKey);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return result;
|
|
35
|
+
},
|
|
36
|
+
});
|
package/src/cmd/auth/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createCommand } from '../../types';
|
|
2
|
+
import { apikeyCommand } from './apikey';
|
|
2
3
|
import { loginCommand } from './login';
|
|
3
4
|
import { logoutCommand } from './logout';
|
|
4
5
|
import { signupCommand } from './signup';
|
|
@@ -14,5 +15,12 @@ export const command = createCommand({
|
|
|
14
15
|
{ command: getCommand('auth login'), description: 'Login to your account' },
|
|
15
16
|
{ command: getCommand('auth whoami'), description: 'Show current user info' },
|
|
16
17
|
],
|
|
17
|
-
subcommands: [
|
|
18
|
+
subcommands: [
|
|
19
|
+
apikeyCommand,
|
|
20
|
+
loginCommand,
|
|
21
|
+
logoutCommand,
|
|
22
|
+
signupCommand,
|
|
23
|
+
whoamiCommand,
|
|
24
|
+
sshSubcommand,
|
|
25
|
+
],
|
|
18
26
|
});
|
package/src/cmd/build/ast.ts
CHANGED
|
@@ -967,9 +967,19 @@ function hasValidatorCall(args: unknown[]): ValidatorInfo {
|
|
|
967
967
|
if (callExpr.callee.type === 'Identifier') {
|
|
968
968
|
const identifier = callExpr.callee as ASTNodeIdentifier;
|
|
969
969
|
if (identifier.name === 'validator') {
|
|
970
|
-
// Try to extract schema variables from validator({ input, output })
|
|
970
|
+
// Try to extract schema variables from validator({ input, output, stream })
|
|
971
971
|
const schemas = extractValidatorSchemas(callExpr);
|
|
972
|
-
|
|
972
|
+
// Return if we found any schema variables OR a stream flag
|
|
973
|
+
if (
|
|
974
|
+
schemas.inputSchemaVariable ||
|
|
975
|
+
schemas.outputSchemaVariable ||
|
|
976
|
+
schemas.stream !== undefined
|
|
977
|
+
) {
|
|
978
|
+
return { hasValidator: true, ...schemas };
|
|
979
|
+
}
|
|
980
|
+
// Try Hono validator('json', callback) pattern
|
|
981
|
+
const honoSchemas = extractHonoValidatorSchema(callExpr);
|
|
982
|
+
return { hasValidator: true, ...honoSchemas };
|
|
973
983
|
}
|
|
974
984
|
// Check for zValidator('json', schema)
|
|
975
985
|
if (identifier.name === 'zValidator') {
|
|
@@ -1129,6 +1139,114 @@ function extractZValidatorSchema(callExpr: ASTCallExpression): {
|
|
|
1129
1139
|
return result;
|
|
1130
1140
|
}
|
|
1131
1141
|
|
|
1142
|
+
/**
|
|
1143
|
+
* Extract schema from Hono validator('json', callback) pattern
|
|
1144
|
+
* Example: validator('json', (value, c) => { const result = mySchema['~standard'].validate(value); ... })
|
|
1145
|
+
* Searches the callback function body for schema.validate() or schema['~standard'].validate() calls
|
|
1146
|
+
*/
|
|
1147
|
+
function extractHonoValidatorSchema(callExpr: ASTCallExpression): {
|
|
1148
|
+
inputSchemaVariable?: string;
|
|
1149
|
+
} {
|
|
1150
|
+
const result: { inputSchemaVariable?: string } = {};
|
|
1151
|
+
|
|
1152
|
+
// Hono validator requires at least 2 arguments: validator(target, callback)
|
|
1153
|
+
if (!callExpr.arguments || callExpr.arguments.length < 2) {
|
|
1154
|
+
return result;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// First argument should be 'json' literal (only extract for JSON validation)
|
|
1158
|
+
const targetArg = callExpr.arguments[0] as ASTNode;
|
|
1159
|
+
if (targetArg.type === 'Literal') {
|
|
1160
|
+
const targetValue = (targetArg as ASTLiteral).value;
|
|
1161
|
+
if (typeof targetValue === 'string' && targetValue !== 'json') {
|
|
1162
|
+
return result;
|
|
1163
|
+
}
|
|
1164
|
+
} else {
|
|
1165
|
+
return result;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// Second argument should be a function (arrow or regular)
|
|
1169
|
+
const callbackArg = callExpr.arguments[1] as ASTNode;
|
|
1170
|
+
if (
|
|
1171
|
+
callbackArg.type !== 'ArrowFunctionExpression' &&
|
|
1172
|
+
callbackArg.type !== 'FunctionExpression'
|
|
1173
|
+
) {
|
|
1174
|
+
return result;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
// Get the function body
|
|
1178
|
+
const funcExpr = callbackArg as {
|
|
1179
|
+
body?: ASTNode;
|
|
1180
|
+
};
|
|
1181
|
+
|
|
1182
|
+
if (!funcExpr.body) {
|
|
1183
|
+
return result;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// Search the function body for schema.validate() or schema['~standard'].validate() calls
|
|
1187
|
+
const schemaVar = findSchemaValidateCall(funcExpr.body);
|
|
1188
|
+
if (schemaVar) {
|
|
1189
|
+
result.inputSchemaVariable = schemaVar;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
return result;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
/**
|
|
1196
|
+
* Recursively search AST for schema.validate() or schema['~standard'].validate() calls
|
|
1197
|
+
* Returns the schema variable name if found
|
|
1198
|
+
*/
|
|
1199
|
+
function findSchemaValidateCall(node: ASTNode): string | undefined {
|
|
1200
|
+
if (!node || typeof node !== 'object') return undefined;
|
|
1201
|
+
|
|
1202
|
+
// Check if this is a CallExpression with .validate()
|
|
1203
|
+
if (node.type === 'CallExpression') {
|
|
1204
|
+
const callExpr = node as ASTCallExpression;
|
|
1205
|
+
|
|
1206
|
+
// Check for schema['~standard'].validate(value) pattern
|
|
1207
|
+
// AST: CallExpression -> MemberExpression(validate) -> MemberExpression(['~standard']) -> Identifier(schema)
|
|
1208
|
+
if (callExpr.callee.type === 'MemberExpression') {
|
|
1209
|
+
const member = callExpr.callee as ASTMemberExpression;
|
|
1210
|
+
const propName =
|
|
1211
|
+
member.property.type === 'Identifier'
|
|
1212
|
+
? (member.property as ASTNodeIdentifier).name
|
|
1213
|
+
: undefined;
|
|
1214
|
+
|
|
1215
|
+
if (propName === 'validate') {
|
|
1216
|
+
// Check if the object is schema['~standard'] or just schema
|
|
1217
|
+
if (member.object.type === 'MemberExpression') {
|
|
1218
|
+
// schema['~standard'].validate() pattern
|
|
1219
|
+
const innerMember = member.object as ASTMemberExpression;
|
|
1220
|
+
if (innerMember.object.type === 'Identifier') {
|
|
1221
|
+
return (innerMember.object as ASTNodeIdentifier).name;
|
|
1222
|
+
}
|
|
1223
|
+
} else if (member.object.type === 'Identifier') {
|
|
1224
|
+
// schema.validate() pattern
|
|
1225
|
+
return (member.object as ASTNodeIdentifier).name;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
// Recursively search child nodes
|
|
1232
|
+
for (const key of Object.keys(node)) {
|
|
1233
|
+
const value = (node as unknown as Record<string, unknown>)[key];
|
|
1234
|
+
if (Array.isArray(value)) {
|
|
1235
|
+
for (const item of value) {
|
|
1236
|
+
if (item && typeof item === 'object') {
|
|
1237
|
+
const found = findSchemaValidateCall(item as ASTNode);
|
|
1238
|
+
if (found) return found;
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
} else if (value && typeof value === 'object') {
|
|
1242
|
+
const found = findSchemaValidateCall(value as ASTNode);
|
|
1243
|
+
if (found) return found;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
return undefined;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1132
1250
|
export async function parseRoute(
|
|
1133
1251
|
rootDir: string,
|
|
1134
1252
|
filename: string,
|
|
@@ -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}
|
|
@@ -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,
|
|
@@ -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,
|
|
@@ -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');
|
|
@@ -84,6 +84,43 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
|
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
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
|
+
|
|
87
124
|
// Generate imports for all agents
|
|
88
125
|
const imports = sortedAgents
|
|
89
126
|
.map(({ name, filename }) => {
|
|
@@ -172,11 +209,21 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
|
|
|
172
209
|
})
|
|
173
210
|
.join('\n');
|
|
174
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
|
+
|
|
175
221
|
const generatedContent = `// @generated
|
|
176
222
|
// Auto-generated by Agentuity - DO NOT EDIT
|
|
177
223
|
${imports}
|
|
178
224
|
import type { AgentRunner } from '@agentuity/runtime';
|
|
179
225
|
import type { InferInput, InferOutput } from '@agentuity/core';
|
|
226
|
+
${evalImportsSection}
|
|
180
227
|
|
|
181
228
|
// ============================================================================
|
|
182
229
|
// Schema Type Exports
|
|
@@ -103,6 +103,7 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
|
|
|
103
103
|
logger,
|
|
104
104
|
mode: dev ? 'dev' : 'prod',
|
|
105
105
|
workbench: workbenchConfig.enabled ? workbenchConfig : undefined,
|
|
106
|
+
analytics: config?.analytics,
|
|
106
107
|
});
|
|
107
108
|
|
|
108
109
|
// Finally, build with Bun.build
|
|
@@ -165,7 +166,7 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
|
|
|
165
166
|
const isLocalRegion = options.region === 'local';
|
|
166
167
|
const cdnDomain = isLocalRegion
|
|
167
168
|
? 'localstack-static-assets.t3.storage.dev'
|
|
168
|
-
: '
|
|
169
|
+
: 'cdn.agentuity.com';
|
|
169
170
|
const cdnBaseUrl =
|
|
170
171
|
!dev && deploymentId ? `https://${cdnDomain}/${deploymentId}/client/` : undefined;
|
|
171
172
|
|