@alexkroman1/aai-cli 5.1.0 → 5.1.1

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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as serverOrigin, i as readProjectConfig, n as ensureApiKey, r as readGlobalConfig, t as approveServer } from "./_config-Czjhvaax.mjs";
2
+ import { a as serverOrigin, i as readProjectConfig, n as ensureApiKey, r as readGlobalConfig, t as approveServer } from "./_config-D3F9km8X.mjs";
3
3
  import { existsSync } from "node:fs";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -71,8 +71,7 @@ function resolveServerUrl(explicit, configUrl, approvedOrigins = []) {
71
71
  * the project has never been deployed), server URL, and API key.
72
72
  */
73
73
  async function resolveDeployTarget(cwd, explicitServer) {
74
- const config = await readProjectConfig(cwd);
75
- const globalConfig = await readGlobalConfig();
74
+ const [config, globalConfig] = await Promise.all([readProjectConfig(cwd), readGlobalConfig()]);
76
75
  const serverUrl = resolveServerUrl(explicitServer, config?.serverUrl, globalConfig.approvedServers ?? []);
77
76
  if (explicitServer) await approveServer(serverUrl);
78
77
  return {
@@ -9,6 +9,8 @@ import { FetchError, ofetch } from "ofetch";
9
9
  * 5xx/429) are retried before surfacing an error.
10
10
  */
11
11
  const HINT_INVALID_API_KEY = "Your API key may be invalid. Run `aai` to re-enter your AssemblyAI API key.";
12
+ /** 404 hint for requests scoped to a deployed agent's slug. */
13
+ const HINT_NOT_DEPLOYED = "The agent may not be deployed. Check `.aai/project.json` for the correct slug.";
12
14
  /**
13
15
  * Send an authenticated request to the platform API and return the parsed
14
16
  * JSON response. Throws a descriptive error with status-specific hints on
@@ -44,4 +46,4 @@ function toApiError(err, url, opts) {
44
46
  return new Error(`${opts.action} failed: could not reach ${url}\n ${hint}`, { cause });
45
47
  }
46
48
  //#endregion
47
- export { apiRequest as t };
49
+ export { apiRequest as n, HINT_NOT_DEPLOYED as t };
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, u as ok } from "./_ui-DXZ9prrM.mjs";
3
- import { c as validateAgentExport } from "./_utils-C502jKo8.mjs";
4
- import { t as buildClient } from "./client-bundler-DO3GgO6p.mjs";
2
+ import { u as validateAgentExport } from "./_utils-Ch0J4s6a.mjs";
3
+ import { t as buildClient } from "./client-bundler-BWDkUeEP.mjs";
5
4
  import { buildWorker } from "./worker-bundler.mjs";
6
5
  import path from "node:path";
7
6
  import { pathToFileURL } from "node:url";
@@ -79,14 +78,5 @@ function createWorkerEvaluator() {
79
78
  return agentDef;
80
79
  };
81
80
  }
82
- async function executeBuild(cwd) {
83
- const bundle = await buildAgentBundle(cwd, { minify: true });
84
- const agentDef = await evalWorkerBundle(bundle.worker);
85
- log.success("Build complete");
86
- return ok({
87
- name: agentDef.name,
88
- workerBytes: bundle.worker.length
89
- });
90
- }
91
81
  //#endregion
92
- export { buildAgentBundle, createWorkerEvaluator, executeBuild };
82
+ export { createWorkerEvaluator as n, evalWorkerBundle as r, buildAgentBundle as t };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { a as unwrapCancel, n as log, o as CliError } from "./_ui-DXZ9prrM.mjs";
3
- import { l as writeJson, o as readJson, r as errorMessage } from "./_utils-C502jKo8.mjs";
2
+ import { a as unwrapCancel, n as log, o as CliError } from "./_ui-8kOEB-JH.mjs";
3
+ import { a as errorMessage, c as readJson, d as writeJson } from "./_utils-Ch0J4s6a.mjs";
4
4
  import path from "node:path";
5
5
  import * as p from "@clack/prompts";
6
6
  import envPaths from "env-paths";
@@ -116,7 +116,7 @@ async function ensureApiKey(configDir) {
116
116
  return envKey;
117
117
  }
118
118
  if (!process.stdin.isTTY) throw new CliError("no_api_key", "No API key configured and no TTY to prompt for one.", "Set the ASSEMBLYAI_API_KEY environment variable, or run `aai` interactively once to save a key.");
119
- const apiKey = unwrapCancel(await p.password({ message: "Enter your AssemblyAI API key" }));
119
+ const apiKey = unwrapCancel(await p.password({ message: "Enter your AssemblyAI API key" }), "Setup cancelled");
120
120
  await trySaveApiKey(dir, config, apiKey);
121
121
  return apiKey;
122
122
  }
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { n as log } from "./_ui-DXZ9prrM.mjs";
3
- import { r as errorMessage, t as errorCode } from "./_utils-C502jKo8.mjs";
4
- import { n as fallbackHtmlPlugin } from "./client-bundler-DO3GgO6p.mjs";
2
+ import { n as log } from "./_ui-8kOEB-JH.mjs";
3
+ import { a as errorMessage, r as errorCode } from "./_utils-Ch0J4s6a.mjs";
4
+ import { n as fallbackHtmlPlugin } from "./client-bundler-BWDkUeEP.mjs";
5
5
  import { buildWorker } from "./worker-bundler.mjs";
6
- import { createWorkerEvaluator } from "./_bundler-DdmuZzeR.mjs";
7
- import { n as ensureApiKey } from "./_config-Czjhvaax.mjs";
8
- import { t as resolveServerEnv } from "./_server-common-B75oco06.mjs";
6
+ import { n as createWorkerEvaluator } from "./_bundler-DFS4xxqE.mjs";
7
+ import { n as ensureApiKey } from "./_config-D3F9km8X.mjs";
8
+ import { t as resolveServerEnv } from "./_server-common-CnaP_Urf.mjs";
9
9
  import { createRequire } from "node:module";
10
10
  import { existsSync } from "node:fs";
11
11
  import path from "node:path";
12
12
  import { setTimeout } from "node:timers/promises";
13
- import { requiredProviderEnvVars, withHostCredentialFallback } from "@alexkroman1/aai/runtime";
13
+ import { createRuntime, createServer, requiredProviderEnvVars, withHostCredentialFallback } from "@alexkroman1/aai/runtime";
14
14
  import { watch } from "chokidar";
15
15
  import getPort, { portNumbers } from "get-port";
16
16
  import pDebounce from "p-debounce";
@@ -183,7 +183,6 @@ function viteDevConfig(cwd, vitePort, backendPort) {
183
183
  */
184
184
  async function startDevServer(opts) {
185
185
  const { cwd, port } = opts;
186
- const { createRuntime, createServer } = await import("@alexkroman1/aai/runtime");
187
186
  const hasClient = existsSync(path.join(cwd, "client.tsx"));
188
187
  const backendPort = hasClient ? await getPort({ port: portNumbers(port + 1, port + 100) }) : port;
189
188
  const vitePort = port;
@@ -194,13 +193,12 @@ async function startDevServer(opts) {
194
193
  const agentDef = await loadAgentDef(cwd, evaluateWorker);
195
194
  const env = await resolveAgentEnv(cwd, agentDef);
196
195
  const providerEnv = withHostCredentialFallback(env);
197
- const runtime = createRuntime({
198
- agent: agentDef,
199
- env,
200
- providerEnv
201
- });
202
196
  return createServer({
203
- runtime,
197
+ runtime: createRuntime({
198
+ agent: agentDef,
199
+ env,
200
+ providerEnv
201
+ }),
204
202
  name: agentDef.name,
205
203
  env: hostModeEnv(providerEnv),
206
204
  hostBaseAgent: agentDef,
@@ -1,13 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { a as isEexist, l as writeJson, o as readJson, r as errorMessage } from "./_utils-C502jKo8.mjs";
3
- import { r as isDevMode, t as getMonorepoRoot } from "./_agent-D39qatZJ.mjs";
2
+ import { a as errorMessage, c as readJson, d as writeJson, s as isEexist } from "./_utils-Ch0J4s6a.mjs";
3
+ import { r as isDevMode, t as getMonorepoRoot } from "./_agent-D8zBb3M5.mjs";
4
4
  import { existsSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import fs from "node:fs/promises";
7
7
  import os from "node:os";
8
8
  import { downloadTemplate } from "giget";
9
9
  //#region _templates.ts
10
- const GIGET_SOURCE = "github:alexkroman/agent/packages/aai-templates";
10
+ /** The GitHub repo (owner/name) that hosts this project and its templates. */
11
+ const REPO = "alexkroman/agent";
12
+ const REPO_URL = `https://github.com/${REPO}`;
13
+ const GIGET_SOURCE = `github:${REPO}/packages/aai-templates`;
11
14
  const GIGET_REF = process.env.AAI_TEMPLATES_REF ?? "main";
12
15
  const VALID_REF_RE = /^[\w./-]+$/;
13
16
  const noCleanup = async () => void 0;
@@ -79,7 +82,7 @@ async function downloadAndMergeTemplate(template, targetDir) {
79
82
  function readmeContent(slug) {
80
83
  return `# ${slug}
81
84
 
82
- A voice agent built with [aai](https://github.com/anthropics/aai).
85
+ A voice agent built with [aai](${REPO_URL}).
83
86
 
84
87
  ## Getting started
85
88
 
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { r as errorCode } from "./_utils-Ch0J4s6a.mjs";
2
3
  import path from "node:path";
3
4
  import { parseEnv } from "node:util";
4
5
  import fs from "node:fs/promises";
@@ -26,7 +27,7 @@ async function resolveServerEnv(cwd, baseEnv) {
26
27
  try {
27
28
  content = await fs.readFile(path.join(cwd, ".env"), "utf-8");
28
29
  } catch (err) {
29
- if (err.code !== "ENOENT") throw err;
30
+ if (errorCode(err) !== "ENOENT") throw err;
30
31
  }
31
32
  if (content !== null) fileEntries = parseEnv(content);
32
33
  }
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import { n as getServerInfo } from "./_agent-D8zBb3M5.mjs";
3
+ import { n as apiRequest, t as HINT_NOT_DEPLOYED } from "./_api-client-MenP4-O7.mjs";
4
+ //#region _slug-api.ts
5
+ /**
6
+ * Authenticated request against a deployed agent's slug-scoped resource
7
+ * (`${serverUrl}/${slug}${resourcePath}`) — the one shape every per-agent
8
+ * command (secret, storage) shares, including the standard "not deployed"
9
+ * 404 hint.
10
+ *
11
+ * Its own module (rather than living beside `getServerInfo` in `_agent.ts`)
12
+ * so tests can mock `_agent.ts`/`_api-client.ts` while this composition
13
+ * stays real — an intra-module call would bypass those mocks.
14
+ */
15
+ async function slugRequest(cwd, resourcePath, init, server) {
16
+ const { serverUrl, slug, apiKey } = await getServerInfo(cwd, server);
17
+ return {
18
+ data: await apiRequest(`${serverUrl}/${slug}${resourcePath}`, {
19
+ ...init,
20
+ apiKey,
21
+ hints: { 404: HINT_NOT_DEPLOYED }
22
+ }),
23
+ slug
24
+ };
25
+ }
26
+ //#endregion
27
+ export { slugRequest as t };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, o as CliError } from "./_ui-DXZ9prrM.mjs";
2
+ import { n as log, o as CliError } from "./_ui-8kOEB-JH.mjs";
3
3
  import { typecheckProject } from "./typecheck.mjs";
4
4
  //#region _typecheck-gate.ts
5
5
  /**
@@ -14,4 +14,4 @@ async function assertTypechecks(cwd) {
14
14
  if (!result.ok) throw new CliError("typecheck_failed", result.output, "Fix the type errors, or pass --skipTypecheck to build anyway");
15
15
  }
16
16
  //#endregion
17
- export { assertTypechecks };
17
+ export { assertTypechecks as t };
@@ -83,10 +83,13 @@ const log = new Proxy(p.log, { get(target, prop, receiver) {
83
83
  function silenceOutput() {
84
84
  silenced = true;
85
85
  }
86
- /** Unwrap a clack prompt result, exiting cleanly if the user cancelled. */
87
- function unwrapCancel(result) {
86
+ /**
87
+ * Unwrap a clack prompt result, exiting cleanly if the user cancelled.
88
+ * `message` lets the caller name what was cancelled (e.g. "Setup cancelled").
89
+ */
90
+ function unwrapCancel(result, message = "Cancelled") {
88
91
  if (p.isCancel(result)) {
89
- p.cancel("Setup cancelled");
92
+ p.cancel(message);
90
93
  process.exit(0);
91
94
  }
92
95
  return result;
@@ -1,8 +1,14 @@
1
1
  #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
2
3
  import path from "node:path";
3
4
  import fs from "node:fs/promises";
4
5
  import { errorDetail, errorMessage, errorMessage as errorMessage$1 } from "@alexkroman1/aai/utils";
5
6
  //#region _utils.ts
7
+ /**
8
+ * The file that marks a directory as an agent project — the single source
9
+ * for the entry filename every command checks or scaffolds.
10
+ */
11
+ const AGENT_ENTRY = "agent.ts";
6
12
  /** Resolve the working directory from INIT_CWD or process.cwd(). */
7
13
  function resolveCwd() {
8
14
  return process.env.INIT_CWD || process.cwd();
@@ -19,6 +25,16 @@ function isEexist(err) {
19
25
  function validateAgentExport(mod) {
20
26
  if (!mod?.name || typeof mod.name !== "string") throw new Error("agent.ts must export default agent({ name: ... })");
21
27
  }
28
+ /**
29
+ * Absolute path of `binName`'s script declared by the package.json at
30
+ * `pkgJsonPath`, or undefined when the package declares no such bin.
31
+ * Handles both `"bin": "script.js"` and `"bin": { name: "script.js" }`.
32
+ */
33
+ function binFromPackageJson(pkgJsonPath, binName) {
34
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
35
+ const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.[binName];
36
+ return bin ? path.join(path.dirname(pkgJsonPath), bin) : void 0;
37
+ }
22
38
  async function fileExists(p) {
23
39
  try {
24
40
  await fs.access(p);
@@ -79,4 +95,4 @@ async function writeJson(filePath, data, opts = {}) {
79
95
  }
80
96
  }
81
97
  //#endregion
82
- export { isEexist as a, validateAgentExport as c, fileExists as i, writeJson as l, errorDetail as n, readJson as o, errorMessage$1 as r, resolveCwd as s, errorCode as t };
98
+ export { errorMessage$1 as a, readJson as c, writeJson as d, errorDetail as i, resolveCwd as l, binFromPackageJson as n, fileExists as o, errorCode as r, isEexist as s, AGENT_ENTRY as t, validateAgentExport as u };
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ import { n as log, o as CliError, u as ok } from "./_ui-8kOEB-JH.mjs";
3
+ import { r as evalWorkerBundle, t as buildAgentBundle } from "./_bundler-DFS4xxqE.mjs";
4
+ import { t as assertTypechecks } from "./_typecheck-gate-9IHWDnl1.mjs";
5
+ import { classifyVitestError, runVitest } from "./test-3Gq4pqH_.mjs";
6
+ //#region build.ts
7
+ /**
8
+ * `aai build` — bundle the agent without deploying, behind the same gates
9
+ * deploy runs (tests, then typecheck), so the command previews the deploy
10
+ * artifact and its failures alike.
11
+ */
12
+ /**
13
+ * Map a {@link runVitest} failure to a CliError — distinguishing a real test
14
+ * failure (test_failed) from the runner not spawning (spawn_failed) instead
15
+ * of a generic command_failed.
16
+ */
17
+ function testGateError(err) {
18
+ const { code, message } = classifyVitestError(err);
19
+ return new CliError(code, message, "Re-run with --skipTests to build without tests", { cause: err });
20
+ }
21
+ async function executeBuild(opts) {
22
+ const { cwd } = opts;
23
+ if (!opts.skipTests) try {
24
+ runVitest(cwd);
25
+ } catch (err) {
26
+ throw testGateError(err);
27
+ }
28
+ if (!opts.skipTypecheck) await assertTypechecks(cwd);
29
+ const bundle = await buildAgentBundle(cwd, { minify: true });
30
+ const agentDef = await evalWorkerBundle(bundle.worker);
31
+ log.success("Build complete");
32
+ return ok({
33
+ name: agentDef.name,
34
+ workerBytes: bundle.worker.length
35
+ });
36
+ }
37
+ //#endregion
38
+ export { executeBuild };
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { c as getOutputMode, d as writeLine, i as silenceOutput, l as installStdoutGuard, n as log, o as CliError, s as fail } from "./_ui-DXZ9prrM.mjs";
3
- import { i as fileExists, r as errorMessage, s as resolveCwd } from "./_utils-C502jKo8.mjs";
2
+ import { c as getOutputMode, d as writeLine, i as silenceOutput, l as installStdoutGuard, n as log, o as CliError, s as fail } from "./_ui-8kOEB-JH.mjs";
3
+ import { a as errorMessage, l as resolveCwd, o as fileExists, t as AGENT_ENTRY } from "./_utils-Ch0J4s6a.mjs";
4
4
  import { existsSync, readFileSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
@@ -8,12 +8,6 @@ import { defineCommand, runMain } from "citty";
8
8
  //#region cli.ts
9
9
  /** Shared arg definitions for citty commands. */
10
10
  const sharedArgs = {
11
- port: {
12
- type: "string",
13
- alias: "p",
14
- description: "Port to listen on",
15
- default: "3000"
16
- },
17
11
  server: {
18
12
  type: "string",
19
13
  alias: "s",
@@ -48,7 +42,7 @@ const VERSION = readCliVersion(cliDir);
48
42
  async function setup(opts) {
49
43
  const cwd = resolveCwd();
50
44
  if (opts?.agent) {
51
- if (!await fileExists(path.join(cwd, "agent.ts"))) throw new Error("No agent.ts found in the current directory. Run `aai init` first.");
45
+ if (!await fileExists(path.join(cwd, "agent.ts"))) throw new Error(`No ${AGENT_ENTRY} found in the current directory. Run \`aai init\` first.`);
52
46
  }
53
47
  return cwd;
54
48
  }
@@ -56,7 +50,6 @@ async function setup(opts) {
56
50
  * Run a command body with standard output-mode resolution, error handling,
57
51
  * and result emission.
58
52
  *
59
- * - `setYes`: json mode sets `args.yes = true` (only meaningful for commands with a `yes` arg).
60
53
  * - API key acquisition is owned by `resolveDeployTarget`/`getServerInfo`
61
54
  * inside the commands that talk to the platform — after the server-trust
62
55
  * check, so an untrusted `serverUrl` is refused without prompting for a
@@ -66,12 +59,9 @@ async function setup(opts) {
66
59
  * human mode logs the message, JSON mode writes exactly one result line,
67
60
  * and both exit 1.
68
61
  */
69
- async function runCommand(args, fn, opts = {}) {
62
+ async function runCommand(args, fn) {
70
63
  const mode = getOutputMode(args);
71
- if (mode === "json") {
72
- silenceOutput();
73
- if (opts.setYes) args.yes = true;
74
- }
64
+ if (mode === "json") silenceOutput();
75
65
  let result;
76
66
  try {
77
67
  result = await fn(mode);
@@ -115,16 +105,16 @@ const init = defineCommand({
115
105
  },
116
106
  async run({ args }) {
117
107
  await runCommand(args, async (mode) => {
118
- const { executeInit } = await import("./init-B53rR3yD.mjs");
108
+ const { executeInit } = await import("./init-tc3Rbgrf.mjs");
119
109
  return executeInit({
120
110
  dir: args.dir,
121
111
  force: args.force,
122
112
  template: args.template,
123
- yes: args.yes,
113
+ yes: mode === "json" ? true : args.yes,
124
114
  skipDeploy: args.skipDeploy,
125
115
  server: args.server
126
116
  }, mode === "json" ? { silent: true } : void 0);
127
- }, { setYes: true });
117
+ });
128
118
  }
129
119
  });
130
120
  const dev = defineCommand({
@@ -133,13 +123,18 @@ const dev = defineCommand({
133
123
  description: "Start a local development server"
134
124
  },
135
125
  args: {
136
- port: sharedArgs.port,
126
+ port: {
127
+ type: "string",
128
+ alias: "p",
129
+ description: "Port to listen on",
130
+ default: "3000"
131
+ },
137
132
  json: sharedArgs.json
138
133
  },
139
134
  async run({ args }) {
140
135
  await runCommand(args, async () => {
141
136
  const cwd = await setup({ agent: true });
142
- const { executeDev } = await import("./dev-C8o-p13B.mjs");
137
+ const { executeDev } = await import("./dev-g7sGt8qX.mjs");
143
138
  return executeDev({
144
139
  cwd,
145
140
  port: args.port
@@ -156,7 +151,7 @@ const test = defineCommand({
156
151
  async run({ args }) {
157
152
  await runCommand(args, async () => {
158
153
  const cwd = await setup();
159
- const { executeTest } = await import("./test-CgWhus_Z.mjs");
154
+ const { executeTest } = await import("./test-3Gq4pqH_.mjs");
160
155
  return executeTest(cwd);
161
156
  });
162
157
  }
@@ -180,24 +175,12 @@ const build = defineCommand({
180
175
  async run({ args }) {
181
176
  await runCommand(args, async () => {
182
177
  const cwd = await setup({ agent: true });
183
- if (!args.skipTests) {
184
- const { classifyVitestError, runVitest } = await import("./test-CgWhus_Z.mjs");
185
- const toCliError = (err) => {
186
- const { code, message } = classifyVitestError(err);
187
- return new CliError(code, message, "Re-run with --skipTests to build without tests", { cause: err });
188
- };
189
- try {
190
- runVitest(cwd);
191
- } catch (err) {
192
- throw toCliError(err);
193
- }
194
- }
195
- if (!args.skipTypecheck) {
196
- const { assertTypechecks } = await import("./_typecheck-gate-B1GcKZX-.mjs");
197
- await assertTypechecks(cwd);
198
- }
199
- const { executeBuild } = await import("./_bundler-DdmuZzeR.mjs");
200
- return executeBuild(cwd);
178
+ const { executeBuild } = await import("./build-Xq1xxoSg.mjs");
179
+ return executeBuild({
180
+ cwd,
181
+ skipTests: args.skipTests,
182
+ skipTypecheck: args.skipTypecheck
183
+ });
201
184
  });
202
185
  }
203
186
  });
@@ -221,12 +204,12 @@ const deploy = defineCommand({
221
204
  async run({ args }) {
222
205
  await runCommand(args, async () => {
223
206
  const cwd = await setup({ agent: true });
224
- const { executeDeploy } = await import("./deploy-D-dnt9L8.mjs");
207
+ const { executeDeploy } = await import("./deploy-Ci0X1gp2.mjs");
225
208
  return executeDeploy({
226
209
  cwd,
227
- ...args.server ? { server: args.server } : {},
228
- ...args.allowMissingSecrets ? { allowMissingSecrets: true } : {},
229
- ...args.skipTypecheck ? { skipTypecheck: true } : {}
210
+ server: args.server,
211
+ allowMissingSecrets: args.allowMissingSecrets,
212
+ skipTypecheck: args.skipTypecheck
230
213
  });
231
214
  });
232
215
  }
@@ -243,10 +226,10 @@ const del = defineCommand({
243
226
  async run({ args }) {
244
227
  await runCommand(args, async () => {
245
228
  const cwd = await setup();
246
- const { executeDelete } = await import("./delete-K24hW1ab.mjs");
229
+ const { executeDelete } = await import("./delete-kSXFLxek.mjs");
247
230
  return executeDelete({
248
231
  cwd,
249
- ...args.server ? { server: args.server } : {}
232
+ server: args.server
250
233
  });
251
234
  });
252
235
  }
@@ -274,9 +257,9 @@ const secret = defineCommand({
274
257
  async run({ args }) {
275
258
  await runCommand(args, async (mode) => {
276
259
  const cwd = await setup();
277
- const { executeSecretPut, readStdin } = await import("./secret-C4unwCEw.mjs");
260
+ const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-DOva9OGk.mjs");
278
261
  const value = mode === "json" ? await readStdin() : void 0;
279
- if (mode === "json" && !value) throw new CliError("no_input", "No value provided", "Pipe secret value to stdin");
262
+ if (mode === "json" && !value) throw new CliError(...NO_INPUT);
280
263
  return executeSecretPut(cwd, args.name, value, args.server);
281
264
  });
282
265
  }
@@ -298,7 +281,7 @@ const secret = defineCommand({
298
281
  async run({ args }) {
299
282
  await runCommand(args, async () => {
300
283
  const cwd = await setup();
301
- const { executeSecretDelete } = await import("./secret-C4unwCEw.mjs");
284
+ const { executeSecretDelete } = await import("./secret-DOva9OGk.mjs");
302
285
  return executeSecretDelete(cwd, args.name, args.server);
303
286
  });
304
287
  }
@@ -315,7 +298,7 @@ const secret = defineCommand({
315
298
  async run({ args }) {
316
299
  await runCommand(args, async () => {
317
300
  const cwd = await setup();
318
- const { executeSecretList } = await import("./secret-C4unwCEw.mjs");
301
+ const { executeSecretList } = await import("./secret-DOva9OGk.mjs");
319
302
  return executeSecretList(cwd, args.server);
320
303
  });
321
304
  }
@@ -350,7 +333,7 @@ const storage = defineCommand({
350
333
  },
351
334
  async run({ args }) {
352
335
  await runCommand(args, async () => {
353
- const { executeStorageStatus } = await import("./storage-tZM1J8qj.mjs");
336
+ const { executeStorageStatus } = await import("./storage-vM6HjDZZ.mjs");
354
337
  return executeStorageStatus(resolveStorageCwd(args.dir), args.server);
355
338
  });
356
339
  }
@@ -367,7 +350,7 @@ const storage = defineCommand({
367
350
  },
368
351
  async run({ args }) {
369
352
  await runCommand(args, async () => {
370
- const { executeStorageEnable } = await import("./storage-tZM1J8qj.mjs");
353
+ const { executeStorageEnable } = await import("./storage-vM6HjDZZ.mjs");
371
354
  return executeStorageEnable(resolveStorageCwd(args.dir), args.server);
372
355
  });
373
356
  }
@@ -389,7 +372,7 @@ const storage = defineCommand({
389
372
  },
390
373
  async run({ args }) {
391
374
  await runCommand(args, async () => {
392
- const { executeStorageDisable } = await import("./storage-tZM1J8qj.mjs");
375
+ const { executeStorageDisable } = await import("./storage-vM6HjDZZ.mjs");
393
376
  return executeStorageDisable(resolveStorageCwd(args.dir), {
394
377
  server: args.server,
395
378
  force: args.force
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { i as fileExists, r as errorMessage } from "./_utils-C502jKo8.mjs";
2
+ import { a as errorMessage$1, o as fileExists } from "./_utils-Ch0J4s6a.mjs";
3
3
  import { t as withPreservedNodeEnv } from "./_vite-env-Dg_QlVv0.mjs";
4
4
  import { existsSync, unlinkSync, writeFileSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import fs from "node:fs/promises";
7
- import { isTextAssetPath } from "@alexkroman1/aai";
7
+ import { isTextAssetPath } from "@alexkroman1/aai/utils";
8
8
  import { build } from "vite";
9
9
  //#region _default-html.ts
10
10
  /**
@@ -65,7 +65,7 @@ function writeTempHtml(root) {
65
65
  writeFileSync(htmlPath, DEFAULT_HTML);
66
66
  } catch (err) {
67
67
  cleanup();
68
- throw new Error(`Failed to write a temporary index.html at ${htmlPath} for the client build — is the project directory writable? (${errorMessage(err)})`, { cause: err });
68
+ throw new Error(`Failed to write a temporary index.html at ${htmlPath} for the client build — is the project directory writable? (${errorMessage$1(err)})`, { cause: err });
69
69
  }
70
70
  return cleanup;
71
71
  }
@@ -88,8 +88,7 @@ const DEFAULT_OUT_DIR = ".aai/client";
88
88
  *
89
89
  * Deduping states the peer contract in terms the bundler enforces, and it is
90
90
  * what a React app wants anyway: two copies of React in one bundle break
91
- * hooks. Guarded by `client-bundler.test.ts` and, for the half that has to
92
- * hold in the image, `aai-server/dockerfile-packaging.test.ts`.
91
+ * hooks. Guarded by `client-bundler.test.ts`.
93
92
  */
94
93
  const DEDUPED_PEERS = ["react", "react-dom"];
95
94
  /**
@@ -131,7 +130,7 @@ async function readClientDir(clientDir) {
131
130
  withFileTypes: true
132
131
  });
133
132
  } catch (err) {
134
- throw new Error(`Client build produced no output at ${clientDir}: ${errorMessage(err)}`, { cause: err });
133
+ throw new Error(`Client build produced no output at ${clientDir}: ${errorMessage$1(err)}`, { cause: err });
135
134
  }
136
135
  await Promise.all(entries.filter((entry) => entry.isFile()).map(async (entry) => {
137
136
  const abs = path.join(entry.parentPath, entry.name);
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { t as buildClient } from "./client-bundler-DO3GgO6p.mjs";
2
+ import { t as buildClient } from "./client-bundler-BWDkUeEP.mjs";
3
3
  export { buildClient };
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, u as ok } from "./_ui-DXZ9prrM.mjs";
3
- import { n as getServerInfo } from "./_agent-D39qatZJ.mjs";
4
- import { t as apiRequest } from "./_api-client-a6cPMebU.mjs";
2
+ import { n as log, u as ok } from "./_ui-8kOEB-JH.mjs";
3
+ import { n as getServerInfo } from "./_agent-D8zBb3M5.mjs";
4
+ import { n as apiRequest, t as HINT_NOT_DEPLOYED } from "./_api-client-MenP4-O7.mjs";
5
5
  //#region delete.ts
6
6
  async function runDelete(opts) {
7
7
  await apiRequest(`${opts.url}/${opts.slug}`, {
8
8
  method: "DELETE",
9
9
  apiKey: opts.apiKey,
10
10
  action: "delete",
11
- hints: { 404: "The agent may not be deployed. Check `.aai/project.json` for the correct slug." },
11
+ hints: { 404: HINT_NOT_DEPLOYED },
12
12
  ...opts.fetch ? { fetch: opts.fetch } : {}
13
13
  });
14
14
  }
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, t as fmtUrl, u as ok } from "./_ui-DXZ9prrM.mjs";
3
- import { r as errorMessage } from "./_utils-C502jKo8.mjs";
4
- import { buildAgentBundle } from "./_bundler-DdmuZzeR.mjs";
5
- import { o as writeProjectConfig } from "./_config-Czjhvaax.mjs";
6
- import { t as resolveServerEnv } from "./_server-common-B75oco06.mjs";
7
- import { i as resolveDeployTarget } from "./_agent-D39qatZJ.mjs";
8
- import { assertTypechecks } from "./_typecheck-gate-B1GcKZX-.mjs";
9
- import { t as apiRequest } from "./_api-client-a6cPMebU.mjs";
2
+ import { n as log, t as fmtUrl, u as ok } from "./_ui-8kOEB-JH.mjs";
3
+ import { a as errorMessage } from "./_utils-Ch0J4s6a.mjs";
4
+ import { t as buildAgentBundle } from "./_bundler-DFS4xxqE.mjs";
5
+ import { o as writeProjectConfig } from "./_config-D3F9km8X.mjs";
6
+ import { t as resolveServerEnv } from "./_server-common-CnaP_Urf.mjs";
7
+ import { i as resolveDeployTarget } from "./_agent-D8zBb3M5.mjs";
8
+ import { t as assertTypechecks } from "./_typecheck-gate-9IHWDnl1.mjs";
9
+ import { n as apiRequest } from "./_api-client-MenP4-O7.mjs";
10
10
  import { gzipSync } from "node:zlib";
11
11
  //#region _deploy.ts
12
12
  async function runDeploy(opts) {
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, r as parsePort, t as fmtUrl, u as ok } from "./_ui-DXZ9prrM.mjs";
3
- import { n as errorDetail } from "./_utils-C502jKo8.mjs";
2
+ import { n as log, r as parsePort, t as fmtUrl, u as ok } from "./_ui-8kOEB-JH.mjs";
3
+ import { i as errorDetail } from "./_utils-Ch0J4s6a.mjs";
4
4
  import path from "node:path";
5
5
  import { styleText } from "node:util";
6
6
  //#region dev.ts
@@ -11,7 +11,7 @@ import { styleText } from "node:util";
11
11
  async function executeDev(opts) {
12
12
  const port = parsePort(opts.port);
13
13
  const agentName = path.basename(path.resolve(opts.cwd));
14
- const { startDevServer } = await import("./_dev-server-BCbEUhmv.mjs");
14
+ const { startDevServer } = await import("./_dev-server-BBUWo0sb.mjs");
15
15
  let cleanup;
16
16
  let shuttingDown = false;
17
17
  const onSignal = () => {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { a as unwrapCancel, n as log, u as ok } from "./_ui-DXZ9prrM.mjs";
3
- import { i as fileExists, o as readJson, r as errorMessage, s as resolveCwd } from "./_utils-C502jKo8.mjs";
4
- import { r as isDevMode, t as getMonorepoRoot } from "./_agent-D39qatZJ.mjs";
2
+ import { a as unwrapCancel, n as log, u as ok } from "./_ui-8kOEB-JH.mjs";
3
+ import { a as errorMessage, c as readJson, l as resolveCwd, o as fileExists, t as AGENT_ENTRY } from "./_utils-Ch0J4s6a.mjs";
4
+ import { r as isDevMode, t as getMonorepoRoot } from "./_agent-D8zBb3M5.mjs";
5
5
  import path from "node:path";
6
6
  import { styleText } from "node:util";
7
7
  import * as p from "@clack/prompts";
@@ -15,7 +15,7 @@ async function promptProjectName(yes) {
15
15
  message: "What is your project named?",
16
16
  placeholder: DEFAULT_PROJECT_NAME,
17
17
  defaultValue: DEFAULT_PROJECT_NAME
18
- })) || DEFAULT_PROJECT_NAME;
18
+ }), "Setup cancelled") || DEFAULT_PROJECT_NAME;
19
19
  }
20
20
  /** Enable corepack so pnpm is available (scaffold declares packageManager: pnpm). */
21
21
  async function ensurePnpm() {
@@ -74,7 +74,7 @@ function resolveTargetDir(dir) {
74
74
  }
75
75
  /** Run deploy after init and return deploy metadata if successful. */
76
76
  async function tryDeploy(cwd, server) {
77
- const { executeDeploy } = await import("./deploy-D-dnt9L8.mjs");
77
+ const { executeDeploy } = await import("./deploy-Ci0X1gp2.mjs");
78
78
  try {
79
79
  const result = await executeDeploy({
80
80
  cwd,
@@ -92,21 +92,14 @@ async function tryDeploy(cwd, server) {
92
92
  }
93
93
  /** Scaffold the project, optionally showing a spinner. */
94
94
  async function scaffoldProject(dir, cwd, template, silent) {
95
- const { runInit } = await import("./_init-H-lw7czL.mjs");
96
- if (silent) {
97
- await runInit({
98
- targetDir: cwd,
99
- template
100
- });
101
- return;
102
- }
103
- const s = p.spinner();
104
- s.start(`Creating ${dir}`);
95
+ const { runInit } = await import("./_init-B-LEVTHx.mjs");
96
+ const s = silent ? void 0 : p.spinner();
97
+ s?.start(`Creating ${dir}`);
105
98
  await runInit({
106
99
  targetDir: cwd,
107
100
  template
108
101
  });
109
- s.stop("Project created");
102
+ s?.stop("Project created");
110
103
  }
111
104
  /** Print post-init instructions. */
112
105
  function printPostInitInfo(cwd, monorepoRoot) {
@@ -120,7 +113,7 @@ async function executeInit(opts, extra) {
120
113
  const dir = opts.dir ?? await promptProjectName(opts.yes);
121
114
  const monorepoRoot = getMonorepoRoot();
122
115
  const cwd = resolveTargetDir(dir);
123
- if (!opts.force && await fileExists(path.join(cwd, "agent.ts"))) throw new Error(`agent.ts already exists in this directory. Use ${styleText("cyanBright", "--force")} to overwrite.`);
116
+ if (!opts.force && await fileExists(path.join(cwd, "agent.ts"))) throw new Error(`${AGENT_ENTRY} already exists in this directory. Use ${styleText("cyanBright", "--force")} to overwrite.`);
124
117
  const template = opts.template ?? "simple";
125
118
  await scaffoldProject(dir, cwd, template, suppressUi);
126
119
  const installed = await installDeps(cwd, suppressUi);
@@ -1,21 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import { a as unwrapCancel, n as log, s as fail, u as ok } from "./_ui-DXZ9prrM.mjs";
3
- import { n as getServerInfo } from "./_agent-D39qatZJ.mjs";
4
- import { t as apiRequest } from "./_api-client-a6cPMebU.mjs";
2
+ import { a as unwrapCancel, n as log, s as fail, u as ok } from "./_ui-8kOEB-JH.mjs";
3
+ import { t as slugRequest } from "./_slug-api-19R5kZ0U.mjs";
5
4
  import * as p from "@clack/prompts";
6
5
  import { text } from "node:stream/consumers";
7
6
  //#region secret.ts
8
- async function secretRequest(cwd, pathSuffix, init, server) {
9
- const { serverUrl, slug, apiKey } = await getServerInfo(cwd, server);
10
- return {
11
- data: await apiRequest(`${serverUrl}/${slug}/secret${pathSuffix}`, {
12
- ...init,
13
- apiKey,
14
- action: "secret"
15
- }),
16
- slug
17
- };
18
- }
7
+ /**
8
+ * The one `no_input` failure for `secret put`, shared by the JSON-mode stdin
9
+ * path (cli.ts) and the TTY prompt path below so the two can't drift.
10
+ */
11
+ const NO_INPUT = [
12
+ "no_input",
13
+ "No value provided",
14
+ "Pipe secret value to stdin"
15
+ ];
19
16
  /** Read secret value from stdin (for non-TTY / piped input). */
20
17
  async function readStdin() {
21
18
  return (await text(process.stdin)).trim();
@@ -28,23 +25,27 @@ async function executeSecretPut(cwd, name, value, server) {
28
25
  let secretValue = value;
29
26
  if (!secretValue) {
30
27
  const result = unwrapCancel(await p.password({ message: `Enter value for ${name}` }));
31
- if (!result) return fail("no_input", "No value provided", "Pipe secret value to stdin");
28
+ if (!result) return fail(...NO_INPUT);
32
29
  secretValue = result;
33
30
  }
34
- const { slug } = await secretRequest(cwd, "", {
31
+ const { slug } = await slugRequest(cwd, "/secret", {
35
32
  method: "PUT",
36
- body: { [name]: secretValue }
33
+ body: { [name]: secretValue },
34
+ action: "secret"
37
35
  }, server);
38
36
  log.success(`Set ${name} for ${slug}`);
39
37
  return ok({ name });
40
38
  }
41
39
  async function executeSecretDelete(cwd, name, server) {
42
- const { slug } = await secretRequest(cwd, `/${encodeURIComponent(name)}`, { method: "DELETE" }, server);
40
+ const { slug } = await slugRequest(cwd, `/secret/${encodeURIComponent(name)}`, {
41
+ method: "DELETE",
42
+ action: "secret"
43
+ }, server);
43
44
  log.success(`Deleted ${name} from ${slug}`);
44
45
  return ok({ name });
45
46
  }
46
47
  async function executeSecretList(cwd, server) {
47
- const { data: { vars } } = await secretRequest(cwd, "", void 0, server);
48
+ const { data: { vars } } = await slugRequest(cwd, "/secret", { action: "secret" }, server);
48
49
  if (vars.length === 0) log.info("No secrets set. Use `aai secret put <name>` to add one.");
49
50
  else {
50
51
  log.message(`${vars.length} secret${vars.length === 1 ? "" : "s"}:`);
@@ -53,4 +54,4 @@ async function executeSecretList(cwd, server) {
53
54
  return ok({ secrets: vars });
54
55
  }
55
56
  //#endregion
56
- export { executeSecretDelete, executeSecretList, executeSecretPut, readStdin };
57
+ export { NO_INPUT, executeSecretDelete, executeSecretList, executeSecretPut, readStdin };
@@ -1,20 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, s as fail, u as ok } from "./_ui-DXZ9prrM.mjs";
3
- import { n as getServerInfo } from "./_agent-D39qatZJ.mjs";
4
- import { t as apiRequest } from "./_api-client-a6cPMebU.mjs";
2
+ import { n as log, s as fail, u as ok } from "./_ui-8kOEB-JH.mjs";
3
+ import { t as slugRequest } from "./_slug-api-19R5kZ0U.mjs";
5
4
  import * as p from "@clack/prompts";
6
5
  //#region storage.ts
7
6
  async function storageRequest(cwd, init, server) {
8
- const { serverUrl, slug, apiKey } = await getServerInfo(cwd, server);
9
- return {
10
- data: await apiRequest(`${serverUrl}/${slug}/storage`, {
11
- ...init,
12
- apiKey,
13
- action: "storage",
14
- hints: { 404: "The agent may not be deployed. Check `.aai/project.json` for the correct slug." }
15
- }),
16
- slug
17
- };
7
+ return slugRequest(cwd, "/storage", {
8
+ ...init,
9
+ action: "storage"
10
+ }, server);
18
11
  }
19
12
  async function executeStorageStatus(cwd, server) {
20
13
  const { data: { enabled }, slug } = await storageRequest(cwd, void 0, server);
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, s as fail, u as ok } from "./_ui-DXZ9prrM.mjs";
3
- import { r as errorMessage, t as errorCode } from "./_utils-C502jKo8.mjs";
2
+ import { n as log, s as fail, u as ok } from "./_ui-8kOEB-JH.mjs";
3
+ import { a as errorMessage, n as binFromPackageJson, r as errorCode } from "./_utils-Ch0J4s6a.mjs";
4
4
  import { createRequire } from "node:module";
5
- import { existsSync, readFileSync } from "node:fs";
5
+ import { existsSync } from "node:fs";
6
6
  import path from "node:path";
7
7
  import { execaSync } from "execa";
8
8
  //#region test.ts
@@ -19,12 +19,10 @@ import { execaSync } from "execa";
19
19
  */
20
20
  function resolveVitestCommand(cwd, resolve = createRequire(path.join(cwd, "package.json")).resolve) {
21
21
  try {
22
- const pkgPath = resolve("vitest/package.json");
23
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
24
- const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.vitest;
22
+ const bin = binFromPackageJson(resolve("vitest/package.json"), "vitest");
25
23
  if (bin) return {
26
24
  cmd: process.execPath,
27
- args: [path.join(path.dirname(pkgPath), bin)]
25
+ args: [bin]
28
26
  };
29
27
  } catch {}
30
28
  return {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync, readFileSync } from "node:fs";
2
+ import { a as errorMessage, n as binFromPackageJson } from "./_utils-Ch0J4s6a.mjs";
3
+ import { existsSync } from "node:fs";
3
4
  import path from "node:path";
4
- import { readFile } from "node:fs/promises";
5
5
  import { spawn } from "node:child_process";
6
6
  //#region typecheck.ts
7
7
  /**
@@ -55,17 +55,16 @@ function findTypescriptPackage(cwd) {
55
55
  function resolveTscEntry(cwd) {
56
56
  const dir = findTypescriptPackage(cwd);
57
57
  if (dir === void 0) throw new Error("no typescript package in the project's node_modules");
58
- const pkg = JSON.parse(readFileSync(path.join(dir, "package.json"), "utf-8"));
59
- const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.tsc;
58
+ const bin = binFromPackageJson(path.join(dir, "package.json"), "tsc");
60
59
  if (!bin) throw new Error("installed typescript package declares no tsc bin");
61
- return path.join(dir, bin);
60
+ return bin;
62
61
  }
63
62
  /**
64
63
  * Typecheck the project at `cwd` with its own tsconfig + compiler.
65
64
  * Skips (ok, skipped: true) when the project has no tsconfig.json.
66
65
  */
67
66
  async function typecheckProject(cwd) {
68
- if (!await readFile(path.join(cwd, "tsconfig.json"), "utf-8").then(() => true, () => false)) return {
67
+ if (!existsSync(path.join(cwd, "tsconfig.json"))) return {
69
68
  ok: true,
70
69
  skipped: true
71
70
  };
@@ -75,7 +74,7 @@ async function typecheckProject(cwd) {
75
74
  } catch (err) {
76
75
  return {
77
76
  ok: false,
78
- output: `tsconfig.json is present but TypeScript is not installed — add it (npm install -D typescript) or remove tsconfig.json: ${errMessage(err)}`
77
+ output: `tsconfig.json is present but TypeScript is not installed — add it (npm install -D typescript) or remove tsconfig.json: ${errorMessage(err)}`
79
78
  };
80
79
  }
81
80
  const result = await new Promise((resolve, reject) => {
@@ -122,8 +121,5 @@ async function typecheckProject(cwd) {
122
121
  output: `Type check failed:\n${result.output.trim()}`
123
122
  };
124
123
  }
125
- function errMessage(err) {
126
- return err instanceof Error ? err.message : String(err);
127
- }
128
124
  //#endregion
129
125
  export { typecheckProject };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexkroman1/aai-cli",
3
- "version": "5.1.0",
3
+ "version": "5.1.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "aai": "dist/cli.mjs"
@@ -35,8 +35,8 @@
35
35
  "p-timeout": "^7.0.1",
36
36
  "vite": "^8.1.5",
37
37
  "zod": "^4.4.3",
38
- "@alexkroman1/aai": "5.1.0",
39
- "@alexkroman1/aai-ui": "5.1.0"
38
+ "@alexkroman1/aai": "5.1.1",
39
+ "@alexkroman1/aai-ui": "5.1.1"
40
40
  },
41
41
  "devDependencies": {
42
42
  "playwright": "^1.61.1",