@alexkroman1/aai-cli 0.9.2 → 0.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.
Files changed (65) hide show
  1. package/dist/{_build-Dw66C1m4.mjs → _build-aW_zyPpr.mjs} +61 -17
  2. package/dist/{_discover-DsorPpR_.mjs → _discover-D7HCLa_N.mjs} +62 -27
  3. package/dist/_init-CweK2mJJ.mjs +108 -0
  4. package/dist/{_link-BGXGFYWa.mjs → _link-D6mmDQ0B.mjs} +5 -3
  5. package/dist/_server-common-B6EXxxB2.mjs +105 -0
  6. package/dist/_ui-C9IvR7Fh.mjs +50 -0
  7. package/dist/cli.mjs +186 -31
  8. package/dist/delete-DxECFYOp.mjs +40 -0
  9. package/dist/{deploy-D_TBrC3r.mjs → deploy-DB0PeNtc.mjs} +11 -7
  10. package/dist/dev-DCtHG1pz.mjs +60 -0
  11. package/dist/doctor-bWuArZi6.mjs +215 -0
  12. package/dist/generate-D7zJtqoC.mjs +393 -0
  13. package/dist/{init-z8-W0Q1u.mjs → init-COkINbH_.mjs} +13 -17
  14. package/dist/{rag-D0xqGIrS.mjs → rag-BNfrEr4A.mjs} +12 -7
  15. package/dist/{secret-BQl3zBOS.mjs → secret-Zzv7fJ_3.mjs} +2 -2
  16. package/dist/{start-Df8c2ciS.mjs → start-DQypQkOq.mjs} +5 -5
  17. package/dist/test-9fFn9DCf.mjs +40 -0
  18. package/package.json +18 -11
  19. package/dist/_init-l_uoyFCN.mjs +0 -82
  20. package/dist/_server-common-CpK4rWGs.mjs +0 -36
  21. package/dist/_ui-kJIua5L9.mjs +0 -44
  22. package/dist/dev-DhHd1FRP.mjs +0 -39
  23. package/templates/_shared/.env.example +0 -5
  24. package/templates/_shared/CLAUDE.md +0 -1051
  25. package/templates/_shared/biome.json +0 -32
  26. package/templates/_shared/global.d.ts +0 -1
  27. package/templates/_shared/index.html +0 -16
  28. package/templates/_shared/package.json +0 -23
  29. package/templates/_shared/tsconfig.json +0 -15
  30. package/templates/code-interpreter/agent.ts +0 -27
  31. package/templates/code-interpreter/client.tsx +0 -3
  32. package/templates/css.d.ts +0 -1
  33. package/templates/dispatch-center/agent.ts +0 -1227
  34. package/templates/dispatch-center/client.tsx +0 -505
  35. package/templates/embedded-assets/agent.ts +0 -48
  36. package/templates/embedded-assets/client.tsx +0 -3
  37. package/templates/embedded-assets/knowledge.json +0 -20
  38. package/templates/health-assistant/agent.ts +0 -160
  39. package/templates/health-assistant/client.tsx +0 -3
  40. package/templates/infocom-adventure/agent.ts +0 -164
  41. package/templates/infocom-adventure/client.tsx +0 -300
  42. package/templates/math-buddy/agent.ts +0 -21
  43. package/templates/math-buddy/client.tsx +0 -3
  44. package/templates/memory-agent/agent.ts +0 -20
  45. package/templates/memory-agent/client.tsx +0 -3
  46. package/templates/night-owl/agent.ts +0 -98
  47. package/templates/night-owl/client.tsx +0 -12
  48. package/templates/personal-finance/agent.ts +0 -26
  49. package/templates/personal-finance/client.tsx +0 -3
  50. package/templates/pizza-ordering/agent.ts +0 -218
  51. package/templates/pizza-ordering/client.tsx +0 -264
  52. package/templates/simple/agent.ts +0 -6
  53. package/templates/simple/client.tsx +0 -3
  54. package/templates/smart-research/agent.ts +0 -164
  55. package/templates/smart-research/client.tsx +0 -3
  56. package/templates/solo-rpg/agent.ts +0 -1244
  57. package/templates/solo-rpg/client.tsx +0 -698
  58. package/templates/support/README.md +0 -62
  59. package/templates/support/agent.ts +0 -19
  60. package/templates/support/client.tsx +0 -3
  61. package/templates/travel-concierge/agent.ts +0 -29
  62. package/templates/travel-concierge/client.tsx +0 -3
  63. package/templates/tsconfig.json +0 -1
  64. package/templates/web-researcher/agent.ts +0 -17
  65. package/templates/web-researcher/client.tsx +0 -3
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { i as getServerInfo } from "./_discover-DsorPpR_.mjs";
3
- import { a as step, i as runCommand, n as info, s as warn, t as detail } from "./_ui-kJIua5L9.mjs";
2
+ import { a as getServerInfo } from "./_discover-D7HCLa_N.mjs";
3
+ import { a as runCommand, c as warn, n as info, o as step, t as detail } from "./_ui-C9IvR7Fh.mjs";
4
4
  import { errorMessage } from "@alexkroman1/aai/utils";
5
5
  import pLimit from "p-limit";
6
6
  //#region rag.ts
@@ -64,11 +64,15 @@ async function upsertChunks(chunks, vectorUrl, apiKey, setStatus, fetchFn = glob
64
64
  let upserted = 0;
65
65
  let errors = 0;
66
66
  let lastError = "";
67
- const updateStatus = () => {
67
+ let lastStatusUpdate = 0;
68
+ const updateStatus = (force = false) => {
69
+ const now = Date.now();
70
+ if (!force && now - lastStatusUpdate < 100) return;
71
+ lastStatusUpdate = now;
68
72
  const pct = Math.round(completed / total * 100);
69
73
  setStatus(` Upsert ${completed}/${total} (${pct}%)`);
70
74
  };
71
- updateStatus();
75
+ updateStatus(true);
72
76
  const limit = pLimit(5);
73
77
  await Promise.all(chunks.map((chunk) => limit(async () => {
74
78
  try {
@@ -107,11 +111,12 @@ async function runRagCommand(opts) {
107
111
  const { url, cwd } = opts;
108
112
  try {
109
113
  new URL(url);
110
- } catch {
111
- throw new Error(`Invalid URL: ${url}`);
114
+ } catch (err) {
115
+ throw new Error(`Invalid URL: ${url}\n Provide a fully qualified URL including the protocol (e.g., https://example.com/docs).`, { cause: err });
112
116
  }
113
- const { apiKey, serverUrl, slug } = await getServerInfo(cwd, opts.server);
114
117
  const chunkSize = Number.parseInt(opts.chunkSize ?? "512", 10);
118
+ if (Number.isNaN(chunkSize) || chunkSize <= 0) throw new Error(`Invalid chunk size: "${opts.chunkSize}". Must be a positive integer.`);
119
+ const { apiKey, serverUrl, slug } = await getServerInfo(cwd, opts.server);
115
120
  await runCommand(async ({ log, setStatus }) => {
116
121
  await runRag({
117
122
  url,
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { d as askPassword, i as getServerInfo } from "./_discover-DsorPpR_.mjs";
3
- import { a as step, i as runCommand, o as stepInfo, t as detail } from "./_ui-kJIua5L9.mjs";
2
+ import { a as getServerInfo, f as askPassword } from "./_discover-D7HCLa_N.mjs";
3
+ import { a as runCommand, o as step, s as stepInfo, t as detail } from "./_ui-C9IvR7Fh.mjs";
4
4
  //#region secret.ts
5
5
  async function apiFetch(cwd, pathSuffix, init) {
6
6
  const { serverUrl, slug, apiKey } = await getServerInfo(cwd);
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { t as fileExists } from "./_discover-DsorPpR_.mjs";
3
- import { a as step, i as runCommand } from "./_ui-kJIua5L9.mjs";
4
- import { n as loadAgentDef, r as resolveServerEnv, t as bootServer } from "./_server-common-CpK4rWGs.mjs";
2
+ import { n as fileExists } from "./_discover-D7HCLa_N.mjs";
3
+ import { a as runCommand, i as parsePort, o as step } from "./_ui-C9IvR7Fh.mjs";
4
+ import { a as resolveServerEnv, i as loadAgentDef, n as bootServer } from "./_server-common-B6EXxxB2.mjs";
5
5
  import path from "node:path";
6
6
  //#region start.ts
7
7
  async function _startProductionServer(cwd, port, log) {
8
8
  const clientDir = path.join(cwd, ".aai", "client");
9
9
  log(step("Start", "loading agent"));
10
- await bootServer(await loadAgentDef(cwd), clientDir, await resolveServerEnv(), port);
10
+ await bootServer(await loadAgentDef(cwd), clientDir, await resolveServerEnv(cwd), port);
11
11
  log(step("Ready", `http://localhost:${port}`));
12
12
  }
13
13
  async function runStartCommand(opts) {
14
- const port = Number.parseInt(opts.port, 10);
14
+ const port = parsePort(opts.port);
15
15
  const buildDir = path.join(opts.cwd, ".aai", "build");
16
16
  if (!await fileExists(path.join(buildDir, "worker.js"))) throw new Error("No build found — run `aai build` first");
17
17
  await runCommand(async ({ log }) => {
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ import { a as runCommand, o as step } from "./_ui-C9IvR7Fh.mjs";
3
+ import { existsSync } from "node:fs";
4
+ import path from "node:path";
5
+ import { execSync } from "node:child_process";
6
+ //#region test.ts
7
+ /**
8
+ * `aai test` — run agent tests via vitest.
9
+ */
10
+ /**
11
+ * Run vitest in the given project directory.
12
+ *
13
+ * Returns `true` if tests passed, `false` if no test files exist.
14
+ * Throws on test failure.
15
+ */
16
+ function runVitest(cwd) {
17
+ if (!(existsSync(path.join(cwd, "agent.test.ts")) || existsSync(path.join(cwd, "agent.test.js")))) return false;
18
+ execSync("npx vitest run", {
19
+ cwd,
20
+ stdio: "inherit",
21
+ env: {
22
+ ...process.env,
23
+ NODE_OPTIONS: "--experimental-strip-types"
24
+ }
25
+ });
26
+ return true;
27
+ }
28
+ /** Run agent tests. Used by `aai test`. */
29
+ async function runTestCommand(cwd) {
30
+ await runCommand(async ({ log }) => {
31
+ log(step("Test", "running agent tests"));
32
+ if (!runVitest(cwd)) {
33
+ log("No test files found (agent.test.ts). Skipping.");
34
+ return;
35
+ }
36
+ log(step("Test", "ok"));
37
+ });
38
+ }
39
+ //#endregion
40
+ export { runTestCommand, runVitest };
package/package.json CHANGED
@@ -1,41 +1,48 @@
1
1
  {
2
2
  "name": "@alexkroman1/aai-cli",
3
- "version": "0.9.2",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "aai": "dist/cli.mjs"
7
7
  },
8
8
  "files": [
9
- "dist",
10
- "templates"
9
+ "dist"
11
10
  ],
12
11
  "dependencies": {
13
- "@hono/node-server": "^1.19.11",
14
- "hono": "^4.12.9",
12
+ "@ai-sdk/openai-compatible": "^2.0.37",
15
13
  "@chonkiejs/core": "^0.0.8",
16
- "@clack/prompts": "^1.1.0",
14
+ "consola": "^3.4.2",
15
+ "giget": "^2.0.0",
16
+ "@hono/node-server": "^1.19.11",
17
17
  "@preact/preset-vite": "^2.10.5",
18
18
  "@tailwindcss/vite": "^4.2.2",
19
+ "ai": "^6.0.140",
19
20
  "citty": "^0.2.1",
21
+ "hono": "^4.12.9",
20
22
  "human-id": "^4.1.3",
21
23
  "p-limit": "^7.3.0",
22
- "picocolors": "^1.1.1",
23
- "vite": "^8.0.2",
24
+ "vite": "^8.0.3",
24
25
  "zod": "^4.3.6",
25
- "@alexkroman1/aai": "0.9.2"
26
+ "@alexkroman1/aai": "0.10.0"
26
27
  },
27
28
  "devDependencies": {
28
29
  "playwright": "^1.58.2",
29
- "tsdown": "^0.21.4"
30
+ "tsdown": "^0.21.5"
30
31
  },
31
32
  "engines": {
32
33
  "node": ">=22.6"
33
34
  },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/alexkroman/agent.git",
38
+ "directory": "packages/aai-cli"
39
+ },
34
40
  "scripts": {
35
41
  "build": "tsdown",
36
42
  "typecheck": "tsc --noEmit",
37
43
  "lint": "biome check .",
38
44
  "test:integration": "vitest run pack-build.test.ts -c vitest.slow.config.ts",
39
- "test:e2e": "vitest run e2e.test.ts -c vitest.slow.config.ts"
45
+ "test:e2e": "vitest run e2e.test.ts -c vitest.slow.config.ts",
46
+ "check:e2e": "vitest run e2e.test.ts -c vitest.slow.config.ts"
40
47
  }
41
48
  }
@@ -1,82 +0,0 @@
1
- #!/usr/bin/env node
2
- import path from "node:path";
3
- import fs from "node:fs/promises";
4
- //#region _init.ts
5
- async function listTemplates(dir) {
6
- const templates = [];
7
- const entries = await fs.readdir(dir, { withFileTypes: true });
8
- for (const entry of entries) if (entry.isDirectory() && !entry.name.startsWith("_")) templates.push(entry.name);
9
- return templates.sort();
10
- }
11
- /**
12
- * Copy all files from `src` into `dest`, skipping files that already exist
13
- * in `dest` so that template-specific files take precedence over shared ones.
14
- */
15
- async function copyDirNoOverwrite(src, dest) {
16
- const entries = await fs.readdir(src, {
17
- recursive: true,
18
- withFileTypes: true
19
- });
20
- for (const entry of entries) {
21
- if (!entry.isFile()) continue;
22
- const rel = path.relative(src, path.join(entry.parentPath, entry.name));
23
- const destPath = path.join(dest, rel);
24
- await fs.mkdir(path.dirname(destPath), { recursive: true });
25
- try {
26
- await fs.copyFile(path.join(src, rel), destPath, fs.constants.COPYFILE_EXCL);
27
- } catch (err) {
28
- if (!(err instanceof Error && "code" in err && err.code === "EEXIST")) throw err;
29
- }
30
- }
31
- }
32
- async function runInit(opts) {
33
- const { targetDir, template, templatesDir } = opts;
34
- const available = await listTemplates(templatesDir);
35
- if (!available.includes(template)) throw new Error(`unknown template '${template}' -- available: ${available.join(", ")}`);
36
- await fs.cp(path.join(templatesDir, template), targetDir, {
37
- recursive: true,
38
- force: true
39
- });
40
- await copyDirNoOverwrite(path.join(templatesDir, "_shared"), targetDir);
41
- try {
42
- await fs.copyFile(path.join(targetDir, ".env.example"), path.join(targetDir, ".env"));
43
- } catch {}
44
- const readmePath = path.join(targetDir, "README.md");
45
- const readme = `# ${path.basename(path.resolve(targetDir))}
46
-
47
- A voice agent built with [aai](https://github.com/anthropics/aai).
48
-
49
- ## Getting started
50
-
51
- \`\`\`sh
52
- npm install # Install dependencies
53
- npm run dev # Run locally (opens browser)
54
- npm run deploy # Deploy to production
55
- \`\`\`
56
-
57
- ## Environment variables
58
-
59
- Secrets are managed on the server, not in local files:
60
-
61
- \`\`\`sh
62
- aai env add MY_KEY # Set a secret (prompts for value)
63
- aai env ls # List secret names
64
- aai env pull # Pull names into .env for reference
65
- aai env rm MY_KEY # Remove a secret
66
- \`\`\`
67
-
68
- Access secrets in your agent via \`ctx.env.MY_KEY\`.
69
-
70
- ## Learn more
71
-
72
- See \`CLAUDE.md\` for the full agent API reference.
73
- `;
74
- try {
75
- await fs.writeFile(readmePath, readme, { flag: "wx" });
76
- } catch (err) {
77
- if (err.code !== "EEXIST") throw err;
78
- }
79
- return targetDir;
80
- }
81
- //#endregion
82
- export { runInit };
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env node
2
- import { r as getApiKey } from "./_discover-DsorPpR_.mjs";
3
- import path from "node:path";
4
- import fs from "node:fs/promises";
5
- //#region _server-common.ts
6
- /** Load an AgentDef by dynamically importing agent.ts via Node's native TS support. */
7
- async function loadAgentDef(cwd) {
8
- const agentDef = (await import(path.resolve(cwd, "agent.ts"))).default;
9
- if (!agentDef || typeof agentDef !== "object" || !agentDef.name) throw new Error("agent.ts must export a default agent definition (from defineAgent())");
10
- return agentDef;
11
- }
12
- /**
13
- * Build an env record, ensuring ASSEMBLYAI_API_KEY is set.
14
- *
15
- * @param baseEnv - Override the base environment (defaults to process.env).
16
- */
17
- async function resolveServerEnv(baseEnv) {
18
- const env = Object.fromEntries(Object.entries(baseEnv ?? process.env).filter((e) => e[1] !== void 0));
19
- if (!env.ASSEMBLYAI_API_KEY) env.ASSEMBLYAI_API_KEY = await getApiKey();
20
- return env;
21
- }
22
- /** Create and start an agent server with static file serving. */
23
- async function bootServer(agentDef, clientDir, env, port) {
24
- const clientHtml = await fs.readFile(path.join(clientDir, "index.html"), "utf-8");
25
- const { createServer } = await import("@alexkroman1/aai/server");
26
- const server = createServer({
27
- agent: agentDef,
28
- clientHtml,
29
- clientDir,
30
- env
31
- });
32
- await server.listen(port);
33
- return server;
34
- }
35
- //#endregion
36
- export { loadAgentDef as n, resolveServerEnv as r, bootServer as t };
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env node
2
- import pc from "picocolors";
3
- //#region _ui.ts
4
- /** Interactive/info color wrapper. */
5
- function interactive(s) {
6
- return pc.cyan(s);
7
- }
8
- /** Colored step message: bold action label + message. */
9
- function step(action, msg) {
10
- return `${pc.bold(pc.yellow(action))} ${msg}`;
11
- }
12
- /** Informational step message: bold cyan action + message. */
13
- function stepInfo(action, msg) {
14
- return `${pc.bold(pc.cyan(action))} ${msg}`;
15
- }
16
- /** Dimmed info sub-line (indented). */
17
- function info(msg) {
18
- return pc.dim(` ${msg}`);
19
- }
20
- /** Detail sub-line (indented). */
21
- function detail(msg) {
22
- return ` ${msg}`;
23
- }
24
- /** Yellow warning message. */
25
- function warn(msg) {
26
- return `${pc.yellow("!")} ${msg}`;
27
- }
28
- /**
29
- * Run an async command function, logging each step to stdout.
30
- * Replaces the Ink `runWithInk` pattern.
31
- */
32
- async function runCommand(fn) {
33
- const log = (msg) => console.log(msg);
34
- const setStatus = (msg) => {
35
- if (msg) process.stdout.write(`\r${pc.dim(msg)}`);
36
- else process.stdout.write("\r\x1B[K");
37
- };
38
- await fn({
39
- log,
40
- setStatus
41
- });
42
- }
43
- //#endregion
44
- export { step as a, runCommand as i, info as n, stepInfo as o, interactive as r, warn as s, detail as t };
@@ -1,39 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./_discover-DsorPpR_.mjs";
3
- import { a as step, i as runCommand, n as info } from "./_ui-kJIua5L9.mjs";
4
- import { buildAgentBundle } from "./_build-Dw66C1m4.mjs";
5
- import { n as loadAgentDef, r as resolveServerEnv, t as bootServer } from "./_server-common-CpK4rWGs.mjs";
6
- //#region dev.ts
7
- async function _startDevServer(cwd, port, log, opts) {
8
- const bundle = await buildAgentBundle(cwd, log);
9
- const agentDef = await loadAgentDef(cwd);
10
- const env = await resolveServerEnv();
11
- const server = await bootServer(agentDef, bundle.clientDir, env, port);
12
- log(step("Ready", `http://localhost:${port}`));
13
- const base = `http://localhost:${port}`;
14
- try {
15
- const healthRes = await fetch(`${base}/health`);
16
- if (!healthRes.ok) throw new Error(`GET /health returned ${healthRes.status}`);
17
- const health = await healthRes.json();
18
- if (health.status !== "ok") throw new Error(`GET /health returned ${JSON.stringify(health)}`);
19
- log(step("Health", health.name ?? "ok"));
20
- const pageRes = await fetch(`${base}/`);
21
- if (!pageRes.ok) throw new Error(`GET / returned ${pageRes.status}`);
22
- const html = await pageRes.text();
23
- if (!(html.includes("<") && html.includes("html"))) throw new Error("GET / did not return valid HTML");
24
- log(step("Client", "ok"));
25
- } catch (err) {
26
- await server.close();
27
- throw err;
28
- }
29
- if (opts?.check) await server.close();
30
- else log(info("Ctrl-C to quit"));
31
- }
32
- async function runDevCommand(opts) {
33
- const port = Number.parseInt(opts.port, 10);
34
- await runCommand(async ({ log }) => {
35
- await _startDevServer(opts.cwd, port, log, opts.check ? { check: true } : void 0);
36
- });
37
- }
38
- //#endregion
39
- export { runDevCommand };
@@ -1,5 +0,0 @@
1
- # Set secrets on the server with: aai env add <NAME>
2
- # Pull secret names here for local reference: aai env pull
3
- #
4
- # ASSEMBLYAI_API_KEY is managed globally by the CLI (~/.config/aai/).
5
- # Add any additional secrets your agent needs below: