@alexkroman1/aai-cli 5.8.1 → 5.9.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.
package/README.md CHANGED
@@ -52,8 +52,12 @@ required credentials, and print the agent's public URL.
52
52
  outside one it runs `init`.
53
53
  - `--server <url>` targets a self-hosted platform; the origin is remembered
54
54
  in your user config after explicit approval.
55
+ - `aai login` is the only way to authenticate — it links an account already
56
+ signed in to the studio. An exported `ASSEMBLYAI_API_KEY` does not log you
57
+ in; in a project that variable is a provider credential for `aai dev`.
55
58
  - The API key is stored `0600` in your user config dir (`AAI_CONFIG_DIR`
56
- overrides the location).
59
+ overrides the location). Non-interactive callers point `AAI_CONFIG_DIR` at a
60
+ config dir holding a key from an interactive `aai login`.
57
61
 
58
62
  ## Documentation
59
63
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as readProjectConfig, i as readGlobalConfig, n as ensureApiKey, o as serverOrigin, t as approveServer } from "./_config-Y5V-5Krn.mjs";
2
+ import { a as readProjectConfig, i as readGlobalConfig, n as ensureApiKey, o as serverOrigin, t as approveServer } from "./_config-BJm2o795.mjs";
3
3
  import { existsSync } from "node:fs";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, o as CliError } from "./_ui-8kOEB-JH.mjs";
2
+ import { t as CliError } from "./_output-CC300DzW.mjs";
3
3
  import { a as errorMessage, c as readJson, d as writeJson } from "./_utils-Ch0J4s6a.mjs";
4
4
  import { mkdtempSync } from "node:fs";
5
5
  import path from "node:path";
@@ -131,43 +131,30 @@ async function writeGlobalConfig(configDir, data) {
131
131
  await writeJson(path.join(configDir, "config.json"), data, { mode: 384 });
132
132
  }
133
133
  /**
134
- * Persist the API key to the global config, warning (not failing) when the
135
- * config dir is unwritable — the key in hand still works for this run.
136
- */
137
- async function trySaveApiKey(dir, config, apiKey) {
138
- try {
139
- await writeGlobalConfig(dir, {
140
- ...config,
141
- apiKey
142
- });
143
- } catch (err) {
144
- log.warn(`Couldn't save your API key to ${path.join(dir, "config.json")}: ${errorMessage(err)} — you'll be prompted again next run.`);
145
- }
146
- }
147
- /**
148
134
  * The credential every platform command runs on.
149
135
  *
150
- * Two sources, in order: the key `aai login` saved, then
151
- * `ASSEMBLYAI_API_KEY` for non-interactive callers (CI, scripts, the eval
152
- * harnesses).
136
+ * ONE source: the key `aai login` saved to the global config. Nothing else
137
+ * authenticates the CLI.
138
+ *
139
+ * There is deliberately no "paste a key" prompt and no `ASSEMBLYAI_API_KEY`
140
+ * fallback. Both produced the same half-configured CLI — able to push,
141
+ * publish, and read/write another account's secrets while linked to no
142
+ * account the user could see in the studio — and both made `aai login`, the
143
+ * real onboarding path, optional in practice. The env var was the worse of
144
+ * the two: it applies to every invocation in a shell, it silently PERSISTED
145
+ * itself into the global config on first use (so the CLI stayed authenticated
146
+ * as that key long after the export was gone), and it collides with the
147
+ * variable the same name serves in a project `.env`, where it is a *provider*
148
+ * credential for the local dev server rather than a platform identity.
153
149
  *
154
- * There is deliberately NO "paste a key" prompt. Pasting one produced a
155
- * half-configured CLI able to push and publish while linked to no account
156
- * the user could see in the studio — and it made `aai login`, which is the
157
- * real onboarding path, optional in practice. It was also the riskier code
158
- * path: a hidden password prompt reads stdin, so a piped invocation could
159
- * have its input eaten and persisted as the API key.
150
+ * Non-interactive callers (CI, scripts, the eval harnesses) authenticate by
151
+ * pointing `AAI_CONFIG_DIR` at a config dir holding a key from an interactive
152
+ * `aai login`.
160
153
  */
161
154
  async function ensureApiKey(configDir) {
162
- const dir = configDir ?? getConfigDir();
163
- const config = await readGlobalConfig(dir);
155
+ const config = await readGlobalConfig(configDir ?? getConfigDir());
164
156
  if (config.apiKey) return config.apiKey;
165
- const envKey = process.env.ASSEMBLYAI_API_KEY;
166
- if (envKey) {
167
- await trySaveApiKey(dir, config, envKey);
168
- return envKey;
169
- }
170
- throw new CliError("not_logged_in", "You're not logged in.", "Run `aai login` to link your account, or set ASSEMBLYAI_API_KEY for non-interactive use.");
157
+ throw new CliError("not_logged_in", "You're not logged in.", "Run `aai login` to link your account. Non-interactive setups can point AAI_CONFIG_DIR at a config dir holding a logged-in key.");
171
158
  }
172
159
  //#endregion
173
160
  export { readProjectConfig as a, writeGlobalConfig as c, readGlobalConfig as i, writeProjectConfig as l, ensureApiKey as n, serverOrigin as o, getConfigDir as r, updateProjectConfig as s, approveServer as t };
package/dist/_config.d.ts CHANGED
@@ -64,16 +64,23 @@ export declare function writeGlobalConfig(configDir: string, data: GlobalConfig)
64
64
  /**
65
65
  * The credential every platform command runs on.
66
66
  *
67
- * Two sources, in order: the key `aai login` saved, then
68
- * `ASSEMBLYAI_API_KEY` for non-interactive callers (CI, scripts, the eval
69
- * harnesses).
67
+ * ONE source: the key `aai login` saved to the global config. Nothing else
68
+ * authenticates the CLI.
70
69
  *
71
- * There is deliberately NO "paste a key" prompt. Pasting one produced a
72
- * half-configured CLI — able to push and publish while linked to no account
73
- * the user could see in the studio and it made `aai login`, which is the
74
- * real onboarding path, optional in practice. It was also the riskier code
75
- * path: a hidden password prompt reads stdin, so a piped invocation could
76
- * have its input eaten and persisted as the API key.
70
+ * There is deliberately no "paste a key" prompt and no `ASSEMBLYAI_API_KEY`
71
+ * fallback. Both produced the same half-configured CLI — able to push,
72
+ * publish, and read/write another account's secrets while linked to no
73
+ * account the user could see in the studio and both made `aai login`, the
74
+ * real onboarding path, optional in practice. The env var was the worse of
75
+ * the two: it applies to every invocation in a shell, it silently PERSISTED
76
+ * itself into the global config on first use (so the CLI stayed authenticated
77
+ * as that key long after the export was gone), and it collides with the
78
+ * variable the same name serves in a project `.env`, where it is a *provider*
79
+ * credential for the local dev server rather than a platform identity.
80
+ *
81
+ * Non-interactive callers (CI, scripts, the eval harnesses) authenticate by
82
+ * pointing `AAI_CONFIG_DIR` at a config dir holding a key from an interactive
83
+ * `aai login`.
77
84
  */
78
85
  export declare function ensureApiKey(configDir?: string): Promise<string>;
79
86
  export {};
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { n as log } from "./_ui-8kOEB-JH.mjs";
2
+ import { n as log } from "./_ui-RZmPgrF6.mjs";
3
3
  import { a as errorMessage, r as errorCode } from "./_utils-Ch0J4s6a.mjs";
4
4
  import { n as fallbackHtmlPlugin } from "./client-bundler-yiWoXrgb.mjs";
5
5
  import { buildWorker } from "./worker-bundler.mjs";
6
6
  import { n as createWorkerEvaluator } from "./_bundler-Cjaxa2wi.mjs";
7
- import { n as ensureApiKey } from "./_config-Y5V-5Krn.mjs";
7
+ import { n as ensureApiKey } from "./_config-BJm2o795.mjs";
8
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";
@@ -51,7 +51,9 @@ function agentEnvWarnings(agentDef, env, shellEnv = process.env) {
51
51
  }
52
52
  async function resolveAgentEnv(root, agentDef) {
53
53
  const env = await resolveServerEnv(root);
54
- if (requiredProviderEnvVars(agentDef).includes("ASSEMBLYAI_API_KEY") && !env.ASSEMBLYAI_API_KEY) env.ASSEMBLYAI_API_KEY = await ensureApiKey();
54
+ const required = requiredProviderEnvVars(agentDef);
55
+ const hasShellKey = Boolean(process.env.ASSEMBLYAI_API_KEY);
56
+ if (required.includes("ASSEMBLYAI_API_KEY") && !env.ASSEMBLYAI_API_KEY && !hasShellKey) env.ASSEMBLYAI_API_KEY = await ensureApiKey();
55
57
  for (const warning of agentEnvWarnings(agentDef, env)) log.warn(warning);
56
58
  return env;
57
59
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { c as readJson, d as writeJson, s as isEexist } from "./_utils-Ch0J4s6a.mjs";
3
- import { r as isDevMode, t as getMonorepoRoot } from "./_agent-2nVugrN3.mjs";
4
- import { REPO_URL, downloadAndMergeTemplate } from "./_templates-BfyRyE7z.mjs";
3
+ import { r as isDevMode, t as getMonorepoRoot } from "./_agent-BPEXSdWX.mjs";
4
+ import { REPO_URL, downloadAndMergeTemplate } from "./_templates-DDx08LIG.mjs";
5
5
  import path from "node:path";
6
6
  import fs from "node:fs/promises";
7
7
  //#region _init.ts
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { styleText } from "node:util";
3
- import * as p from "@clack/prompts";
4
2
  //#region _output.ts
5
3
  /**
6
4
  * Determine output mode from CLI flags and TTY state.
@@ -72,43 +70,4 @@ var CliError = class extends Error {
72
70
  }
73
71
  };
74
72
  //#endregion
75
- //#region _ui.ts
76
- const noop = () => {};
77
- let silenced = false;
78
- /** Log instance that delegates to clack (human mode) or no-ops (JSON mode). */
79
- const log = new Proxy(p.log, { get(target, prop, receiver) {
80
- return silenced ? noop : Reflect.get(target, prop, receiver);
81
- } });
82
- /** Replace all log methods with no-ops. Call once in JSON mode. */
83
- function silenceOutput() {
84
- silenced = true;
85
- }
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") {
91
- if (p.isCancel(result)) {
92
- p.cancel(message);
93
- process.exit(0);
94
- }
95
- return result;
96
- }
97
- /** Format a URL for display. */
98
- function fmtUrl(url) {
99
- return styleText("cyanBright", url);
100
- }
101
- /**
102
- * Parse and validate a port string. Returns the numeric port or throws.
103
- *
104
- * Deliberately zod-free: this module loads on every CLI invocation
105
- * (including `aai --help`), and keeping zod off that path is the same
106
- * startup-cost invariant `_utils.ts` documents for its error helpers.
107
- */
108
- function parsePort(raw) {
109
- const port = raw.trim() === "" ? NaN : Number(raw);
110
- if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error(`Invalid port: ${raw}. Must be a number between 0 and 65535.`);
111
- return port;
112
- }
113
- //#endregion
114
- export { unwrapCancel as a, getOutputMode as c, writeLine as d, silenceOutput as i, installStdoutGuard as l, log as n, CliError as o, parsePort as r, fail as s, fmtUrl as t, ok as u };
73
+ export { ok as a, installStdoutGuard as i, fail as n, writeLine as o, getOutputMode as r, CliError as t };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as getServerInfo } from "./_agent-2nVugrN3.mjs";
2
+ import { n as getServerInfo } from "./_agent-BPEXSdWX.mjs";
3
3
  import { n as apiRequest, t as HINT_NOT_DEPLOYED } from "./_api-client-B-upMGkc.mjs";
4
4
  //#region _slug-api.ts
5
5
  /**
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as errorMessage } from "./_utils-Ch0J4s6a.mjs";
3
- import { t as getMonorepoRoot } from "./_agent-2nVugrN3.mjs";
3
+ import { t as getMonorepoRoot } from "./_agent-BPEXSdWX.mjs";
4
4
  import { existsSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import fs from "node:fs/promises";
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, o as CliError } from "./_ui-8kOEB-JH.mjs";
2
+ import { t as CliError } from "./_output-CC300DzW.mjs";
3
+ import { n as log } from "./_ui-RZmPgrF6.mjs";
3
4
  import { typecheckProject } from "./typecheck.mjs";
4
5
  //#region _typecheck-gate.ts
5
6
  /**
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ import { styleText } from "node:util";
3
+ import * as p from "@clack/prompts";
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
+ /**
16
+ * Unwrap a clack prompt result, exiting cleanly if the user cancelled.
17
+ * `message` lets the caller name what was cancelled (e.g. "Setup cancelled").
18
+ */
19
+ function unwrapCancel(result, message = "Cancelled") {
20
+ if (p.isCancel(result)) {
21
+ p.cancel(message);
22
+ process.exit(0);
23
+ }
24
+ return result;
25
+ }
26
+ /** Format a URL for display. */
27
+ function fmtUrl(url) {
28
+ return styleText("cyanBright", url);
29
+ }
30
+ /**
31
+ * Parse and validate a port string. Returns the numeric port or throws.
32
+ *
33
+ * Deliberately zod-free: this module loads on every CLI invocation
34
+ * (including `aai --help`), and keeping zod off that path is the same
35
+ * startup-cost invariant `_utils.ts` documents for its error helpers.
36
+ */
37
+ function parsePort(raw) {
38
+ const port = raw.trim() === "" ? NaN : Number(raw);
39
+ if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error(`Invalid port: ${raw}. Must be a number between 0 and 65535.`);
40
+ return port;
41
+ }
42
+ //#endregion
43
+ export { unwrapCancel as a, silenceOutput as i, log as n, parsePort as r, fmtUrl as t };
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, o as CliError, u as ok } from "./_ui-8kOEB-JH.mjs";
2
+ import { a as ok, t as CliError } from "./_output-CC300DzW.mjs";
3
+ import { n as log } from "./_ui-RZmPgrF6.mjs";
3
4
  import { r as evalWorkerBundle, t as buildAgentBundle } from "./_bundler-Cjaxa2wi.mjs";
4
- import { assertTypechecks } from "./_typecheck-gate-DvE8S3aQ.mjs";
5
- import { classifyVitestError, runVitest } from "./test-3Gq4pqH_.mjs";
5
+ import { assertTypechecks } from "./_typecheck-gate-BT4iPz7A.mjs";
6
+ import { classifyVitestError, runVitest } from "./test-CkXvfcpq.mjs";
6
7
  //#region build.ts
7
8
  /**
8
9
  * `aai build` — bundle the agent without deploying, behind the same gates
package/dist/cli.mjs CHANGED
@@ -1,5 +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-8kOEB-JH.mjs";
2
+ import { i as installStdoutGuard, n as fail, o as writeLine, r as getOutputMode, t as CliError } from "./_output-CC300DzW.mjs";
3
+ import { i as silenceOutput, n as log } from "./_ui-RZmPgrF6.mjs";
3
4
  import { a as errorMessage, l as resolveCwd, o as fileExists, t as AGENT_ENTRY } from "./_utils-Ch0J4s6a.mjs";
4
5
  import { existsSync, readFileSync } from "node:fs";
5
6
  import path from "node:path";
@@ -165,7 +166,7 @@ const list = defineCommand({
165
166
  async run({ args }) {
166
167
  await runCommand(args, async () => {
167
168
  const cwd = resolveCwd();
168
- const { executeList } = await import("./studio-_UBBvh5V.mjs");
169
+ const { executeList } = await import("./studio-B6zDNPPr.mjs");
169
170
  return executeList({
170
171
  cwd,
171
172
  server: args.server
@@ -200,7 +201,7 @@ const pull = defineCommand({
200
201
  async run({ args }) {
201
202
  await runCommand(args, async () => {
202
203
  const cwd = resolveCwd();
203
- const { executePull } = await import("./studio-_UBBvh5V.mjs");
204
+ const { executePull } = await import("./studio-B6zDNPPr.mjs");
204
205
  return executePull({
205
206
  cwd,
206
207
  project: args.project,
@@ -228,7 +229,7 @@ const push = defineCommand({
228
229
  async run({ args }) {
229
230
  await runCommand(args, async () => {
230
231
  const cwd = await setup({ agent: true });
231
- const { executePush } = await import("./studio-_UBBvh5V.mjs");
232
+ const { executePush } = await import("./studio-B6zDNPPr.mjs");
232
233
  return executePush({
233
234
  cwd,
234
235
  server: args.server,
@@ -258,7 +259,7 @@ const publish = defineCommand({
258
259
  async run({ args }) {
259
260
  await runCommand(args, async () => {
260
261
  const cwd = await setup({ agent: true });
261
- const { executePublish } = await import("./studio-_UBBvh5V.mjs");
262
+ const { executePublish } = await import("./studio-B6zDNPPr.mjs");
262
263
  return executePublish({
263
264
  cwd,
264
265
  server: args.server,
@@ -316,7 +317,7 @@ const init = defineCommand({
316
317
  },
317
318
  async run({ args }) {
318
319
  await runCommand(args, async (mode) => {
319
- const { executeInit } = await import("./init-BpBbttOv.mjs");
320
+ const { executeInit } = await import("./init-BYGp3Usr.mjs");
320
321
  return executeInit({
321
322
  dir: args.dir,
322
323
  force: args.force,
@@ -345,7 +346,7 @@ const dev = defineCommand({
345
346
  async run({ args }) {
346
347
  await runCommand(args, async () => {
347
348
  const cwd = await setup({ agent: true });
348
- const { executeDev } = await import("./dev-C4KyxouE.mjs");
349
+ const { executeDev } = await import("./dev-HBCgChsA.mjs");
349
350
  return executeDev({
350
351
  cwd,
351
352
  port: args.port
@@ -362,7 +363,7 @@ const test = defineCommand({
362
363
  async run({ args }) {
363
364
  await runCommand(args, async () => {
364
365
  const cwd = await setup();
365
- const { executeTest } = await import("./test-3Gq4pqH_.mjs");
366
+ const { executeTest } = await import("./test-CkXvfcpq.mjs");
366
367
  return executeTest(cwd);
367
368
  });
368
369
  }
@@ -386,7 +387,7 @@ const build = defineCommand({
386
387
  async run({ args }) {
387
388
  await runCommand(args, async () => {
388
389
  const cwd = await setup({ agent: true });
389
- const { executeBuild } = await import("./build-BXwDB78d.mjs");
390
+ const { executeBuild } = await import("./build-WdGtFsSx.mjs");
390
391
  return executeBuild({
391
392
  cwd,
392
393
  skipTests: args.skipTests,
@@ -420,7 +421,7 @@ const deploy = defineCommand({
420
421
  async run({ args }) {
421
422
  await runCommand(args, async () => {
422
423
  const cwd = await setup({ agent: true });
423
- const { executeDeploy } = await import("./deploy-Cp-wgME3.mjs");
424
+ const { executeDeploy } = await import("./deploy-Bij1jES6.mjs");
424
425
  return executeDeploy({
425
426
  cwd,
426
427
  server: args.server,
@@ -443,7 +444,7 @@ const del = defineCommand({
443
444
  async run({ args }) {
444
445
  await runCommand(args, async () => {
445
446
  const cwd = await setup();
446
- const { executeDelete } = await import("./delete-DRNfvczK.mjs");
447
+ const { executeDelete } = await import("./delete-Dr1Jn65f.mjs");
447
448
  return executeDelete({
448
449
  cwd,
449
450
  server: args.server
@@ -474,7 +475,7 @@ const secret = defineCommand({
474
475
  async run({ args }) {
475
476
  await runCommand(args, async (mode) => {
476
477
  const cwd = await setup();
477
- const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-Dr0qnxeb.mjs");
478
+ const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-vhGe-r2a.mjs");
478
479
  const value = mode === "json" ? await readStdin() : void 0;
479
480
  if (mode === "json" && !value) throw new CliError(...NO_INPUT);
480
481
  return executeSecretPut(cwd, args.name, value, args.server);
@@ -498,7 +499,7 @@ const secret = defineCommand({
498
499
  async run({ args }) {
499
500
  await runCommand(args, async () => {
500
501
  const cwd = await setup();
501
- const { executeSecretDelete } = await import("./secret-Dr0qnxeb.mjs");
502
+ const { executeSecretDelete } = await import("./secret-vhGe-r2a.mjs");
502
503
  return executeSecretDelete(cwd, args.name, args.server);
503
504
  });
504
505
  }
@@ -515,7 +516,7 @@ const secret = defineCommand({
515
516
  async run({ args }) {
516
517
  await runCommand(args, async () => {
517
518
  const cwd = await setup();
518
- const { executeSecretList } = await import("./secret-Dr0qnxeb.mjs");
519
+ const { executeSecretList } = await import("./secret-vhGe-r2a.mjs");
519
520
  return executeSecretList(cwd, args.server);
520
521
  });
521
522
  }
@@ -550,7 +551,7 @@ const storage = defineCommand({
550
551
  },
551
552
  async run({ args }) {
552
553
  await runCommand(args, async () => {
553
- const { executeStorageStatus } = await import("./storage-CoQB8d-u.mjs");
554
+ const { executeStorageStatus } = await import("./storage-CMPsAmch.mjs");
554
555
  return executeStorageStatus(resolveStorageCwd(args.dir), args.server);
555
556
  });
556
557
  }
@@ -567,7 +568,7 @@ const storage = defineCommand({
567
568
  },
568
569
  async run({ args }) {
569
570
  await runCommand(args, async () => {
570
- const { executeStorageEnable } = await import("./storage-CoQB8d-u.mjs");
571
+ const { executeStorageEnable } = await import("./storage-CMPsAmch.mjs");
571
572
  return executeStorageEnable(resolveStorageCwd(args.dir), args.server);
572
573
  });
573
574
  }
@@ -589,7 +590,7 @@ const storage = defineCommand({
589
590
  },
590
591
  async run({ args }) {
591
592
  await runCommand(args, async () => {
592
- const { executeStorageDisable } = await import("./storage-CoQB8d-u.mjs");
593
+ const { executeStorageDisable } = await import("./storage-CMPsAmch.mjs");
593
594
  return executeStorageDisable(resolveStorageCwd(args.dir), {
594
595
  server: args.server,
595
596
  force: args.force
@@ -610,7 +611,7 @@ const login = defineCommand({
610
611
  },
611
612
  async run({ args }) {
612
613
  await runCommand(args, async () => {
613
- const { executeLogin } = await import("./login-AA_UdRI-.mjs");
614
+ const { executeLogin } = await import("./login-CXazkkcR.mjs");
614
615
  return executeLogin({ server: args.server });
615
616
  });
616
617
  }
@@ -623,7 +624,7 @@ const templates = defineCommand({
623
624
  args: { json: sharedArgs.json },
624
625
  async run({ args }) {
625
626
  await runCommand(args, async (mode) => {
626
- const { listTemplates } = await import("./_templates-BfyRyE7z.mjs");
627
+ const { listTemplates } = await import("./_templates-DDx08LIG.mjs");
627
628
  const names = await listTemplates();
628
629
  if (mode === "human") {
629
630
  for (const name of names) log.message(name);
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, u as ok } from "./_ui-8kOEB-JH.mjs";
3
- import { l as writeProjectConfig } from "./_config-Y5V-5Krn.mjs";
4
- import { i as resolveDeployTarget, n as getServerInfo } from "./_agent-2nVugrN3.mjs";
2
+ import { a as ok } from "./_output-CC300DzW.mjs";
3
+ import { n as log } from "./_ui-RZmPgrF6.mjs";
4
+ import { l as writeProjectConfig } from "./_config-BJm2o795.mjs";
5
+ import { i as resolveDeployTarget, n as getServerInfo } from "./_agent-BPEXSdWX.mjs";
5
6
  import { n as apiRequest, t as HINT_NOT_DEPLOYED } from "./_api-client-B-upMGkc.mjs";
6
7
  //#region delete.ts
7
8
  async function runDelete(opts) {
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, t as fmtUrl, u as ok } from "./_ui-8kOEB-JH.mjs";
2
+ import { a as ok } from "./_output-CC300DzW.mjs";
3
+ import { n as log, t as fmtUrl } from "./_ui-RZmPgrF6.mjs";
3
4
  import { a as errorMessage } from "./_utils-Ch0J4s6a.mjs";
4
5
  import { t as buildAgentBundle } from "./_bundler-Cjaxa2wi.mjs";
5
- import { s as updateProjectConfig } from "./_config-Y5V-5Krn.mjs";
6
+ import { s as updateProjectConfig } from "./_config-BJm2o795.mjs";
6
7
  import { t as resolveServerEnv } from "./_server-common-CnaP_Urf.mjs";
7
- import { i as resolveDeployTarget } from "./_agent-2nVugrN3.mjs";
8
- import { assertTypechecks } from "./_typecheck-gate-DvE8S3aQ.mjs";
8
+ import { i as resolveDeployTarget } from "./_agent-BPEXSdWX.mjs";
9
+ import { assertTypechecks } from "./_typecheck-gate-BT4iPz7A.mjs";
9
10
  import { n as apiRequest } from "./_api-client-B-upMGkc.mjs";
10
11
  import { gzipSync } from "node:zlib";
11
12
  //#region _deploy.ts
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, r as parsePort, t as fmtUrl, u as ok } from "./_ui-8kOEB-JH.mjs";
2
+ import { a as ok } from "./_output-CC300DzW.mjs";
3
+ import { n as log, r as parsePort, t as fmtUrl } from "./_ui-RZmPgrF6.mjs";
3
4
  import { i as errorDetail } from "./_utils-Ch0J4s6a.mjs";
4
5
  import path from "node:path";
5
6
  import { styleText } from "node:util";
@@ -11,7 +12,7 @@ import { styleText } from "node:util";
11
12
  async function executeDev(opts) {
12
13
  const port = parsePort(opts.port);
13
14
  const agentName = path.basename(path.resolve(opts.cwd));
14
- const { startDevServer } = await import("./_dev-server-BB5N8kdh.mjs");
15
+ const { startDevServer } = await import("./_dev-server-Cnf4jNzE.mjs");
15
16
  let cleanup;
16
17
  let shuttingDown = false;
17
18
  const onSignal = () => {
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { a as unwrapCancel, n as log, u as ok } from "./_ui-8kOEB-JH.mjs";
2
+ import { a as ok } from "./_output-CC300DzW.mjs";
3
+ import { a as unwrapCancel, n as log } from "./_ui-RZmPgrF6.mjs";
3
4
  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-2nVugrN3.mjs";
5
+ import { r as isDevMode, t as getMonorepoRoot } from "./_agent-BPEXSdWX.mjs";
5
6
  import path from "node:path";
6
7
  import { styleText } from "node:util";
7
8
  import * as p from "@clack/prompts";
@@ -74,7 +75,7 @@ function resolveTargetDir(dir) {
74
75
  }
75
76
  /** Publish after init and return deploy metadata if successful. */
76
77
  async function tryPublish(cwd, server) {
77
- const { executePublish } = await import("./studio-_UBBvh5V.mjs");
78
+ const { executePublish } = await import("./studio-B6zDNPPr.mjs");
78
79
  try {
79
80
  const result = await executePublish({
80
81
  cwd,
@@ -93,7 +94,7 @@ async function tryPublish(cwd, server) {
93
94
  }
94
95
  /** Scaffold the project, optionally showing a spinner. */
95
96
  async function scaffoldProject(dir, cwd, template, silent) {
96
- const { runInit } = await import("./_init-Dei2JRmn.mjs");
97
+ const { runInit } = await import("./_init-DVNeyGSl.mjs");
97
98
  const s = silent ? void 0 : p.spinner();
98
99
  s?.start(`Creating ${dir}`);
99
100
  await runInit({
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, o as CliError, u as ok } from "./_ui-8kOEB-JH.mjs";
3
- import { c as writeGlobalConfig, i as readGlobalConfig, r as getConfigDir, t as approveServer } from "./_config-Y5V-5Krn.mjs";
4
- import { a as resolveServerUrl } from "./_agent-2nVugrN3.mjs";
2
+ import { a as ok, t as CliError } from "./_output-CC300DzW.mjs";
3
+ import { n as log } from "./_ui-RZmPgrF6.mjs";
4
+ import { c as writeGlobalConfig, i as readGlobalConfig, r as getConfigDir, t as approveServer } from "./_config-BJm2o795.mjs";
5
+ import { a as resolveServerUrl } from "./_agent-BPEXSdWX.mjs";
5
6
  import { spawn } from "node:child_process";
6
7
  import { setTimeout } from "node:timers/promises";
7
8
  import { randomBytes } from "node:crypto";
@@ -103,7 +104,7 @@ async function pollForGrant(fetchFn, serverUrl, code, opts) {
103
104
  }
104
105
  }
105
106
  function requireTty() {
106
- if (!process.stdin.isTTY) throw new CliError("login_interactive", "`aai login` is interactive and needs a TTY.", "Non-interactive setups can set the ASSEMBLYAI_API_KEY environment variable instead.");
107
+ if (!process.stdin.isTTY) throw new CliError("login_interactive", "`aai login` is interactive and needs a TTY.", "Log in on a machine with a terminal, then point AAI_CONFIG_DIR at that config dir — logging in is the only way to authenticate.");
107
108
  }
108
109
  function openerFor(platform) {
109
110
  if (platform === "darwin") return ["open", []];
@@ -144,7 +145,7 @@ async function executeLogin(opts, deps = {}) {
144
145
  const globalConfig = await readGlobalConfig();
145
146
  const serverUrl = resolveServerUrl(opts.server, void 0, globalConfig.approvedServers ?? []);
146
147
  if (opts.server) await approveServer(serverUrl);
147
- if ((await jsonBody(await reachable(fetchFn, `${serverUrl}/studio/auth`, serverUrl), "Reading the server's login configuration")).mode === "none") throw new CliError("login_unavailable", "This server has no browser login configured, so there is no account to link.", "Set the ASSEMBLYAI_API_KEY environment variable insteadit's the only other way to authenticate.");
148
+ if ((await jsonBody(await reachable(fetchFn, `${serverUrl}/studio/auth`, serverUrl), "Reading the server's login configuration")).mode === "none") throw new CliError("login_unavailable", "This server has no browser login configured, so there is no account to link.", "Point `--server` at a platform with browser login configured linking an account there is the only way to authenticate.");
148
149
  const code = randomBytes(32).toString("base64url");
149
150
  const linkUrl = `${serverUrl}/?cli-link=${code}`;
150
151
  log.info(`Opening the browser to link your account…\n ${linkUrl}`);
@@ -929,8 +929,10 @@ Never hardcode secrets in agent code.
929
929
  `ctx.env`.
930
930
  - **Production:** `npx @alexkroman1/aai-cli secret put NAME`
931
931
  - **Access:** `ctx.env.MY_KEY` in tool execute functions.
932
- - **AssemblyAI key:** CLI prompts on first use, stores globally. No `.env`
933
- entry needed. For CI, set `ASSEMBLYAI_API_KEY` env var.
932
+ - **AssemblyAI key:** `npx @alexkroman1/aai-cli login` links your account and
933
+ stores the key globally the only way the CLI authenticates. No `.env`
934
+ entry needed. For CI, point `AAI_CONFIG_DIR` at a config dir holding a
935
+ logged-in key (an exported `ASSEMBLYAI_API_KEY` does not authenticate).
934
936
 
935
937
  ## Voice rules for systemPrompt
936
938
 
@@ -11,15 +11,15 @@
11
11
  "publish:agent": "aai publish"
12
12
  },
13
13
  "dependencies": {
14
- "@alexkroman1/aai": "^5.8.1",
15
- "@alexkroman1/aai-ui": "^5.8.1",
14
+ "@alexkroman1/aai": "^5.9.0",
15
+ "@alexkroman1/aai-ui": "^5.9.0",
16
16
  "react": "^19.2.8",
17
17
  "react-dom": "^19.2.8",
18
18
  "tailwindcss": "^4.0.0",
19
19
  "zod": "^4.4.3"
20
20
  },
21
21
  "devDependencies": {
22
- "@alexkroman1/aai-cli": "^5.8.1",
22
+ "@alexkroman1/aai-cli": "^5.9.0",
23
23
  "@tailwindcss/vite": "^4.3.3",
24
24
  "@types/node": "^26.1.1",
25
25
  "@types/react": "^19.2.17",
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
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-CGJSST9B.mjs";
2
+ import { a as ok, n as fail } from "./_output-CC300DzW.mjs";
3
+ import { a as unwrapCancel, n as log } from "./_ui-RZmPgrF6.mjs";
4
+ import { t as slugRequest } from "./_slug-api-CQw1YGR5.mjs";
4
5
  import * as p from "@clack/prompts";
5
6
  import { text } from "node:stream/consumers";
6
7
  //#region secret.ts
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, s as fail, u as ok } from "./_ui-8kOEB-JH.mjs";
3
- import { t as slugRequest } from "./_slug-api-CGJSST9B.mjs";
2
+ import { a as ok, n as fail } from "./_output-CC300DzW.mjs";
3
+ import { n as log } from "./_ui-RZmPgrF6.mjs";
4
+ import { t as slugRequest } from "./_slug-api-CQw1YGR5.mjs";
4
5
  import * as p from "@clack/prompts";
5
6
  //#region storage.ts
6
7
  async function storageRequest(cwd, init, server) {
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, o as CliError, t as fmtUrl, u as ok } from "./_ui-8kOEB-JH.mjs";
3
- import { s as updateProjectConfig } from "./_config-Y5V-5Krn.mjs";
2
+ import { a as ok, t as CliError } from "./_output-CC300DzW.mjs";
3
+ import { n as log, t as fmtUrl } from "./_ui-RZmPgrF6.mjs";
4
+ import { s as updateProjectConfig } from "./_config-BJm2o795.mjs";
4
5
  import { t as resolveServerEnv } from "./_server-common-CnaP_Urf.mjs";
5
- import { i as resolveDeployTarget } from "./_agent-2nVugrN3.mjs";
6
- import { layerScaffold } from "./_templates-BfyRyE7z.mjs";
6
+ import { i as resolveDeployTarget } from "./_agent-BPEXSdWX.mjs";
7
+ import { layerScaffold } from "./_templates-DDx08LIG.mjs";
7
8
  import { n as apiRequest } from "./_api-client-B-upMGkc.mjs";
8
9
  import path from "node:path";
9
10
  import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
@@ -290,7 +291,7 @@ async function syncEnvSecrets(cwd, serverUrl, apiKey, slug) {
290
291
  }
291
292
  async function executePublish(opts) {
292
293
  if (!opts.skipTypecheck) {
293
- const { assertTypechecks } = await import("./_typecheck-gate-DvE8S3aQ.mjs");
294
+ const { assertTypechecks } = await import("./_typecheck-gate-BT4iPz7A.mjs");
294
295
  await assertTypechecks(opts.cwd);
295
296
  }
296
297
  const pushed = await pushProject(opts);
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { n as log, s as fail, u as ok } from "./_ui-8kOEB-JH.mjs";
2
+ import { a as ok, n as fail } from "./_output-CC300DzW.mjs";
3
+ import { n as log } from "./_ui-RZmPgrF6.mjs";
3
4
  import { a as errorMessage, n as binFromPackageJson, r as errorCode } from "./_utils-Ch0J4s6a.mjs";
4
5
  import { createRequire } from "node:module";
5
6
  import { existsSync } from "node:fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexkroman1/aai-cli",
3
- "version": "5.8.1",
3
+ "version": "5.9.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "aai": "dist/cli.mjs"
@@ -37,8 +37,8 @@
37
37
  "p-timeout": "^7.0.1",
38
38
  "vite": "^8.1.5",
39
39
  "zod": "^4.4.3",
40
- "@alexkroman1/aai-ui": "5.8.1",
41
- "@alexkroman1/aai": "5.8.1"
40
+ "@alexkroman1/aai": "5.9.0",
41
+ "@alexkroman1/aai-ui": "5.9.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "playwright": "^1.61.1",