@alexkroman1/aai 0.7.11 → 0.8.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 (92) hide show
  1. package/README.md +1 -1
  2. package/dist/aai.js +1 -1
  3. package/dist/cli.js +693 -349
  4. package/dist/sdk/_internal_types.d.ts +0 -1
  5. package/dist/sdk/_internal_types.d.ts.map +1 -1
  6. package/dist/sdk/_internal_types.js.map +1 -1
  7. package/dist/sdk/_render_check.d.ts +7 -0
  8. package/dist/sdk/_render_check.d.ts.map +1 -0
  9. package/dist/sdk/_render_check.js +38 -0
  10. package/dist/sdk/_render_check.js.map +1 -0
  11. package/dist/sdk/builtin_tools.d.ts.map +1 -1
  12. package/dist/sdk/builtin_tools.js +21 -0
  13. package/dist/sdk/builtin_tools.js.map +1 -1
  14. package/dist/sdk/define_agent.d.ts.map +1 -1
  15. package/dist/sdk/define_agent.js +0 -1
  16. package/dist/sdk/define_agent.js.map +1 -1
  17. package/dist/sdk/direct_executor.d.ts.map +1 -1
  18. package/dist/sdk/direct_executor.js +0 -1
  19. package/dist/sdk/direct_executor.js.map +1 -1
  20. package/dist/sdk/memory_tools.d.ts +38 -0
  21. package/dist/sdk/memory_tools.d.ts.map +1 -0
  22. package/dist/sdk/memory_tools.js +77 -0
  23. package/dist/sdk/memory_tools.js.map +1 -0
  24. package/dist/sdk/mod.d.ts +3 -1
  25. package/dist/sdk/mod.d.ts.map +1 -1
  26. package/dist/sdk/mod.js +2 -0
  27. package/dist/sdk/mod.js.map +1 -1
  28. package/dist/sdk/protocol.d.ts +9 -3
  29. package/dist/sdk/protocol.d.ts.map +1 -1
  30. package/dist/sdk/protocol.js +2 -1
  31. package/dist/sdk/protocol.js.map +1 -1
  32. package/dist/sdk/s2s.d.ts.map +1 -1
  33. package/dist/sdk/s2s.js +9 -3
  34. package/dist/sdk/s2s.js.map +1 -1
  35. package/dist/sdk/session.d.ts.map +1 -1
  36. package/dist/sdk/session.js +5 -0
  37. package/dist/sdk/session.js.map +1 -1
  38. package/dist/sdk/types.d.ts +23 -14
  39. package/dist/sdk/types.d.ts.map +1 -1
  40. package/dist/sdk/types.js +29 -0
  41. package/dist/sdk/types.js.map +1 -1
  42. package/dist/ui/_components/app.d.ts.map +1 -1
  43. package/dist/ui/_components/app.js +6 -7
  44. package/dist/ui/_components/app.js.map +1 -1
  45. package/dist/ui/_components/message_list.d.ts.map +1 -1
  46. package/dist/ui/_components/message_list.js +2 -1
  47. package/dist/ui/_components/message_list.js.map +1 -1
  48. package/dist/ui/_components/sidebar_layout.d.ts +19 -0
  49. package/dist/ui/_components/sidebar_layout.d.ts.map +1 -0
  50. package/dist/ui/_components/sidebar_layout.js +21 -0
  51. package/dist/ui/_components/sidebar_layout.js.map +1 -0
  52. package/dist/ui/_components/start_screen.d.ts +24 -0
  53. package/dist/ui/_components/start_screen.d.ts.map +1 -0
  54. package/dist/ui/_components/start_screen.js +25 -0
  55. package/dist/ui/_components/start_screen.js.map +1 -0
  56. package/dist/ui/_hooks.d.ts +21 -0
  57. package/dist/ui/_hooks.d.ts.map +1 -0
  58. package/dist/ui/_hooks.js +35 -0
  59. package/dist/ui/_hooks.js.map +1 -0
  60. package/dist/ui/components.d.ts +20 -0
  61. package/dist/ui/components.d.ts.map +1 -1
  62. package/dist/ui/components.js +12 -0
  63. package/dist/ui/components.js.map +1 -1
  64. package/dist/ui/components_mod.d.ts +3 -2
  65. package/dist/ui/components_mod.d.ts.map +1 -1
  66. package/dist/ui/components_mod.js +3 -2
  67. package/dist/ui/components_mod.js.map +1 -1
  68. package/dist/ui/mod.d.ts +4 -3
  69. package/dist/ui/mod.d.ts.map +1 -1
  70. package/dist/ui/mod.js +3 -2
  71. package/dist/ui/mod.js.map +1 -1
  72. package/dist/ui/session.d.ts +7 -0
  73. package/dist/ui/session.d.ts.map +1 -1
  74. package/dist/ui/session.js +21 -3
  75. package/dist/ui/session.js.map +1 -1
  76. package/dist/ui/signals.d.ts +14 -0
  77. package/dist/ui/signals.d.ts.map +1 -1
  78. package/dist/ui/signals.js +55 -3
  79. package/dist/ui/signals.js.map +1 -1
  80. package/package.json +19 -2
  81. package/templates/_shared/CLAUDE.md +305 -116
  82. package/templates/_shared/package.json +4 -1
  83. package/templates/dispatch-center/agent.ts +43 -72
  84. package/templates/embedded-assets/agent.ts +4 -5
  85. package/templates/health-assistant/agent.ts +7 -7
  86. package/templates/infocom-adventure/agent.ts +20 -20
  87. package/templates/memory-agent/agent.ts +1 -55
  88. package/templates/night-owl/agent.ts +4 -4
  89. package/templates/night-owl/client.tsx +6 -23
  90. package/templates/pizza-ordering/agent.ts +214 -0
  91. package/templates/pizza-ordering/client.tsx +264 -0
  92. package/templates/smart-research/agent.ts +10 -10
package/dist/cli.js CHANGED
@@ -21,6 +21,16 @@ var COLORS;
21
21
  var init_colors = __esm({
22
22
  "cli/_colors.ts"() {
23
23
  "use strict";
24
+ if (chalk.level === 0 && !process.env.NO_COLOR) {
25
+ const ct = process.env.COLORTERM;
26
+ if (ct === "truecolor" || ct === "24bit") {
27
+ chalk.level = 3;
28
+ } else if (ct || /-256(color)?$/i.test(process.env.TERM ?? "")) {
29
+ chalk.level = 2;
30
+ } else if (process.env.TERM_PROGRAM) {
31
+ chalk.level = 1;
32
+ }
33
+ }
24
34
  COLORS = {
25
35
  primary: "#fab283",
26
36
  interactive: "#56b6c2",
@@ -52,10 +62,11 @@ function rootHelp(version) {
52
62
  const cmds = [
53
63
  ["init", "[dir]", "Scaffold a new agent project"],
54
64
  ["dev", "", "Start a local development server"],
65
+ ["build", "", "Bundle and validate (no server or deploy)"],
55
66
  ["deploy", "", "Bundle and deploy to production"],
56
67
  ["start", "", "Start production server from build"],
57
68
  ["secret", "<cmd>", "Manage secrets"],
58
- ["rag", "<url>", "Ingest a site's llms-full.txt into the vector store"]
69
+ ["rag", "<url>", "Ingest a site into the vector store"]
59
70
  ];
60
71
  for (const [name, args, desc] of cmds) {
61
72
  const nameStr = interactive(name.padEnd(8));
@@ -78,15 +89,9 @@ function rootHelp(version) {
78
89
  lines.push("");
79
90
  lines.push(` ${chalk2.bold(interactive("Getting started"))}`);
80
91
  lines.push("");
81
- lines.push(
82
- ` ${chalk2.dim("$")} ${primary("aai init")} ${interactive("my-agent")} ${chalk2.dim(
83
- "Create a new agent"
84
- )}`
85
- );
86
- lines.push(` ${chalk2.dim("$")} ${primary("cd my-agent")}`);
87
- lines.push(
88
- ` ${chalk2.dim("$")} ${primary("aai deploy")} ${chalk2.dim("Deploy to production")}`
89
- );
92
+ lines.push(` ${chalk2.dim("$")} ${primary("aai init")} ${interactive("my-agent")}`);
93
+ lines.push(` ${chalk2.dim("$")} ${primary("cd")} ${interactive("my-agent")}`);
94
+ lines.push(` ${chalk2.dim("$")} ${primary("aai dev")}`);
90
95
  lines.push("");
91
96
  return lines.join("\n");
92
97
  }
@@ -273,6 +278,7 @@ async function askText(message, defaultValue) {
273
278
  onSubmit: (value) => {
274
279
  resolve(value || defaultValue);
275
280
  app.unmount();
281
+ app.clear();
276
282
  }
277
283
  }
278
284
  )
@@ -415,57 +421,6 @@ var init_discover = __esm({
415
421
  }
416
422
  });
417
423
 
418
- // cli/_deploy.ts
419
- async function attemptDeploy(url, slug, apiKey, env, worker, clientFiles) {
420
- return await _internals.fetch(`${url}/${slug}/deploy`, {
421
- method: "POST",
422
- headers: {
423
- "Content-Type": "application/json",
424
- Authorization: `Bearer ${apiKey}`
425
- },
426
- body: JSON.stringify({
427
- env,
428
- worker,
429
- clientFiles
430
- })
431
- });
432
- }
433
- async function runDeploy(opts) {
434
- const worker = opts.bundle.worker;
435
- const clientFiles = opts.bundle.clientFiles;
436
- let slug = opts.slug;
437
- if (opts.dryRun) {
438
- return { slug };
439
- }
440
- for (let i = 0; i < MAX_RETRIES; i++) {
441
- const resp = await attemptDeploy(opts.url, slug, opts.apiKey, opts.env, worker, clientFiles);
442
- if (resp.ok) {
443
- return { slug };
444
- }
445
- if (resp.status === 403) {
446
- const text2 = await resp.text();
447
- if (text2.includes("Slug")) {
448
- slug = generateSlug();
449
- continue;
450
- }
451
- }
452
- const text = await resp.text();
453
- throw new Error(`deploy failed (${resp.status}): ${text}`);
454
- }
455
- throw new Error(`deploy failed: could not find available slug after ${MAX_RETRIES} attempts`);
456
- }
457
- var _internals, MAX_RETRIES;
458
- var init_deploy = __esm({
459
- "cli/_deploy.ts"() {
460
- "use strict";
461
- init_discover();
462
- _internals = {
463
- fetch: globalThis.fetch.bind(globalThis)
464
- };
465
- MAX_RETRIES = 20;
466
- }
467
- });
468
-
469
424
  // cli/_ink.tsx
470
425
  import { Spinner } from "@inkjs/ui";
471
426
  import { Box as Box2, render as render2, Static, Text as Text2, useApp } from "ink";
@@ -490,14 +445,20 @@ function StepInfo({ action, msg }) {
490
445
  ] });
491
446
  }
492
447
  function Info({ msg }) {
493
- return /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: msg });
448
+ return /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
449
+ " ",
450
+ msg
451
+ ] });
494
452
  }
495
453
  function Detail({ msg }) {
496
- return /* @__PURE__ */ jsx2(Text2, { children: msg });
454
+ return /* @__PURE__ */ jsxs2(Text2, { children: [
455
+ " ",
456
+ msg
457
+ ] });
497
458
  }
498
459
  function Warn({ msg }) {
499
460
  return /* @__PURE__ */ jsxs2(Text2, { children: [
500
- /* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.warning, children: "warning" }),
461
+ /* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.warning, children: "\u25B2" }),
501
462
  /* @__PURE__ */ jsxs2(Text2, { children: [
502
463
  " ",
503
464
  msg
@@ -506,9 +467,9 @@ function Warn({ msg }) {
506
467
  }
507
468
  function ErrorLine({ msg }) {
508
469
  return /* @__PURE__ */ jsxs2(Text2, { children: [
509
- /* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.error, children: "error" }),
470
+ /* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.error, children: "\u2717" }),
510
471
  /* @__PURE__ */ jsxs2(Text2, { children: [
511
- ": ",
472
+ " ",
512
473
  msg
513
474
  ] })
514
475
  ] });
@@ -587,7 +548,7 @@ async function runWithInk(fn) {
587
548
  )
588
549
  );
589
550
  await app.waitUntilExit();
590
- if (thrownError) throw thrownError;
551
+ if (thrownError) process.exit(1);
591
552
  }
592
553
  var init_ink = __esm({
593
554
  "cli/_ink.tsx"() {
@@ -596,6 +557,244 @@ var init_ink = __esm({
596
557
  }
597
558
  });
598
559
 
560
+ // ui/_dom_shim.ts
561
+ import { DOMParser } from "linkedom";
562
+ function installDomShim() {
563
+ if (installed) return;
564
+ installed = true;
565
+ const doc = new DOMParser().parseFromString(
566
+ "<!DOCTYPE html><html><head></head><body></body></html>",
567
+ "text/html"
568
+ );
569
+ const g2 = globalThis;
570
+ g2.document = doc;
571
+ g2.HTMLElement = doc.documentElement.constructor;
572
+ if (!Object.getOwnPropertyDescriptor(
573
+ g2.HTMLElement.prototype,
574
+ "scrollIntoView"
575
+ )) {
576
+ g2.HTMLElement.prototype.scrollIntoView = () => {
577
+ };
578
+ }
579
+ }
580
+ var installed;
581
+ var init_dom_shim = __esm({
582
+ "ui/_dom_shim.ts"() {
583
+ "use strict";
584
+ installed = false;
585
+ }
586
+ });
587
+
588
+ // sdk/_mock_ws.ts
589
+ function installMockWebSocket() {
590
+ const saved = globalThis.WebSocket;
591
+ const created = [];
592
+ g.WebSocket = class extends MockWebSocket {
593
+ constructor(url, protocols) {
594
+ super(url, protocols);
595
+ created.push(this);
596
+ }
597
+ };
598
+ return {
599
+ created,
600
+ get lastWs() {
601
+ return created.at(-1) ?? null;
602
+ },
603
+ restore() {
604
+ globalThis.WebSocket = saved;
605
+ },
606
+ [Symbol.dispose]() {
607
+ globalThis.WebSocket = saved;
608
+ }
609
+ };
610
+ }
611
+ var MockWebSocket, g;
612
+ var init_mock_ws = __esm({
613
+ "sdk/_mock_ws.ts"() {
614
+ "use strict";
615
+ MockWebSocket = class _MockWebSocket extends EventTarget {
616
+ // mirrors the WebSocket API
617
+ static CONNECTING = 0;
618
+ // mirrors the WebSocket API
619
+ static OPEN = 1;
620
+ // mirrors the WebSocket API
621
+ static CLOSING = 2;
622
+ // mirrors the WebSocket API
623
+ static CLOSED = 3;
624
+ readyState = _MockWebSocket.CONNECTING;
625
+ binaryType = "arraybuffer";
626
+ /** All messages passed to {@linkcode send}, in order. */
627
+ sent = [];
628
+ url;
629
+ /**
630
+ * Create a new MockWebSocket.
631
+ *
632
+ * Automatically transitions to `OPEN` state on the next microtask,
633
+ * dispatching an `"open"` event.
634
+ *
635
+ * @param url - The WebSocket URL.
636
+ * @param _protocols - Ignored; accepted for API compatibility.
637
+ */
638
+ constructor(url, _protocols) {
639
+ super();
640
+ this.url = typeof url === "string" ? url : url.toString();
641
+ queueMicrotask(() => {
642
+ if (this.readyState === _MockWebSocket.CONNECTING) {
643
+ this.readyState = _MockWebSocket.OPEN;
644
+ this.dispatchEvent(new Event("open"));
645
+ }
646
+ });
647
+ }
648
+ /**
649
+ * Record a sent message without transmitting it.
650
+ *
651
+ * @param data - The message data to record.
652
+ */
653
+ send(data) {
654
+ this.sent.push(data);
655
+ }
656
+ /**
657
+ * Transition to `CLOSED` state and dispatch a `"close"` event.
658
+ *
659
+ * @param code - The close code (defaults to 1000).
660
+ * @param _reason - Ignored; accepted for API compatibility.
661
+ */
662
+ close(code, _reason) {
663
+ this.readyState = _MockWebSocket.CLOSED;
664
+ this.dispatchEvent(new CloseEvent("close", { code: code ?? 1e3 }));
665
+ }
666
+ /**
667
+ * Simulate receiving a message from the server.
668
+ *
669
+ * @param data - The message data (string or binary).
670
+ */
671
+ simulateMessage(data) {
672
+ this.dispatchEvent(new MessageEvent("message", { data }));
673
+ }
674
+ /** Transition to `OPEN` state and dispatch an `"open"` event. */
675
+ open() {
676
+ this.readyState = _MockWebSocket.OPEN;
677
+ this.dispatchEvent(new Event("open"));
678
+ }
679
+ /**
680
+ * Shorthand for {@linkcode simulateMessage}.
681
+ *
682
+ * @param data - The message data to dispatch.
683
+ */
684
+ msg(data) {
685
+ this.dispatchEvent(new MessageEvent("message", { data }));
686
+ }
687
+ /**
688
+ * Simulate a connection close from the server.
689
+ *
690
+ * @param code - The close code (defaults to 1000).
691
+ */
692
+ disconnect(code = 1e3) {
693
+ this.dispatchEvent(new CloseEvent("close", { code }));
694
+ }
695
+ /** Dispatch an `"error"` event on this socket. */
696
+ error() {
697
+ this.dispatchEvent(new Event("error"));
698
+ }
699
+ /**
700
+ * Return all sent string messages parsed as JSON objects.
701
+ *
702
+ * Binary messages are filtered out.
703
+ *
704
+ * @returns An array of parsed JSON objects from sent string messages.
705
+ */
706
+ sentJson() {
707
+ return this.sent.filter((d) => typeof d === "string").map((s) => JSON.parse(s));
708
+ }
709
+ };
710
+ g = globalThis;
711
+ }
712
+ });
713
+
714
+ // sdk/_render_check.ts
715
+ var render_check_exports = {};
716
+ __export(render_check_exports, {
717
+ renderCheck: () => renderCheck
718
+ });
719
+ import { createServer as createViteServer } from "vite";
720
+ async function renderCheck(clientEntry, cwd) {
721
+ installDomShim();
722
+ const g2 = globalThis;
723
+ const doc = new DOMParser().parseFromString(
724
+ '<!DOCTYPE html><html><head></head><body><main id="app"></main></body></html>',
725
+ "text/html"
726
+ );
727
+ const prevDoc = g2.document;
728
+ const prevLocation = g2.location;
729
+ g2.document = doc;
730
+ g2.location = { origin: "http://localhost:3000", pathname: "/", href: "http://localhost:3000/" };
731
+ const mock = installMockWebSocket();
732
+ const vite = await createViteServer({
733
+ root: cwd,
734
+ logLevel: "silent",
735
+ server: { middlewareMode: true }
736
+ });
737
+ try {
738
+ await vite.ssrLoadModule(clientEntry);
739
+ const app = doc.querySelector("#app");
740
+ if (!app?.innerHTML) {
741
+ throw new Error("client.tsx render check failed: #app is empty after mount()");
742
+ }
743
+ } finally {
744
+ await vite.close();
745
+ mock.restore();
746
+ g2.document = prevDoc;
747
+ g2.location = prevLocation;
748
+ }
749
+ }
750
+ var init_render_check = __esm({
751
+ "sdk/_render_check.ts"() {
752
+ "use strict";
753
+ init_dom_shim();
754
+ init_mock_ws();
755
+ }
756
+ });
757
+
758
+ // cli/_build.ts
759
+ import React2 from "react";
760
+ async function buildAgentBundle(cwd, log) {
761
+ const agent = await loadAgent(cwd);
762
+ if (!agent) {
763
+ throw new Error("No agent found \u2014 run `aai init` first");
764
+ }
765
+ log(React2.createElement(Step, { action: "Bundle", msg: agent.slug }));
766
+ let bundle;
767
+ try {
768
+ bundle = await bundleAgent(agent);
769
+ } catch (err) {
770
+ if (err instanceof BundleError) {
771
+ throw new Error(`Bundle failed: ${err.message}`);
772
+ }
773
+ throw err;
774
+ }
775
+ const kb = (bundle.workerBytes / 1024).toFixed(1);
776
+ const clientCount = Object.keys(bundle.clientFiles).length;
777
+ log(React2.createElement(Info, { msg: `worker: ${kb} KB, client: ${clientCount} file(s)` }));
778
+ if (agent.clientEntry) {
779
+ log(React2.createElement(Step, { action: "Render", msg: "check" }));
780
+ try {
781
+ const { renderCheck: renderCheck2 } = await Promise.resolve().then(() => (init_render_check(), render_check_exports));
782
+ await renderCheck2(agent.clientEntry, cwd);
783
+ } catch (err) {
784
+ throw new Error(`Render check failed: ${err instanceof Error ? err.message : String(err)}`);
785
+ }
786
+ }
787
+ return bundle;
788
+ }
789
+ var init_build = __esm({
790
+ "cli/_build.ts"() {
791
+ "use strict";
792
+ init_bundler();
793
+ init_discover();
794
+ init_ink();
795
+ }
796
+ });
797
+
599
798
  // cli/_init.ts
600
799
  var init_exports = {};
601
800
  __export(init_exports, {
@@ -684,19 +883,163 @@ var init_init = __esm({
684
883
  }
685
884
  });
686
885
 
886
+ // cli/_deploy.ts
887
+ async function attemptDeploy(url, slug, apiKey, env, worker, clientFiles) {
888
+ try {
889
+ return await _internals.fetch(`${url}/${slug}/deploy`, {
890
+ method: "POST",
891
+ headers: {
892
+ "Content-Type": "application/json",
893
+ Authorization: `Bearer ${apiKey}`
894
+ },
895
+ body: JSON.stringify({
896
+ env,
897
+ worker,
898
+ clientFiles
899
+ })
900
+ });
901
+ } catch {
902
+ throw new Error(`deployment failed: could not reach ${url}`);
903
+ }
904
+ }
905
+ async function runDeploy(opts) {
906
+ const worker = opts.bundle.worker;
907
+ const clientFiles = opts.bundle.clientFiles;
908
+ let slug = opts.slug;
909
+ if (opts.dryRun) {
910
+ return { slug };
911
+ }
912
+ for (let i = 0; i < MAX_RETRIES; i++) {
913
+ const resp = await attemptDeploy(opts.url, slug, opts.apiKey, opts.env, worker, clientFiles);
914
+ if (resp.ok) {
915
+ return { slug };
916
+ }
917
+ if (resp.status === 403) {
918
+ const text2 = await resp.text();
919
+ if (text2.includes("Slug")) {
920
+ slug = generateSlug();
921
+ continue;
922
+ }
923
+ }
924
+ const text = await resp.text();
925
+ throw new Error(`deploy failed (${resp.status}): ${text}`);
926
+ }
927
+ throw new Error(`deploy failed: could not find available slug after ${MAX_RETRIES} attempts`);
928
+ }
929
+ var _internals, MAX_RETRIES;
930
+ var init_deploy = __esm({
931
+ "cli/_deploy.ts"() {
932
+ "use strict";
933
+ init_discover();
934
+ _internals = {
935
+ fetch: globalThis.fetch.bind(globalThis)
936
+ };
937
+ MAX_RETRIES = 20;
938
+ }
939
+ });
940
+
941
+ // cli/deploy.tsx
942
+ var deploy_exports = {};
943
+ __export(deploy_exports, {
944
+ runDeployCommand: () => runDeployCommand
945
+ });
946
+ import path4 from "node:path";
947
+ import minimist from "minimist";
948
+ import { jsx as jsx3 } from "react/jsx-runtime";
949
+ function resolveServerUrl(parsed) {
950
+ return parsed.server || (isDevMode() ? "http://localhost:3100" : DEFAULT_SERVER);
951
+ }
952
+ async function deployBundle(opts) {
953
+ const { bundle, serverUrl, apiKey, cwd, log } = opts;
954
+ let { slug } = opts;
955
+ log(/* @__PURE__ */ jsx3(Step, { action: "Deploy", msg: slug }));
956
+ const deployed = await runDeploy({
957
+ url: serverUrl,
958
+ bundle,
959
+ env: { ASSEMBLYAI_API_KEY: apiKey },
960
+ slug,
961
+ dryRun: false,
962
+ apiKey
963
+ });
964
+ slug = deployed.slug;
965
+ await writeProjectConfig(cwd, { slug, serverUrl });
966
+ const agentUrl = `${serverUrl}/${slug}`;
967
+ log(/* @__PURE__ */ jsx3(Step, { action: "Ready", msg: agentUrl }));
968
+ return agentUrl;
969
+ }
970
+ async function runDeployCommand(args, version) {
971
+ const parsed = minimist(args, {
972
+ string: ["server"],
973
+ boolean: ["dry-run", "help", "yes"],
974
+ alias: { s: "server", h: "help", y: "yes" }
975
+ });
976
+ if (parsed.help) {
977
+ console.log(subcommandHelp(deployCommandDef, version));
978
+ return;
979
+ }
980
+ const cwd = process.env.INIT_CWD || process.cwd();
981
+ if (!await fileExists(path4.join(cwd, "agent.ts"))) {
982
+ await runInitCommand(parsed.yes ? ["-y"] : [], version, { quiet: true });
983
+ }
984
+ const serverUrl = resolveServerUrl(parsed);
985
+ const dryRun = parsed["dry-run"] ?? false;
986
+ const apiKey = dryRun ? "" : await getApiKey();
987
+ const projectConfig = await readProjectConfig(cwd);
988
+ const slug = projectConfig?.slug ?? generateSlug();
989
+ let agentUrl = "";
990
+ await runWithInk(async (log) => {
991
+ const bundle = await buildAgentBundle(cwd, log);
992
+ if (dryRun) {
993
+ log(/* @__PURE__ */ jsx3(StepInfo, { action: "Dry run", msg: `would deploy as ${slug}` }));
994
+ return;
995
+ }
996
+ agentUrl = await deployBundle({ bundle, serverUrl, apiKey, slug, cwd, log });
997
+ });
998
+ if (agentUrl && !dryRun) {
999
+ await askEnter("Press enter to open in browser");
1000
+ const { exec } = await import("node:child_process");
1001
+ exec(`open "${agentUrl}"`);
1002
+ }
1003
+ }
1004
+ var deployCommandDef;
1005
+ var init_deploy2 = __esm({
1006
+ "cli/deploy.tsx"() {
1007
+ "use strict";
1008
+ init_build();
1009
+ init_deploy();
1010
+ init_discover();
1011
+ init_help();
1012
+ init_ink();
1013
+ init_prompts();
1014
+ init_init2();
1015
+ deployCommandDef = {
1016
+ name: "deploy",
1017
+ description: "Bundle and deploy to production",
1018
+ options: [
1019
+ { flags: "-s, --server <url>", description: "Server URL" },
1020
+ {
1021
+ flags: "--dry-run",
1022
+ description: "Validate and bundle without deploying"
1023
+ },
1024
+ { flags: "-y, --yes", description: "Accept defaults (no prompts)" }
1025
+ ]
1026
+ };
1027
+ }
1028
+ });
1029
+
687
1030
  // cli/init.tsx
688
1031
  import { execFile } from "node:child_process";
689
1032
  import fs4 from "node:fs/promises";
690
- import path4 from "node:path";
1033
+ import path5 from "node:path";
691
1034
  import { fileURLToPath } from "node:url";
692
1035
  import { promisify } from "node:util";
693
- import minimist from "minimist";
694
- import { jsx as jsx3 } from "react/jsx-runtime";
1036
+ import minimist2 from "minimist";
1037
+ import { jsx as jsx4 } from "react/jsx-runtime";
695
1038
  async function rewriteDevDeps(cwd, cliDir2) {
696
- const monorepoRoot = path4.join(cliDir2, "..");
697
- const pkgJsonPath2 = path4.join(cwd, "package.json");
1039
+ const monorepoRoot = path5.join(cliDir2, "..");
1040
+ const pkgJsonPath2 = path5.join(cwd, "package.json");
698
1041
  const pkgJson2 = JSON.parse(await fs4.readFile(pkgJsonPath2, "utf-8"));
699
- const rootPkg = JSON.parse(await fs4.readFile(path4.join(monorepoRoot, "package.json"), "utf-8"));
1042
+ const rootPkg = JSON.parse(await fs4.readFile(path5.join(monorepoRoot, "package.json"), "utf-8"));
700
1043
  const rootPkgName = rootPkg.name;
701
1044
  if (pkgJson2.dependencies[rootPkgName]) {
702
1045
  pkgJson2.dependencies[rootPkgName] = `file:${monorepoRoot}`;
@@ -705,29 +1048,29 @@ async function rewriteDevDeps(cwd, cliDir2) {
705
1048
  `);
706
1049
  }
707
1050
  async function installDeps(cwd, log) {
708
- if (await fileExists(path4.join(cwd, "node_modules"))) return;
1051
+ if (await fileExists(path5.join(cwd, "node_modules"))) return;
709
1052
  let pkgJson2;
710
1053
  try {
711
- pkgJson2 = JSON.parse(await fs4.readFile(path4.join(cwd, "package.json"), "utf-8"));
1054
+ pkgJson2 = JSON.parse(await fs4.readFile(path5.join(cwd, "package.json"), "utf-8"));
712
1055
  } catch {
713
1056
  pkgJson2 = {};
714
1057
  }
715
1058
  const deps = Object.keys(pkgJson2.dependencies ?? {});
716
1059
  const devDeps = Object.keys(pkgJson2.devDependencies ?? {});
717
1060
  if (deps.length > 0) {
718
- log(/* @__PURE__ */ jsx3(Step, { action: "Install", msg: deps.join(", ") }));
1061
+ log(/* @__PURE__ */ jsx4(Step, { action: "Install", msg: deps.join(", ") }));
719
1062
  }
720
1063
  if (devDeps.length > 0) {
721
- log(/* @__PURE__ */ jsx3(Step, { action: "Install", msg: `dev: ${devDeps.join(", ")}` }));
1064
+ log(/* @__PURE__ */ jsx4(Step, { action: "Install", msg: `dev: ${devDeps.join(", ")}` }));
722
1065
  }
723
1066
  try {
724
1067
  await execFileAsync("npm", ["install"], { cwd });
725
1068
  } catch {
726
- log(/* @__PURE__ */ jsx3(Step, { action: "Skip", msg: "npm install failed" }));
1069
+ log(/* @__PURE__ */ jsx4(Warn, { msg: "npm install failed" }));
727
1070
  }
728
1071
  }
729
1072
  async function runInitCommand(args, version, opts) {
730
- const parsed = minimist(args, {
1073
+ const parsed = minimist2(args, {
731
1074
  string: ["template"],
732
1075
  boolean: ["force", "help"],
733
1076
  alias: { t: "template", f: "force", h: "help" }
@@ -742,19 +1085,19 @@ async function runInitCommand(args, version, opts) {
742
1085
  if (!dir) {
743
1086
  dir = await askText("What is your project named?", "my-voice-agent");
744
1087
  }
745
- const cwd = path4.resolve(process.env.INIT_CWD || process.cwd(), dir);
746
- if (!parsed.force && await fileExists(path4.join(cwd, "agent.ts"))) {
1088
+ const cwd = path5.resolve(process.env.INIT_CWD || process.cwd(), dir);
1089
+ if (!parsed.force && await fileExists(path5.join(cwd, "agent.ts"))) {
747
1090
  console.log(
748
1091
  `agent.ts already exists in this directory. Use ${interactive("--force")} to overwrite.`
749
1092
  );
750
1093
  process.exit(1);
751
1094
  }
752
- const cliDir2 = path4.dirname(fileURLToPath(import.meta.url));
753
- const templatesDir = path4.join(cliDir2, "..", "templates");
1095
+ const cliDir2 = path5.dirname(fileURLToPath(import.meta.url));
1096
+ const templatesDir = path5.join(cliDir2, "..", "templates");
754
1097
  const { runInit: runInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
755
1098
  const template = parsed.template || "simple";
756
1099
  await runWithInk(async (log) => {
757
- log(/* @__PURE__ */ jsx3(Step, { action: "Create", msg: dir }));
1100
+ log(/* @__PURE__ */ jsx4(Step, { action: "Create", msg: dir }));
758
1101
  await runInit2({ targetDir: cwd, template, templatesDir });
759
1102
  if (isDevMode()) {
760
1103
  await rewriteDevDeps(cwd, cliDir2);
@@ -794,112 +1137,6 @@ var init_init2 = __esm({
794
1137
  }
795
1138
  });
796
1139
 
797
- // cli/deploy.tsx
798
- var deploy_exports = {};
799
- __export(deploy_exports, {
800
- runDeployCommand: () => runDeployCommand
801
- });
802
- import path5 from "node:path";
803
- import minimist2 from "minimist";
804
- import { jsx as jsx4 } from "react/jsx-runtime";
805
- function resolveServerUrl(parsed) {
806
- return parsed.server || (isDevMode() ? "http://localhost:3100" : DEFAULT_SERVER);
807
- }
808
- async function buildAgent(cwd, log) {
809
- log(/* @__PURE__ */ jsx4(Step, { action: "Build", msg: "bundling agent" }));
810
- const agent = await loadAgent(cwd);
811
- if (!agent) {
812
- throw new Error("No agent found \u2014 run `aai init` first");
813
- }
814
- let bundle;
815
- try {
816
- bundle = await bundleAgent(agent);
817
- } catch (err) {
818
- if (err instanceof BundleError) {
819
- throw new Error(`Bundle failed: ${err.message}`);
820
- }
821
- throw err;
822
- }
823
- return bundle;
824
- }
825
- async function deployBundle(opts) {
826
- const { bundle, serverUrl, apiKey, cwd, log } = opts;
827
- let { slug } = opts;
828
- log(/* @__PURE__ */ jsx4(Step, { action: "Deploy", msg: slug }));
829
- const deployed = await runDeploy({
830
- url: serverUrl,
831
- bundle,
832
- env: { ASSEMBLYAI_API_KEY: apiKey },
833
- slug,
834
- dryRun: false,
835
- apiKey
836
- });
837
- slug = deployed.slug;
838
- await writeProjectConfig(cwd, { slug, serverUrl });
839
- const agentUrl = `${serverUrl}/${slug}`;
840
- log(/* @__PURE__ */ jsx4(Step, { action: "Ready", msg: agentUrl }));
841
- return agentUrl;
842
- }
843
- async function runDeployCommand(args, version) {
844
- const parsed = minimist2(args, {
845
- string: ["server"],
846
- boolean: ["dry-run", "help", "yes"],
847
- alias: { s: "server", h: "help", y: "yes" }
848
- });
849
- if (parsed.help) {
850
- console.log(subcommandHelp(deployCommandDef, version));
851
- return;
852
- }
853
- const cwd = process.env.INIT_CWD || process.cwd();
854
- if (!await fileExists(path5.join(cwd, "agent.ts"))) {
855
- await runInitCommand(parsed.yes ? ["-y"] : [], version, { quiet: true });
856
- }
857
- const serverUrl = resolveServerUrl(parsed);
858
- const dryRun = parsed["dry-run"] ?? false;
859
- const apiKey = dryRun ? "" : await getApiKey();
860
- const projectConfig = await readProjectConfig(cwd);
861
- const slug = projectConfig?.slug ?? generateSlug();
862
- let agentUrl = "";
863
- await runWithInk(async (log) => {
864
- const bundle = await buildAgent(cwd, log);
865
- if (dryRun) {
866
- log(/* @__PURE__ */ jsx4(StepInfo, { action: "Dry run", msg: `would deploy as ${slug}` }));
867
- return;
868
- }
869
- agentUrl = await deployBundle({ bundle, serverUrl, apiKey, slug, cwd, log });
870
- });
871
- if (agentUrl && !dryRun) {
872
- await askEnter("Press enter to open in browser");
873
- const { exec } = await import("node:child_process");
874
- exec(`open "${agentUrl}"`);
875
- }
876
- }
877
- var deployCommandDef;
878
- var init_deploy2 = __esm({
879
- "cli/deploy.tsx"() {
880
- "use strict";
881
- init_bundler();
882
- init_deploy();
883
- init_discover();
884
- init_help();
885
- init_ink();
886
- init_prompts();
887
- init_init2();
888
- deployCommandDef = {
889
- name: "deploy",
890
- description: "Bundle and deploy to production",
891
- options: [
892
- { flags: "-s, --server <url>", description: "Server URL" },
893
- {
894
- flags: "--dry-run",
895
- description: "Validate and bundle without deploying"
896
- },
897
- { flags: "-y, --yes", description: "Accept defaults (no prompts)" }
898
- ]
899
- };
900
- }
901
- });
902
-
903
1140
  // sdk/protocol.ts
904
1141
  import { z } from "zod";
905
1142
  var DEFAULT_TTS_SAMPLE_RATE, AUDIO_FORMAT, _bitsPerSample, _channels, AudioFrameSpec, KvRequestBaseSchema, HOOK_TIMEOUT_MS, SessionErrorCodeSchema, TranscriptEventSchema, ClientEventSchema, ClientMessageSchema;
@@ -965,6 +1202,7 @@ var init_protocol = __esm({
965
1202
  turnOrder: z.number().int().nonnegative().optional()
966
1203
  }),
967
1204
  z.object({ type: z.literal("chat"), text: z.string() }),
1205
+ z.object({ type: z.literal("chat_delta"), text: z.string() }),
968
1206
  z.object({
969
1207
  type: z.literal("tool_call_start"),
970
1208
  toolCallId: z.string(),
@@ -1058,9 +1296,86 @@ var init_internal_types = __esm({
1058
1296
  }
1059
1297
  });
1060
1298
 
1299
+ // sdk/types.ts
1300
+ function tool(def) {
1301
+ return def;
1302
+ }
1303
+ var DEFAULT_INSTRUCTIONS;
1304
+ var init_types = __esm({
1305
+ "sdk/types.ts"() {
1306
+ "use strict";
1307
+ DEFAULT_INSTRUCTIONS = `You are AAI, a helpful AI assistant.
1308
+
1309
+ Voice-First Rules:
1310
+ - Optimize for natural speech. Avoid jargon unless central to the answer. Use short, punchy sentences.
1311
+ - Never mention "search results," "sources," or "the provided text." Speak as if the knowledge is your own.
1312
+ - No visual formatting. Do not say "bullet point," "bold," or "bracketed one." If you need to list items, say "First," "Next," and "Finally."
1313
+ - Start with the most important information. No introductory filler.
1314
+ - Be concise. Keep answers to 1-3 sentences. For complex topics, provide a high-level summary.
1315
+ - Be confident. Avoid hedging phrases like "It seems that" or "I believe."
1316
+ - If you don't have enough information, say so directly rather than guessing.
1317
+ - Never use exclamation points. Keep your tone calm and conversational.`;
1318
+ }
1319
+ });
1320
+
1321
+ // sdk/memory_tools.ts
1322
+ import { z as z3 } from "zod";
1323
+ function memoryTools() {
1324
+ return {
1325
+ save_memory: tool({
1326
+ description: "Save a piece of information to persistent memory. Use a descriptive key like 'user:name' or 'project:status'.",
1327
+ parameters: z3.object({
1328
+ key: z3.string().describe("A descriptive key for this memory (e.g. 'user:name', 'preference:color')"),
1329
+ value: z3.string().describe("The information to remember")
1330
+ }),
1331
+ execute: async ({ key, value }, ctx) => {
1332
+ await ctx.kv.set(key, value);
1333
+ return { saved: key };
1334
+ }
1335
+ }),
1336
+ recall_memory: tool({
1337
+ description: "Retrieve a previously saved memory by its key.",
1338
+ parameters: z3.object({
1339
+ key: z3.string().describe("The key to look up")
1340
+ }),
1341
+ execute: async ({ key }, ctx) => {
1342
+ const value = await ctx.kv.get(key);
1343
+ if (value === null) return { found: false, key };
1344
+ return { found: true, key, value };
1345
+ }
1346
+ }),
1347
+ list_memories: tool({
1348
+ description: "List all saved memory keys, optionally filtered by a prefix (e.g. 'user:').",
1349
+ parameters: z3.object({
1350
+ prefix: z3.string().describe("Prefix to filter keys (e.g. 'user:'). Use empty string for all.").optional()
1351
+ }),
1352
+ execute: async ({ prefix }, ctx) => {
1353
+ const entries = await ctx.kv.list(prefix ?? "");
1354
+ return { count: entries.length, keys: entries.map((e) => e.key) };
1355
+ }
1356
+ }),
1357
+ forget_memory: tool({
1358
+ description: "Delete a previously saved memory by its key.",
1359
+ parameters: z3.object({
1360
+ key: z3.string().describe("The key to delete")
1361
+ }),
1362
+ execute: async ({ key }, ctx) => {
1363
+ await ctx.kv.delete(key);
1364
+ return { deleted: key };
1365
+ }
1366
+ })
1367
+ };
1368
+ }
1369
+ var init_memory_tools = __esm({
1370
+ "sdk/memory_tools.ts"() {
1371
+ "use strict";
1372
+ init_types();
1373
+ }
1374
+ });
1375
+
1061
1376
  // sdk/builtin_tools.ts
1062
1377
  import { convert } from "html-to-text";
1063
- import { z as z3 } from "zod";
1378
+ import { z as z4 } from "zod";
1064
1379
  function htmlToText(html) {
1065
1380
  return convert(html, { wordwrap: false });
1066
1381
  }
@@ -1213,12 +1528,27 @@ function getBuiltinToolDefs(names, opts) {
1213
1528
  defs[name] = createVectorSearch(opts.vectorSearch);
1214
1529
  }
1215
1530
  break;
1531
+ case "memory": {
1532
+ const mt = memoryTools();
1533
+ for (const [toolName, toolDef] of Object.entries(mt)) {
1534
+ defs[toolName] = toolDef;
1535
+ }
1536
+ break;
1537
+ }
1216
1538
  }
1217
1539
  }
1218
1540
  return defs;
1219
1541
  }
1220
1542
  function getBuiltinToolSchemas(names) {
1221
1543
  return names.flatMap((name) => {
1544
+ const multiCreator = MULTI_TOOL_BUILTINS[name];
1545
+ if (multiCreator) {
1546
+ return Object.entries(multiCreator()).map(([toolName, def2]) => ({
1547
+ name: toolName,
1548
+ description: def2.description,
1549
+ parameters: z4.toJSONSchema(def2.parameters ?? EMPTY_PARAMS)
1550
+ }));
1551
+ }
1222
1552
  const creator = TOOL_CREATORS[name];
1223
1553
  if (!creator) return [];
1224
1554
  const def = creator();
@@ -1226,49 +1556,50 @@ function getBuiltinToolSchemas(names) {
1226
1556
  {
1227
1557
  name,
1228
1558
  description: def.description,
1229
- parameters: z3.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
1559
+ parameters: z4.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
1230
1560
  }
1231
1561
  ];
1232
1562
  });
1233
1563
  }
1234
- var webSearchParams, BRAVE_SEARCH_URL, BraveSearchResponseSchema, MAX_PAGE_CHARS, MAX_HTML_BYTES, visitWebpageParams, fetchJsonParams, runCodeParams, vectorSearchParams, TOOL_CREATORS;
1564
+ var webSearchParams, BRAVE_SEARCH_URL, BraveSearchResponseSchema, MAX_PAGE_CHARS, MAX_HTML_BYTES, visitWebpageParams, fetchJsonParams, runCodeParams, vectorSearchParams, TOOL_CREATORS, MULTI_TOOL_BUILTINS;
1235
1565
  var init_builtin_tools = __esm({
1236
1566
  "sdk/builtin_tools.ts"() {
1237
1567
  "use strict";
1238
1568
  init_internal_types();
1239
- webSearchParams = z3.object({
1240
- query: z3.string().describe("The search query"),
1241
- max_results: z3.number().describe("Maximum number of results to return (default 5)").optional()
1569
+ init_memory_tools();
1570
+ webSearchParams = z4.object({
1571
+ query: z4.string().describe("The search query"),
1572
+ max_results: z4.number().describe("Maximum number of results to return (default 5)").optional()
1242
1573
  });
1243
1574
  BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search";
1244
- BraveSearchResponseSchema = z3.object({
1245
- web: z3.object({
1246
- results: z3.array(
1247
- z3.object({
1248
- title: z3.string(),
1249
- url: z3.string(),
1250
- description: z3.string()
1575
+ BraveSearchResponseSchema = z4.object({
1576
+ web: z4.object({
1577
+ results: z4.array(
1578
+ z4.object({
1579
+ title: z4.string(),
1580
+ url: z4.string(),
1581
+ description: z4.string()
1251
1582
  })
1252
1583
  )
1253
1584
  }).optional()
1254
1585
  });
1255
1586
  MAX_PAGE_CHARS = 1e4;
1256
1587
  MAX_HTML_BYTES = 2e5;
1257
- visitWebpageParams = z3.object({
1258
- url: z3.string().describe("The full URL to fetch (e.g., 'https://example.com/page')")
1588
+ visitWebpageParams = z4.object({
1589
+ url: z4.string().describe("The full URL to fetch (e.g., 'https://example.com/page')")
1259
1590
  });
1260
- fetchJsonParams = z3.object({
1261
- url: z3.string().describe("The URL to fetch JSON from"),
1262
- headers: z3.record(z3.string(), z3.string()).describe("Optional HTTP headers to include in the request").optional()
1591
+ fetchJsonParams = z4.object({
1592
+ url: z4.string().describe("The URL to fetch JSON from"),
1593
+ headers: z4.record(z4.string(), z4.string()).describe("Optional HTTP headers to include in the request").optional()
1263
1594
  });
1264
- runCodeParams = z3.object({
1265
- code: z3.string().describe("JavaScript code to execute. Use console.log() for output.")
1595
+ runCodeParams = z4.object({
1596
+ code: z4.string().describe("JavaScript code to execute. Use console.log() for output.")
1266
1597
  });
1267
- vectorSearchParams = z3.object({
1268
- query: z3.string().describe(
1598
+ vectorSearchParams = z4.object({
1599
+ query: z4.string().describe(
1269
1600
  'Short keyword query to search the knowledge base. Use specific topic terms, not full sentences. Do NOT include the company or product name since all documents are from the same source. For example, if the user asks "how much does Acme cost", search for "pricing plans rates".'
1270
1601
  ),
1271
- topK: z3.number().describe("Maximum results to return (default: 5)").optional()
1602
+ topK: z4.number().describe("Maximum results to return (default: 5)").optional()
1272
1603
  });
1273
1604
  TOOL_CREATORS = {
1274
1605
  web_search: createWebSearch,
@@ -1278,6 +1609,9 @@ var init_builtin_tools = __esm({
1278
1609
  // vector_search uses a stub for schema generation
1279
1610
  vector_search: () => createVectorSearch(async () => "")
1280
1611
  };
1612
+ MULTI_TOOL_BUILTINS = {
1613
+ memory: memoryTools
1614
+ };
1281
1615
  }
1282
1616
  });
1283
1617
 
@@ -1348,7 +1682,7 @@ var init_kv = __esm({
1348
1682
  });
1349
1683
 
1350
1684
  // sdk/s2s.ts
1351
- import { z as z4 } from "zod";
1685
+ import { z as z5 } from "zod";
1352
1686
  function uint8ToBase64(bytes) {
1353
1687
  return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
1354
1688
  }
@@ -1486,7 +1820,9 @@ function connectS2s(opts) {
1486
1820
  }
1487
1821
  },
1488
1822
  sendToolResult(callId, result) {
1489
- send({ type: "tool.result", call_id: callId, result });
1823
+ const msg = { type: "tool.result", call_id: callId, result };
1824
+ log.debug("S2S >> tool.result", { call_id: callId, resultLength: result.length });
1825
+ send(msg);
1490
1826
  },
1491
1827
  updateSession(sessionConfig) {
1492
1828
  send({ type: "session.update", session: sessionConfig });
@@ -1516,6 +1852,9 @@ function connectS2s(opts) {
1516
1852
  return;
1517
1853
  }
1518
1854
  const obj = raw;
1855
+ if (obj.type !== "reply.audio" && obj.type !== "input.audio" && obj.type !== "transcript.agent.delta") {
1856
+ log.info(`S2S << ${obj.type}`);
1857
+ }
1519
1858
  if (obj.type === "reply.audio" && typeof obj.data === "string") {
1520
1859
  const audioBytes = base64ToUint8(obj.data);
1521
1860
  target.dispatchEvent(new CustomEvent("audio", { detail: { audio: audioBytes } }));
@@ -1523,13 +1862,12 @@ function connectS2s(opts) {
1523
1862
  }
1524
1863
  const parsed = S2sServerMessageSchema.safeParse(raw);
1525
1864
  if (!parsed.success) {
1526
- log.debug(
1527
- `S2S << unrecognised message type: ${obj.type ?? JSON.stringify(raw).slice(0, 100)}`
1865
+ log.warn(
1866
+ `S2S << unrecognised message type: ${obj.type ?? JSON.stringify(raw).slice(0, 200)}`
1528
1867
  );
1529
1868
  return;
1530
1869
  }
1531
1870
  const msg = parsed.data;
1532
- log.debug(`S2S << ${msg.type}`);
1533
1871
  dispatchS2sMessage(target, msg);
1534
1872
  });
1535
1873
  ws.on("close", (code, reason) => {
@@ -1560,66 +1898,47 @@ var init_s2s = __esm({
1560
1898
  "use strict";
1561
1899
  init_runtime();
1562
1900
  WS_OPEN = 1;
1563
- S2sServerMessageSchema = z4.discriminatedUnion("type", [
1564
- z4.object({ type: z4.literal("session.ready"), session_id: z4.string() }),
1565
- z4.object({ type: z4.literal("session.updated") }).passthrough(),
1566
- z4.object({ type: z4.literal("input.speech.started") }),
1567
- z4.object({ type: z4.literal("input.speech.stopped") }),
1568
- z4.object({ type: z4.literal("transcript.user.delta"), text: z4.string() }),
1569
- z4.object({
1570
- type: z4.literal("transcript.user"),
1571
- item_id: z4.string(),
1572
- text: z4.string()
1901
+ S2sServerMessageSchema = z5.discriminatedUnion("type", [
1902
+ z5.object({ type: z5.literal("session.ready"), session_id: z5.string() }),
1903
+ z5.object({ type: z5.literal("session.updated") }).passthrough(),
1904
+ z5.object({ type: z5.literal("input.speech.started") }),
1905
+ z5.object({ type: z5.literal("input.speech.stopped") }),
1906
+ z5.object({ type: z5.literal("transcript.user.delta"), text: z5.string() }),
1907
+ z5.object({
1908
+ type: z5.literal("transcript.user"),
1909
+ item_id: z5.string(),
1910
+ text: z5.string()
1573
1911
  }),
1574
- z4.object({ type: z4.literal("reply.started"), reply_id: z4.string() }),
1912
+ z5.object({ type: z5.literal("reply.started"), reply_id: z5.string() }),
1575
1913
  // reply.audio is handled on the fast path before Zod — see message handler.
1576
- z4.object({ type: z4.literal("transcript.agent.delta"), delta: z4.string() }).passthrough(),
1577
- z4.object({ type: z4.literal("transcript.agent"), text: z4.string() }),
1578
- z4.object({ type: z4.literal("reply.content_part.started") }).passthrough(),
1579
- z4.object({ type: z4.literal("reply.content_part.done") }).passthrough(),
1580
- z4.object({
1581
- type: z4.literal("tool.call"),
1582
- call_id: z4.string(),
1583
- name: z4.string(),
1584
- args: z4.record(z4.string(), z4.unknown()).optional().default({})
1914
+ z5.object({ type: z5.literal("transcript.agent.delta"), delta: z5.string() }).passthrough(),
1915
+ z5.object({ type: z5.literal("transcript.agent"), text: z5.string() }),
1916
+ z5.object({ type: z5.literal("reply.content_part.started") }).passthrough(),
1917
+ z5.object({ type: z5.literal("reply.content_part.done") }).passthrough(),
1918
+ z5.object({
1919
+ type: z5.literal("tool.call"),
1920
+ call_id: z5.string(),
1921
+ name: z5.string(),
1922
+ args: z5.record(z5.string(), z5.unknown()).optional().default({})
1585
1923
  }),
1586
- z4.object({
1587
- type: z4.literal("reply.done"),
1588
- status: z4.string().optional()
1924
+ z5.object({
1925
+ type: z5.literal("reply.done"),
1926
+ status: z5.string().optional()
1589
1927
  }),
1590
- z4.object({
1591
- type: z4.literal("session.error"),
1592
- code: z4.string(),
1593
- message: z4.string()
1928
+ z5.object({
1929
+ type: z5.literal("session.error"),
1930
+ code: z5.string(),
1931
+ message: z5.string()
1594
1932
  }),
1595
1933
  // Connection-level error (bare "error" without "session." prefix).
1596
- z4.object({
1597
- type: z4.literal("error"),
1598
- message: z4.string()
1934
+ z5.object({
1935
+ type: z5.literal("error"),
1936
+ message: z5.string()
1599
1937
  })
1600
1938
  ]);
1601
1939
  }
1602
1940
  });
1603
1941
 
1604
- // sdk/types.ts
1605
- var DEFAULT_INSTRUCTIONS;
1606
- var init_types = __esm({
1607
- "sdk/types.ts"() {
1608
- "use strict";
1609
- DEFAULT_INSTRUCTIONS = `You are AAI, a helpful AI assistant.
1610
-
1611
- Voice-First Rules:
1612
- - Optimize for natural speech. Avoid jargon unless central to the answer. Use short, punchy sentences.
1613
- - Never mention "search results," "sources," or "the provided text." Speak as if the knowledge is your own.
1614
- - No visual formatting. Do not say "bullet point," "bold," or "bracketed one." If you need to list items, say "First," "Next," and "Finally."
1615
- - Start with the most important information. No introductory filler.
1616
- - Be concise. Keep answers to 1-3 sentences. For complex topics, provide a high-level summary.
1617
- - Be confident. Avoid hedging phrases like "It seems that" or "I believe."
1618
- - If you don't have enough information, say so directly rather than guessing.
1619
- - Never use exclamation points. Keep your tone calm and conversational.`;
1620
- }
1621
- });
1622
-
1623
1942
  // sdk/system_prompt.ts
1624
1943
  function buildSystemPrompt(config, opts) {
1625
1944
  const { hasTools } = opts;
@@ -1822,6 +2141,9 @@ function createS2sSession(opts) {
1822
2141
  on(handle, "audio", (e) => {
1823
2142
  client.playAudioChunk(e.detail.audio);
1824
2143
  });
2144
+ on(handle, "agent_transcript_delta", (e) => {
2145
+ client.event({ type: "chat_delta", text: e.detail.text });
2146
+ });
1825
2147
  on(handle, "agent_transcript", (e) => {
1826
2148
  const { text } = e.detail;
1827
2149
  client.event({ type: "chat", text });
@@ -1841,8 +2163,8 @@ function createS2sSession(opts) {
1841
2163
  pendingTools = [];
1842
2164
  client.event({ type: "cancelled" });
1843
2165
  } else if (pendingTools.length > 0) {
1844
- for (const tool of pendingTools) {
1845
- s2s?.sendToolResult(tool.call_id, tool.result);
2166
+ for (const tool2 of pendingTools) {
2167
+ s2s?.sendToolResult(tool2.call_id, tool2.result);
1846
2168
  }
1847
2169
  pendingTools = [];
1848
2170
  } else {
@@ -1860,6 +2182,7 @@ function createS2sSession(opts) {
1860
2182
  code: "internal",
1861
2183
  message: e.detail.message
1862
2184
  });
2185
+ handle.close();
1863
2186
  });
1864
2187
  handle.addEventListener("close", () => {
1865
2188
  log.info("S2S closed");
@@ -2023,8 +2346,8 @@ function buildToolContext(opts) {
2023
2346
  };
2024
2347
  }
2025
2348
  async function executeToolCall(name, args, options) {
2026
- const { tool } = options;
2027
- const schema = tool.parameters ?? EMPTY_PARAMS;
2349
+ const { tool: tool2 } = options;
2350
+ const schema = tool2.parameters ?? EMPTY_PARAMS;
2028
2351
  const parsed = schema.safeParse(args);
2029
2352
  if (!parsed.success) {
2030
2353
  const issues = (parsed.error?.issues ?? []).map((i) => `${i.path.map(String).join(".")}: ${i.message}`).join(", ");
@@ -2033,7 +2356,7 @@ async function executeToolCall(name, args, options) {
2033
2356
  try {
2034
2357
  const ctx = buildToolContext(options);
2035
2358
  await yieldTick();
2036
- const result = await Promise.resolve(tool.execute(parsed.data, ctx));
2359
+ const result = await Promise.resolve(tool2.execute(parsed.data, ctx));
2037
2360
  await yieldTick();
2038
2361
  if (result == null) return "null";
2039
2362
  return typeof result === "string" ? result : JSON.stringify(result);
@@ -2061,8 +2384,7 @@ function buildAgentConfig(agent) {
2061
2384
  const config = {
2062
2385
  name: agent.name,
2063
2386
  instructions: agent.instructions,
2064
- greeting: agent.greeting,
2065
- voice: agent.voice
2387
+ greeting: agent.greeting
2066
2388
  };
2067
2389
  if (agent.sttPrompt !== void 0) config.sttPrompt = agent.sttPrompt;
2068
2390
  if (typeof agent.maxSteps !== "function") config.maxSteps = agent.maxSteps;
@@ -2117,10 +2439,10 @@ function createDirectExecutor(opts) {
2117
2439
  };
2118
2440
  }
2119
2441
  const executeTool = async (name, args, sessionId, messages) => {
2120
- const tool = allTools[name];
2121
- if (!tool) return JSON.stringify({ error: `Unknown tool: ${name}` });
2442
+ const tool2 = allTools[name];
2443
+ if (!tool2) return JSON.stringify({ error: `Unknown tool: ${name}` });
2122
2444
  return executeToolCall(name, args, {
2123
- tool,
2445
+ tool: tool2,
2124
2446
  env: frozenEnv,
2125
2447
  sessionId,
2126
2448
  state: getState(sessionId ?? ""),
@@ -2590,30 +2912,64 @@ var init_server = __esm({
2590
2912
 
2591
2913
  // cli/cli.ts
2592
2914
  init_help();
2593
- init_deploy2();
2594
2915
  import { readFileSync } from "node:fs";
2595
- import path10 from "node:path";
2916
+ import path11 from "node:path";
2596
2917
  import { fileURLToPath as fileURLToPath2 } from "node:url";
2597
- import minimist7 from "minimist";
2918
+ import minimist8 from "minimist";
2598
2919
 
2599
- // cli/dev.tsx
2600
- import path7 from "node:path";
2920
+ // cli/build.tsx
2921
+ init_build();
2922
+ init_discover();
2923
+ init_help();
2924
+ init_ink();
2925
+ init_init2();
2926
+ import path6 from "node:path";
2601
2927
  import minimist3 from "minimist";
2928
+ import { jsx as jsx5 } from "react/jsx-runtime";
2929
+ var buildCommandDef = {
2930
+ name: "build",
2931
+ description: "Bundle agent and client (validates code without deploying or starting a server)",
2932
+ options: [{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }]
2933
+ };
2934
+ async function runBuildCommand(args, version) {
2935
+ const parsed = minimist3(args, {
2936
+ boolean: ["help", "yes"],
2937
+ alias: { h: "help", y: "yes" }
2938
+ });
2939
+ if (parsed.help) {
2940
+ console.log(subcommandHelp(buildCommandDef, version));
2941
+ return;
2942
+ }
2943
+ const cwd = process.env.INIT_CWD || process.cwd();
2944
+ if (!await fileExists(path6.join(cwd, "agent.ts"))) {
2945
+ await runInitCommand(parsed.yes ? ["-y"] : [], version, { quiet: true });
2946
+ }
2947
+ await runWithInk(async (log) => {
2948
+ await buildAgentBundle(cwd, log);
2949
+ log(/* @__PURE__ */ jsx5(Step, { action: "Build", msg: "ok" }));
2950
+ });
2951
+ }
2952
+
2953
+ // cli/cli.ts
2954
+ init_deploy2();
2955
+
2956
+ // cli/dev.tsx
2957
+ import path8 from "node:path";
2958
+ import minimist4 from "minimist";
2602
2959
 
2603
2960
  // cli/_dev.ts
2604
- init_bundler();
2605
- init_discover();
2961
+ init_build();
2606
2962
  init_ink();
2607
- import React2 from "react";
2963
+ import React3 from "react";
2608
2964
 
2609
2965
  // cli/_server_common.ts
2610
2966
  init_discover();
2611
2967
  import fs5 from "node:fs/promises";
2612
- import path6 from "node:path";
2613
- import { createServer as createViteServer } from "vite";
2968
+ import path7 from "node:path";
2969
+ import { createServer as createViteServer2 } from "vite";
2614
2970
  async function loadAgentDef(cwd) {
2615
- const agentPath = path6.resolve(cwd, "agent.ts");
2616
- const vite = await createViteServer({
2971
+ const agentPath = path7.resolve(cwd, "agent.ts");
2972
+ const vite = await createViteServer2({
2617
2973
  root: cwd,
2618
2974
  logLevel: "silent",
2619
2975
  server: { middlewareMode: true }
@@ -2642,7 +2998,7 @@ async function bootServer(agentDef, clientDir, env, port) {
2642
2998
  const wsMod = await import("ws");
2643
2999
  const WS = wsMod.default ?? wsMod;
2644
3000
  const createWebSocket = (url, opts) => new WS(url, { headers: opts.headers });
2645
- const clientHtml = await fs5.readFile(path6.join(clientDir, "index.html"), "utf-8");
3001
+ const clientHtml = await fs5.readFile(path7.join(clientDir, "index.html"), "utf-8");
2646
3002
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
2647
3003
  const server = createServer2({
2648
3004
  agent: agentDef,
@@ -2656,25 +3012,11 @@ async function bootServer(agentDef, clientDir, env, port) {
2656
3012
 
2657
3013
  // cli/_dev.ts
2658
3014
  async function _startDevServer(cwd, port, log) {
2659
- const agent = await loadAgent(cwd);
2660
- if (!agent) {
2661
- throw new Error("No agent found \u2014 run `aai init` first");
2662
- }
2663
- log(React2.createElement(Step, { action: "Build", msg: agent.slug }));
2664
- let clientDir;
2665
- try {
2666
- const bundle = await bundleAgent(agent);
2667
- clientDir = bundle.clientDir;
2668
- } catch (err) {
2669
- if (err instanceof BundleError) {
2670
- throw new Error(`Bundle failed: ${err.message}`);
2671
- }
2672
- throw err;
2673
- }
3015
+ const bundle = await buildAgentBundle(cwd, log);
2674
3016
  const agentDef = await loadAgentDef(cwd);
2675
3017
  const env = await resolveServerEnv();
2676
- await bootServer(agentDef, clientDir, env, port);
2677
- log(React2.createElement(Step, { action: "Ready", msg: `http://localhost:${port}` }));
3018
+ await bootServer(agentDef, bundle.clientDir, env, port);
3019
+ log(React3.createElement(Step, { action: "Ready", msg: `http://localhost:${port}` }));
2678
3020
  }
2679
3021
 
2680
3022
  // cli/dev.tsx
@@ -2694,7 +3036,7 @@ var devCommandDef = {
2694
3036
  ]
2695
3037
  };
2696
3038
  async function runDevCommand(args, version) {
2697
- const parsed = minimist3(args, {
3039
+ const parsed = minimist4(args, {
2698
3040
  string: ["port"],
2699
3041
  boolean: ["help", "yes"],
2700
3042
  alias: { p: "port", h: "help", y: "yes" }
@@ -2705,7 +3047,7 @@ async function runDevCommand(args, version) {
2705
3047
  }
2706
3048
  const cwd = process.env.INIT_CWD || process.cwd();
2707
3049
  const port = Number.parseInt(parsed.port ?? "3000", 10);
2708
- if (!await fileExists(path7.join(cwd, "agent.ts"))) {
3050
+ if (!await fileExists(path8.join(cwd, "agent.ts"))) {
2709
3051
  await runInitCommand(parsed.yes ? ["-y"] : [], version, { quiet: true });
2710
3052
  }
2711
3053
  await getApiKey();
@@ -2722,10 +3064,10 @@ init_discover();
2722
3064
  init_help();
2723
3065
  init_ink();
2724
3066
  import { render as render3, Text as Text3, useApp as useApp2 } from "ink";
2725
- import minimist4 from "minimist";
3067
+ import minimist5 from "minimist";
2726
3068
  import pLimit from "p-limit";
2727
3069
  import { useEffect, useState as useState2 } from "react";
2728
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
3070
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
2729
3071
  var ragCommandDef = {
2730
3072
  name: "rag",
2731
3073
  description: "Ingest a site's llms-full.txt into the vector store",
@@ -2740,7 +3082,7 @@ var ragCommandDef = {
2740
3082
  ]
2741
3083
  };
2742
3084
  var FETCH_TIMEOUT_MS = 6e4;
2743
- var PAD = 9;
3085
+ var PAD = 2;
2744
3086
  function RagUI({ url, apiKey, serverUrl, slug, chunkSize, onError }) {
2745
3087
  const { exit } = useApp2();
2746
3088
  const { items, log } = useStepLog();
@@ -2768,8 +3110,8 @@ function RagUI({ url, apiKey, serverUrl, slug, chunkSize, onError }) {
2768
3110
  })();
2769
3111
  }, [apiKey, chunkSize, exit, log, onError, serverUrl, slug, url]);
2770
3112
  return /* @__PURE__ */ jsxs3(Fragment2, { children: [
2771
- /* @__PURE__ */ jsx5(StepLog, { items }),
2772
- err && /* @__PURE__ */ jsx5(ErrorLine, { msg: err }),
3113
+ /* @__PURE__ */ jsx6(StepLog, { items }),
3114
+ err && /* @__PURE__ */ jsx6(ErrorLine, { msg: err }),
2773
3115
  progress && /* @__PURE__ */ jsxs3(Text3, { children: [
2774
3116
  " ".repeat(PAD + 1),
2775
3117
  "Upsert ",
@@ -2784,7 +3126,7 @@ function RagUI({ url, apiKey, serverUrl, slug, chunkSize, onError }) {
2784
3126
  }
2785
3127
  async function runRag(opts) {
2786
3128
  const { url, apiKey, serverUrl, slug, chunkSize, log, setProgress } = opts;
2787
- log(/* @__PURE__ */ jsx5(Step, { action: "Fetch", msg: url }));
3129
+ log(/* @__PURE__ */ jsx6(Step, { action: "Fetch", msg: url }));
2788
3130
  const resp = await fetch(url, {
2789
3131
  headers: { "User-Agent": "aai-cli/1.0" },
2790
3132
  redirect: "follow",
@@ -2795,27 +3137,27 @@ async function runRag(opts) {
2795
3137
  }
2796
3138
  const content = await resp.text();
2797
3139
  if (content.length === 0) {
2798
- log(/* @__PURE__ */ jsx5(Warn, { msg: "File is empty" }));
3140
+ log(/* @__PURE__ */ jsx6(Warn, { msg: "File is empty" }));
2799
3141
  return;
2800
3142
  }
2801
- log(/* @__PURE__ */ jsx5(Info, { msg: `${(content.length / 1024).toFixed(0)} KB` }));
3143
+ log(/* @__PURE__ */ jsx6(Info, { msg: `${(content.length / 1024).toFixed(0)} KB` }));
2802
3144
  const origin = new URL(url).origin;
2803
3145
  const pages = splitPages(content);
2804
- log(/* @__PURE__ */ jsx5(Step, { action: "Parsed", msg: `${pages.length} pages` }));
3146
+ log(/* @__PURE__ */ jsx6(Step, { action: "Parse", msg: `${pages.length} pages` }));
2805
3147
  const { RecursiveChunker } = await import("@chonkiejs/core");
2806
3148
  const chunker = await RecursiveChunker.create({ chunkSize });
2807
3149
  const siteSlug = slugify(origin);
2808
3150
  const allChunks = await chunkPages(pages, chunker, origin, siteSlug);
2809
- log(/* @__PURE__ */ jsx5(Step, { action: "Chunked", msg: `${allChunks.length} chunks` }));
3151
+ log(/* @__PURE__ */ jsx6(Step, { action: "Chunk", msg: `${allChunks.length} chunks` }));
2810
3152
  const vectorUrl = `${serverUrl}/${slug}/vector`;
2811
- log(/* @__PURE__ */ jsx5(Info, { msg: `target: ${vectorUrl}` }));
3153
+ log(/* @__PURE__ */ jsx6(Info, { msg: `target: ${vectorUrl}` }));
2812
3154
  const result = await upsertChunks(allChunks, vectorUrl, apiKey, setProgress);
2813
- log(/* @__PURE__ */ jsx5(Step, { action: "Done", msg: `${result.upserted} chunks upserted` }));
3155
+ log(/* @__PURE__ */ jsx6(Step, { action: "Done", msg: `${result.upserted} chunks upserted` }));
2814
3156
  if (result.errors > 0) {
2815
- log(/* @__PURE__ */ jsx5(Warn, { msg: `${result.errors} failed` }));
2816
- if (result.lastError) log(/* @__PURE__ */ jsx5(Info, { msg: `last error: ${result.lastError}` }));
3157
+ log(/* @__PURE__ */ jsx6(Warn, { msg: `${result.errors} failed` }));
3158
+ if (result.lastError) log(/* @__PURE__ */ jsx6(Info, { msg: `last error: ${result.lastError}` }));
2817
3159
  }
2818
- log(/* @__PURE__ */ jsx5(Detail, { msg: `Agent: ${slug}` }));
3160
+ log(/* @__PURE__ */ jsx6(Detail, { msg: `Agent: ${slug}` }));
2819
3161
  }
2820
3162
  async function chunkPages(pages, chunker, origin, siteSlug) {
2821
3163
  const allChunks = [];
@@ -2884,7 +3226,7 @@ async function upsertChunks(chunks, vectorUrl, apiKey, setProgress) {
2884
3226
  return { upserted, errors, lastError };
2885
3227
  }
2886
3228
  async function runRagCommand(args, version) {
2887
- const parsed = minimist4(args, {
3229
+ const parsed = minimist5(args, {
2888
3230
  string: ["server", "chunk-size"],
2889
3231
  boolean: ["help", "yes"],
2890
3232
  alias: { s: "server", h: "help", y: "yes" },
@@ -2916,7 +3258,7 @@ async function runRagCommand(args, version) {
2916
3258
  const chunkSize = Number.parseInt(parsed["chunk-size"] ?? "512", 10);
2917
3259
  let thrownError;
2918
3260
  const app = render3(
2919
- /* @__PURE__ */ jsx5(
3261
+ /* @__PURE__ */ jsx6(
2920
3262
  RagUI,
2921
3263
  {
2922
3264
  url,
@@ -2984,8 +3326,8 @@ init_discover();
2984
3326
  init_help();
2985
3327
  init_ink();
2986
3328
  init_prompts();
2987
- import minimist5 from "minimist";
2988
- import { jsx as jsx6 } from "react/jsx-runtime";
3329
+ import minimist6 from "minimist";
3330
+ import { jsx as jsx7 } from "react/jsx-runtime";
2989
3331
  var secretCommandDef = {
2990
3332
  name: "secret",
2991
3333
  description: "Manage secrets",
@@ -3003,7 +3345,7 @@ async function requireProjectConfig(cwd) {
3003
3345
  return config;
3004
3346
  }
3005
3347
  async function runSecretCommand(args, version) {
3006
- const parsed = minimist5(args, {
3348
+ const parsed = minimist6(args, {
3007
3349
  boolean: ["help", "yes"],
3008
3350
  alias: { h: "help", y: "yes" },
3009
3351
  stopEarly: true
@@ -3058,7 +3400,7 @@ async function secretPut(cwd, name, value) {
3058
3400
  const text = await resp.text();
3059
3401
  throw new Error(`Failed to set secret: ${text}`);
3060
3402
  }
3061
- log(/* @__PURE__ */ jsx6(Step, { action: "Set", msg: `${name} for ${slug}` }));
3403
+ log(/* @__PURE__ */ jsx7(Step, { action: "Set", msg: `${name} for ${slug}` }));
3062
3404
  });
3063
3405
  }
3064
3406
  async function secretDelete(cwd, name) {
@@ -3073,7 +3415,7 @@ async function secretDelete(cwd, name) {
3073
3415
  const text = await resp.text();
3074
3416
  throw new Error(`Failed to delete secret: ${text}`);
3075
3417
  }
3076
- log(/* @__PURE__ */ jsx6(Step, { action: "Deleted", msg: `${name} from ${slug}` }));
3418
+ log(/* @__PURE__ */ jsx7(Step, { action: "Deleted", msg: `${name} from ${slug}` }));
3077
3419
  });
3078
3420
  }
3079
3421
  async function secretList(cwd) {
@@ -3088,10 +3430,10 @@ async function secretList(cwd) {
3088
3430
  }
3089
3431
  const { vars } = await resp.json();
3090
3432
  if (vars.length === 0) {
3091
- log(/* @__PURE__ */ jsx6(StepInfo, { action: "Secrets", msg: "No secrets set" }));
3433
+ log(/* @__PURE__ */ jsx7(StepInfo, { action: "Secrets", msg: "none set" }));
3092
3434
  } else {
3093
3435
  for (const name of vars) {
3094
- log(/* @__PURE__ */ jsx6(Detail, { msg: name }));
3436
+ log(/* @__PURE__ */ jsx7(Detail, { msg: name }));
3095
3437
  }
3096
3438
  }
3097
3439
  });
@@ -3101,25 +3443,24 @@ async function secretList(cwd) {
3101
3443
  init_discover();
3102
3444
  init_help();
3103
3445
  init_ink();
3104
- import path9 from "node:path";
3105
- import minimist6 from "minimist";
3446
+ import path10 from "node:path";
3447
+ import minimist7 from "minimist";
3106
3448
 
3107
3449
  // cli/_start.ts
3108
3450
  init_ink();
3109
- import path8 from "node:path";
3110
- import React3 from "react";
3451
+ import path9 from "node:path";
3452
+ import React4 from "react";
3111
3453
  async function _startProductionServer(cwd, port, log) {
3112
- const clientDir = path8.join(cwd, ".aai", "client");
3113
- log(React3.createElement(Step, { action: "Load", msg: "agent" }));
3454
+ const clientDir = path9.join(cwd, ".aai", "client");
3455
+ log(React4.createElement(Step, { action: "Start", msg: "loading agent" }));
3114
3456
  const agentDef = await loadAgentDef(cwd);
3115
3457
  const env = await resolveServerEnv();
3116
- log(React3.createElement(Step, { action: "Start", msg: `http://localhost:${port}` }));
3117
3458
  await bootServer(agentDef, clientDir, env, port);
3118
- log(React3.createElement(Step, { action: "Ready", msg: `http://localhost:${port}` }));
3459
+ log(React4.createElement(Step, { action: "Ready", msg: `http://localhost:${port}` }));
3119
3460
  }
3120
3461
 
3121
3462
  // cli/start.tsx
3122
- import { jsx as jsx7 } from "react/jsx-runtime";
3463
+ import { jsx as jsx8 } from "react/jsx-runtime";
3123
3464
  var startCommandDef = {
3124
3465
  name: "start",
3125
3466
  description: "Start the production server from a build",
@@ -3132,7 +3473,7 @@ var startCommandDef = {
3132
3473
  ]
3133
3474
  };
3134
3475
  async function runStartCommand(args, version) {
3135
- const parsed = minimist6(args, {
3476
+ const parsed = minimist7(args, {
3136
3477
  string: ["port"],
3137
3478
  boolean: ["help", "yes"],
3138
3479
  alias: { p: "port", h: "help", y: "yes" }
@@ -3143,24 +3484,24 @@ async function runStartCommand(args, version) {
3143
3484
  }
3144
3485
  const cwd = process.env.INIT_CWD || process.cwd();
3145
3486
  const port = Number.parseInt(parsed.port ?? "3000", 10);
3146
- const buildDir = path9.join(cwd, ".aai", "build");
3147
- if (!await fileExists(path9.join(buildDir, "worker.js"))) {
3487
+ const buildDir = path10.join(cwd, ".aai", "build");
3488
+ if (!await fileExists(path10.join(buildDir, "worker.js"))) {
3148
3489
  throw new Error("No build found \u2014 run `aai build` first");
3149
3490
  }
3150
3491
  await getApiKey();
3151
3492
  await runWithInk(async (log) => {
3152
- log(/* @__PURE__ */ jsx7(Step, { action: "Start", msg: `production server on port ${port}` }));
3493
+ log(/* @__PURE__ */ jsx8(Step, { action: "Start", msg: `production server on port ${port}` }));
3153
3494
  await _startProductionServer(cwd, port, log);
3154
3495
  });
3155
3496
  }
3156
3497
 
3157
3498
  // cli/cli.ts
3158
- var cliDir = path10.dirname(fileURLToPath2(import.meta.url));
3159
- var pkgJsonPath = path10.join(cliDir, "..", "package.json");
3499
+ var cliDir = path11.dirname(fileURLToPath2(import.meta.url));
3500
+ var pkgJsonPath = path11.join(cliDir, "..", "package.json");
3160
3501
  var pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
3161
3502
  var VERSION = pkgJson.version;
3162
3503
  async function main(args) {
3163
- const parsed = minimist7(args, {
3504
+ const parsed = minimist8(args, {
3164
3505
  boolean: ["help", "version"],
3165
3506
  alias: { h: "help", V: "version" },
3166
3507
  stopEarly: true
@@ -3179,6 +3520,9 @@ async function main(args) {
3179
3520
  case "init":
3180
3521
  await runInitCommand(subArgs, VERSION);
3181
3522
  return;
3523
+ case "build":
3524
+ await runBuildCommand(subArgs, VERSION);
3525
+ return;
3182
3526
  case "deploy":
3183
3527
  await runDeployCommand(subArgs, VERSION);
3184
3528
  return;