@alexkroman1/aai-cli 6.5.0 → 6.5.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.
Files changed (48) hide show
  1. package/dist/{_agent-vGW5SBnX.mjs → _agent-DpH2pBJd.mjs} +1 -5
  2. package/dist/{_bundler-BapCUUJN.mjs → _bundler-C2BDwU7r.mjs} +5 -7
  3. package/dist/{_dev-server-DQ1t9sbw.mjs → _dev-server-LLLWnFBs.mjs} +3 -3
  4. package/dist/_e2e-test-utils.d.ts +17 -17
  5. package/dist/{_init-CpISqoR8.mjs → _init-C57bWAQ8.mjs} +2 -2
  6. package/dist/{_slug-api-D2heILuC.mjs → _slug-api-BxrsJXVI.mjs} +3 -3
  7. package/dist/_slug-api.d.ts +1 -1
  8. package/dist/{_api-client-LgLksMhN.mjs → _studio-U3jhKlA3.mjs} +105 -2
  9. package/dist/_studio.d.ts +11 -0
  10. package/dist/{_templates-iDGjGiPf.mjs → _templates-Dxb_P2Wz.mjs} +1 -1
  11. package/dist/bin.d.mts +2 -0
  12. package/dist/{build-BO1Ni6oJ.mjs → build-Dfza2pRI.mjs} +2 -2
  13. package/dist/cli.mjs +43 -42
  14. package/dist/{client-bundler-B8Q9F8gJ.mjs → client-bundler-BEIqgOtd.mjs} +2 -2
  15. package/dist/client-bundler.mjs +1 -1
  16. package/dist/{delete-4I0uNR4a.mjs → delete-vbpjGzqs.mjs} +3 -3
  17. package/dist/{deploy-DJ3HRcia.mjs → deploy-B8lubiRT.mjs} +3 -4
  18. package/dist/{dev-C6SWaAZP.mjs → dev-Uq5ujP8a.mjs} +1 -1
  19. package/dist/{eject-Zrzk5KV3.mjs → eject-31gjtaHF.mjs} +2 -2
  20. package/dist/{init-BTRGiPQr.mjs → init-l6xfU4xX.mjs} +3 -3
  21. package/dist/{login-k0Z3VQu9.mjs → login-C71-qz8F.mjs} +1 -1
  22. package/dist/scaffold/package.json +3 -3
  23. package/dist/{secret-DzSQx1Ds.mjs → secret-BuMuFR4B.mjs} +2 -2
  24. package/dist/{storage-C-Do0mIA.mjs → storage-DzRZ-eCw.mjs} +2 -2
  25. package/dist/{studio-BGVmCA2G.mjs → studio-BCNUpDgP.mjs} +4 -5
  26. package/dist/templates/retail/resolve.ts +16 -0
  27. package/dist/templates/retail/store.ts +20 -0
  28. package/dist/templates/retail/tools/cancel_pending_order.ts +2 -5
  29. package/dist/templates/retail/tools/exchange_delivered_order_items.ts +2 -5
  30. package/dist/templates/retail/tools/get_order_details.ts +4 -6
  31. package/dist/templates/retail/tools/get_user_details.ts +2 -7
  32. package/dist/templates/retail/tools/modify_pending_order_address.ts +2 -5
  33. package/dist/templates/retail/tools/modify_pending_order_items.ts +2 -5
  34. package/dist/templates/retail/tools/modify_pending_order_payment.ts +2 -5
  35. package/dist/templates/retail/tools/modify_user_address.ts +2 -7
  36. package/dist/templates/retail/tools/return_delivered_order_items.ts +2 -5
  37. package/dist/templates/transcription-workflow/agent.test.ts +2 -3
  38. package/dist/templates/transcription-workflow/workflows/batch.ts +2 -13
  39. package/dist/templates/transcription-workflow/workflows/stream.ts +1 -10
  40. package/dist/templates/transcription-workflow/workflows/sync-api.ts +8 -2
  41. package/dist/templates/transcription-workflow/workflows/transcribe.ts +8 -2
  42. package/dist/{test-B6ZBxSpk.mjs → test-9kPKJI-w.mjs} +1 -3
  43. package/dist/typecheck.mjs +4 -5
  44. package/dist/{worker-bundler-CIdDhZ0c.mjs → worker-bundler-CGD4r8Kc.mjs} +25 -11
  45. package/dist/worker-bundler.mjs +1 -1
  46. package/dist/{workflow-B-O97AqI.mjs → workflow-CFpxOFfQ.mjs} +1 -1
  47. package/package.json +4 -4
  48. package/dist/_studio-zAJycZ8j.mjs +0 -94
@@ -11,11 +11,7 @@ let _cachedMonorepoRoot;
11
11
  function getMonorepoRoot() {
12
12
  if (_cachedMonorepoRoot !== void 0) return _cachedMonorepoRoot;
13
13
  const cliDir = path.dirname(fileURLToPath(import.meta.url));
14
- const root1 = path.resolve(cliDir, "../..");
15
- const root2 = path.resolve(cliDir, "../../..");
16
- if (existsSync(path.join(root1, "pnpm-workspace.yaml"))) _cachedMonorepoRoot = root1;
17
- else if (existsSync(path.join(root2, "pnpm-workspace.yaml"))) _cachedMonorepoRoot = root2;
18
- else _cachedMonorepoRoot = null;
14
+ _cachedMonorepoRoot = ["../..", "../../.."].map((up) => path.resolve(cliDir, up)).find((root) => existsSync(path.join(root, "pnpm-workspace.yaml"))) ?? null;
19
15
  return _cachedMonorepoRoot;
20
16
  }
21
17
  function isDevMode() {
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { f as validateAgentExport } from "./_utils-B8QmtFhK.mjs";
3
- import { t as buildClient } from "./client-bundler-B8Q9F8gJ.mjs";
4
- import { n as buildWorkflows, t as buildWorker } from "./worker-bundler-CIdDhZ0c.mjs";
3
+ import { t as buildClient } from "./client-bundler-BEIqgOtd.mjs";
4
+ import { n as buildWorkflows, t as buildWorker } from "./worker-bundler-CGD4r8Kc.mjs";
5
5
  import path from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
+ import { omitUndefined } from "@alexkroman1/aai/utils";
7
8
  import { mkdtemp, rm, writeFile } from "node:fs/promises";
8
9
  import { tmpdir } from "node:os";
9
10
  import { hash } from "node:crypto";
@@ -24,7 +25,7 @@ async function buildAgentBundle(cwd, opts = {}) {
24
25
  workflows
25
26
  }),
26
27
  clientFiles,
27
- ...workflows && { workflows }
28
+ ...omitUndefined({ workflows })
28
29
  };
29
30
  }
30
31
  /**
@@ -46,10 +47,7 @@ async function buildAgentBundle(cwd, opts = {}) {
46
47
  * experimental.
47
48
  */
48
49
  async function evalWorkerBundle(code) {
49
- const mod = await importWorkerModule(code);
50
- const agentDef = mod.default ?? mod;
51
- validateAgentExport(agentDef);
52
- return agentDef;
50
+ return (await evalWorkerWithWorkflows(code)).agent;
53
51
  }
54
52
  /**
55
53
  * {@link evalWorkerBundle}, keeping the workflow exports the AgentDef cannot
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { i as outputSilenced, r as notify } from "./_ui-u7T4YooX.mjs";
3
3
  import { i as errorCode, o as errorMessage$1 } from "./_utils-B8QmtFhK.mjs";
4
- import { n as fallbackHtmlPlugin } from "./client-bundler-B8Q9F8gJ.mjs";
4
+ import { n as fallbackHtmlPlugin } from "./client-bundler-BEIqgOtd.mjs";
5
5
  import { t as DEDUPED_PEERS } from "./_vite-env-BNveawd1.mjs";
6
- import { n as buildWorkflows, t as buildWorker } from "./worker-bundler-CIdDhZ0c.mjs";
6
+ import { n as buildWorkflows, t as buildWorker } from "./worker-bundler-CGD4r8Kc.mjs";
7
7
  import { n as ensureApiKey } from "./_config-D_s09e7g.mjs";
8
- import { n as createWorkerEvaluator } from "./_bundler-BapCUUJN.mjs";
8
+ import { n as createWorkerEvaluator } from "./_bundler-C2BDwU7r.mjs";
9
9
  import { t as resolveServerEnv } from "./_server-common-6e0QI4mq.mjs";
10
10
  import { existsSync } from "node:fs";
11
11
  import path from "node:path";
@@ -39,23 +39,6 @@ export declare function startRegistry(): Promise<MockRegistry>;
39
39
  export declare function waitForHealth(url: string, child?: ChildProcess, timeoutMs?: number): Promise<void>;
40
40
  /** Wait for a child process to exit (for clean teardown). */
41
41
  export declare function waitForExit(child: ChildProcess, timeoutMs?: number): Promise<void>;
42
- /**
43
- * Install dependencies using the mock registry.
44
- *
45
- * **`ignore-scripts` is set HERE and nowhere else, and that placement is
46
- * load-bearing.** It exists to stop a linked package's `postinstall` running
47
- * during THIS install — but `npm_config_ignore_scripts` is read by every npm
48
- * invocation, so while it sat in `aaiEnv()` it silently suppressed every
49
- * lifecycle script in every spawned command. That took out `npm start`'s
50
- * `prestart`, i.e. the build the self-hosted entrypoint cannot boot without: the
51
- * child printed `> start` with no `> prestart` above it and died on the missing
52
- * artifact, naming a project file rather than the env var that skipped the step.
53
- *
54
- * The trap generalizes past this repo — an install-time protection that is
55
- * really a global one — and the second half is worse than the failure: had the
56
- * artifact happened to exist from an earlier build, the test would have PASSED
57
- * while never running the script it exists to exercise.
58
- */
59
42
  /**
60
43
  * Whether a failed install may be excused as the mock registry's npmjs
61
44
  * passthrough failing rather than as a real dependency-resolution break.
@@ -77,4 +60,21 @@ export declare function waitForExit(child: ChildProcess, timeoutMs?: number): Pr
77
60
  * resolve one means the published packages are actually broken.
78
61
  */
79
62
  export declare function isRegistryProxyFailure(err: unknown): boolean;
63
+ /**
64
+ * Install dependencies using the mock registry.
65
+ *
66
+ * **`ignore-scripts` is set HERE and nowhere else, and that placement is
67
+ * load-bearing.** It exists to stop a linked package's `postinstall` running
68
+ * during THIS install — but `npm_config_ignore_scripts` is read by every npm
69
+ * invocation, so while it sat in `aaiEnv()` it silently suppressed every
70
+ * lifecycle script in every spawned command. That took out `npm start`'s
71
+ * `prestart`, i.e. the build the self-hosted entrypoint cannot boot without: the
72
+ * child printed `> start` with no `> prestart` above it and died on the missing
73
+ * artifact, naming a project file rather than the env var that skipped the step.
74
+ *
75
+ * The trap generalizes past this repo — an install-time protection that is
76
+ * really a global one — and the second half is worse than the failure: had the
77
+ * artifact happened to exist from an earlier build, the test would have PASSED
78
+ * while never running the script it exists to exercise.
79
+ */
80
80
  export declare function installDeps(registry: MockRegistry, projectDir: string): void;
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { c as isEexist, l as readJson, p as writeJson } from "./_utils-B8QmtFhK.mjs";
3
- import { r as isDevMode, t as getMonorepoRoot } from "./_agent-vGW5SBnX.mjs";
4
- import { REPO_URL, downloadAndMergeTemplate } from "./_templates-iDGjGiPf.mjs";
3
+ import { r as isDevMode, t as getMonorepoRoot } from "./_agent-DpH2pBJd.mjs";
4
+ import { REPO_URL, downloadAndMergeTemplate } from "./_templates-Dxb_P2Wz.mjs";
5
5
  import path from "node:path";
6
6
  import fs from "node:fs/promises";
7
7
  //#region _init.ts
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { n as getServerInfo } from "./_agent-vGW5SBnX.mjs";
3
- import { n as apiRequest, t as HINT_NOT_DEPLOYED } from "./_api-client-LgLksMhN.mjs";
2
+ import { n as getServerInfo } from "./_agent-DpH2pBJd.mjs";
3
+ import { l as HINT_NOT_DEPLOYED, s as studioProjectApiUrl, u as apiRequest } from "./_studio-U3jhKlA3.mjs";
4
4
  //#region _slug-api.ts
5
5
  /**
6
6
  * Authenticated request against a deployed agent's slug-scoped resource
@@ -27,7 +27,7 @@ import { n as apiRequest, t as HINT_NOT_DEPLOYED } from "./_api-client-LgLksMhN.
27
27
  async function secretRequest(cwd, resourcePath, init, server) {
28
28
  const { serverUrl, slug, apiKey, studioProject } = await getServerInfo(cwd, server);
29
29
  return {
30
- data: await apiRequest(studioProject ? `${serverUrl}/studio/projects/${encodeURIComponent(studioProject)}/secret${resourcePath}` : `${serverUrl}/${slug}/secret${resourcePath}`, {
30
+ data: await apiRequest(studioProject ? `${studioProjectApiUrl(serverUrl, studioProject)}/secret${resourcePath}` : `${serverUrl}/${slug}/secret${resourcePath}`, {
31
31
  ...init,
32
32
  apiKey,
33
33
  hints: { 404: HINT_NOT_DEPLOYED }
@@ -1,4 +1,3 @@
1
- import { type ApiRequestOptions } from "./_api-client.ts";
2
1
  /**
3
2
  * Authenticated request against a deployed agent's slug-scoped resource
4
3
  * (`${serverUrl}/${slug}${resourcePath}`) — the one shape every per-agent
@@ -9,6 +8,7 @@ import { type ApiRequestOptions } from "./_api-client.ts";
9
8
  * so tests can mock `_agent.ts`/`_api-client.ts` while this composition
10
9
  * stays real — an intra-module call would bypass those mocks.
11
10
  */
11
+ import { type ApiRequestOptions } from "./_api-client.ts";
12
12
  /**
13
13
  * A SECRET request, routed to the project when this directory is linked to
14
14
  * one and to the bare slug otherwise.
@@ -1,7 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as CliError } from "./_output-CKkmWs7i.mjs";
3
- import { isRecord, omitUndefined } from "@alexkroman1/aai/utils";
3
+ import path from "node:path";
4
+ import { MAX_SLUG_LENGTH, PREVIEW_SLUG_SUFFIX, VALID_SLUG_RE, isRecord, omitUndefined } from "@alexkroman1/aai/utils";
4
5
  import { FetchError, ofetch } from "ofetch";
6
+ import { slugifyName } from "@alexkroman1/aai/slugify";
7
+ import { isLocalOnlyFile, snapshotWorkspaceFiles } from "@alexkroman1/aai/workspace-files";
5
8
  //#region _api-client.ts
6
9
  /**
7
10
  * Shared HTTP helper for platform API calls (deploy, delete, secrets).
@@ -139,4 +142,104 @@ function toApiError(err, url, opts) {
139
142
  return new Error(`${opts.action} failed: could not reach ${url}\n ${hint}`, { cause });
140
143
  }
141
144
  //#endregion
142
- export { isStringArray as a, checkedResponse as i, apiRequest as n, apiTestSeam as r, HINT_NOT_DEPLOYED as t };
145
+ //#region _studio.ts
146
+ /**
147
+ * Internals of the studio-workspace commands (`aai list/pull/push/publish`):
148
+ * the local source-file walk and the thin clients for the platform's
149
+ * `/studio/projects` routes. The workspace is the single source of truth —
150
+ * these helpers only move files between a local directory and the project's
151
+ * workspace row; production deploys happen exclusively through the studio's
152
+ * Publish route (which runs the deploy machinery in the project's sandbox).
153
+ */
154
+ /**
155
+ * Snapshot the local project into a workspace file map.
156
+ *
157
+ * The walk, the caps, the skip rules and the strict UTF-8 decode all come
158
+ * from the SDK (`@alexkroman1/aai/workspace-files`), which is also what the
159
+ * guest's end-of-turn sync uses — the two write the same map from opposite
160
+ * ends, and a disagreement between them is not an error but a file silently
161
+ * dropped here and resurrected there.
162
+ *
163
+ * `isLocalOnlyFile` is the one rule this side adds: `.env` rides the secret
164
+ * routes and lockfiles are install output, so neither belongs in a row.
165
+ */
166
+ function collectSourceFiles(dir) {
167
+ return snapshotWorkspaceFiles(dir, {
168
+ subject: "Project",
169
+ skipFile: isLocalOnlyFile
170
+ });
171
+ }
172
+ /**
173
+ * A studio project name derived from a directory name, or null if unusable.
174
+ *
175
+ * The normalization is the platform's own (`slugifyName`), not a local
176
+ * regex. This used to strip `[^a-z0-9-_]` by hand, which differs from the
177
+ * studio's slugifier on exactly the names people give agents: `Café
178
+ * Ordering` reduced to `caf-ordering` here and `cafe-ordering` there, so the
179
+ * same directory produced a different project depending on whether it was
180
+ * created by `aai push` or by typing the name into the studio.
181
+ *
182
+ * A `-preview` suffix is deliberately unusable. Publishing a project deploys
183
+ * it under the project's own name, so a `*-preview` project would claim a
184
+ * slug the studio's orphan-preview sweep reaps hourly — deleting the agent,
185
+ * its app-database schema, and its secrets on a schedule the user never
186
+ * asked for. Refusing the name is recoverable (rename the directory); losing
187
+ * a published agent to the reaper is not.
188
+ */
189
+ function projectNameFromDir(dir) {
190
+ const name = slugifyName(path.basename(dir), MAX_SLUG_LENGTH);
191
+ if (name.endsWith(PREVIEW_SLUG_SUFFIX)) return null;
192
+ return VALID_SLUG_RE.test(name) ? name : null;
193
+ }
194
+ /** The shareable studio URL for a project — what every command prints. */
195
+ function studioProjectUrl(serverUrl, project) {
196
+ return `${serverUrl}/studio/chat/${project}`;
197
+ }
198
+ /**
199
+ * The `/studio/projects/:project` base every project-scoped route hangs off —
200
+ * the source, the deploy, the secret fan-out, the delete.
201
+ *
202
+ * One definition because of the `encodeURIComponent`: the project name comes
203
+ * from `.aai/project.json` or from a directory name, i.e. from the working
204
+ * tree, and every request built on it carries the user's API key. Six call
205
+ * sites spelled this template out by hand, so "did that one encode?" was a
206
+ * question the reader had to answer six times.
207
+ */
208
+ function studioProjectApiUrl(serverUrl, project) {
209
+ return `${serverUrl}/studio/projects/${encodeURIComponent(project)}`;
210
+ }
211
+ function listStudioProjects(serverUrl, apiKey) {
212
+ return apiRequest(`${serverUrl}/studio/projects`, {
213
+ apiKey,
214
+ action: "list"
215
+ }).then((res) => checkedResponse(res, (value) => isRecord(value) && isStringArray(value.projects), `the studio project list at ${serverUrl}`).projects);
216
+ }
217
+ /** Fetch a project, or null when it doesn't exist (the push existence probe). */
218
+ function fetchStudioProject(serverUrl, apiKey, project) {
219
+ return apiRequest(studioProjectApiUrl(serverUrl, project), {
220
+ apiKey,
221
+ action: "pull",
222
+ allow404: true
223
+ });
224
+ }
225
+ /** `PUT /studio/projects/:project/source` — the atomic whole-tree push. */
226
+ function pushStudioSource(serverUrl, apiKey, project, body) {
227
+ return apiRequest(`${studioProjectApiUrl(serverUrl, project)}/source`, {
228
+ apiKey,
229
+ action: "push",
230
+ method: "PUT",
231
+ body,
232
+ hints: { 409: "The studio has newer changes. Run `aai pull` to fetch them, or `aai push --force` to overwrite." }
233
+ });
234
+ }
235
+ /** `POST /studio/projects/:project/deploy` — Publish, in the project's sandbox. */
236
+ function publishStudioProject(serverUrl, apiKey, project) {
237
+ return apiRequest(`${studioProjectApiUrl(serverUrl, project)}/deploy`, {
238
+ apiKey,
239
+ action: "publish",
240
+ method: "POST",
241
+ retry: 0
242
+ });
243
+ }
244
+ //#endregion
245
+ export { publishStudioProject as a, studioProjectUrl as c, apiTestSeam as d, checkedResponse as f, projectNameFromDir as i, HINT_NOT_DEPLOYED as l, fetchStudioProject as n, pushStudioSource as o, isStringArray as p, listStudioProjects as r, studioProjectApiUrl as s, collectSourceFiles as t, apiRequest as u };
package/dist/_studio.d.ts CHANGED
@@ -40,6 +40,17 @@ export declare function collectSourceFiles(dir: string): Promise<WorkspaceSnapsh
40
40
  export declare function projectNameFromDir(dir: string): string | null;
41
41
  /** The shareable studio URL for a project — what every command prints. */
42
42
  export declare function studioProjectUrl(serverUrl: string, project: string): string;
43
+ /**
44
+ * The `/studio/projects/:project` base every project-scoped route hangs off —
45
+ * the source, the deploy, the secret fan-out, the delete.
46
+ *
47
+ * One definition because of the `encodeURIComponent`: the project name comes
48
+ * from `.aai/project.json` or from a directory name, i.e. from the working
49
+ * tree, and every request built on it carries the user's API key. Six call
50
+ * sites spelled this template out by hand, so "did that one encode?" was a
51
+ * question the reader had to answer six times.
52
+ */
53
+ export declare function studioProjectApiUrl(serverUrl: string, project: string): string;
43
54
  /** `GET /studio/projects/:project` — see `projectPayload` server-side. */
44
55
  export type StudioProject = {
45
56
  files: Record<string, string>;
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { o as errorMessage$1 } from "./_utils-B8QmtFhK.mjs";
3
- import { t as getMonorepoRoot } from "./_agent-vGW5SBnX.mjs";
3
+ import { t as getMonorepoRoot } from "./_agent-DpH2pBJd.mjs";
4
4
  import { existsSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import { isRecord } from "@alexkroman1/aai/utils";
package/dist/bin.d.mts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as ok, t as CliError } from "./_output-CKkmWs7i.mjs";
3
3
  import { n as log } from "./_ui-u7T4YooX.mjs";
4
- import { r as evalWorkerBundle, t as buildAgentBundle } from "./_bundler-BapCUUJN.mjs";
4
+ import { r as evalWorkerBundle, t as buildAgentBundle } from "./_bundler-C2BDwU7r.mjs";
5
5
  import { assertTypechecks } from "./_typecheck-gate-BXvUNnfs.mjs";
6
- import { classifyVitestError, runVitest } from "./test-B6ZBxSpk.mjs";
6
+ import { classifyVitestError, runVitest } from "./test-9kPKJI-w.mjs";
7
7
  import path from "node:path";
8
8
  import fs from "node:fs/promises";
9
9
  //#region build.ts
package/dist/cli.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { i as installStdoutGuard, n as fail, o as writeLine, r as getOutputMode, t as CliError } from "./_output-CKkmWs7i.mjs";
3
3
  import { n as log, o as silenceOutput } from "./_ui-u7T4YooX.mjs";
4
- import { d as resolveCwd, o as errorMessage$1, s as fileExists, t as AGENT_ENTRY } from "./_utils-B8QmtFhK.mjs";
5
- import { existsSync, readFileSync } from "node:fs";
4
+ import { d as resolveCwd, o as errorMessage$1, s as fileExists, t as AGENT_ENTRY, u as readPackageJson } from "./_utils-B8QmtFhK.mjs";
5
+ import { existsSync } from "node:fs";
6
6
  import path from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { defineCommand, runMain, showUsage } from "citty";
@@ -250,7 +250,7 @@ const list = defineExec({
250
250
  },
251
251
  cwd: "any",
252
252
  async run({ args, cwd }) {
253
- const { executeList } = await import("./studio-BGVmCA2G.mjs");
253
+ const { executeList } = await import("./studio-BCNUpDgP.mjs");
254
254
  return executeList({
255
255
  cwd,
256
256
  server: args.server
@@ -283,7 +283,7 @@ const pull = defineExec({
283
283
  },
284
284
  cwd: "any",
285
285
  async run({ args, cwd }) {
286
- const { executePull } = await import("./studio-BGVmCA2G.mjs");
286
+ const { executePull } = await import("./studio-BCNUpDgP.mjs");
287
287
  return executePull({
288
288
  cwd,
289
289
  project: args.project,
@@ -309,7 +309,7 @@ const push = defineExec({
309
309
  },
310
310
  cwd: "agent",
311
311
  async run({ args, cwd }) {
312
- const { executePush } = await import("./studio-BGVmCA2G.mjs");
312
+ const { executePush } = await import("./studio-BCNUpDgP.mjs");
313
313
  return executePush({
314
314
  cwd,
315
315
  server: args.server,
@@ -337,7 +337,7 @@ const publish = defineExec({
337
337
  },
338
338
  cwd: "agent",
339
339
  async run({ args, cwd }) {
340
- const { executePublish } = await import("./studio-BGVmCA2G.mjs");
340
+ const { executePublish } = await import("./studio-BCNUpDgP.mjs");
341
341
  return executePublish({
342
342
  cwd,
343
343
  server: args.server,
@@ -375,6 +375,16 @@ const runIdArg = {
375
375
  required: true
376
376
  };
377
377
  /**
378
+ * The flags all four verbs take. Declared once so a flag added to the group
379
+ * reaches every verb — four hand-copied triples is how one of them ends up
380
+ * without `--token`.
381
+ */
382
+ const workflowArgs = {
383
+ server: sharedArgs.server,
384
+ json: sharedArgs.json,
385
+ token: workflowToken
386
+ };
387
+ /**
378
388
  * Every verb here reads `.aai/project.json` for the origin and the published
379
389
  * slug, and none of them touches `agent.ts` — a directory `aai pull`ed but
380
390
  * never edited still names a deployed agent whose runs are worth asking about.
@@ -391,14 +401,10 @@ const workflow = defineCommand({
391
401
  name: "list",
392
402
  description: "List the workflows this agent declares"
393
403
  },
394
- args: {
395
- server: sharedArgs.server,
396
- json: sharedArgs.json,
397
- token: workflowToken
398
- },
404
+ args: workflowArgs,
399
405
  cwd: WORKFLOW_CWD,
400
406
  async run({ args, cwd }) {
401
- const { executeWorkflowList } = await import("./workflow-B-O97AqI.mjs");
407
+ const { executeWorkflowList } = await import("./workflow-CFpxOFfQ.mjs");
402
408
  return executeWorkflowList(cwd, {
403
409
  server: args.server,
404
410
  token: args.token
@@ -420,13 +426,11 @@ const workflow = defineCommand({
420
426
  type: "string",
421
427
  description: "How many runs to list"
422
428
  },
423
- server: sharedArgs.server,
424
- json: sharedArgs.json,
425
- token: workflowToken
429
+ ...workflowArgs
426
430
  },
427
431
  cwd: WORKFLOW_CWD,
428
432
  async run({ args, cwd }) {
429
- const { executeWorkflowRuns } = await import("./workflow-B-O97AqI.mjs");
433
+ const { executeWorkflowRuns } = await import("./workflow-CFpxOFfQ.mjs");
430
434
  const limit = args.limit === void 0 ? void 0 : Number(args.limit);
431
435
  if (limit !== void 0 && !Number.isFinite(limit)) throw new CliError("bad_limit", "--limit must be a number");
432
436
  return executeWorkflowRuns(cwd, args.workflow, {
@@ -443,13 +447,11 @@ const workflow = defineCommand({
443
447
  },
444
448
  args: {
445
449
  runId: runIdArg,
446
- server: sharedArgs.server,
447
- json: sharedArgs.json,
448
- token: workflowToken
450
+ ...workflowArgs
449
451
  },
450
452
  cwd: WORKFLOW_CWD,
451
453
  async run({ args, cwd }) {
452
- const { executeWorkflowShow } = await import("./workflow-B-O97AqI.mjs");
454
+ const { executeWorkflowShow } = await import("./workflow-CFpxOFfQ.mjs");
453
455
  return executeWorkflowShow(cwd, args.runId, {
454
456
  server: args.server,
455
457
  token: args.token
@@ -463,13 +465,11 @@ const workflow = defineCommand({
463
465
  },
464
466
  args: {
465
467
  runId: runIdArg,
466
- server: sharedArgs.server,
467
- json: sharedArgs.json,
468
- token: workflowToken
468
+ ...workflowArgs
469
469
  },
470
470
  cwd: WORKFLOW_CWD,
471
471
  async run({ args, cwd }) {
472
- const { executeWorkflowCancel } = await import("./workflow-B-O97AqI.mjs");
472
+ const { executeWorkflowCancel } = await import("./workflow-CFpxOFfQ.mjs");
473
473
  return executeWorkflowCancel(cwd, args.runId, {
474
474
  server: args.server,
475
475
  token: args.token
@@ -488,8 +488,8 @@ const cliDir = path.dirname(fileURLToPath(import.meta.url));
488
488
  */
489
489
  function readCliVersion(dir) {
490
490
  for (const candidate of [path.join(dir, "package.json"), path.join(dir, "..", "package.json")]) try {
491
- const parsed = JSON.parse(readFileSync(candidate, "utf-8"));
492
- if (typeof parsed.version === "string") return parsed.version;
491
+ const { version } = readPackageJson(candidate);
492
+ if (typeof version === "string") return version;
493
493
  } catch {}
494
494
  process.stderr.write("warning: could not read aai's package.json — reporting version unknown\n");
495
495
  return "unknown";
@@ -545,7 +545,7 @@ const init = defineExec({
545
545
  },
546
546
  cwd: "none",
547
547
  async run({ args, mode }) {
548
- const { executeInit } = await import("./init-BTRGiPQr.mjs");
548
+ const { executeInit } = await import("./init-l6xfU4xX.mjs");
549
549
  return executeInit({
550
550
  dir: args.dir,
551
551
  force: args.force,
@@ -572,7 +572,7 @@ const dev = defineExec({
572
572
  },
573
573
  cwd: "agent",
574
574
  async run({ args, cwd }) {
575
- const { executeDev } = await import("./dev-C6SWaAZP.mjs");
575
+ const { executeDev } = await import("./dev-Uq5ujP8a.mjs");
576
576
  return executeDev({
577
577
  cwd,
578
578
  port: args.port
@@ -587,7 +587,7 @@ const test = defineExec({
587
587
  args: { json: sharedArgs.json },
588
588
  cwd: "agent",
589
589
  async run({ cwd }) {
590
- const { executeTest } = await import("./test-B6ZBxSpk.mjs");
590
+ const { executeTest } = await import("./test-9kPKJI-w.mjs");
591
591
  return executeTest(cwd);
592
592
  }
593
593
  });
@@ -609,7 +609,7 @@ const build = defineExec({
609
609
  },
610
610
  cwd: "agent",
611
611
  async run({ args, cwd }) {
612
- const { executeBuild } = await import("./build-BO1Ni6oJ.mjs");
612
+ const { executeBuild } = await import("./build-Dfza2pRI.mjs");
613
613
  return executeBuild({
614
614
  cwd,
615
615
  skipTests: args.skipTests,
@@ -632,7 +632,7 @@ const eject = defineExec({
632
632
  },
633
633
  cwd: "agent",
634
634
  async run({ args, cwd }) {
635
- const { executeEject } = await import("./eject-Zrzk5KV3.mjs");
635
+ const { executeEject } = await import("./eject-31gjtaHF.mjs");
636
636
  return executeEject({
637
637
  cwd,
638
638
  force: args.force
@@ -659,7 +659,7 @@ const deploy = defineExec({
659
659
  },
660
660
  cwd: "agent",
661
661
  async run({ args, cwd }) {
662
- const { executeDeploy } = await import("./deploy-DJ3HRcia.mjs");
662
+ const { executeDeploy } = await import("./deploy-B8lubiRT.mjs");
663
663
  return executeDeploy({
664
664
  cwd,
665
665
  server: args.server,
@@ -679,7 +679,7 @@ const del = defineExec({
679
679
  },
680
680
  cwd: "any",
681
681
  async run({ args, cwd }) {
682
- const { executeDelete } = await import("./delete-4I0uNR4a.mjs");
682
+ const { executeDelete } = await import("./delete-vbpjGzqs.mjs");
683
683
  return executeDelete({
684
684
  cwd,
685
685
  server: args.server
@@ -708,7 +708,7 @@ const secret = defineCommand({
708
708
  },
709
709
  cwd: "any",
710
710
  async run({ args, mode, cwd }) {
711
- const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-DzSQx1Ds.mjs");
711
+ const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-BuMuFR4B.mjs");
712
712
  const value = mode === "json" ? await readStdin() : void 0;
713
713
  if (mode === "json" && !value) throw new CliError(...NO_INPUT);
714
714
  return executeSecretPut(cwd, args.name, value, args.server);
@@ -730,7 +730,7 @@ const secret = defineCommand({
730
730
  },
731
731
  cwd: "any",
732
732
  async run({ args, cwd }) {
733
- const { executeSecretDelete } = await import("./secret-DzSQx1Ds.mjs");
733
+ const { executeSecretDelete } = await import("./secret-BuMuFR4B.mjs");
734
734
  return executeSecretDelete(cwd, args.name, args.server);
735
735
  }
736
736
  }),
@@ -745,7 +745,7 @@ const secret = defineCommand({
745
745
  },
746
746
  cwd: "any",
747
747
  async run({ args, cwd }) {
748
- const { executeSecretList } = await import("./secret-DzSQx1Ds.mjs");
748
+ const { executeSecretList } = await import("./secret-BuMuFR4B.mjs");
749
749
  return executeSecretList(cwd, args.server);
750
750
  }
751
751
  })
@@ -778,7 +778,7 @@ const storage = defineCommand({
778
778
  },
779
779
  cwd: "any",
780
780
  async run({ args, cwd }) {
781
- const { executeStorageStatus } = await import("./storage-C-Do0mIA.mjs");
781
+ const { executeStorageStatus } = await import("./storage-DzRZ-eCw.mjs");
782
782
  return executeStorageStatus(resolveStorageCwd(cwd, args.dir), args.server);
783
783
  }
784
784
  }),
@@ -794,7 +794,7 @@ const storage = defineCommand({
794
794
  },
795
795
  cwd: "any",
796
796
  async run({ args, cwd }) {
797
- const { executeStorageEnable } = await import("./storage-C-Do0mIA.mjs");
797
+ const { executeStorageEnable } = await import("./storage-DzRZ-eCw.mjs");
798
798
  return executeStorageEnable(resolveStorageCwd(cwd, args.dir), args.server);
799
799
  }
800
800
  }),
@@ -815,7 +815,7 @@ const storage = defineCommand({
815
815
  },
816
816
  cwd: "any",
817
817
  async run({ args, cwd }) {
818
- const { executeStorageDisable } = await import("./storage-C-Do0mIA.mjs");
818
+ const { executeStorageDisable } = await import("./storage-DzRZ-eCw.mjs");
819
819
  return executeStorageDisable(resolveStorageCwd(cwd, args.dir), {
820
820
  server: args.server,
821
821
  force: args.force
@@ -849,7 +849,7 @@ const mainCommand = defineCommand({
849
849
  },
850
850
  cwd: "none",
851
851
  async run({ args }) {
852
- const { executeLogin } = await import("./login-k0Z3VQu9.mjs");
852
+ const { executeLogin } = await import("./login-C71-qz8F.mjs");
853
853
  return executeLogin({ server: args.server });
854
854
  }
855
855
  }),
@@ -864,7 +864,7 @@ const mainCommand = defineCommand({
864
864
  args: { json: sharedArgs.json },
865
865
  cwd: "none",
866
866
  async run({ mode }) {
867
- const { listTemplates } = await import("./_templates-iDGjGiPf.mjs");
867
+ const { listTemplates } = await import("./_templates-Dxb_P2Wz.mjs");
868
868
  const names = await listTemplates();
869
869
  if (mode === "human") {
870
870
  for (const name of names) log.message(name);
@@ -917,7 +917,8 @@ if (process.env.VITEST !== "true") {
917
917
  await showUsage(cmd, parent);
918
918
  return;
919
919
  }
920
- await writeLine(`${JSON.stringify(fail("usage", `Invalid arguments for \`${commandPath(cmd, parent)}\`.`, `Run \`${commandPath(cmd, parent)} --help\` to see the arguments it accepts.`))}\n`);
920
+ const named = commandPath(cmd, parent);
921
+ await writeLine(`${JSON.stringify(fail("usage", `Invalid arguments for \`${named}\`.`, `Run \`${named} --help\` to see the arguments it accepts.`))}\n`);
921
922
  };
922
923
  /**
923
924
  * Refuse an unrecognized flag instead of ignoring it.
@@ -3,7 +3,7 @@ import { o as errorMessage$1, s as fileExists } from "./_utils-B8QmtFhK.mjs";
3
3
  import { n as withPreservedNodeEnv, t as DEDUPED_PEERS } from "./_vite-env-BNveawd1.mjs";
4
4
  import { existsSync, unlinkSync, writeFileSync } from "node:fs";
5
5
  import path from "node:path";
6
- import { isTextAssetPath } from "@alexkroman1/aai/utils";
6
+ import { isTextAssetPath, omitUndefined } from "@alexkroman1/aai/utils";
7
7
  import fs from "node:fs/promises";
8
8
  import { build } from "vite";
9
9
  //#region _default-html.ts
@@ -92,7 +92,7 @@ async function buildClient(cwd, opts = {}) {
92
92
  base: "./",
93
93
  logLevel: "silent",
94
94
  ...opts.configFile === false && { configFile: false },
95
- ...opts.plugins && { plugins: opts.plugins },
95
+ ...omitUndefined({ plugins: opts.plugins }),
96
96
  resolve: { dedupe: DEDUPED_PEERS },
97
97
  build: {
98
98
  outDir,
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { t as buildClient } from "./client-bundler-B8Q9F8gJ.mjs";
2
+ import { t as buildClient } from "./client-bundler-BEIqgOtd.mjs";
3
3
  export { buildClient };
@@ -2,8 +2,8 @@
2
2
  import { a as ok } from "./_output-CKkmWs7i.mjs";
3
3
  import { n as log } from "./_ui-u7T4YooX.mjs";
4
4
  import { l as writeProjectConfig } from "./_config-D_s09e7g.mjs";
5
- import { a as resolveDeployTarget, i as requireDeployedSlug } from "./_agent-vGW5SBnX.mjs";
6
- import { n as apiRequest, r as apiTestSeam, t as HINT_NOT_DEPLOYED } from "./_api-client-LgLksMhN.mjs";
5
+ import { a as resolveDeployTarget, i as requireDeployedSlug } from "./_agent-DpH2pBJd.mjs";
6
+ import { d as apiTestSeam, l as HINT_NOT_DEPLOYED, s as studioProjectApiUrl, u as apiRequest } from "./_studio-U3jhKlA3.mjs";
7
7
  //#region delete.ts
8
8
  async function runDelete(opts) {
9
9
  await apiRequest(`${opts.url}/${opts.slug}`, {
@@ -27,7 +27,7 @@ async function executeDelete(opts) {
27
27
  if (config?.studioProject) {
28
28
  const project = config.studioProject;
29
29
  log.step(`Deleting studio project ${project} (and its deployed agents)`);
30
- await apiRequest(`${serverUrl}/studio/projects/${encodeURIComponent(project)}`, {
30
+ await apiRequest(studioProjectApiUrl(serverUrl, project), {
31
31
  method: "DELETE",
32
32
  apiKey,
33
33
  action: "delete",
@@ -3,12 +3,11 @@ import { a as ok } from "./_output-CKkmWs7i.mjs";
3
3
  import { n as log, r as notify, t as fmtUrl } from "./_ui-u7T4YooX.mjs";
4
4
  import { o as errorMessage$1 } from "./_utils-B8QmtFhK.mjs";
5
5
  import { s as updateProjectConfig } from "./_config-D_s09e7g.mjs";
6
- import { i as evalWorkerConfig, t as buildAgentBundle } from "./_bundler-BapCUUJN.mjs";
6
+ import { i as evalWorkerConfig, t as buildAgentBundle } from "./_bundler-C2BDwU7r.mjs";
7
7
  import { t as resolveServerEnv } from "./_server-common-6e0QI4mq.mjs";
8
- import { a as resolveDeployTarget } from "./_agent-vGW5SBnX.mjs";
8
+ import { a as resolveDeployTarget } from "./_agent-DpH2pBJd.mjs";
9
9
  import { assertTypechecks } from "./_typecheck-gate-BXvUNnfs.mjs";
10
- import { i as checkedResponse, n as apiRequest, r as apiTestSeam } from "./_api-client-LgLksMhN.mjs";
11
- import { i as projectNameFromDir } from "./_studio-zAJycZ8j.mjs";
10
+ import { d as apiTestSeam, f as checkedResponse, i as projectNameFromDir, u as apiRequest } from "./_studio-U3jhKlA3.mjs";
12
11
  import { isRecord } from "@alexkroman1/aai/utils";
13
12
  import { gzipSync } from "node:zlib";
14
13
  //#region _deploy.ts