@alexkroman1/aai-cli 0.12.2 → 1.0.2
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/_agent-CzbSa09n.mjs +38 -0
- package/dist/{_api-client-H4MFOr8j.mjs → _api-client-CFfjWfNa.mjs} +13 -2
- package/dist/_bundler-DgRDzBzD.mjs +137 -0
- package/dist/_config-Dv-T6uRj.mjs +77 -0
- package/dist/_dev-server-Cag4LlkI.mjs +133 -0
- package/dist/_init-DhX1a2Zb.mjs +153 -0
- package/dist/_output-BKdAJaM5.mjs +70 -0
- package/dist/_server-common-Pdb-KUSK.mjs +36 -0
- package/dist/_ui-r2t6_2eP.mjs +40 -0
- package/dist/_utils-DZo3_J_v.mjs +23 -0
- package/dist/cli.mjs +131 -88
- package/dist/delete-CaiAsY1S.mjs +33 -0
- package/dist/deploy-CmY2AtML.mjs +61 -0
- package/dist/dev-Wmola4F6.mjs +30 -0
- package/dist/init-DJQVk0Gw.mjs +154 -0
- package/dist/rolldown-runtime-DacLjcLf.mjs +14 -0
- package/dist/secret-lSaf6Uax.mjs +60 -0
- package/dist/test-DhQ4aznR.mjs +56 -0
- package/package.json +31 -11
- package/dist/_bundler-2yKukgnU.mjs +0 -125
- package/dist/_discover-a8yIuqEp.mjs +0 -220
- package/dist/_init-VzVTpJFZ.mjs +0 -56
- package/dist/_templates-CtZBILce.mjs +0 -72
- package/dist/_ui-DWGXImbO.mjs +0 -30
- package/dist/delete-BvRel3Tw.mjs +0 -34
- package/dist/deploy-CnscqVZv.mjs +0 -92
- package/dist/dev-DEZKrw8v.mjs +0 -18
- package/dist/init-BYX6pxjd.mjs +0 -114
- package/dist/secret-DLosn47q.mjs +0 -47
- package/dist/test-CYoqKJP0.mjs +0 -38
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as ok } from "./_output-BKdAJaM5.mjs";
|
|
3
|
+
import { r as log$1 } from "./_ui-r2t6_2eP.mjs";
|
|
4
|
+
import { n as resolveCwd, t as fileExists } from "./_utils-DZo3_J_v.mjs";
|
|
5
|
+
import { getMonorepoRoot, isDevMode } from "./_agent-CzbSa09n.mjs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { errorMessage } from "@alexkroman1/aai";
|
|
8
|
+
import * as p from "@clack/prompts";
|
|
9
|
+
import { colorize } from "consola/utils";
|
|
10
|
+
import fs from "node:fs/promises";
|
|
11
|
+
import { execFile } from "node:child_process";
|
|
12
|
+
import { promisify } from "node:util";
|
|
13
|
+
//#region init.ts
|
|
14
|
+
const execFileAsync = promisify(execFile);
|
|
15
|
+
const DEFAULT_PROJECT_NAME = "my-voice-agent";
|
|
16
|
+
/** Prompt for project name or return default when --yes is set. */
|
|
17
|
+
async function promptProjectName(yes) {
|
|
18
|
+
if (yes) return DEFAULT_PROJECT_NAME;
|
|
19
|
+
const result = await p.text({
|
|
20
|
+
message: "What is your project named?",
|
|
21
|
+
placeholder: DEFAULT_PROJECT_NAME,
|
|
22
|
+
defaultValue: DEFAULT_PROJECT_NAME
|
|
23
|
+
});
|
|
24
|
+
if (p.isCancel(result)) {
|
|
25
|
+
p.cancel("Setup cancelled");
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
return result || DEFAULT_PROJECT_NAME;
|
|
29
|
+
}
|
|
30
|
+
/** Enable corepack so pnpm is available (scaffold declares packageManager: pnpm). */
|
|
31
|
+
async function ensurePnpm() {
|
|
32
|
+
try {
|
|
33
|
+
await execFileAsync("corepack", ["enable"]);
|
|
34
|
+
} catch {}
|
|
35
|
+
}
|
|
36
|
+
/** Check if the project has any dependencies to install. */
|
|
37
|
+
async function hasDeps(cwd) {
|
|
38
|
+
if (await fileExists(path.join(cwd, "node_modules"))) return false;
|
|
39
|
+
let pkgJson;
|
|
40
|
+
try {
|
|
41
|
+
pkgJson = JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf-8"));
|
|
42
|
+
} catch {
|
|
43
|
+
pkgJson = {};
|
|
44
|
+
}
|
|
45
|
+
const deps = Object.keys(pkgJson.dependencies ?? {});
|
|
46
|
+
const devDeps = Object.keys(pkgJson.devDependencies ?? {});
|
|
47
|
+
return deps.length > 0 || devDeps.length > 0;
|
|
48
|
+
}
|
|
49
|
+
/** Run pnpm install and warn on failure. */
|
|
50
|
+
async function runPnpmInstall(cwd) {
|
|
51
|
+
await execFileAsync("pnpm", isDevMode() ? ["install"] : ["install", "--ignore-workspace"], { cwd });
|
|
52
|
+
}
|
|
53
|
+
/** Install deps with pnpm (scaffold declares packageManager: pnpm). */
|
|
54
|
+
async function installDeps(cwd, silent) {
|
|
55
|
+
if (!await hasDeps(cwd)) return;
|
|
56
|
+
await ensurePnpm();
|
|
57
|
+
if (silent) {
|
|
58
|
+
try {
|
|
59
|
+
await runPnpmInstall(cwd);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
log$1.warn(`pnpm install failed: ${errorMessage(err)}`);
|
|
62
|
+
log$1.warn("Run `corepack enable && pnpm install` manually in the project directory.");
|
|
63
|
+
}
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const s = p.spinner();
|
|
67
|
+
s.start("Installing dependencies with pnpm");
|
|
68
|
+
try {
|
|
69
|
+
await runPnpmInstall(cwd);
|
|
70
|
+
s.stop("Dependencies installed");
|
|
71
|
+
} catch (err) {
|
|
72
|
+
s.stop("Dependency install failed");
|
|
73
|
+
log$1.warn(`pnpm install failed: ${errorMessage(err)}`);
|
|
74
|
+
log$1.warn("Run `corepack enable && pnpm install` manually in the project directory.");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Resolve target directory relative to the user's current directory. */
|
|
78
|
+
function resolveTargetDir(dir) {
|
|
79
|
+
return path.resolve(resolveCwd(), dir);
|
|
80
|
+
}
|
|
81
|
+
/** Resolve the deploy server — in dev mode, default to localhost. */
|
|
82
|
+
function resolveDeployServer(explicit, monorepoRoot) {
|
|
83
|
+
return explicit ?? (monorepoRoot ? "http://localhost:8080" : void 0);
|
|
84
|
+
}
|
|
85
|
+
/** Run deploy after init and return deploy metadata if successful. */
|
|
86
|
+
async function tryDeploy(cwd, server, monorepoRoot) {
|
|
87
|
+
const resolvedServer = resolveDeployServer(server, monorepoRoot);
|
|
88
|
+
const { executeDeploy } = await import("./deploy-CmY2AtML.mjs");
|
|
89
|
+
const result = await executeDeploy({
|
|
90
|
+
cwd,
|
|
91
|
+
...resolvedServer ? { server: resolvedServer } : {}
|
|
92
|
+
});
|
|
93
|
+
return result.ok ? {
|
|
94
|
+
slug: result.data.slug,
|
|
95
|
+
url: result.data.url
|
|
96
|
+
} : null;
|
|
97
|
+
}
|
|
98
|
+
/** Scaffold the project, optionally showing a spinner. */
|
|
99
|
+
async function scaffoldProject(dir, cwd, template, silent) {
|
|
100
|
+
const { runInit } = await import("./_init-DhX1a2Zb.mjs");
|
|
101
|
+
if (silent) {
|
|
102
|
+
await runInit({
|
|
103
|
+
targetDir: cwd,
|
|
104
|
+
template
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const s = p.spinner();
|
|
109
|
+
s.start(`Creating ${dir}`);
|
|
110
|
+
await runInit({
|
|
111
|
+
targetDir: cwd,
|
|
112
|
+
template
|
|
113
|
+
});
|
|
114
|
+
s.stop("Project created");
|
|
115
|
+
}
|
|
116
|
+
/** Print post-init instructions. */
|
|
117
|
+
function printPostInitInfo(cwd, monorepoRoot) {
|
|
118
|
+
log$1.success(`Created ${cwd}`);
|
|
119
|
+
if (monorepoRoot) log$1.info("Dev mode: project linked to workspace packages");
|
|
120
|
+
log$1.info(`Next: cd ${cwd} && aai dev`);
|
|
121
|
+
}
|
|
122
|
+
async function executeInit(opts, extra) {
|
|
123
|
+
const suppressUi = extra?.quiet ?? extra?.silent;
|
|
124
|
+
if (!suppressUi) p.intro(colorize("cyanBright", "Create a new voice agent"));
|
|
125
|
+
const dir = opts.dir ?? await promptProjectName(opts.yes);
|
|
126
|
+
const monorepoRoot = getMonorepoRoot();
|
|
127
|
+
const cwd = resolveTargetDir(dir);
|
|
128
|
+
if (!opts.force && await fileExists(path.join(cwd, "agent.ts"))) throw new Error(`agent.ts already exists in this directory. Use ${colorize("cyanBright", "--force")} to overwrite.`);
|
|
129
|
+
const template = opts.template ?? "simple";
|
|
130
|
+
await scaffoldProject(dir, cwd, template, suppressUi);
|
|
131
|
+
await installDeps(cwd, suppressUi);
|
|
132
|
+
let deployed = false;
|
|
133
|
+
let slug;
|
|
134
|
+
let url;
|
|
135
|
+
if (!(opts.skipDeploy || extra?.quiet)) {
|
|
136
|
+
const deployInfo = await tryDeploy(cwd, opts.server, monorepoRoot);
|
|
137
|
+
if (deployInfo) {
|
|
138
|
+
deployed = true;
|
|
139
|
+
slug = deployInfo.slug;
|
|
140
|
+
url = deployInfo.url;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (!suppressUi) printPostInitInfo(cwd, monorepoRoot);
|
|
144
|
+
const data = {
|
|
145
|
+
dir: cwd,
|
|
146
|
+
template,
|
|
147
|
+
deployed
|
|
148
|
+
};
|
|
149
|
+
if (slug) data.slug = slug;
|
|
150
|
+
if (url) data.url = url;
|
|
151
|
+
return ok(data);
|
|
152
|
+
}
|
|
153
|
+
//#endregion
|
|
154
|
+
export { executeInit };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __exportAll = (all, no_symbols) => {
|
|
5
|
+
let target = {};
|
|
6
|
+
for (var name in all) __defProp(target, name, {
|
|
7
|
+
get: all[name],
|
|
8
|
+
enumerable: true
|
|
9
|
+
});
|
|
10
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
11
|
+
return target;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { __exportAll as t };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as ok, r as fail } from "./_output-BKdAJaM5.mjs";
|
|
3
|
+
import { r as log$1 } from "./_ui-r2t6_2eP.mjs";
|
|
4
|
+
import { getServerInfo } from "./_agent-CzbSa09n.mjs";
|
|
5
|
+
import { t as apiRequestOrThrow } from "./_api-client-CFfjWfNa.mjs";
|
|
6
|
+
import * as p from "@clack/prompts";
|
|
7
|
+
//#region secret.ts
|
|
8
|
+
async function secretRequest(cwd, pathSuffix, init, server) {
|
|
9
|
+
const { serverUrl, slug, apiKey } = await getServerInfo(cwd, server);
|
|
10
|
+
return {
|
|
11
|
+
resp: await apiRequestOrThrow(`${serverUrl}/${slug}/secret${pathSuffix}`, {
|
|
12
|
+
...init,
|
|
13
|
+
apiKey,
|
|
14
|
+
action: "secret"
|
|
15
|
+
}),
|
|
16
|
+
slug
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** Read secret value from stdin (for non-TTY / piped input). */
|
|
20
|
+
async function readStdin() {
|
|
21
|
+
const chunks = [];
|
|
22
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
23
|
+
return Buffer.concat(chunks).toString("utf-8").trim();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Execute secret put. If `value` is provided, use it directly (non-TTY path).
|
|
27
|
+
* If not provided, prompt interactively (TTY path).
|
|
28
|
+
*/
|
|
29
|
+
async function executeSecretPut(cwd, name, value, server) {
|
|
30
|
+
let secretValue = value;
|
|
31
|
+
if (!secretValue) {
|
|
32
|
+
const result = await p.password({ message: `Enter value for ${name}` });
|
|
33
|
+
if (p.isCancel(result)) process.exit(0);
|
|
34
|
+
if (!result) return fail("no_input", "No value provided", "Pipe secret value to stdin");
|
|
35
|
+
secretValue = result;
|
|
36
|
+
}
|
|
37
|
+
const { slug } = await secretRequest(cwd, "", {
|
|
38
|
+
method: "PUT",
|
|
39
|
+
body: JSON.stringify({ [name]: secretValue })
|
|
40
|
+
}, server);
|
|
41
|
+
log$1.success(`Set ${name} for ${slug}`);
|
|
42
|
+
return ok({ name });
|
|
43
|
+
}
|
|
44
|
+
async function executeSecretDelete(cwd, name, server) {
|
|
45
|
+
const { slug } = await secretRequest(cwd, `/${name}`, { method: "DELETE" }, server);
|
|
46
|
+
log$1.success(`Deleted ${name} from ${slug}`);
|
|
47
|
+
return ok({ name });
|
|
48
|
+
}
|
|
49
|
+
async function executeSecretList(cwd, server) {
|
|
50
|
+
const { resp } = await secretRequest(cwd, "", void 0, server);
|
|
51
|
+
const { vars } = await resp.json();
|
|
52
|
+
if (vars.length === 0) log$1.info("No secrets set. Use `aai secret put <name>` to add one.");
|
|
53
|
+
else {
|
|
54
|
+
log$1.message(`${vars.length} secret${vars.length === 1 ? "" : "s"}:`);
|
|
55
|
+
for (const v of vars) log$1.message(` ${v}`);
|
|
56
|
+
}
|
|
57
|
+
return ok({ secrets: vars });
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
export { executeSecretDelete, executeSecretList, executeSecretPut, readStdin };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as ok, r as fail } from "./_output-BKdAJaM5.mjs";
|
|
3
|
+
import { r as log } from "./_ui-r2t6_2eP.mjs";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { execFileSync } from "node:child_process";
|
|
7
|
+
//#region test.ts
|
|
8
|
+
/**
|
|
9
|
+
* `aai test` — run agent tests via vitest.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Run vitest in the given project directory.
|
|
13
|
+
*
|
|
14
|
+
* Returns `true` if tests passed, `false` if no test files exist.
|
|
15
|
+
* Throws on test failure.
|
|
16
|
+
*/
|
|
17
|
+
function runVitest(cwd) {
|
|
18
|
+
let testFile = null;
|
|
19
|
+
if (existsSync(path.join(cwd, "agent.test.ts"))) testFile = "agent.test.ts";
|
|
20
|
+
else if (existsSync(path.join(cwd, "agent.test.js"))) testFile = "agent.test.js";
|
|
21
|
+
if (!testFile) return false;
|
|
22
|
+
execFileSync("npx", [
|
|
23
|
+
"vitest",
|
|
24
|
+
"run",
|
|
25
|
+
"--root",
|
|
26
|
+
".",
|
|
27
|
+
testFile
|
|
28
|
+
], {
|
|
29
|
+
cwd,
|
|
30
|
+
stdio: "inherit",
|
|
31
|
+
env: {
|
|
32
|
+
...process.env,
|
|
33
|
+
NODE_OPTIONS: "--experimental-strip-types"
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
/** Execute agent tests and return structured result. */
|
|
39
|
+
async function executeTest(cwd) {
|
|
40
|
+
log.step("Running agent tests");
|
|
41
|
+
try {
|
|
42
|
+
if (!runVitest(cwd)) {
|
|
43
|
+
log.info("No test file found. Create agent.test.ts to add tests.");
|
|
44
|
+
return ok({
|
|
45
|
+
passed: true,
|
|
46
|
+
skipped: true
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
log.success("Tests passed");
|
|
50
|
+
return ok({ passed: true });
|
|
51
|
+
} catch {
|
|
52
|
+
return fail("test_failed", "Tests failed");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { executeTest, runVitest };
|
package/package.json
CHANGED
|
@@ -1,30 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexkroman1/aai-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aai": "dist/cli.mjs"
|
|
7
7
|
},
|
|
8
|
+
"exports": {
|
|
9
|
+
"./types": {
|
|
10
|
+
"@dev/source": "./types.ts",
|
|
11
|
+
"import": "./dist/types.mjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
8
14
|
"files": [
|
|
9
15
|
"dist"
|
|
10
16
|
],
|
|
11
17
|
"dependencies": {
|
|
12
|
-
"@clack/prompts": "^1.
|
|
13
|
-
"citty": "^0.2.
|
|
18
|
+
"@clack/prompts": "^1.2.0",
|
|
19
|
+
"citty": "^0.2.2",
|
|
14
20
|
"consola": "^3.4.2",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
21
|
+
"dotenv": "^17.4.1",
|
|
22
|
+
"giget": "^3.2.0",
|
|
23
|
+
"p-debounce": "^5.1.0",
|
|
17
24
|
"vite": "^8.0.3",
|
|
18
25
|
"zod": "^4.3.6",
|
|
19
|
-
"@alexkroman1/aai": "0.
|
|
26
|
+
"@alexkroman1/aai": "1.0.2"
|
|
20
27
|
},
|
|
21
28
|
"devDependencies": {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
29
|
+
"get-port": "^7.2.0",
|
|
30
|
+
"playwright": "^1.59.1",
|
|
31
|
+
"tree-kill": "^1.2.2",
|
|
32
|
+
"tsdown": "^0.21.7",
|
|
33
|
+
"verdaccio": "^6.4.0",
|
|
34
|
+
"vitest": "^4.1.3"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"vitest": "^4.1.3"
|
|
38
|
+
},
|
|
39
|
+
"peerDependenciesMeta": {
|
|
40
|
+
"vitest": {
|
|
41
|
+
"optional": true
|
|
42
|
+
}
|
|
25
43
|
},
|
|
26
44
|
"engines": {
|
|
27
|
-
"node": ">=
|
|
45
|
+
"node": ">=24"
|
|
28
46
|
},
|
|
29
47
|
"repository": {
|
|
30
48
|
"type": "git",
|
|
@@ -32,10 +50,12 @@
|
|
|
32
50
|
"directory": "packages/aai-cli"
|
|
33
51
|
},
|
|
34
52
|
"scripts": {
|
|
53
|
+
"test": "vitest run",
|
|
54
|
+
"test:coverage": "vitest run --coverage",
|
|
35
55
|
"build": "tsdown",
|
|
36
56
|
"typecheck": "tsc --noEmit",
|
|
37
57
|
"lint": "biome check .",
|
|
38
|
-
"test:e2e": "
|
|
58
|
+
"test:e2e": "VITEST_PROFILE=e2e VITEST_INCLUDE=e2e.test.ts vitest run -c ../../vitest.slow.config.ts",
|
|
39
59
|
"check:e2e": "pnpm run test:e2e"
|
|
40
60
|
}
|
|
41
61
|
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import fs from "node:fs/promises";
|
|
4
|
-
import { errorMessage } from "@alexkroman1/aai/utils";
|
|
5
|
-
import { build } from "vite";
|
|
6
|
-
//#region _bundler.ts
|
|
7
|
-
var BundleError = class extends Error {
|
|
8
|
-
constructor(message, options) {
|
|
9
|
-
super(message, options);
|
|
10
|
-
this.name = "BundleError";
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
const TEXT_EXTENSIONS = new Set([
|
|
14
|
-
".html",
|
|
15
|
-
".htm",
|
|
16
|
-
".css",
|
|
17
|
-
".js",
|
|
18
|
-
".mjs",
|
|
19
|
-
".cjs",
|
|
20
|
-
".ts",
|
|
21
|
-
".mts",
|
|
22
|
-
".json",
|
|
23
|
-
".map",
|
|
24
|
-
".svg",
|
|
25
|
-
".xml",
|
|
26
|
-
".txt",
|
|
27
|
-
".md"
|
|
28
|
-
]);
|
|
29
|
-
async function readDirFiles(dir) {
|
|
30
|
-
let entries;
|
|
31
|
-
try {
|
|
32
|
-
entries = await fs.readdir(dir, {
|
|
33
|
-
recursive: true,
|
|
34
|
-
withFileTypes: true
|
|
35
|
-
});
|
|
36
|
-
} catch (err) {
|
|
37
|
-
if (err instanceof Error && "code" in err && err.code === "ENOENT") return {};
|
|
38
|
-
throw err;
|
|
39
|
-
}
|
|
40
|
-
const files = {};
|
|
41
|
-
await Promise.all(entries.filter((e) => e.isFile()).map(async (e) => {
|
|
42
|
-
const full = path.join(e.parentPath, e.name);
|
|
43
|
-
const ext = path.extname(e.name).toLowerCase();
|
|
44
|
-
const rel = path.relative(dir, full);
|
|
45
|
-
if (TEXT_EXTENSIONS.has(ext)) files[rel] = await fs.readFile(full, "utf-8");
|
|
46
|
-
else files[rel] = `base64:${(await fs.readFile(full)).toString("base64")}`;
|
|
47
|
-
}));
|
|
48
|
-
return files;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Bundle an agent project using Vite.
|
|
52
|
-
*
|
|
53
|
-
* - Worker: `vite build --ssr agent.ts` (uses project's vite.config.ts)
|
|
54
|
-
* - Client: `vite build` (uses project's vite.config.ts)
|
|
55
|
-
*/
|
|
56
|
-
async function bundleAgent(agent, opts) {
|
|
57
|
-
const aaiDir = path.join(agent.dir, ".aai");
|
|
58
|
-
const buildDir = path.join(aaiDir, "build");
|
|
59
|
-
const clientDir = path.join(aaiDir, "client");
|
|
60
|
-
try {
|
|
61
|
-
await build({
|
|
62
|
-
root: agent.dir,
|
|
63
|
-
logLevel: "warn",
|
|
64
|
-
build: {
|
|
65
|
-
ssr: path.join(agent.dir, "agent.ts"),
|
|
66
|
-
outDir: buildDir,
|
|
67
|
-
emptyOutDir: true,
|
|
68
|
-
rollupOptions: {
|
|
69
|
-
external: ["zod"],
|
|
70
|
-
output: {
|
|
71
|
-
entryFileNames: "worker.js",
|
|
72
|
-
paths: { zod: "/app/_zod.mjs" }
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
ssr: { external: ["zod"] }
|
|
77
|
-
});
|
|
78
|
-
} catch (err) {
|
|
79
|
-
throw new BundleError(errorMessage(err), { cause: err });
|
|
80
|
-
}
|
|
81
|
-
if (!(opts?.skipClient ?? !agent.clientEntry)) try {
|
|
82
|
-
await build({
|
|
83
|
-
root: agent.dir,
|
|
84
|
-
base: "./",
|
|
85
|
-
logLevel: "warn",
|
|
86
|
-
build: {
|
|
87
|
-
outDir: clientDir,
|
|
88
|
-
emptyOutDir: true
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
} catch (err) {
|
|
92
|
-
throw new BundleError(errorMessage(err), { cause: err });
|
|
93
|
-
}
|
|
94
|
-
const worker = await fs.readFile(path.join(buildDir, "worker.js"), "utf-8");
|
|
95
|
-
const clientFiles = await readDirFiles(clientDir);
|
|
96
|
-
return {
|
|
97
|
-
slug: agent.slug,
|
|
98
|
-
worker,
|
|
99
|
-
clientFiles,
|
|
100
|
-
clientDir,
|
|
101
|
-
workerBytes: Buffer.byteLength(worker)
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
async function buildAgentBundle(cwd) {
|
|
105
|
-
const { loadAgent } = await import("./_discover-a8yIuqEp.mjs").then((n) => n.t);
|
|
106
|
-
const { log } = await import("./_ui-DWGXImbO.mjs");
|
|
107
|
-
const agent = await loadAgent(cwd);
|
|
108
|
-
if (!agent) throw new Error("No agent found — run `aai init` first");
|
|
109
|
-
log.step(`Bundling ${agent.slug}`);
|
|
110
|
-
let bundle;
|
|
111
|
-
try {
|
|
112
|
-
bundle = await bundleAgent(agent);
|
|
113
|
-
} catch (err) {
|
|
114
|
-
if (err instanceof BundleError) throw new Error(`Build failed: ${err.message}`, { cause: err });
|
|
115
|
-
throw err;
|
|
116
|
-
}
|
|
117
|
-
return bundle;
|
|
118
|
-
}
|
|
119
|
-
async function runBuildCommand(cwd) {
|
|
120
|
-
const { log } = await import("./_ui-DWGXImbO.mjs");
|
|
121
|
-
await buildAgentBundle(cwd);
|
|
122
|
-
log.success("Build complete");
|
|
123
|
-
}
|
|
124
|
-
//#endregion
|
|
125
|
-
export { buildAgentBundle, runBuildCommand };
|