@alexkroman1/aai-cli 1.9.2 → 1.10.0

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.
@@ -1,11 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { i as ok } from "./_output-fy2bXRNb.mjs";
3
- import { a as unwrapCancel, n as log } from "./_ui-YqQ6Fi8K.mjs";
4
- import { a as readJson, n as errorMessage, o as resolveCwd, r as fileExists } from "./_utils-BeU10C7O.mjs";
5
- import { i as isDevMode, n as getMonorepoRoot } from "./_agent-cHGzbDVG.mjs";
2
+ import { a as unwrapCancel, n as log, u as ok } from "./_ui-CKEIHAtB.mjs";
3
+ import { i as fileExists, o as readJson, r as errorMessage, s as resolveCwd } from "./_utils-ECl2je7-.mjs";
4
+ import { r as isDevMode, t as getMonorepoRoot } from "./_agent-Ba5Ykp05.mjs";
6
5
  import path from "node:path";
7
6
  import * as p from "@clack/prompts";
8
- import { colorize } from "consola/utils";
7
+ import pc from "picocolors";
9
8
  import { execa } from "execa";
10
9
  //#region init.ts
11
10
  const DEFAULT_PROJECT_NAME = "my-voice-agent";
@@ -75,19 +74,25 @@ function resolveTargetDir(dir) {
75
74
  }
76
75
  /** Run deploy after init and return deploy metadata if successful. */
77
76
  async function tryDeploy(cwd, server) {
78
- const { executeDeploy } = await import("./deploy-DOy6wOCd.mjs");
79
- const result = await executeDeploy({
80
- cwd,
81
- ...server ? { server } : {}
82
- });
83
- return result.ok ? {
84
- slug: result.data.slug,
85
- url: result.data.url
86
- } : null;
77
+ const { executeDeploy } = await import("./deploy-Ds1spTPC.mjs");
78
+ try {
79
+ const result = await executeDeploy({
80
+ cwd,
81
+ ...server ? { server } : {}
82
+ });
83
+ return result.ok ? {
84
+ slug: result.data.slug,
85
+ url: result.data.url
86
+ } : null;
87
+ } catch (err) {
88
+ log.warn(`Deploy failed: ${errorMessage(err)}`);
89
+ log.warn("Your project was still created — run `aai deploy` in it to retry.");
90
+ return null;
91
+ }
87
92
  }
88
93
  /** Scaffold the project, optionally showing a spinner. */
89
94
  async function scaffoldProject(dir, cwd, template, silent) {
90
- const { runInit } = await import("./_init-y7K-dzni.mjs");
95
+ const { runInit } = await import("./_init-BznoJC91.mjs");
91
96
  if (silent) {
92
97
  await runInit({
93
98
  targetDir: cwd,
@@ -111,11 +116,11 @@ function printPostInitInfo(cwd, monorepoRoot) {
111
116
  }
112
117
  async function executeInit(opts, extra) {
113
118
  const suppressUi = extra?.silent;
114
- if (!suppressUi) p.intro(colorize("cyanBright", "Create a new voice agent"));
119
+ if (!suppressUi) p.intro(pc.cyanBright("Create a new voice agent"));
115
120
  const dir = opts.dir ?? await promptProjectName(opts.yes);
116
121
  const monorepoRoot = getMonorepoRoot();
117
122
  const cwd = resolveTargetDir(dir);
118
- 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.`);
123
+ if (!opts.force && await fileExists(path.join(cwd, "agent.ts"))) throw new Error(`agent.ts already exists in this directory. Use ${pc.cyanBright("--force")} to overwrite.`);
119
124
  const template = opts.template ?? "simple";
120
125
  await scaffoldProject(dir, cwd, template, suppressUi);
121
126
  const installed = await installDeps(cwd, suppressUi);
@@ -1,8 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { i as ok, n as fail } from "./_output-fy2bXRNb.mjs";
3
- import { n as log } from "./_ui-YqQ6Fi8K.mjs";
4
- import { r as getServerInfo } from "./_agent-cHGzbDVG.mjs";
5
- import { t as apiRequest } from "./_api-client-yJD7xGfd.mjs";
2
+ import { a as unwrapCancel, n as log, s as fail, u as ok } from "./_ui-CKEIHAtB.mjs";
3
+ import { n as getServerInfo } from "./_agent-Ba5Ykp05.mjs";
4
+ import { t as apiRequest } from "./_api-client-a6cPMebU.mjs";
6
5
  import * as p from "@clack/prompts";
7
6
  import { text } from "node:stream/consumers";
8
7
  //#region secret.ts
@@ -28,8 +27,7 @@ async function readStdin() {
28
27
  async function executeSecretPut(cwd, name, value, server) {
29
28
  let secretValue = value;
30
29
  if (!secretValue) {
31
- const result = await p.password({ message: `Enter value for ${name}` });
32
- if (p.isCancel(result)) process.exit(0);
30
+ const result = unwrapCancel(await p.password({ message: `Enter value for ${name}` }));
33
31
  if (!result) return fail("no_input", "No value provided", "Pipe secret value to stdin");
34
32
  secretValue = result;
35
33
  }
@@ -41,7 +39,7 @@ async function executeSecretPut(cwd, name, value, server) {
41
39
  return ok({ name });
42
40
  }
43
41
  async function executeSecretDelete(cwd, name, server) {
44
- const { slug } = await secretRequest(cwd, `/${name}`, { method: "DELETE" }, server);
42
+ const { slug } = await secretRequest(cwd, `/${encodeURIComponent(name)}`, { method: "DELETE" }, server);
45
43
  log.success(`Deleted ${name} from ${slug}`);
46
44
  return ok({ name });
47
45
  }
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { i as ok, n as fail } from "./_output-fy2bXRNb.mjs";
3
- import { n as log } from "./_ui-YqQ6Fi8K.mjs";
2
+ import { n as log, s as fail, u as ok } from "./_ui-CKEIHAtB.mjs";
3
+ import { r as errorMessage, t as errorCode } from "./_utils-ECl2je7-.mjs";
4
4
  import { createRequire } from "node:module";
5
5
  import { existsSync, readFileSync } from "node:fs";
6
6
  import path from "node:path";
7
- import { execFileSync } from "node:child_process";
7
+ import { execaSync } from "execa";
8
8
  //#region test.ts
9
9
  /**
10
10
  * `aai test` — run agent tests via vitest.
@@ -44,7 +44,7 @@ function runVitest(cwd) {
44
44
  else if (existsSync(path.join(cwd, "agent.test.js"))) testFile = "agent.test.js";
45
45
  if (!testFile) return false;
46
46
  const { cmd, args } = resolveVitestCommand(cwd);
47
- execFileSync(cmd, [
47
+ execaSync(cmd, [
48
48
  ...args,
49
49
  "run",
50
50
  "--root",
@@ -53,13 +53,25 @@ function runVitest(cwd) {
53
53
  ], {
54
54
  cwd,
55
55
  stdio: "inherit",
56
- env: {
57
- ...process.env,
58
- NODE_OPTIONS: "--experimental-strip-types"
59
- }
56
+ env: { NODE_OPTIONS: "--experimental-strip-types" }
60
57
  });
61
58
  return true;
62
59
  }
60
+ /**
61
+ * Classify a {@link runVitest} failure. execaSync throws an ENOENT-coded
62
+ * error when the binary itself couldn't be spawned (infrastructure problem)
63
+ * and an exit-code error when vitest ran and the tests failed.
64
+ */
65
+ function classifyVitestError(err) {
66
+ if (errorCode(err) === "ENOENT") return {
67
+ code: "spawn_failed",
68
+ message: `Could not launch the test runner: ${errorMessage(err)} — is the binary on your PATH?`
69
+ };
70
+ return {
71
+ code: "test_failed",
72
+ message: `Tests failed: ${errorMessage(err)}`
73
+ };
74
+ }
63
75
  /** Execute agent tests and return structured result. */
64
76
  async function executeTest(cwd) {
65
77
  log.step("Running agent tests");
@@ -73,9 +85,10 @@ async function executeTest(cwd) {
73
85
  }
74
86
  log.success("Tests passed");
75
87
  return ok({ passed: true });
76
- } catch {
77
- return fail("test_failed", "Tests failed");
88
+ } catch (err) {
89
+ const { code, message } = classifyVitestError(err);
90
+ return fail(code, message);
78
91
  }
79
92
  }
80
93
  //#endregion
81
- export { executeTest, runVitest };
94
+ export { classifyVitestError, executeTest, runVitest };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as withPreservedNodeEnv } from "./_vite-env-CmXG4ZAu.mjs";
2
+ import { t as withPreservedNodeEnv } from "./_vite-env-DNb9R8xq.mjs";
3
3
  import path from "node:path";
4
4
  import { build } from "vite";
5
5
  //#region worker-bundler.ts
package/package.json CHANGED
@@ -1,15 +1,11 @@
1
1
  {
2
2
  "name": "@alexkroman1/aai-cli",
3
- "version": "1.9.2",
3
+ "version": "1.10.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "aai": "dist/cli.mjs"
7
7
  },
8
8
  "exports": {
9
- "./types": {
10
- "@dev/source": "./types.ts",
11
- "import": "./dist/types.mjs"
12
- },
13
9
  "./client-bundler": {
14
10
  "@dev/source": "./client-bundler.ts",
15
11
  "import": "./dist/client-bundler.mjs"
@@ -26,21 +22,21 @@
26
22
  "@clack/prompts": "^1.7.0",
27
23
  "chokidar": "^5.0.0",
28
24
  "citty": "^0.2.2",
29
- "consola": "^3.4.2",
30
- "dotenv": "^17.4.2",
31
- "execa": "^9.6.1",
25
+ "env-paths": "^4.0.0",
26
+ "esbuild": "^0.28.1",
27
+ "execa": "^10.0.0",
32
28
  "get-port": "^7.2.0",
33
29
  "giget": "^3.3.0",
34
30
  "ofetch": "^1.5.1",
35
31
  "p-debounce": "^5.1.0",
32
+ "picocolors": "^1.1.1",
36
33
  "vite": "^8.1.5",
37
34
  "zod": "^4.4.3",
38
- "@alexkroman1/aai": "1.9.2",
39
- "@alexkroman1/aai-ui": "1.9.2"
35
+ "@alexkroman1/aai": "1.10.0",
36
+ "@alexkroman1/aai-ui": "1.10.0"
40
37
  },
41
38
  "devDependencies": {
42
39
  "playwright": "^1.61.1",
43
- "tree-kill": "^1.2.2",
44
40
  "tsdown": "^0.22.13",
45
41
  "verdaccio": "^6.8.0",
46
42
  "vitest": "^4.1.10"
@@ -1,62 +0,0 @@
1
- #!/usr/bin/env node
2
- import { i as ok } from "./_output-fy2bXRNb.mjs";
3
- import { n as log } from "./_ui-YqQ6Fi8K.mjs";
4
- import { s as validateAgentExport } from "./_utils-BeU10C7O.mjs";
5
- import { t as buildClient } from "./client-bundler-Bki_Rned.mjs";
6
- import { buildWorker } from "./worker-bundler.mjs";
7
- import path from "node:path";
8
- import { pathToFileURL } from "node:url";
9
- import fs from "node:fs/promises";
10
- import { agentToolsToSchemas, toAgentConfig } from "@alexkroman1/aai/manifest";
11
- //#region _bundler.ts
12
- /**
13
- * Bundle an agent directory: build agent.ts into worker ESM + extract config.
14
- *
15
- * - agent.ts is the single entry point: `export default agent({...})`
16
- * - A single Vite build produces the worker ESM (all deps bundled in).
17
- * The AgentDef is extracted from that bundle via dynamic import, avoiding a
18
- * second build pass.
19
- */
20
- async function buildAgentBundle(cwd, opts = {}) {
21
- const [[worker, agentDef], clientFiles] = await Promise.all([buildWorker(cwd, opts).then(async (code) => [code, await evalWorkerBundle(code, cwd)]), buildClient(cwd)]);
22
- log.step(`Bundling ${agentDef.name}`);
23
- const config = toAgentConfig(agentDef);
24
- const toolSchemas = agentToolsToSchemas(agentDef.tools ?? {});
25
- return {
26
- worker,
27
- clientFiles,
28
- agentConfig: {
29
- ...config,
30
- toolSchemas
31
- }
32
- };
33
- }
34
- /**
35
- * Write the worker ESM to a temp file and dynamic-import it, returning
36
- * the AgentDef default export. All dependencies are bundled in, so the
37
- * file can be evaluated from any directory.
38
- */
39
- async function evalWorkerBundle(code, cwd) {
40
- const evalDir = path.join(cwd, ".aai", "eval");
41
- await fs.mkdir(evalDir, { recursive: true });
42
- const tmpPath = path.join(evalDir, `agent-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`);
43
- try {
44
- await fs.writeFile(tmpPath, code);
45
- const mod = await import(pathToFileURL(tmpPath).href);
46
- const agentDef = mod.default ?? mod;
47
- validateAgentExport(agentDef);
48
- return agentDef;
49
- } finally {
50
- await fs.rm(tmpPath).catch(() => {});
51
- }
52
- }
53
- async function executeBuild(cwd) {
54
- const bundle = await buildAgentBundle(cwd, { minify: true });
55
- log.success("Build complete");
56
- return ok({
57
- name: bundle.agentConfig.name,
58
- workerBytes: bundle.worker.length
59
- });
60
- }
61
- //#endregion
62
- export { buildAgentBundle, evalWorkerBundle, executeBuild };
@@ -1,214 +0,0 @@
1
- #!/usr/bin/env node
2
- import { r as ensureApiKey } from "./_config-zV70t71V.mjs";
3
- import { n as log } from "./_ui-YqQ6Fi8K.mjs";
4
- import { n as errorMessage } from "./_utils-BeU10C7O.mjs";
5
- import { n as fallbackHtmlPlugin } from "./client-bundler-Bki_Rned.mjs";
6
- import { buildWorker } from "./worker-bundler.mjs";
7
- import { evalWorkerBundle } from "./_bundler-CpLVjRzc.mjs";
8
- import { t as resolveServerEnv } from "./_server-common-QpOTRZgi.mjs";
9
- import { createRequire } from "node:module";
10
- import { existsSync } from "node:fs";
11
- import path from "node:path";
12
- import { requiredProviderEnvVars, withHostCredentialFallback } from "@alexkroman1/aai/runtime";
13
- import { watch } from "chokidar";
14
- import getPort, { portNumbers } from "get-port";
15
- import pDebounce from "p-debounce";
16
- //#region _dev-server.ts
17
- /**
18
- * Dev server for directory-based agents.
19
- *
20
- * Imports agent.ts directly for the full agent definition,
21
- * builds a runtime, and starts an HTTP+WebSocket server. Watches for
22
- * file changes and restarts automatically. Optionally runs Vite for
23
- * client SPA HMR.
24
- */
25
- async function resolveAgentEnv(root, agentDef) {
26
- const env = await resolveServerEnv(root);
27
- const required = requiredProviderEnvVars(agentDef);
28
- if (required.includes("ASSEMBLYAI_API_KEY") && !env.ASSEMBLYAI_API_KEY) env.ASSEMBLYAI_API_KEY = await ensureApiKey();
29
- const missing = required.filter((name) => !(env[name] || process.env[name]));
30
- if (missing.length > 0) log.warn(`Missing provider credential${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}. Set ${missing.length > 1 ? "them" : "it"} in .env or the environment.`);
31
- return env;
32
- }
33
- /**
34
- * The env handed to `createServer` for host-mode connections: provider
35
- * credentials plus the `AAI_ALLOW_HOST` gate read straight from the shell
36
- * (it is a control variable, not something an agent declares in `.env`).
37
- */
38
- function hostModeEnv(providerEnv) {
39
- const gate = process.env.AAI_ALLOW_HOST;
40
- return gate === void 0 ? providerEnv : {
41
- ...providerEnv,
42
- AAI_ALLOW_HOST: gate
43
- };
44
- }
45
- /**
46
- * Explicit bind host for the dev server, or `undefined` to take the
47
- * loopback default. An empty `AAI_DEV_HOST` means "unset", not "every
48
- * interface" — Node treats `listen(port, "")` as 0.0.0.0, which would quietly
49
- * undo the loopback default this exists to guard.
50
- */
51
- function devBindHost() {
52
- const host = process.env.AAI_DEV_HOST?.trim();
53
- return host ? host : void 0;
54
- }
55
- /**
56
- * Load the agent definition by bundling agent.ts (and all its local imports)
57
- * into a single ESM file, then importing that. A raw `import(agent.ts?t=...)`
58
- * only cache-busts agent.ts itself — transitive imports (./tools.ts, etc.)
59
- * stay in Node's ESM registry, so edits to them are ignored on reload.
60
- * Bundling picks them up and matches the deploy path exactly.
61
- */
62
- async function loadAgentDef(cwd) {
63
- return evalWorkerBundle(await buildWorker(cwd), cwd);
64
- }
65
- /**
66
- * True for paths that should never trigger a restart: anything inside
67
- * `node_modules/` and any dot-entry (`.git/`, `.aai/`, `.DS_Store`, …).
68
- * `.git/` especially matters — commits and status checks churn the index
69
- * and would otherwise cause spurious full backend restarts.
70
- *
71
- * Exception: `.env` / `.env.*` files stay watched — env edits should
72
- * restart the server with the new values.
73
- */
74
- function isIgnoredPath(dir, filePath) {
75
- const rel = path.relative(dir, filePath);
76
- if (!rel || rel.startsWith("..")) return false;
77
- return rel.split(path.sep).some((segment) => {
78
- if (segment === "node_modules") return true;
79
- if (segment === ".env" || segment.startsWith(".env.")) return false;
80
- return segment.startsWith(".");
81
- });
82
- }
83
- /**
84
- * Watch the agent directory for changes and call `onChange` when detected.
85
- * Debounces to avoid rapid restarts. Uses chokidar for reliable recursive
86
- * watching across platforms (raw `fs.watch` misses events on Linux).
87
- */
88
- function watchDirectory(dir, onChange) {
89
- const debouncedChange = pDebounce(() => {
90
- log.info("File change detected, restarting...");
91
- onChange();
92
- }, 300);
93
- const watcher = watch(dir, {
94
- ignored: (filePath) => isIgnoredPath(dir, filePath),
95
- ignoreInitial: true,
96
- persistent: false
97
- });
98
- watcher.on("all", () => void debouncedChange());
99
- return watcher;
100
- }
101
- /** Locate the pre-built default aai-ui client (served when no custom client.tsx). */
102
- function resolveDefaultClientDir() {
103
- const pkgPath = createRequire(import.meta.url).resolve("@alexkroman1/aai-ui/package.json");
104
- return path.join(path.dirname(pkgPath), "dist", "default-client");
105
- }
106
- /**
107
- * Start the dev server for a directory-based agent.
108
- *
109
- * Returns a cleanup function to shut down the server and watchers.
110
- */
111
- async function startDevServer(opts) {
112
- const { cwd, port } = opts;
113
- const { createRuntime, createServer } = await import("@alexkroman1/aai/runtime");
114
- const hasClient = existsSync(path.join(cwd, "client.tsx"));
115
- const backendPort = hasClient ? await getPort({ port: portNumbers(port + 1, port + 100) }) : port;
116
- const vitePort = port;
117
- const clientDirOpt = hasClient ? {} : { clientDir: resolveDefaultClientDir() };
118
- /** Full build sequence, shared by initial startup and every restart. */
119
- async function buildServer() {
120
- const agentDef = await loadAgentDef(cwd);
121
- const env = await resolveAgentEnv(cwd, agentDef);
122
- const providerEnv = withHostCredentialFallback(env);
123
- const runtime = createRuntime({
124
- agent: agentDef,
125
- env,
126
- providerEnv
127
- });
128
- return createServer({
129
- runtime,
130
- name: agentDef.name,
131
- env: hostModeEnv(providerEnv),
132
- hostBaseAgent: agentDef,
133
- ...clientDirOpt
134
- });
135
- }
136
- const agentServer = await buildServer();
137
- await agentServer.listen(backendPort, devBindHost());
138
- let viteServer;
139
- if (hasClient) {
140
- const { createServer: createViteServer } = await import("vite");
141
- const target = `http://localhost:${backendPort}`;
142
- viteServer = await createViteServer({
143
- root: cwd,
144
- plugins: [fallbackHtmlPlugin(cwd)],
145
- server: {
146
- port: vitePort,
147
- proxy: {
148
- "/health": target,
149
- "/websocket": {
150
- target,
151
- ws: true
152
- }
153
- }
154
- }
155
- });
156
- await viteServer.listen();
157
- }
158
- let restarting = false;
159
- let pendingRestart = false;
160
- let closed = false;
161
- let currentServer = agentServer;
162
- const watcher = watchDirectory(cwd, () => {
163
- if (restarting) {
164
- pendingRestart = true;
165
- return;
166
- }
167
- restarting = true;
168
- restart().finally(() => {
169
- restarting = false;
170
- });
171
- });
172
- async function restart() {
173
- do {
174
- pendingRestart = false;
175
- await restartOnce();
176
- } while (pendingRestart && !closed);
177
- }
178
- async function restartOnce() {
179
- let newServer;
180
- try {
181
- newServer = await buildServer();
182
- } catch (err) {
183
- log.error(`Restart failed: ${errorMessage(err)} (previous server still running)`);
184
- return;
185
- }
186
- if (closed) {
187
- await newServer.close().catch(() => void 0);
188
- return;
189
- }
190
- try {
191
- await currentServer.close();
192
- } catch {}
193
- try {
194
- await newServer.listen(backendPort, devBindHost());
195
- currentServer = newServer;
196
- if (closed) {
197
- await newServer.close().catch(() => void 0);
198
- return;
199
- }
200
- log.success("Restarted");
201
- } catch (err) {
202
- log.error(`Restart failed: ${errorMessage(err)}`);
203
- await newServer.close().catch(() => void 0);
204
- }
205
- }
206
- return async () => {
207
- closed = true;
208
- await watcher.close();
209
- await viteServer?.close();
210
- await currentServer.close();
211
- };
212
- }
213
- //#endregion
214
- export { startDevServer };
@@ -1,63 +0,0 @@
1
- #!/usr/bin/env node
2
- //#region _output.ts
3
- /**
4
- * Determine output mode from CLI flags and TTY state.
5
- *
6
- * Priority: --json flag > --no-json flag > TTY auto-detection.
7
- */
8
- function getOutputMode(args, isTTY = Boolean(process.stdout.isTTY)) {
9
- if (args.json === true) return "json";
10
- if (args.json === false) return "human";
11
- return isTTY ? "human" : "json";
12
- }
13
- /**
14
- * Wrap a command function to handle output formatting.
15
- *
16
- * - `fn` does the work and returns a `CommandResult<T>`. Human-readable
17
- * output is printed inside `fn` itself.
18
- * - In JSON mode, writes exactly one JSON line to stdout.
19
- */
20
- async function withOutput(mode, fn) {
21
- const result = await fn();
22
- if (mode === "json") await writeLine(`${JSON.stringify(result)}\n`);
23
- if (!result.ok) process.exit(1);
24
- }
25
- /** Write a line to stdout, resolving only once it has been flushed. */
26
- function writeLine(line) {
27
- return new Promise((resolve) => {
28
- process.stdout.write(line, () => resolve());
29
- });
30
- }
31
- /** Create an ok result. */
32
- function ok(data) {
33
- return {
34
- ok: true,
35
- data
36
- };
37
- }
38
- /** Create an error result. */
39
- function fail(code, error, hint) {
40
- return hint ? {
41
- ok: false,
42
- error,
43
- code,
44
- hint
45
- } : {
46
- ok: false,
47
- error,
48
- code
49
- };
50
- }
51
- /** Typed CLI error that carries a structured error code and optional hint. */
52
- var CliError = class extends Error {
53
- code;
54
- hint;
55
- constructor(code, message, hint) {
56
- super(message);
57
- this.name = "CliError";
58
- this.code = code;
59
- if (hint !== void 0) this.hint = hint;
60
- }
61
- };
62
- //#endregion
63
- export { withOutput as a, ok as i, fail as n, writeLine as o, getOutputMode as r, CliError as t };
@@ -1,34 +0,0 @@
1
- #!/usr/bin/env node
2
- import * as p from "@clack/prompts";
3
- import { colorize } from "consola/utils";
4
- //#region _ui.ts
5
- const noop = () => {};
6
- let silenced = false;
7
- /** Log instance that delegates to clack (human mode) or no-ops (JSON mode). */
8
- const log = new Proxy(p.log, { get(target, prop, receiver) {
9
- return silenced ? noop : Reflect.get(target, prop, receiver);
10
- } });
11
- /** Replace all log methods with no-ops. Call once in JSON mode. */
12
- function silenceOutput() {
13
- silenced = true;
14
- }
15
- /** Unwrap a clack prompt result, exiting cleanly if the user cancelled. */
16
- function unwrapCancel(result) {
17
- if (p.isCancel(result)) {
18
- p.cancel("Setup cancelled");
19
- process.exit(0);
20
- }
21
- return result;
22
- }
23
- /** Format a URL for display. */
24
- function fmtUrl(url) {
25
- return colorize("cyanBright", url);
26
- }
27
- /** Parse and validate a port string. Returns the numeric port or throws. */
28
- function parsePort(raw) {
29
- const port = Number.parseInt(raw, 10);
30
- if (Number.isNaN(port) || port < 0 || port > 65535) throw new Error(`Invalid port: ${raw}. Must be a number between 0 and 65535.`);
31
- return port;
32
- }
33
- //#endregion
34
- export { unwrapCancel as a, silenceOutput as i, log as n, parsePort as r, fmtUrl as t };
@@ -1,55 +0,0 @@
1
- #!/usr/bin/env node
2
- import path from "node:path";
3
- import fs from "node:fs/promises";
4
- //#region _utils.ts
5
- /** Resolve the working directory from INIT_CWD or process.cwd(). */
6
- function resolveCwd() {
7
- return process.env.INIT_CWD || process.cwd();
8
- }
9
- /**
10
- * Extract a message from an unknown error. Local copy of `errorMessage` from
11
- * `@alexkroman1/aai` — importing the root barrel pulls zod into every CLI
12
- * invocation (including `aai --help`), so the one-liner lives here instead.
13
- */
14
- function errorMessage(err) {
15
- return err instanceof Error ? err.message : String(err);
16
- }
17
- /**
18
- * Extract a stack (falling back to the message) from an unknown error. Local
19
- * copy of `errorDetail` from `@alexkroman1/aai` for the same reason as
20
- * {@link errorMessage} above.
21
- */
22
- function errorDetail(err) {
23
- return err instanceof Error ? err.stack ?? err.message : String(err);
24
- }
25
- /** True when `err` is a filesystem EEXIST error (target already exists). */
26
- function isEexist(err) {
27
- return err instanceof Error && "code" in err && err.code === "EEXIST";
28
- }
29
- /** Validate that a module's default export is a valid agent definition. Throws if invalid. */
30
- function validateAgentExport(mod) {
31
- if (!mod?.name || typeof mod.name !== "string") throw new Error("agent.ts must export default agent({ name: ... })");
32
- }
33
- async function fileExists(p) {
34
- try {
35
- await fs.access(p);
36
- return true;
37
- } catch {
38
- return false;
39
- }
40
- }
41
- /** Read and parse a JSON file. Returns null if the file is missing or malformed. */
42
- async function readJson(filePath) {
43
- try {
44
- return JSON.parse(await fs.readFile(filePath, "utf-8"));
45
- } catch {
46
- return null;
47
- }
48
- }
49
- /** Write `data` as pretty-printed JSON (+ trailing newline), creating parent dirs. */
50
- async function writeJson(filePath, data) {
51
- await fs.mkdir(path.dirname(filePath), { recursive: true });
52
- await fs.writeFile(filePath, `${JSON.stringify(data, null, 2)}\n`);
53
- }
54
- //#endregion
55
- export { readJson as a, writeJson as c, isEexist as i, errorMessage as n, resolveCwd as o, fileExists as r, validateAgentExport as s, errorDetail as t };
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env node
2
- //#region _vite-env.ts
3
- /**
4
- * Run a Vite build without letting it mutate the calling process's env.
5
- *
6
- * Vite's `build()` sets `process.env.NODE_ENV = "production"` when NODE_ENV is
7
- * unset — a global, permanent side effect on whatever process invoked it. That
8
- * is fine for a one-shot `aai build`, but both long-lived callers are broken by
9
- * it:
10
- *
11
- * - `aai dev` rebuilds on every file change, so the first rebuild would flip
12
- * the dev server into production mode.
13
- * - The platform studio builds inside the server process, where flipping
14
- * NODE_ENV makes the sandbox demand gVisor ("gVisor (runsc) is required in
15
- * production but not found on PATH") and refuse every subsequent deploy on a
16
- * dev machine.
17
- *
18
- * Snapshot and restore rather than pinning a value: callers that legitimately
19
- * run with NODE_ENV=production must keep it.
20
- */
21
- async function withPreservedNodeEnv(fn) {
22
- const saved = process.env.NODE_ENV;
23
- try {
24
- return await fn();
25
- } finally {
26
- if (saved === void 0) delete process.env.NODE_ENV;
27
- else process.env.NODE_ENV = saved;
28
- }
29
- }
30
- //#endregion
31
- export { withPreservedNodeEnv as t };