@alexkroman1/aai-cli 5.5.1 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +16 -7
  2. package/dist/{_agent-DMyOab9_.mjs → _agent-2nVugrN3.mjs} +22 -3
  3. package/dist/_agent.d.ts +3 -1
  4. package/dist/_api-client-B-upMGkc.mjs +104 -0
  5. package/dist/_api-client.d.ts +16 -0
  6. package/dist/_cli-common.d.ts +65 -0
  7. package/dist/{_config-5AEqhh-O.mjs → _config-Y5V-5Krn.mjs} +58 -9
  8. package/dist/_config.d.ts +23 -1
  9. package/dist/_deploy.d.ts +7 -0
  10. package/dist/{_dev-server-vV05Fnki.mjs → _dev-server-BB5N8kdh.mjs} +2 -2
  11. package/dist/{_init-BZ9t_Kz-.mjs → _init-D7JIT-IJ.mjs} +3 -3
  12. package/dist/{_slug-api-DaqQJHk8.mjs → _slug-api-CGJSST9B.mjs} +2 -2
  13. package/dist/_studio-commands.d.ts +73 -0
  14. package/dist/_studio.d.ts +64 -0
  15. package/dist/{_templates-Bv8CR800.mjs → _templates-Bt6u9_68.mjs} +19 -8
  16. package/dist/_templates.d.ts +9 -0
  17. package/dist/{_typecheck-gate-9IHWDnl1.mjs → _typecheck-gate-DvE8S3aQ.mjs} +1 -1
  18. package/dist/{build-D_PgQOD4.mjs → build-BXwDB78d.mjs} +1 -1
  19. package/dist/cli.mjs +264 -32
  20. package/dist/delete-DRNfvczK.mjs +53 -0
  21. package/dist/delete.d.ts +9 -2
  22. package/dist/{deploy-1eaXcfUw.mjs → deploy-Cp-wgME3.mjs} +7 -5
  23. package/dist/deploy.d.ts +2 -0
  24. package/dist/{dev-gVNdGFYY.mjs → dev-C4KyxouE.mjs} +1 -1
  25. package/dist/{init-DoU4_txp.mjs → init-BT-IU9AR.mjs} +15 -14
  26. package/dist/login-AA_UdRI-.mjs +172 -0
  27. package/dist/login.d.ts +33 -20
  28. package/dist/scaffold/package.json +4 -4
  29. package/dist/{secret-CGAIAbUx.mjs → secret-Dr0qnxeb.mjs} +1 -1
  30. package/dist/{storage-CnhOayhm.mjs → storage-CoQB8d-u.mjs} +1 -1
  31. package/dist/studio-sXvYUxr5.mjs +325 -0
  32. package/dist/studio.d.ts +54 -0
  33. package/package.json +4 -4
  34. package/dist/_api-client-MenP4-O7.mjs +0 -49
  35. package/dist/delete-DXilFBb1.mjs +0 -29
  36. package/dist/login-C59ZHzuO.mjs +0 -109
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Internals of the studio-workspace commands (`aai list/pull/push/publish`):
3
+ * the local source-file walk and the thin clients for the platform's
4
+ * `/studio/projects` routes. The workspace is the single source of truth —
5
+ * these helpers only move files between a local directory and the project's
6
+ * workspace row; production deploys happen exclusively through the studio's
7
+ * Publish route (which runs the deploy machinery in the project's sandbox).
8
+ */
9
+ /**
10
+ * Mirrors of the studio workspace caps (`aai-studio-server/studio-limits.ts`)
11
+ * — by value, like `aai-guest/limits.ts`, since the CLI cannot depend on the
12
+ * private server package. The server re-validates every push; these exist so
13
+ * an oversized file is a named warning locally instead of a rejected upload.
14
+ */
15
+ export declare const MAX_STUDIO_FILE_BYTES = 256000;
16
+ export declare const MAX_STUDIO_FILES = 100;
17
+ /**
18
+ * Walk a local project into the path→content record a workspace stores —
19
+ * the CLI-side twin of the guest's `snapshotWorkspace`: same ignored
20
+ * directories, same caps, oversized and non-text files skipped with a
21
+ * warning rather than failing the whole push.
22
+ */
23
+ export declare function collectSourceFiles(dir: string): Promise<{
24
+ files: Record<string, string>;
25
+ warnings: string[];
26
+ }>;
27
+ /**
28
+ * A studio project name derived from a directory name, or null if unusable.
29
+ *
30
+ * A `-preview` suffix is deliberately unusable. Publishing a project deploys
31
+ * it under the project's own name, so a `*-preview` project would claim a
32
+ * slug the studio's orphan-preview sweep reaps hourly — deleting the agent,
33
+ * its app-database schema, and its secrets on a schedule the user never
34
+ * asked for. Refusing the name is recoverable (rename the directory); losing
35
+ * a published agent to the reaper is not.
36
+ */
37
+ export declare function projectNameFromDir(dir: string): string | null;
38
+ /** The shareable studio URL for a project — what every command prints. */
39
+ export declare function studioProjectUrl(serverUrl: string, project: string): string;
40
+ /** `GET /studio/projects/:project` — see `projectPayload` server-side. */
41
+ export type StudioProject = {
42
+ files: Record<string, string>;
43
+ sourceHash: string;
44
+ deployedSlug?: string;
45
+ unpublished?: boolean;
46
+ };
47
+ export declare function listStudioProjects(serverUrl: string, apiKey: string): Promise<string[]>;
48
+ /** Fetch a project, or null when it doesn't exist (the push existence probe). */
49
+ export declare function fetchStudioProject(serverUrl: string, apiKey: string, project: string): Promise<StudioProject | null>;
50
+ /** `PUT /studio/projects/:project/source` — the atomic whole-tree push. */
51
+ export declare function pushStudioSource(serverUrl: string, apiKey: string, project: string, body: {
52
+ files: Record<string, string>;
53
+ baseHash?: string | undefined;
54
+ }): Promise<{
55
+ sourceHash: string;
56
+ created: boolean;
57
+ }>;
58
+ /** `POST /studio/projects/:project/deploy` — Publish, in the project's sandbox. */
59
+ export declare function publishStudioProject(serverUrl: string, apiKey: string, project: string): Promise<{
60
+ ok: true;
61
+ slug: string;
62
+ url: string;
63
+ output: string;
64
+ }>;
@@ -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-DMyOab9_.mjs";
3
+ import { t as getMonorepoRoot } from "./_agent-2nVugrN3.mjs";
4
4
  import { existsSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import fs from "node:fs/promises";
@@ -47,6 +47,22 @@ async function listTemplates(root = resolveTemplatesDir()) {
47
47
  return available.filter((e) => e.isDirectory()).map((e) => e.name).sort();
48
48
  }
49
49
  /**
50
+ * Layer the base scaffold (package.json, tsconfig, …) into targetDir
51
+ * WITHOUT overwriting anything already there. Shared by `aai init`
52
+ * (underneath a template) and `aai pull` (underneath the studio workspace
53
+ * files — the workspace stores source, and the scaffold completes it into a
54
+ * runnable project the same way the guest's `ensureProjectShape` does
55
+ * before an in-sandbox build).
56
+ */
57
+ async function layerScaffold(targetDir) {
58
+ const scaffoldDir = path.join(resolveTemplatesDir(), "scaffold");
59
+ if (existsSync(scaffoldDir)) await fs.cp(scaffoldDir, targetDir, {
60
+ recursive: true,
61
+ force: false,
62
+ errorOnExist: false
63
+ });
64
+ }
65
+ /**
50
66
  * Copy a template into targetDir, merging scaffold files underneath.
51
67
  */
52
68
  async function downloadAndMergeTemplate(template, targetDir) {
@@ -58,12 +74,7 @@ async function downloadAndMergeTemplate(template, targetDir) {
58
74
  recursive: true,
59
75
  force: true
60
76
  });
61
- const scaffoldDir = path.join(root, "scaffold");
62
- if (existsSync(scaffoldDir)) await fs.cp(scaffoldDir, targetDir, {
63
- recursive: true,
64
- force: false,
65
- errorOnExist: false
66
- });
77
+ await layerScaffold(targetDir);
67
78
  }
68
79
  //#endregion
69
- export { REPO_URL, downloadAndMergeTemplate, listTemplates };
80
+ export { REPO_URL, downloadAndMergeTemplate, layerScaffold, listTemplates };
@@ -21,6 +21,15 @@ export declare function bundledTemplatesDir(): string;
21
21
  * can never drift.
22
22
  */
23
23
  export declare function listTemplates(root?: string): Promise<string[]>;
24
+ /**
25
+ * Layer the base scaffold (package.json, tsconfig, …) into targetDir
26
+ * WITHOUT overwriting anything already there. Shared by `aai init`
27
+ * (underneath a template) and `aai pull` (underneath the studio workspace
28
+ * files — the workspace stores source, and the scaffold completes it into a
29
+ * runnable project the same way the guest's `ensureProjectShape` does
30
+ * before an in-sandbox build).
31
+ */
32
+ export declare function layerScaffold(targetDir: string): Promise<void>;
24
33
  /**
25
34
  * Copy a template into targetDir, merging scaffold files underneath.
26
35
  */
@@ -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 as t };
17
+ export { assertTypechecks };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { n as log, o as CliError, u as ok } from "./_ui-8kOEB-JH.mjs";
3
3
  import { r as evalWorkerBundle, t as buildAgentBundle } from "./_bundler-Cjaxa2wi.mjs";
4
- import { t as assertTypechecks } from "./_typecheck-gate-9IHWDnl1.mjs";
4
+ import { assertTypechecks } from "./_typecheck-gate-DvE8S3aQ.mjs";
5
5
  import { classifyVitestError, runVitest } from "./test-3Gq4pqH_.mjs";
6
6
  //#region build.ts
7
7
  /**
package/dist/cli.mjs CHANGED
@@ -5,7 +5,7 @@ import { existsSync, readFileSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { defineCommand, runMain } from "citty";
8
- //#region cli.ts
8
+ //#region _cli-common.ts
9
9
  /** Shared arg definitions for citty commands. */
10
10
  const sharedArgs = {
11
11
  server: {
@@ -23,21 +23,95 @@ const sharedArgs = {
23
23
  description: "Output JSON (auto-detected in non-TTY)"
24
24
  }
25
25
  };
26
- const cliDir = path.dirname(fileURLToPath(import.meta.url));
26
+ /** Flags citty handles itself, so no command declares them. */
27
+ const BUILTIN_FLAGS = /* @__PURE__ */ new Set([
28
+ "help",
29
+ "h",
30
+ "version",
31
+ "v"
32
+ ]);
27
33
  /**
28
- * Read this CLI's own version from its package.json (source layout keeps it
29
- * next to cli.ts; dist layout one level up). A missing or corrupt file must
30
- * not brick every command over a cosmetic string — warn and fall back.
34
+ * Flags in `rawArgs` that `argsDef` doesn't declare, in the form the user
35
+ * typed them.
36
+ *
37
+ * citty silently drops an unrecognized flag, so `aai push --serverr=http://x`
38
+ * exited 0 having pushed to the DEFAULT server — production, for an installed
39
+ * CLI — as if the flag had been honoured. Since `--server` is what decides
40
+ * where the API key and secret values are sent, a typo quietly retargeting it
41
+ * is worth failing on.
31
42
  */
32
- function readCliVersion(dir) {
33
- for (const candidate of [path.join(dir, "package.json"), path.join(dir, "..", "package.json")]) try {
34
- const parsed = JSON.parse(readFileSync(candidate, "utf-8"));
35
- if (typeof parsed.version === "string") return parsed.version;
36
- } catch {}
37
- process.stderr.write("warning: could not read aai's package.json — reporting version unknown\n");
38
- return "unknown";
43
+ function findUnknownFlags(rawArgs, argsDef) {
44
+ const declared = declaredFlagNames(argsDef);
45
+ const unknown = [];
46
+ for (const raw of rawArgs) {
47
+ if (raw === "--") break;
48
+ const token = flagToken(raw);
49
+ if (token && !declared.has(canonicalFlag(token))) unknown.push(token);
50
+ }
51
+ return unknown;
52
+ }
53
+ /**
54
+ * A flag's comparison key: dashes dropped and lower-cased, with a leading
55
+ * `no` negation removed.
56
+ *
57
+ * citty accepts both `--allowMissingSecrets` and `--allow-missing-secrets` for
58
+ * an arg declared as `allowMissingSecrets`, and the guest's in-sandbox Publish
59
+ * spawns the kebab-case spelling. Comparing the literal text rejected
60
+ * `--allow-missing-secrets` as unknown and broke Publish for every studio
61
+ * user, so both sides are normalized to one key.
62
+ */
63
+ function canonicalFlag(flag) {
64
+ return flag.replace(/^--?/, "").replace(/^no-/, "").replace(/-/g, "").toLowerCase();
65
+ }
66
+ /** Every flag name and alias `argsDef` declares, plus citty's built-ins. */
67
+ function declaredFlagNames(argsDef) {
68
+ const declared = new Set([...BUILTIN_FLAGS].map(canonicalFlag));
69
+ for (const [name, def] of Object.entries(argsDef)) {
70
+ const { type, alias } = def;
71
+ if (type === "positional") continue;
72
+ declared.add(canonicalFlag(name));
73
+ if (typeof alias === "string") declared.add(canonicalFlag(alias));
74
+ else if (Array.isArray(alias)) for (const a of alias) declared.add(canonicalFlag(a));
75
+ }
76
+ return declared;
77
+ }
78
+ /** The flag part of `raw` (`--server` from `--server=x`), or null if positional. */
79
+ function flagToken(raw) {
80
+ if (!raw.startsWith("-") || raw === "-" || /^-\d/.test(raw)) return null;
81
+ const eq = raw.indexOf("=");
82
+ return eq === -1 ? raw : raw.slice(0, eq);
83
+ }
84
+ /** Resolve a possibly-nested `Resolvable` citty field. */
85
+ async function resolve(value) {
86
+ return typeof value === "function" ? await value() : await value;
87
+ }
88
+ /**
89
+ * Unknown flags in `argv` for whichever (possibly nested) subcommand it
90
+ * selects — `[]` when everything is declared.
91
+ *
92
+ * Walks the real command tree rather than re-listing flags, so this cannot
93
+ * drift from what the commands accept. An unknown SUBCOMMAND is not reported:
94
+ * citty already answers that with usage text and a non-zero exit.
95
+ */
96
+ async function unknownFlagsForArgv(root, argv) {
97
+ let cmd = root;
98
+ let i = 0;
99
+ for (; i < argv.length; i++) {
100
+ const token = argv[i];
101
+ if (token === void 0 || token.startsWith("-")) break;
102
+ const subCommands = await resolve(cmd.subCommands);
103
+ const next = subCommands?.[token];
104
+ if (next === void 0) {
105
+ if (subCommands && Object.keys(subCommands).length > 0) return [];
106
+ break;
107
+ }
108
+ const resolved = await resolve(next);
109
+ if (resolved === void 0) break;
110
+ cmd = resolved;
111
+ }
112
+ const argsDef = await resolve(cmd.args) ?? {};
113
+ return findUnknownFlags(argv.slice(i), argsDef);
39
114
  }
40
- const VERSION = readCliVersion(cliDir);
41
115
  /** Shared command setup: resolve cwd, optionally require agent.ts. */
42
116
  async function setup(opts) {
43
117
  const cwd = resolveCwd();
@@ -77,6 +151,140 @@ async function runCommand(args, fn) {
77
151
  if (mode === "json") await writeLine(`${JSON.stringify(result)}\n`);
78
152
  if (!result.ok) process.exit(1);
79
153
  }
154
+ //#endregion
155
+ //#region _studio-commands.ts
156
+ const list = defineCommand({
157
+ meta: {
158
+ name: "list",
159
+ description: "List your studio projects"
160
+ },
161
+ args: {
162
+ server: sharedArgs.server,
163
+ json: sharedArgs.json
164
+ },
165
+ async run({ args }) {
166
+ await runCommand(args, async () => {
167
+ const cwd = resolveCwd();
168
+ const { executeList } = await import("./studio-sXvYUxr5.mjs");
169
+ return executeList({
170
+ cwd,
171
+ server: args.server
172
+ });
173
+ });
174
+ }
175
+ });
176
+ const pull = defineCommand({
177
+ meta: {
178
+ name: "pull",
179
+ description: "Pull a studio project into a local directory"
180
+ },
181
+ args: {
182
+ project: {
183
+ type: "positional",
184
+ description: "Studio project name (see `aai list`)",
185
+ required: true
186
+ },
187
+ dir: {
188
+ type: "positional",
189
+ description: "Target directory (default: the project name)",
190
+ required: false
191
+ },
192
+ force: {
193
+ type: "boolean",
194
+ alias: "f",
195
+ description: "Overwrite files in a non-empty directory"
196
+ },
197
+ server: sharedArgs.server,
198
+ json: sharedArgs.json
199
+ },
200
+ async run({ args }) {
201
+ await runCommand(args, async () => {
202
+ const cwd = resolveCwd();
203
+ const { executePull } = await import("./studio-sXvYUxr5.mjs");
204
+ return executePull({
205
+ cwd,
206
+ project: args.project,
207
+ dir: args.dir,
208
+ force: args.force,
209
+ server: args.server
210
+ });
211
+ });
212
+ }
213
+ });
214
+ const push = defineCommand({
215
+ meta: {
216
+ name: "push",
217
+ description: "Sync this project's source to its studio workspace"
218
+ },
219
+ args: {
220
+ force: {
221
+ type: "boolean",
222
+ alias: "f",
223
+ description: "Overwrite studio-side changes instead of failing the fast-forward check"
224
+ },
225
+ server: sharedArgs.server,
226
+ json: sharedArgs.json
227
+ },
228
+ async run({ args }) {
229
+ await runCommand(args, async () => {
230
+ const cwd = await setup({ agent: true });
231
+ const { executePush } = await import("./studio-sXvYUxr5.mjs");
232
+ return executePush({
233
+ cwd,
234
+ server: args.server,
235
+ force: args.force
236
+ });
237
+ });
238
+ }
239
+ });
240
+ const publish = defineCommand({
241
+ meta: {
242
+ name: "publish",
243
+ description: "Push to the studio and deploy to production (the studio's Publish button)"
244
+ },
245
+ args: {
246
+ force: {
247
+ type: "boolean",
248
+ alias: "f",
249
+ description: "Overwrite studio-side changes instead of failing the fast-forward check"
250
+ },
251
+ server: sharedArgs.server,
252
+ json: sharedArgs.json,
253
+ skipTypecheck: {
254
+ type: "boolean",
255
+ description: "Skip type checking before publishing"
256
+ }
257
+ },
258
+ async run({ args }) {
259
+ await runCommand(args, async () => {
260
+ const cwd = await setup({ agent: true });
261
+ const { executePublish } = await import("./studio-sXvYUxr5.mjs");
262
+ return executePublish({
263
+ cwd,
264
+ server: args.server,
265
+ force: args.force,
266
+ skipTypecheck: args.skipTypecheck
267
+ });
268
+ });
269
+ }
270
+ });
271
+ //#endregion
272
+ //#region cli.ts
273
+ const cliDir = path.dirname(fileURLToPath(import.meta.url));
274
+ /**
275
+ * Read this CLI's own version from its package.json (source layout keeps it
276
+ * next to cli.ts; dist layout one level up). A missing or corrupt file must
277
+ * not brick every command over a cosmetic string — warn and fall back.
278
+ */
279
+ function readCliVersion(dir) {
280
+ for (const candidate of [path.join(dir, "package.json"), path.join(dir, "..", "package.json")]) try {
281
+ const parsed = JSON.parse(readFileSync(candidate, "utf-8"));
282
+ if (typeof parsed.version === "string") return parsed.version;
283
+ } catch {}
284
+ process.stderr.write("warning: could not read aai's package.json — reporting version unknown\n");
285
+ return "unknown";
286
+ }
287
+ const VERSION = readCliVersion(cliDir);
80
288
  const init = defineCommand({
81
289
  meta: {
82
290
  name: "init",
@@ -108,7 +316,7 @@ const init = defineCommand({
108
316
  },
109
317
  async run({ args }) {
110
318
  await runCommand(args, async (mode) => {
111
- const { executeInit } = await import("./init-DoU4_txp.mjs");
319
+ const { executeInit } = await import("./init-BT-IU9AR.mjs");
112
320
  return executeInit({
113
321
  dir: args.dir,
114
322
  force: args.force,
@@ -137,7 +345,7 @@ const dev = defineCommand({
137
345
  async run({ args }) {
138
346
  await runCommand(args, async () => {
139
347
  const cwd = await setup({ agent: true });
140
- const { executeDev } = await import("./dev-gVNdGFYY.mjs");
348
+ const { executeDev } = await import("./dev-C4KyxouE.mjs");
141
349
  return executeDev({
142
350
  cwd,
143
351
  port: args.port
@@ -178,7 +386,7 @@ const build = defineCommand({
178
386
  async run({ args }) {
179
387
  await runCommand(args, async () => {
180
388
  const cwd = await setup({ agent: true });
181
- const { executeBuild } = await import("./build-D_PgQOD4.mjs");
389
+ const { executeBuild } = await import("./build-BXwDB78d.mjs");
182
390
  return executeBuild({
183
391
  cwd,
184
392
  skipTests: args.skipTests,
@@ -190,7 +398,8 @@ const build = defineCommand({
190
398
  const deploy = defineCommand({
191
399
  meta: {
192
400
  name: "deploy",
193
- description: "Bundle and deploy to production"
401
+ description: "(internal) used by studio Publish",
402
+ hidden: true
194
403
  },
195
404
  args: {
196
405
  server: sharedArgs.server,
@@ -199,6 +408,10 @@ const deploy = defineCommand({
199
408
  type: "boolean",
200
409
  description: "Deploy even when the agent's providers are missing credentials (the server warns instead of rejecting; set them afterwards with `aai secret put`)"
201
410
  },
411
+ allowPreviewSlug: {
412
+ type: "boolean",
413
+ description: "Permit a `-preview`-suffixed slug (reserved for studio auto-previews; studio-internal — a slug you claim this way is subject to the preview reaper)"
414
+ },
202
415
  skipTypecheck: {
203
416
  type: "boolean",
204
417
  description: "Skip type checking before deploy"
@@ -207,11 +420,12 @@ const deploy = defineCommand({
207
420
  async run({ args }) {
208
421
  await runCommand(args, async () => {
209
422
  const cwd = await setup({ agent: true });
210
- const { executeDeploy } = await import("./deploy-1eaXcfUw.mjs");
423
+ const { executeDeploy } = await import("./deploy-Cp-wgME3.mjs");
211
424
  return executeDeploy({
212
425
  cwd,
213
426
  server: args.server,
214
427
  allowMissingSecrets: args.allowMissingSecrets,
428
+ allowPreviewSlug: args.allowPreviewSlug,
215
429
  skipTypecheck: args.skipTypecheck
216
430
  });
217
431
  });
@@ -220,7 +434,7 @@ const deploy = defineCommand({
220
434
  const del = defineCommand({
221
435
  meta: {
222
436
  name: "delete",
223
- description: "Remove a deployed agent"
437
+ description: "Delete the studio project and its deployed agents"
224
438
  },
225
439
  args: {
226
440
  server: sharedArgs.server,
@@ -229,7 +443,7 @@ const del = defineCommand({
229
443
  async run({ args }) {
230
444
  await runCommand(args, async () => {
231
445
  const cwd = await setup();
232
- const { executeDelete } = await import("./delete-DXilFBb1.mjs");
446
+ const { executeDelete } = await import("./delete-DRNfvczK.mjs");
233
447
  return executeDelete({
234
448
  cwd,
235
449
  server: args.server
@@ -260,7 +474,7 @@ const secret = defineCommand({
260
474
  async run({ args }) {
261
475
  await runCommand(args, async (mode) => {
262
476
  const cwd = await setup();
263
- const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-CGAIAbUx.mjs");
477
+ const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-Dr0qnxeb.mjs");
264
478
  const value = mode === "json" ? await readStdin() : void 0;
265
479
  if (mode === "json" && !value) throw new CliError(...NO_INPUT);
266
480
  return executeSecretPut(cwd, args.name, value, args.server);
@@ -284,7 +498,7 @@ const secret = defineCommand({
284
498
  async run({ args }) {
285
499
  await runCommand(args, async () => {
286
500
  const cwd = await setup();
287
- const { executeSecretDelete } = await import("./secret-CGAIAbUx.mjs");
501
+ const { executeSecretDelete } = await import("./secret-Dr0qnxeb.mjs");
288
502
  return executeSecretDelete(cwd, args.name, args.server);
289
503
  });
290
504
  }
@@ -301,7 +515,7 @@ const secret = defineCommand({
301
515
  async run({ args }) {
302
516
  await runCommand(args, async () => {
303
517
  const cwd = await setup();
304
- const { executeSecretList } = await import("./secret-CGAIAbUx.mjs");
518
+ const { executeSecretList } = await import("./secret-Dr0qnxeb.mjs");
305
519
  return executeSecretList(cwd, args.server);
306
520
  });
307
521
  }
@@ -336,7 +550,7 @@ const storage = defineCommand({
336
550
  },
337
551
  async run({ args }) {
338
552
  await runCommand(args, async () => {
339
- const { executeStorageStatus } = await import("./storage-CnhOayhm.mjs");
553
+ const { executeStorageStatus } = await import("./storage-CoQB8d-u.mjs");
340
554
  return executeStorageStatus(resolveStorageCwd(args.dir), args.server);
341
555
  });
342
556
  }
@@ -353,7 +567,7 @@ const storage = defineCommand({
353
567
  },
354
568
  async run({ args }) {
355
569
  await runCommand(args, async () => {
356
- const { executeStorageEnable } = await import("./storage-CnhOayhm.mjs");
570
+ const { executeStorageEnable } = await import("./storage-CoQB8d-u.mjs");
357
571
  return executeStorageEnable(resolveStorageCwd(args.dir), args.server);
358
572
  });
359
573
  }
@@ -375,7 +589,7 @@ const storage = defineCommand({
375
589
  },
376
590
  async run({ args }) {
377
591
  await runCommand(args, async () => {
378
- const { executeStorageDisable } = await import("./storage-CnhOayhm.mjs");
592
+ const { executeStorageDisable } = await import("./storage-CoQB8d-u.mjs");
379
593
  return executeStorageDisable(resolveStorageCwd(args.dir), {
380
594
  server: args.server,
381
595
  force: args.force
@@ -388,7 +602,7 @@ const storage = defineCommand({
388
602
  const login = defineCommand({
389
603
  meta: {
390
604
  name: "login",
391
- description: "Sign in with your email and save your API key"
605
+ description: "Link your signed-in browser account and save your API key"
392
606
  },
393
607
  args: {
394
608
  server: sharedArgs.server,
@@ -396,7 +610,7 @@ const login = defineCommand({
396
610
  },
397
611
  async run({ args }) {
398
612
  await runCommand(args, async () => {
399
- const { executeLogin } = await import("./login-C59ZHzuO.mjs");
613
+ const { executeLogin } = await import("./login-AA_UdRI-.mjs");
400
614
  return executeLogin({ server: args.server });
401
615
  });
402
616
  }
@@ -409,7 +623,7 @@ const templates = defineCommand({
409
623
  args: { json: sharedArgs.json },
410
624
  async run({ args }) {
411
625
  await runCommand(args, async (mode) => {
412
- const { listTemplates } = await import("./_templates-Bv8CR800.mjs");
626
+ const { listTemplates } = await import("./_templates-Bt6u9_68.mjs");
413
627
  const names = await listTemplates();
414
628
  if (mode === "human") {
415
629
  for (const name of names) log.message(name);
@@ -433,6 +647,10 @@ const mainCommand = defineCommand({
433
647
  dev,
434
648
  test,
435
649
  build,
650
+ list,
651
+ pull,
652
+ push,
653
+ publish,
436
654
  deploy,
437
655
  delete: del,
438
656
  login,
@@ -450,14 +668,28 @@ if (process.env.VITEST !== "true") {
450
668
  return;
451
669
  }
452
670
  if (process.stdin.isTTY && process.stdout.isTTY) {
453
- if (await (await import("@clack/prompts")).confirm({ message: "Deploy this agent to production?" }) !== true) {
671
+ if (await (await import("@clack/prompts")).confirm({ message: "Publish this agent to production?" }) !== true) {
454
672
  log.info("Cancelled. Run `aai --help` to see all commands.");
455
673
  process.exit(0);
456
674
  }
457
675
  }
458
- process.argv.splice(2, 0, "deploy");
676
+ process.argv.splice(2, 0, "publish");
677
+ };
678
+ /**
679
+ * Refuse an unrecognized flag instead of ignoring it.
680
+ *
681
+ * citty drops one silently, so `aai push --serverr=http://x` exited 0 having
682
+ * pushed to the DEFAULT server. `--server` decides where the API key and
683
+ * secret values go, so a typo that quietly retargets it is worth failing on.
684
+ */
685
+ const assertKnownFlags = async () => {
686
+ const unknown = await unknownFlagsForArgv(mainCommand, process.argv.slice(2));
687
+ if (unknown.length === 0) return;
688
+ log.error(`Unknown ${unknown.length === 1 ? "option" : "options"}: ${unknown.join(", ")}`);
689
+ log.info("Run `aai <command> --help` to see the options it accepts.");
690
+ process.exit(1);
459
691
  };
460
- runDefault().then(() => runMain(mainCommand)).catch((err) => {
692
+ runDefault().then(assertKnownFlags).then(() => runMain(mainCommand)).catch((err) => {
461
693
  log.error(errorMessage(err));
462
694
  process.exitCode = 1;
463
695
  });
@@ -0,0 +1,53 @@
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";
5
+ import { n as apiRequest, t as HINT_NOT_DEPLOYED } from "./_api-client-B-upMGkc.mjs";
6
+ //#region delete.ts
7
+ async function runDelete(opts) {
8
+ await apiRequest(`${opts.url}/${opts.slug}`, {
9
+ method: "DELETE",
10
+ apiKey: opts.apiKey,
11
+ action: "delete",
12
+ hints: { 404: HINT_NOT_DEPLOYED },
13
+ ...opts.fetch ? { fetch: opts.fetch } : {}
14
+ });
15
+ }
16
+ /**
17
+ * Delete THE PROJECT. A studio-linked directory deletes its studio project
18
+ * (`DELETE /studio/projects/:project`), which cascades server-side to the
19
+ * workspace, chat, and the project's deployed + preview agents — the exact
20
+ * delete the studio's own Delete button runs. A directory that only knows a
21
+ * slug (no studio link) deletes that deployed agent directly.
22
+ */
23
+ async function executeDelete(opts) {
24
+ const { cwd } = opts;
25
+ const { config, serverUrl, apiKey } = await resolveDeployTarget(cwd, opts.server);
26
+ if (config?.studioProject) {
27
+ const project = config.studioProject;
28
+ log.step(`Deleting studio project ${project} (and its deployed agents)`);
29
+ await apiRequest(`${serverUrl}/studio/projects/${encodeURIComponent(project)}`, {
30
+ method: "DELETE",
31
+ apiKey,
32
+ action: "delete",
33
+ hints: { 404: "Run `aai list` to see your projects." }
34
+ });
35
+ log.success(`Deleted ${project}`);
36
+ await writeProjectConfig(cwd, { serverUrl });
37
+ return ok({
38
+ project,
39
+ ...config.slug ? { slug: config.slug } : {}
40
+ });
41
+ }
42
+ const { slug } = await getServerInfo(cwd, opts.server);
43
+ log.step(`Deleting ${slug}`);
44
+ await runDelete({
45
+ url: serverUrl,
46
+ slug,
47
+ apiKey
48
+ });
49
+ log.success(`Deleted ${serverUrl}/${slug}`);
50
+ return ok({ slug });
51
+ }
52
+ //#endregion
53
+ export { executeDelete };
package/dist/delete.d.ts CHANGED
@@ -8,9 +8,16 @@ export type DeleteOpts = {
8
8
  };
9
9
  export declare function runDelete(opts: DeleteOpts): Promise<void>;
10
10
  type DeleteData = {
11
- slug: string;
11
+ slug?: string;
12
+ project?: string;
12
13
  };
13
- /** Execute delete and return structured result. */
14
+ /**
15
+ * Delete THE PROJECT. A studio-linked directory deletes its studio project
16
+ * (`DELETE /studio/projects/:project`), which cascades server-side to the
17
+ * workspace, chat, and the project's deployed + preview agents — the exact
18
+ * delete the studio's own Delete button runs. A directory that only knows a
19
+ * slug (no studio link) deletes that deployed agent directly.
20
+ */
14
21
  export declare function executeDelete(opts: {
15
22
  cwd: string;
16
23
  server?: string | undefined;