@alexkroman1/aai-cli 5.10.1 → 5.12.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 (44) hide show
  1. package/dist/{_agent-DS2PUJcl.mjs → _agent-JGaAJ5j6.mjs} +3 -2
  2. package/dist/_agent.d.ts +1 -0
  3. package/dist/{_bundler-DC17suWN.mjs → _bundler-BvfPzf8J.mjs} +28 -9
  4. package/dist/_bundler.d.ts +16 -2
  5. package/dist/{_config-DMyolIk9.mjs → _config-riTmrwxX.mjs} +2 -2
  6. package/dist/_deploy.d.ts +0 -10
  7. package/dist/_dev-restart.d.ts +59 -0
  8. package/dist/{_dev-server-B3ivqyEd.mjs → _dev-server-BgXXSijx.mjs} +178 -89
  9. package/dist/_dev-server.d.ts +17 -0
  10. package/dist/{_init-CYLvYU-B.mjs → _init-Ca5Eg5pn.mjs} +2 -2
  11. package/dist/_preflight-BtfaYtbE.mjs +46 -0
  12. package/dist/_preflight.d.ts +57 -0
  13. package/dist/_slug-api-DXm7s9X5.mjs +50 -0
  14. package/dist/_slug-api.d.ts +16 -0
  15. package/dist/_studio-CXoY_Hsg.mjs +94 -0
  16. package/dist/_studio.d.ts +19 -16
  17. package/dist/{_templates-BWJOiWOO.mjs → _templates-CKYDgGyY.mjs} +18 -6
  18. package/dist/_templates.d.ts +10 -0
  19. package/dist/{_typecheck-gate-DB-PY0A3.mjs → _typecheck-gate-4v9UBZHh.mjs} +1 -1
  20. package/dist/{_ui-DfwfDbT-.mjs → _ui-u7T4YooX.mjs} +5 -1
  21. package/dist/_ui.d.ts +2 -0
  22. package/dist/{build-CACFbdQ4.mjs → build-BTOyN3H5.mjs} +4 -4
  23. package/dist/cli.d.ts +2 -1
  24. package/dist/cli.mjs +93 -32
  25. package/dist/{delete-DEZ7u3u4.mjs → delete-D3gZdSs-.mjs} +3 -3
  26. package/dist/{deploy-Ch0d_jje.mjs → deploy-Df6e7YFn.mjs} +21 -21
  27. package/dist/deploy.d.ts +0 -2
  28. package/dist/{dev-CdeRcYiQ.mjs → dev-DqIUtFfS.mjs} +2 -2
  29. package/dist/eject-DSldO60O.mjs +90 -0
  30. package/dist/eject.d.ts +33 -0
  31. package/dist/{init-GQsNWkLJ.mjs → init-B-04lRSV.mjs} +4 -4
  32. package/dist/{login-BeFUiU6M.mjs → login-CtimAsZk.mjs} +4 -15
  33. package/dist/login.d.ts +0 -9
  34. package/dist/project-config.d.ts +23 -0
  35. package/dist/project-config.mjs +3 -0
  36. package/dist/scaffold/CLAUDE.md +23 -0
  37. package/dist/scaffold/package.json +4 -3
  38. package/dist/scaffold/server.mjs +156 -0
  39. package/dist/{secret-4_dYyrpA.mjs → secret-LnFdg8SB.mjs} +7 -7
  40. package/dist/{storage-BTfErOOW.mjs → storage-Cjj3Pv6i.mjs} +2 -2
  41. package/dist/{studio-LNvXtWak.mjs → studio-Rl5Po2M6.mjs} +36 -169
  42. package/dist/{test-C-V98oC-.mjs → test-BtOzTcXE.mjs} +1 -1
  43. package/package.json +8 -3
  44. package/dist/_slug-api-fRNNR8tz.mjs +0 -27
package/dist/cli.mjs CHANGED
@@ -1,11 +1,11 @@
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-CC300DzW.mjs";
3
- import { a as silenceOutput, n as log } from "./_ui-DfwfDbT-.mjs";
3
+ import { n as log, o as silenceOutput } from "./_ui-u7T4YooX.mjs";
4
4
  import { a as errorMessage, l as resolveCwd, o as fileExists, t as AGENT_ENTRY } from "./_utils-8KKw-bzi.mjs";
5
5
  import { existsSync, readFileSync } from "node:fs";
6
6
  import path from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
- import { defineCommand, runMain } from "citty";
8
+ import { defineCommand, runMain, showUsage } from "citty";
9
9
  //#region _cli-common.ts
10
10
  /** Shared arg definitions for citty commands. */
11
11
  const sharedArgs = {
@@ -55,11 +55,11 @@ function findUnknownFlags(rawArgs, argsDef) {
55
55
  * A flag's comparison key: dashes dropped and lower-cased, with a leading
56
56
  * `no` negation removed.
57
57
  *
58
- * citty accepts both `--allowMissingSecrets` and `--allow-missing-secrets` for
59
- * an arg declared as `allowMissingSecrets`, and the guest's in-sandbox Publish
60
- * spawns the kebab-case spelling. Comparing the literal text rejected
61
- * `--allow-missing-secrets` as unknown and broke Publish for every studio
62
- * user, so both sides are normalized to one key.
58
+ * citty accepts both `--allowPreviewSlug` and `--allow-preview-slug` for an
59
+ * arg declared as `allowPreviewSlug`, and the guest's in-sandbox Publish
60
+ * spawns the kebab-case spelling. Comparing the literal text rejected the
61
+ * kebab-case form as unknown and broke Publish for every studio user, so both
62
+ * sides are normalized to one key.
63
63
  */
64
64
  function canonicalFlag(flag) {
65
65
  return flag.replace(/^--?/, "").replace(/^no-/, "").replace(/-/g, "").toLowerCase();
@@ -166,7 +166,7 @@ const list = defineCommand({
166
166
  async run({ args }) {
167
167
  await runCommand(args, async () => {
168
168
  const cwd = resolveCwd();
169
- const { executeList } = await import("./studio-LNvXtWak.mjs");
169
+ const { executeList } = await import("./studio-Rl5Po2M6.mjs");
170
170
  return executeList({
171
171
  cwd,
172
172
  server: args.server
@@ -201,7 +201,7 @@ const pull = defineCommand({
201
201
  async run({ args }) {
202
202
  await runCommand(args, async () => {
203
203
  const cwd = resolveCwd();
204
- const { executePull } = await import("./studio-LNvXtWak.mjs");
204
+ const { executePull } = await import("./studio-Rl5Po2M6.mjs");
205
205
  return executePull({
206
206
  cwd,
207
207
  project: args.project,
@@ -229,7 +229,7 @@ const push = defineCommand({
229
229
  async run({ args }) {
230
230
  await runCommand(args, async () => {
231
231
  const cwd = await setup({ agent: true });
232
- const { executePush } = await import("./studio-LNvXtWak.mjs");
232
+ const { executePush } = await import("./studio-Rl5Po2M6.mjs");
233
233
  return executePush({
234
234
  cwd,
235
235
  server: args.server,
@@ -259,7 +259,7 @@ const publish = defineCommand({
259
259
  async run({ args }) {
260
260
  await runCommand(args, async () => {
261
261
  const cwd = await setup({ agent: true });
262
- const { executePublish } = await import("./studio-LNvXtWak.mjs");
262
+ const { executePublish } = await import("./studio-Rl5Po2M6.mjs");
263
263
  return executePublish({
264
264
  cwd,
265
265
  server: args.server,
@@ -286,6 +286,22 @@ function readCliVersion(dir) {
286
286
  return "unknown";
287
287
  }
288
288
  const VERSION = readCliVersion(cliDir);
289
+ /**
290
+ * `aai secret put` for a subcommand, `aai` for the root — the name to put in
291
+ * front of `--help` when telling someone which usage to read.
292
+ *
293
+ * `meta` is a `Resolvable`, so it can be a function or a promise; only the
294
+ * plain-object form carries a name synchronously and anything else degrades
295
+ * to the binary name rather than blocking the error path on a resolve.
296
+ */
297
+ function commandPath(cmd, parent) {
298
+ const nameOf = (c) => {
299
+ const meta = c?.meta;
300
+ return meta && typeof meta === "object" && "name" in meta && typeof meta.name === "string" ? meta.name : void 0;
301
+ };
302
+ const path = [nameOf(parent), nameOf(cmd)].filter((n) => n !== void 0).join(" ");
303
+ return path.startsWith("aai") ? path : `aai ${path}`.trim();
304
+ }
289
305
  const init = defineCommand({
290
306
  meta: {
291
307
  name: "init",
@@ -317,7 +333,7 @@ const init = defineCommand({
317
333
  },
318
334
  async run({ args }) {
319
335
  await runCommand(args, async (mode) => {
320
- const { executeInit } = await import("./init-GQsNWkLJ.mjs");
336
+ const { executeInit } = await import("./init-B-04lRSV.mjs");
321
337
  return executeInit({
322
338
  dir: args.dir,
323
339
  force: args.force,
@@ -346,7 +362,7 @@ const dev = defineCommand({
346
362
  async run({ args }) {
347
363
  await runCommand(args, async () => {
348
364
  const cwd = await setup({ agent: true });
349
- const { executeDev } = await import("./dev-CdeRcYiQ.mjs");
365
+ const { executeDev } = await import("./dev-DqIUtFfS.mjs");
350
366
  return executeDev({
351
367
  cwd,
352
368
  port: args.port
@@ -362,8 +378,8 @@ const test = defineCommand({
362
378
  args: { json: sharedArgs.json },
363
379
  async run({ args }) {
364
380
  await runCommand(args, async () => {
365
- const cwd = await setup();
366
- const { executeTest } = await import("./test-C-V98oC-.mjs");
381
+ const cwd = await setup({ agent: true });
382
+ const { executeTest } = await import("./test-BtOzTcXE.mjs");
367
383
  return executeTest(cwd);
368
384
  });
369
385
  }
@@ -387,7 +403,7 @@ const build = defineCommand({
387
403
  async run({ args }) {
388
404
  await runCommand(args, async () => {
389
405
  const cwd = await setup({ agent: true });
390
- const { executeBuild } = await import("./build-CACFbdQ4.mjs");
406
+ const { executeBuild } = await import("./build-BTOyN3H5.mjs");
391
407
  return executeBuild({
392
408
  cwd,
393
409
  skipTests: args.skipTests,
@@ -396,6 +412,30 @@ const build = defineCommand({
396
412
  });
397
413
  }
398
414
  });
415
+ const eject = defineCommand({
416
+ meta: {
417
+ name: "eject",
418
+ description: "Add the self-hosted server.mjs entrypoint to an older project"
419
+ },
420
+ args: {
421
+ force: {
422
+ type: "boolean",
423
+ alias: "f",
424
+ description: "Replace an existing server.mjs"
425
+ },
426
+ json: sharedArgs.json
427
+ },
428
+ async run({ args }) {
429
+ await runCommand(args, async () => {
430
+ const cwd = await setup({ agent: true });
431
+ const { executeEject } = await import("./eject-DSldO60O.mjs");
432
+ return executeEject({
433
+ cwd,
434
+ force: args.force
435
+ });
436
+ });
437
+ }
438
+ });
399
439
  const deploy = defineCommand({
400
440
  meta: {
401
441
  name: "deploy",
@@ -405,10 +445,6 @@ const deploy = defineCommand({
405
445
  args: {
406
446
  server: sharedArgs.server,
407
447
  json: sharedArgs.json,
408
- allowMissingSecrets: {
409
- type: "boolean",
410
- description: "Deploy even when the agent's providers are missing credentials (the server warns instead of rejecting; set them afterwards with `aai secret put`)"
411
- },
412
448
  allowPreviewSlug: {
413
449
  type: "boolean",
414
450
  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)"
@@ -421,11 +457,10 @@ const deploy = defineCommand({
421
457
  async run({ args }) {
422
458
  await runCommand(args, async () => {
423
459
  const cwd = await setup({ agent: true });
424
- const { executeDeploy } = await import("./deploy-Ch0d_jje.mjs");
460
+ const { executeDeploy } = await import("./deploy-Df6e7YFn.mjs");
425
461
  return executeDeploy({
426
462
  cwd,
427
463
  server: args.server,
428
- allowMissingSecrets: args.allowMissingSecrets,
429
464
  allowPreviewSlug: args.allowPreviewSlug,
430
465
  skipTypecheck: args.skipTypecheck
431
466
  });
@@ -444,7 +479,7 @@ const del = defineCommand({
444
479
  async run({ args }) {
445
480
  await runCommand(args, async () => {
446
481
  const cwd = await setup();
447
- const { executeDelete } = await import("./delete-DEZ7u3u4.mjs");
482
+ const { executeDelete } = await import("./delete-D3gZdSs-.mjs");
448
483
  return executeDelete({
449
484
  cwd,
450
485
  server: args.server
@@ -475,7 +510,7 @@ const secret = defineCommand({
475
510
  async run({ args }) {
476
511
  await runCommand(args, async (mode) => {
477
512
  const cwd = await setup();
478
- const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-4_dYyrpA.mjs");
513
+ const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-LnFdg8SB.mjs");
479
514
  const value = mode === "json" ? await readStdin() : void 0;
480
515
  if (mode === "json" && !value) throw new CliError(...NO_INPUT);
481
516
  return executeSecretPut(cwd, args.name, value, args.server);
@@ -499,7 +534,7 @@ const secret = defineCommand({
499
534
  async run({ args }) {
500
535
  await runCommand(args, async () => {
501
536
  const cwd = await setup();
502
- const { executeSecretDelete } = await import("./secret-4_dYyrpA.mjs");
537
+ const { executeSecretDelete } = await import("./secret-LnFdg8SB.mjs");
503
538
  return executeSecretDelete(cwd, args.name, args.server);
504
539
  });
505
540
  }
@@ -516,7 +551,7 @@ const secret = defineCommand({
516
551
  async run({ args }) {
517
552
  await runCommand(args, async () => {
518
553
  const cwd = await setup();
519
- const { executeSecretList } = await import("./secret-4_dYyrpA.mjs");
554
+ const { executeSecretList } = await import("./secret-LnFdg8SB.mjs");
520
555
  return executeSecretList(cwd, args.server);
521
556
  });
522
557
  }
@@ -551,7 +586,7 @@ const storage = defineCommand({
551
586
  },
552
587
  async run({ args }) {
553
588
  await runCommand(args, async () => {
554
- const { executeStorageStatus } = await import("./storage-BTfErOOW.mjs");
589
+ const { executeStorageStatus } = await import("./storage-Cjj3Pv6i.mjs");
555
590
  return executeStorageStatus(resolveStorageCwd(args.dir), args.server);
556
591
  });
557
592
  }
@@ -568,7 +603,7 @@ const storage = defineCommand({
568
603
  },
569
604
  async run({ args }) {
570
605
  await runCommand(args, async () => {
571
- const { executeStorageEnable } = await import("./storage-BTfErOOW.mjs");
606
+ const { executeStorageEnable } = await import("./storage-Cjj3Pv6i.mjs");
572
607
  return executeStorageEnable(resolveStorageCwd(args.dir), args.server);
573
608
  });
574
609
  }
@@ -590,7 +625,7 @@ const storage = defineCommand({
590
625
  },
591
626
  async run({ args }) {
592
627
  await runCommand(args, async () => {
593
- const { executeStorageDisable } = await import("./storage-BTfErOOW.mjs");
628
+ const { executeStorageDisable } = await import("./storage-Cjj3Pv6i.mjs");
594
629
  return executeStorageDisable(resolveStorageCwd(args.dir), {
595
630
  server: args.server,
596
631
  force: args.force
@@ -611,7 +646,7 @@ const login = defineCommand({
611
646
  },
612
647
  async run({ args }) {
613
648
  await runCommand(args, async () => {
614
- const { executeLogin } = await import("./login-BeFUiU6M.mjs");
649
+ const { executeLogin } = await import("./login-CtimAsZk.mjs");
615
650
  return executeLogin({ server: args.server });
616
651
  });
617
652
  }
@@ -624,7 +659,7 @@ const templates = defineCommand({
624
659
  args: { json: sharedArgs.json },
625
660
  async run({ args }) {
626
661
  await runCommand(args, async (mode) => {
627
- const { listTemplates } = await import("./_templates-BWJOiWOO.mjs");
662
+ const { listTemplates } = await import("./_templates-CKYDgGyY.mjs");
628
663
  const names = await listTemplates();
629
664
  if (mode === "human") {
630
665
  for (const name of names) log.message(name);
@@ -648,6 +683,7 @@ const mainCommand = defineCommand({
648
683
  dev,
649
684
  test,
650
685
  build,
686
+ eject,
651
687
  list,
652
688
  pull,
653
689
  push,
@@ -677,6 +713,31 @@ if (process.env.VITEST !== "true") {
677
713
  process.argv.splice(2, 0, "publish");
678
714
  };
679
715
  /**
716
+ * Render usage the way the active output mode allows.
717
+ *
718
+ * citty calls `showUsage` from two places: the `--help` path, and its
719
+ * `catch` for a `CLIError` (a missing positional, an unknown subcommand) —
720
+ * where it writes the usage block to STDOUT and the reason to stderr. That
721
+ * second one breaks JSON mode's contract of exactly one result line on
722
+ * stdout, and JSON mode is auto-detected on a pipe: `aai secret put --json`
723
+ * put a usage block where a script's `jq` expected a result, with no JSON
724
+ * emitted at all. Every other failure path in this CLI converges on one
725
+ * emitter and gets this right.
726
+ *
727
+ * `--help` is explicitly still the human block whatever the mode — piping
728
+ * it into a pager is the normal way to read it, and it is not an error.
729
+ * The specific reason keeps going to stderr as citty already writes it, so
730
+ * nothing is lost to a human watching the terminal.
731
+ */
732
+ const usageForMode = async (cmd, parent) => {
733
+ const argv = process.argv.slice(2);
734
+ if (argv.includes("--help") || argv.includes("-h") || getOutputMode({}) === "human") {
735
+ await showUsage(cmd, parent);
736
+ return;
737
+ }
738
+ await writeLine(`${JSON.stringify(fail("usage", `Invalid arguments for \`${commandPath(cmd, parent)}\`.`, `Run \`${commandPath(cmd, parent)} --help\` to see the arguments it accepts.`))}\n`);
739
+ };
740
+ /**
680
741
  * Refuse an unrecognized flag instead of ignoring it.
681
742
  *
682
743
  * citty drops one silently, so `aai push --serverr=http://x` exited 0 having
@@ -690,7 +751,7 @@ if (process.env.VITEST !== "true") {
690
751
  log.info("Run `aai <command> --help` to see the options it accepts.");
691
752
  process.exit(1);
692
753
  };
693
- runDefault().then(assertKnownFlags).then(() => runMain(mainCommand)).catch((err) => {
754
+ runDefault().then(assertKnownFlags).then(() => runMain(mainCommand, { showUsage: usageForMode })).catch((err) => {
694
755
  log.error(errorMessage(err));
695
756
  process.exitCode = 1;
696
757
  });
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as ok } from "./_output-CC300DzW.mjs";
3
- import { n as log } from "./_ui-DfwfDbT-.mjs";
4
- import { c as writeProjectConfig } from "./_config-DMyolIk9.mjs";
5
- import { i as resolveDeployTarget, n as getServerInfo } from "./_agent-DS2PUJcl.mjs";
3
+ import { n as log } from "./_ui-u7T4YooX.mjs";
4
+ import { l as writeProjectConfig } from "./_config-riTmrwxX.mjs";
5
+ import { i as resolveDeployTarget, n as getServerInfo } from "./_agent-JGaAJ5j6.mjs";
6
6
  import { n as apiRequest, t as HINT_NOT_DEPLOYED } from "./_api-client-B-upMGkc.mjs";
7
7
  //#region delete.ts
8
8
  async function runDelete(opts) {
@@ -1,25 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as ok } from "./_output-CC300DzW.mjs";
3
- import { n as log, t as fmtUrl } from "./_ui-DfwfDbT-.mjs";
3
+ import { n as log, r as notify, t as fmtUrl } from "./_ui-u7T4YooX.mjs";
4
4
  import { a as errorMessage } from "./_utils-8KKw-bzi.mjs";
5
- import { t as buildAgentBundle } from "./_bundler-DC17suWN.mjs";
6
- import { s as updateProjectConfig } from "./_config-DMyolIk9.mjs";
5
+ import { s as updateProjectConfig } from "./_config-riTmrwxX.mjs";
6
+ import { i as evalWorkerConfig, t as buildAgentBundle } from "./_bundler-BvfPzf8J.mjs";
7
7
  import { t as resolveServerEnv } from "./_server-common-DX8Bfrf5.mjs";
8
- import { i as resolveDeployTarget } from "./_agent-DS2PUJcl.mjs";
9
- import { assertTypechecks } from "./_typecheck-gate-DB-PY0A3.mjs";
8
+ import { i as resolveDeployTarget } from "./_agent-JGaAJ5j6.mjs";
9
+ import { assertTypechecks } from "./_typecheck-gate-4v9UBZHh.mjs";
10
10
  import { n as apiRequest } from "./_api-client-B-upMGkc.mjs";
11
+ import { i as projectNameFromDir } from "./_studio-CXoY_Hsg.mjs";
11
12
  import { gzipSync } from "node:zlib";
12
13
  //#region _deploy.ts
13
14
  async function runDeploy(opts) {
14
15
  const body = gzipSync(JSON.stringify({
15
16
  ...opts.slug ? { slug: opts.slug } : {},
16
- ...opts.allowMissingSecrets ? { credentialPolicy: "warn" } : {},
17
17
  ...opts.allowPreviewSlug ? { allowPreviewSlug: true } : {},
18
18
  env: opts.env,
19
19
  worker: opts.bundle.worker,
20
20
  clientFiles: opts.bundle.clientFiles
21
21
  }));
22
- const data = await apiRequest(`${opts.url}/deploy`, {
22
+ return { slug: (await apiRequest(`${opts.url}/deploy`, {
23
23
  method: "POST",
24
24
  body,
25
25
  headers: {
@@ -32,11 +32,7 @@ async function runDeploy(opts) {
32
32
  ...opts.slug ? {} : { retry: 0 },
33
33
  ...opts.retryDelay !== void 0 ? { retryDelay: opts.retryDelay } : {},
34
34
  ...opts.fetch ? { fetch: opts.fetch } : {}
35
- });
36
- return {
37
- slug: data.slug,
38
- ...data.warnings ? { warnings: data.warnings } : {}
39
- };
35
+ })).slug };
40
36
  }
41
37
  //#endregion
42
38
  //#region deploy.ts
@@ -44,19 +40,24 @@ async function executeDeploy(opts) {
44
40
  const { cwd } = opts;
45
41
  const { config: projectConfig, serverUrl, apiKey } = await resolveDeployTarget(cwd, opts.server);
46
42
  if (!opts.skipTypecheck) await assertTypechecks(cwd);
43
+ const preflightModule = import("./_preflight-BtfaYtbE.mjs");
47
44
  const bundle = await buildAgentBundle(cwd, { minify: true });
48
- const slug = projectConfig?.slug;
49
- const env = await resolveServerEnv(cwd);
45
+ const slug = projectConfig?.slug ?? projectNameFromDir(cwd) ?? void 0;
46
+ const uploadEnv = {
47
+ ASSEMBLYAI_API_KEY: apiKey,
48
+ ...await resolveServerEnv(cwd)
49
+ };
50
+ const { missingCredentialMessage, missingCredentials } = await preflightModule;
51
+ const config = await evalWorkerConfig(bundle.worker);
52
+ const missing = config ? missingCredentials(config, uploadEnv) : [];
53
+ const warnings = missing.length > 0 ? [missingCredentialMessage(missing)] : [];
54
+ for (const warning of warnings) notify("warn", warning);
50
55
  log.step(`Deploying${slug ? ` ${slug}` : ""}…`);
51
56
  const deployed = await runDeploy({
52
57
  url: serverUrl,
53
58
  bundle,
54
- env: {
55
- ASSEMBLYAI_API_KEY: apiKey,
56
- ...env
57
- },
59
+ env: uploadEnv,
58
60
  ...slug ? { slug } : {},
59
- ...opts.allowMissingSecrets ? { allowMissingSecrets: true } : {},
60
61
  ...opts.allowPreviewSlug ? { allowPreviewSlug: true } : {},
61
62
  apiKey
62
63
  });
@@ -73,12 +74,11 @@ async function executeDeploy(opts) {
73
74
  serverUrl
74
75
  })}`);
75
76
  }
76
- for (const warning of deployed.warnings ?? []) log.warn(warning);
77
77
  log.success(`Deployed ${fmtUrl(agentUrl)}`);
78
78
  return ok({
79
79
  slug: deployed.slug,
80
80
  url: agentUrl,
81
- ...deployed.warnings ? { warnings: deployed.warnings } : {}
81
+ ...warnings.length > 0 ? { warnings } : {}
82
82
  });
83
83
  }
84
84
  //#endregion
package/dist/deploy.d.ts CHANGED
@@ -7,8 +7,6 @@ type DeployData = {
7
7
  export declare function executeDeploy(opts: {
8
8
  cwd: string;
9
9
  server?: string | undefined;
10
- /** See DeployOpts.allowMissingSecrets (`--allow-missing-secrets`). */
11
- allowMissingSecrets?: boolean | undefined;
12
10
  /** See DeployOpts.allowPreviewSlug (`--allow-preview-slug`; studio-internal). */
13
11
  allowPreviewSlug?: boolean | undefined;
14
12
  /** `--skipTypecheck`: deploy without the tsc gate. */
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as ok } from "./_output-CC300DzW.mjs";
3
- import { i as parsePort, n as log, r as notify, t as fmtUrl } from "./_ui-DfwfDbT-.mjs";
3
+ import { a as parsePort, n as log, r as notify, t as fmtUrl } from "./_ui-u7T4YooX.mjs";
4
4
  import { i as errorDetail } from "./_utils-8KKw-bzi.mjs";
5
5
  import path from "node:path";
6
6
  import { styleText } from "node:util";
@@ -12,7 +12,7 @@ import { styleText } from "node:util";
12
12
  async function executeDev(opts) {
13
13
  const port = parsePort(opts.port);
14
14
  const agentName = path.basename(path.resolve(opts.cwd));
15
- const { startDevServer } = await import("./_dev-server-B3ivqyEd.mjs");
15
+ const { startDevServer } = await import("./_dev-server-BgXXSijx.mjs");
16
16
  let cleanup;
17
17
  let shuttingDown = false;
18
18
  const onSignal = () => {
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ import { a as ok, t as CliError } from "./_output-CC300DzW.mjs";
3
+ import { n as log } from "./_ui-u7T4YooX.mjs";
4
+ import { a as errorMessage, c as readJson, d as writeJson, o as fileExists } from "./_utils-8KKw-bzi.mjs";
5
+ import { scaffoldDir } from "./_templates-CKYDgGyY.mjs";
6
+ import path from "node:path";
7
+ import fs from "node:fs/promises";
8
+ //#region eject.ts
9
+ /**
10
+ * `aai eject` — retrofit the self-hosted entrypoint into an existing project.
11
+ *
12
+ * Every project scaffolded from this CLI version onwards already has
13
+ * `server.mjs` and an `npm start` script: the scaffold ships them, so
14
+ * self-hosting is the default rather than something to opt into. This command
15
+ * exists for the projects that predate that — `aai init` before it, or a
16
+ * workspace pulled from a studio that was created earlier — where the files
17
+ * are simply missing.
18
+ *
19
+ * It COPIES from the scaffold rather than writing its own contents. Two
20
+ * definitions of "the self-hosted entrypoint" would drift, and the one nobody
21
+ * runs locally is the one that would rot; this way an ejected project is
22
+ * byte-identical to a freshly scaffolded one.
23
+ */
24
+ /** The file `npm start` runs. Named once — the scaffold ships it under this name. */
25
+ const SERVER_ENTRY = "server.mjs";
26
+ /** The `scripts.start` value that runs {@link SERVER_ENTRY}. */
27
+ const START_SCRIPT = `node ${SERVER_ENTRY}`;
28
+ /**
29
+ * Add `scripts.start` unless the project already declares one.
30
+ *
31
+ * An existing `start` is left alone even under `--force`: `--force` is about
32
+ * replacing the entrypoint file, and silently rewriting the command a project
33
+ * boots with is a different, larger act. The mismatch is reported instead, so
34
+ * the choice stays the author's.
35
+ */
36
+ async function ensureStartScript(cwd) {
37
+ const manifestPath = path.join(cwd, "package.json");
38
+ const manifest = await readJson(manifestPath);
39
+ if (!manifest) {
40
+ log.warn(`No package.json here — add "start": "${START_SCRIPT}" yourself to get \`npm start\`.`);
41
+ return false;
42
+ }
43
+ const existing = manifest.scripts?.start;
44
+ if (existing === START_SCRIPT) return false;
45
+ if (existing !== void 0) {
46
+ log.warn(`Kept your existing "start" script (${existing}) — run \`node ${SERVER_ENTRY}\`.`);
47
+ return false;
48
+ }
49
+ manifest.scripts = {
50
+ ...manifest.scripts,
51
+ start: START_SCRIPT
52
+ };
53
+ await writeJson(manifestPath, manifest);
54
+ return true;
55
+ }
56
+ /**
57
+ * A missing scaffold source means a broken install (or an `AAI_TEMPLATES_DIR`
58
+ * pointed somewhere wrong), not anything the user did — so the message names
59
+ * the file and where it was looked for.
60
+ *
61
+ * Built here and thrown by the caller, the shape `build.ts` uses for the same
62
+ * reason: `useErrorCause` reads a `throw new Error` inside a `catch` as
63
+ * dropping the cause, and cannot see that `CliError` takes its options fourth.
64
+ */
65
+ function scaffoldMissingError(source, err) {
66
+ return new CliError("scaffold_missing", `Could not read the scaffold's ${SERVER_ENTRY} at ${source}: ${errorMessage(err)}`, "Reinstall @alexkroman1/aai-cli.", { cause: err });
67
+ }
68
+ async function executeEject(opts) {
69
+ const { cwd, force } = opts;
70
+ const target = path.join(cwd, SERVER_ENTRY);
71
+ const overwritten = await fileExists(target);
72
+ if (overwritten && !force) throw new CliError("server_exists", `${SERVER_ENTRY} already exists — this project can already be self-hosted.`, `Run \`npm start\`, or re-run with --force to replace it with the current scaffold's copy.`);
73
+ const source = path.join(scaffoldDir(), SERVER_ENTRY);
74
+ try {
75
+ await fs.copyFile(source, target);
76
+ } catch (err) {
77
+ throw scaffoldMissingError(source, err);
78
+ }
79
+ const addedStartScript = await ensureStartScript(cwd);
80
+ log.success(`Wrote ${SERVER_ENTRY}${overwritten ? " (replaced)" : ""}`);
81
+ if (await fileExists(path.join(cwd, "client.tsx"))) log.info("This project has a custom UI: run `aai build` first so it is served.");
82
+ log.info("Next: npm start (PORT and HOST override the 127.0.0.1:3000 default)");
83
+ return ok({
84
+ file: target,
85
+ overwritten,
86
+ addedStartScript
87
+ });
88
+ }
89
+ //#endregion
90
+ export { executeEject };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * `aai eject` — retrofit the self-hosted entrypoint into an existing project.
3
+ *
4
+ * Every project scaffolded from this CLI version onwards already has
5
+ * `server.mjs` and an `npm start` script: the scaffold ships them, so
6
+ * self-hosting is the default rather than something to opt into. This command
7
+ * exists for the projects that predate that — `aai init` before it, or a
8
+ * workspace pulled from a studio that was created earlier — where the files
9
+ * are simply missing.
10
+ *
11
+ * It COPIES from the scaffold rather than writing its own contents. Two
12
+ * definitions of "the self-hosted entrypoint" would drift, and the one nobody
13
+ * runs locally is the one that would rot; this way an ejected project is
14
+ * byte-identical to a freshly scaffolded one.
15
+ */
16
+ import { type CommandResult } from "./_output.ts";
17
+ /** The file `npm start` runs. Named once — the scaffold ships it under this name. */
18
+ export declare const SERVER_ENTRY = "server.mjs";
19
+ /** The `scripts.start` value that runs {@link SERVER_ENTRY}. */
20
+ export declare const START_SCRIPT = "node server.mjs";
21
+ type EjectData = {
22
+ /** Absolute path of the entrypoint written. */
23
+ file: string;
24
+ /** True when an existing `server.mjs` was replaced (`--force`). */
25
+ overwritten: boolean;
26
+ /** True when `scripts.start` was added to package.json by this run. */
27
+ addedStartScript: boolean;
28
+ };
29
+ export declare function executeEject(opts: {
30
+ cwd: string;
31
+ force?: boolean | undefined;
32
+ }): Promise<CommandResult<EjectData>>;
33
+ export {};
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as ok } from "./_output-CC300DzW.mjs";
3
- import { n as log, o as unwrapCancel } from "./_ui-DfwfDbT-.mjs";
3
+ import { n as log, s as unwrapCancel } from "./_ui-u7T4YooX.mjs";
4
4
  import { a as errorMessage, c as readJson, l as resolveCwd, o as fileExists, t as AGENT_ENTRY } from "./_utils-8KKw-bzi.mjs";
5
- import { r as isDevMode, t as getMonorepoRoot } from "./_agent-DS2PUJcl.mjs";
5
+ import { r as isDevMode, t as getMonorepoRoot } from "./_agent-JGaAJ5j6.mjs";
6
6
  import path from "node:path";
7
7
  import { styleText } from "node:util";
8
8
  import * as p from "@clack/prompts";
@@ -75,7 +75,7 @@ function resolveTargetDir(dir) {
75
75
  }
76
76
  /** Publish after init and return deploy metadata if successful. */
77
77
  async function tryPublish(cwd, server) {
78
- const { executePublish } = await import("./studio-LNvXtWak.mjs");
78
+ const { executePublish } = await import("./studio-Rl5Po2M6.mjs");
79
79
  try {
80
80
  const result = await executePublish({
81
81
  cwd,
@@ -94,7 +94,7 @@ async function tryPublish(cwd, server) {
94
94
  }
95
95
  /** Scaffold the project, optionally showing a spinner. */
96
96
  async function scaffoldProject(dir, cwd, template, silent) {
97
- const { runInit } = await import("./_init-CYLvYU-B.mjs");
97
+ const { runInit } = await import("./_init-Ca5Eg5pn.mjs");
98
98
  const s = silent ? void 0 : p.spinner();
99
99
  s?.start(`Creating ${dir}`);
100
100
  await runInit({
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as ok, t as CliError } from "./_output-CC300DzW.mjs";
3
- import { n as log } from "./_ui-DfwfDbT-.mjs";
4
- import { o as updateGlobalConfig, r as readGlobalConfig, t as approveServer } from "./_config-DMyolIk9.mjs";
5
- import { a as resolveServerUrl } from "./_agent-DS2PUJcl.mjs";
3
+ import { n as log } from "./_ui-u7T4YooX.mjs";
4
+ import { o as updateGlobalConfig, r as readGlobalConfig, t as approveServer } from "./_config-riTmrwxX.mjs";
5
+ import { a as resolveServerUrl } from "./_agent-JGaAJ5j6.mjs";
6
+ import { linkConfirmationCode } from "@alexkroman1/aai/utils";
6
7
  import { spawn } from "node:child_process";
7
8
  import { setTimeout } from "node:timers/promises";
8
9
  import { randomBytes } from "node:crypto";
@@ -115,18 +116,6 @@ function openerFor(platform) {
115
116
  ]];
116
117
  return ["xdg-open", []];
117
118
  }
118
- /**
119
- * Human-matchable confirmation derived from the link code — printed in the
120
- * terminal AND shown on the browser approval gate (aai-studio-client's
121
- * cli-link.ts derives the same value; keep the two in lockstep). Not a
122
- * secret: both ends already hold the full code. It exists so someone who
123
- * lands on an approval page they didn't cause has a concrete mismatch to
124
- * notice ("what terminal?") instead of a bare Approve button.
125
- */
126
- function linkConfirmationCode(code) {
127
- const head = code.slice(0, 8).toUpperCase();
128
- return `${head.slice(0, 4)}-${head.slice(4)}`;
129
- }
130
119
  /** Best-effort: the link URL is always printed, so a failure is fine. */
131
120
  function defaultOpenBrowser(url) {
132
121
  const [cmd, args] = openerFor(process.platform);
package/dist/login.d.ts CHANGED
@@ -30,15 +30,6 @@ export type LoginDeps = {
30
30
  /** Test seam — never set outside tests. */
31
31
  timeoutMs?: number;
32
32
  };
33
- /**
34
- * Human-matchable confirmation derived from the link code — printed in the
35
- * terminal AND shown on the browser approval gate (aai-studio-client's
36
- * cli-link.ts derives the same value; keep the two in lockstep). Not a
37
- * secret: both ends already hold the full code. It exists so someone who
38
- * lands on an approval page they didn't cause has a concrete mismatch to
39
- * notice ("what terminal?") instead of a bare Approve button.
40
- */
41
- export declare function linkConfirmationCode(code: string): string;
42
33
  export declare function executeLogin(opts: {
43
34
  server?: string | undefined;
44
35
  }, deps?: LoginDeps): Promise<CommandResult<{
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The two on-disk formats a CLI invocation reads, as WRITERS other packages
3
+ * can call — the config home (`config.json`, which holds the API key) and a
4
+ * project's `.aai/project.json` pin.
5
+ *
6
+ * It exists for the studio guest. Publish materializes a workspace into a
7
+ * real project and then spawns this CLI against it
8
+ * (`aai-guest/studio-publish.ts`), which means writing both files first; it
9
+ * used to do that with `JSON.stringify`, so the shapes agreed by coincidence
10
+ * and nothing tied them to the schemas the CLI parses them back with. Two of
11
+ * this file's properties are not obvious from the JSON and were absent from
12
+ * the hand-written copies' successors-in-waiting: the config home is written
13
+ * 0600 through an atomic rename (so an older world-readable file is
14
+ * TIGHTENED rather than left), and the project pin is MERGED, never
15
+ * replaced — `.aai/project.json` also carries the studio link fields, and a
16
+ * writer that replaces the document drops them.
17
+ *
18
+ * Deliberately a thin re-export of `_config.ts` rather than a second
19
+ * implementation: the point is that there is one writer per format, not that
20
+ * there is a nicer one here.
21
+ */
22
+ export type { GlobalConfig, ProjectConfig } from "./_config.ts";
23
+ export { updateProjectConfig, writeGlobalConfig as writeConfigHome } from "./_config.ts";
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { c as writeGlobalConfig, s as updateProjectConfig } from "./_config-riTmrwxX.mjs";
3
+ export { updateProjectConfig, writeGlobalConfig as writeConfigHome };