@agentuity/cli 2.0.5 → 2.0.6
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/cmd/build/patch/otel-llm.js +2 -2
- package/dist/cmd/build/patch/otel-llm.js.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js +1 -0
- package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
- package/dist/cmd/build/vite/index.d.ts +0 -28
- package/dist/cmd/build/vite/index.d.ts.map +1 -1
- package/dist/cmd/build/vite/index.js +1 -104
- package/dist/cmd/build/vite/index.js.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.js +8 -2
- package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts +2 -0
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js +5 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.d.ts +2 -0
- package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.js +2 -1
- package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +143 -2
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +1 -0
- package/dist/cmd/dev/index.js.map +1 -1
- package/package.json +6 -6
- package/src/cmd/build/patch/otel-llm.ts +2 -2
- package/src/cmd/build/vite/bun-dev-server.ts +1 -0
- package/src/cmd/build/vite/index.ts +1 -148
- package/src/cmd/build/vite/metadata-generator.ts +8 -2
- package/src/cmd/build/vite/vite-asset-server-config.ts +16 -1
- package/src/cmd/build/vite/vite-asset-server.ts +4 -0
- package/src/cmd/build/vite/vite-builder.ts +171 -9
- package/src/cmd/dev/index.ts +1 -0
|
@@ -18,6 +18,8 @@ export interface GenerateAssetServerConfigOptions {
|
|
|
18
18
|
backendPort: number; // The port Bun backend is running on (internal)
|
|
19
19
|
/** User-defined route mount paths from createApp({ router }) (e.g., ['/api', '/v1']) */
|
|
20
20
|
routePaths?: string[];
|
|
21
|
+
/** Live tunnel hostname (e.g. "epXXX.agentuity-us.live.internal") to add to Vite's allowedHosts */
|
|
22
|
+
liveHostname?: string;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/**
|
|
@@ -165,7 +167,15 @@ function spaFallbackPlugin(rootDir: string, routePaths: string[], workbenchPath?
|
|
|
165
167
|
export async function generateAssetServerConfig(
|
|
166
168
|
options: GenerateAssetServerConfigOptions
|
|
167
169
|
): Promise<InlineConfig> {
|
|
168
|
-
const {
|
|
170
|
+
const {
|
|
171
|
+
rootDir,
|
|
172
|
+
logger,
|
|
173
|
+
workbenchPath,
|
|
174
|
+
port,
|
|
175
|
+
backendPort,
|
|
176
|
+
routePaths = ['/api'],
|
|
177
|
+
liveHostname,
|
|
178
|
+
} = options;
|
|
169
179
|
|
|
170
180
|
// Load path aliases from tsconfig.json if available
|
|
171
181
|
const tsconfigPath = join(rootDir, 'tsconfig.json');
|
|
@@ -219,6 +229,11 @@ export async function generateAssetServerConfig(
|
|
|
219
229
|
strictPort: true, // Port is pre-verified as available by findAvailablePort()
|
|
220
230
|
host: '127.0.0.1',
|
|
221
231
|
|
|
232
|
+
// When accessed via an Agentuity live tunnel, the Host header is the
|
|
233
|
+
// tunnel hostname (e.g. "epXXX.agentuity-us.live.internal"). Without
|
|
234
|
+
// adding it here, Vite 6+ rejects the request with "host not allowed".
|
|
235
|
+
...(liveHostname ? { allowedHosts: [liveHostname] } : {}),
|
|
236
|
+
|
|
222
237
|
// Proxy backend routes to Bun server (HTTP only).
|
|
223
238
|
// WebSocket upgrades are handled by the front-door TCP proxy (ws-proxy.ts)
|
|
224
239
|
// which routes them directly to the Bun backend, bypassing Vite entirely.
|
|
@@ -26,6 +26,8 @@ export interface StartViteAssetServerOptions {
|
|
|
26
26
|
backendPort: number; // Port of the Bun backend server
|
|
27
27
|
/** User-defined route mount paths from createApp({ router }) */
|
|
28
28
|
routePaths?: string[];
|
|
29
|
+
/** Live tunnel hostname to add to Vite's allowedHosts */
|
|
30
|
+
liveHostname?: string;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
/**
|
|
@@ -80,6 +82,7 @@ export async function startViteAssetServer(
|
|
|
80
82
|
port: preferredPort = 3500,
|
|
81
83
|
backendPort,
|
|
82
84
|
routePaths,
|
|
85
|
+
liveHostname,
|
|
83
86
|
} = options;
|
|
84
87
|
|
|
85
88
|
logger.debug('Starting Vite dev server (primary, proxying backend on port %d)...', backendPort);
|
|
@@ -101,6 +104,7 @@ export async function startViteAssetServer(
|
|
|
101
104
|
port: availablePort,
|
|
102
105
|
backendPort,
|
|
103
106
|
routePaths,
|
|
107
|
+
liveHostname,
|
|
104
108
|
});
|
|
105
109
|
|
|
106
110
|
// Dynamically import vite from the project's node_modules
|
|
@@ -5,11 +5,132 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { join } from 'node:path';
|
|
8
|
-
import { existsSync, rmSync } from 'node:fs';
|
|
8
|
+
import { existsSync, rmSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
import { createRequire } from 'node:module';
|
|
9
11
|
import type { InlineConfig } from 'vite';
|
|
10
12
|
import type { Logger, DeployOptions } from '../../../types';
|
|
11
13
|
import type { BuildReportCollector } from '../../../build-report';
|
|
12
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Read the pre-built beacon script from @agentuity/frontend package.
|
|
17
|
+
* Tries multiple resolution strategies for workspace/installed/symlink scenarios.
|
|
18
|
+
*/
|
|
19
|
+
async function readBeaconScript(projectRoot: string): Promise<string> {
|
|
20
|
+
let frontendPath: string | null = null;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
frontendPath = await Bun.resolve('@agentuity/frontend', projectRoot);
|
|
24
|
+
} catch {
|
|
25
|
+
// Not found from project root
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!frontendPath) {
|
|
29
|
+
try {
|
|
30
|
+
const thisDir = new URL('.', import.meta.url).pathname;
|
|
31
|
+
frontendPath = await Bun.resolve('@agentuity/frontend', thisDir);
|
|
32
|
+
} catch {
|
|
33
|
+
// Not found from CLI directory
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!frontendPath) {
|
|
38
|
+
try {
|
|
39
|
+
const projectRequire = createRequire(join(projectRoot, 'package.json'));
|
|
40
|
+
frontendPath = projectRequire.resolve('@agentuity/frontend');
|
|
41
|
+
} catch {
|
|
42
|
+
// Not found via createRequire
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!frontendPath) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
'Could not resolve @agentuity/frontend. Ensure the package is installed and built.'
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const packageDir = join(frontendPath, '..');
|
|
53
|
+
const beaconPath = join(packageDir, 'beacon.js');
|
|
54
|
+
|
|
55
|
+
const beaconFile = Bun.file(beaconPath);
|
|
56
|
+
if (!(await beaconFile.exists())) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`Beacon script not found at ${beaconPath}. Run "bun run build" in @agentuity/frontend first.`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return beaconFile.text();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Post-build step: inject the analytics beacon into the built index.html.
|
|
67
|
+
*
|
|
68
|
+
* 1. Reads the beacon script from @agentuity/frontend
|
|
69
|
+
* 2. Writes it as a content-hashed asset file
|
|
70
|
+
* 3. Injects a <script data-agentuity-beacon> tag into the HTML
|
|
71
|
+
*
|
|
72
|
+
* This runs after `vite build` completes so it works regardless of the
|
|
73
|
+
* user's vite.config.ts — no Vite plugin required.
|
|
74
|
+
*/
|
|
75
|
+
async function injectBeacon(rootDir: string, cdnBaseUrl: string, logger: Logger): Promise<void> {
|
|
76
|
+
const clientDir = join(rootDir, '.agentuity/client');
|
|
77
|
+
const indexHtmlPath = join(clientDir, 'index.html');
|
|
78
|
+
|
|
79
|
+
if (!existsSync(indexHtmlPath)) {
|
|
80
|
+
logger.debug('No index.html found, skipping beacon injection');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let beaconCode: string;
|
|
85
|
+
try {
|
|
86
|
+
beaconCode = await readBeaconScript(rootDir);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
logger.warn(
|
|
89
|
+
'Failed to read beacon script, skipping injection: %s',
|
|
90
|
+
error instanceof Error ? error.message : String(error)
|
|
91
|
+
);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Write beacon as a content-hashed asset (matches Vite's naming convention)
|
|
96
|
+
const hash = createHash('sha256').update(beaconCode).digest('hex').slice(0, 8);
|
|
97
|
+
const beaconFileName = `agentuity-beacon-${hash}.js`;
|
|
98
|
+
const assetsDir = join(clientDir, 'assets');
|
|
99
|
+
mkdirSync(assetsDir, { recursive: true });
|
|
100
|
+
writeFileSync(join(assetsDir, beaconFileName), beaconCode);
|
|
101
|
+
|
|
102
|
+
// If a Vite manifest exists, add the beacon so the metadata generator
|
|
103
|
+
// includes it in the asset list. When no manifest exists, the directory
|
|
104
|
+
// scanner in metadata-generator.ts picks up assets/ directly.
|
|
105
|
+
const manifestPath = join(clientDir, '.vite', 'manifest.json');
|
|
106
|
+
if (existsSync(manifestPath)) {
|
|
107
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
|
|
108
|
+
manifest['agentuity-beacon'] = { file: `assets/${beaconFileName}` };
|
|
109
|
+
writeFileSync(manifestPath, JSON.stringify(manifest));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Build the beacon URL using the CDN base
|
|
113
|
+
const normalizedBase = cdnBaseUrl.endsWith('/') ? cdnBaseUrl : `${cdnBaseUrl}/`;
|
|
114
|
+
const beaconUrl = `${normalizedBase}assets/${beaconFileName}`;
|
|
115
|
+
|
|
116
|
+
// Inject the script tag into index.html
|
|
117
|
+
// The script must be sync (no async/defer) to patch history API before router loads.
|
|
118
|
+
// The data-agentuity-beacon attribute is the marker the runtime looks for.
|
|
119
|
+
const beaconScript = `<script data-agentuity-beacon src="${beaconUrl}"></script>`;
|
|
120
|
+
|
|
121
|
+
let html = readFileSync(indexHtmlPath, 'utf-8');
|
|
122
|
+
if (html.includes('</head>')) {
|
|
123
|
+
html = html.replace('</head>', `${beaconScript}</head>`);
|
|
124
|
+
} else if (html.includes('<body')) {
|
|
125
|
+
html = html.replace(/<body([^>]*)>/, `<body$1>${beaconScript}`);
|
|
126
|
+
} else {
|
|
127
|
+
html = beaconScript + html;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
writeFileSync(indexHtmlPath, html);
|
|
131
|
+
logger.debug('Injected analytics beacon: %s', beaconUrl);
|
|
132
|
+
}
|
|
133
|
+
|
|
13
134
|
export interface ViteBuildOptions {
|
|
14
135
|
rootDir: string;
|
|
15
136
|
mode: 'client' | 'server' | 'workbench';
|
|
@@ -116,18 +237,43 @@ export default defineConfig({
|
|
|
116
237
|
await Bun.write(viteConfigPath, fallbackConfig);
|
|
117
238
|
}
|
|
118
239
|
|
|
240
|
+
// Construct CDN base URL for production builds so Vite prefixes all
|
|
241
|
+
// asset URLs (CSS, JS chunks) with the CDN origin instead of "/".
|
|
242
|
+
const cdnBaseUrl =
|
|
243
|
+
!dev && options.deploymentId
|
|
244
|
+
? `https://${options.region === 'local' ? 'localstack-static-assets.t3.storageapi.dev' : 'cdn.agentuity.com'}/${options.deploymentId}/client/`
|
|
245
|
+
: undefined;
|
|
246
|
+
|
|
247
|
+
const args = [
|
|
248
|
+
'bun',
|
|
249
|
+
'x',
|
|
250
|
+
'vite',
|
|
251
|
+
'build',
|
|
252
|
+
'--mode',
|
|
253
|
+
buildMode,
|
|
254
|
+
'--outDir',
|
|
255
|
+
clientOutDir,
|
|
256
|
+
'--logLevel',
|
|
257
|
+
'error',
|
|
258
|
+
'--clearScreen',
|
|
259
|
+
'false',
|
|
260
|
+
];
|
|
261
|
+
if (cdnBaseUrl) {
|
|
262
|
+
args.push('--base', cdnBaseUrl);
|
|
263
|
+
}
|
|
264
|
+
|
|
119
265
|
logger.debug('Spawning vite build for client (subprocess mode)');
|
|
120
266
|
logger.debug(' outDir: %s', clientOutDir);
|
|
121
267
|
logger.debug(' mode: %s', buildMode);
|
|
268
|
+
if (cdnBaseUrl) {
|
|
269
|
+
logger.debug(' base (CDN): %s', cdnBaseUrl);
|
|
270
|
+
}
|
|
122
271
|
|
|
123
|
-
const viteProcess = Bun.spawn(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
stderr: 'inherit',
|
|
129
|
-
}
|
|
130
|
-
);
|
|
272
|
+
const viteProcess = Bun.spawn(args, {
|
|
273
|
+
cwd: rootDir,
|
|
274
|
+
stdout: 'inherit',
|
|
275
|
+
stderr: 'inherit',
|
|
276
|
+
});
|
|
131
277
|
|
|
132
278
|
const exitCode = await viteProcess.exited;
|
|
133
279
|
|
|
@@ -264,6 +410,22 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
|
|
|
264
410
|
logger.debug('Moved index.html from src/web/ to client root');
|
|
265
411
|
}
|
|
266
412
|
|
|
413
|
+
// Post-build: inject analytics beacon into the built HTML.
|
|
414
|
+
// Must run AFTER the index.html normalization above (Vite may
|
|
415
|
+
// output to src/web/index.html which gets moved to the client root).
|
|
416
|
+
const isLocalRegion = options.region === 'local';
|
|
417
|
+
const cdnDomain = isLocalRegion
|
|
418
|
+
? 'localstack-static-assets.t3.storageapi.dev'
|
|
419
|
+
: 'cdn.agentuity.com';
|
|
420
|
+
const cdnBaseUrl =
|
|
421
|
+
!dev && options.deploymentId
|
|
422
|
+
? `https://${cdnDomain}/${options.deploymentId}/client/`
|
|
423
|
+
: undefined;
|
|
424
|
+
|
|
425
|
+
if (cdnBaseUrl && analyticsEnabled) {
|
|
426
|
+
await injectBeacon(rootDir, cdnBaseUrl, logger);
|
|
427
|
+
}
|
|
428
|
+
|
|
267
429
|
result.client.included = true;
|
|
268
430
|
result.client.duration = Date.now() - started;
|
|
269
431
|
endClientDiagnostic?.();
|
package/src/cmd/dev/index.ts
CHANGED