@alexkroman1/aai-cli 6.11.0 → 8.0.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 (234) hide show
  1. package/README.md +1 -0
  2. package/dist/{_agent-DpH2pBJd.mjs → _agent-BTwZJu4P.mjs} +2 -2
  3. package/dist/{_bundler-C2BDwU7r.mjs → _bundler-CDuYl5Gb.mjs} +2 -2
  4. package/dist/_dev-env.d.ts +22 -2
  5. package/dist/{_dev-server-LLLWnFBs.mjs → _dev-server-Me06wgeF.mjs} +38 -47
  6. package/dist/_dev-server.d.ts +0 -17
  7. package/dist/{_init-C57bWAQ8.mjs → _init-BhEfQ6Yi.mjs} +3 -2
  8. package/dist/{_preflight-BtfaYtbE.mjs → _preflight-Co1G9Jww.mjs} +1 -1
  9. package/dist/_preflight.d.ts +1 -1
  10. package/dist/_resource-commands.d.ts +23 -0
  11. package/dist/{_slug-api-BxrsJXVI.mjs → _slug-api-z-USxPtL.mjs} +16 -12
  12. package/dist/_slug-api.d.ts +5 -2
  13. package/dist/{_studio-U3jhKlA3.mjs → _studio-DR5yzZ1T.mjs} +2 -1
  14. package/dist/{_templates-Dxb_P2Wz.mjs → _templates-4WcKOjS5.mjs} +5 -6
  15. package/dist/_templates.d.ts +3 -4
  16. package/dist/_workflow-scan.d.ts +108 -0
  17. package/dist/{build-Dfza2pRI.mjs → build-BBxf8vom.mjs} +6 -3
  18. package/dist/cli.mjs +346 -349
  19. package/dist/{client-bundler-BEIqgOtd.mjs → client-bundler-CWnG42cU.mjs} +2 -1
  20. package/dist/client-bundler.mjs +1 -1
  21. package/dist/{delete-vbpjGzqs.mjs → delete-Dl_LSfvI.mjs} +3 -3
  22. package/dist/{deploy-B8lubiRT.mjs → deploy-DRC8jWr8.mjs} +5 -5
  23. package/dist/{dev-Uq5ujP8a.mjs → dev-BvcctCn2.mjs} +1 -1
  24. package/dist/eval-DfQ8cm5p.mjs +56 -0
  25. package/dist/eval.d.ts +43 -0
  26. package/dist/{init-l6xfU4xX.mjs → init-CUo87gcI.mjs} +3 -3
  27. package/dist/{login-C71-qz8F.mjs → login-BBuM1sxH.mjs} +3 -4
  28. package/dist/{logs-BWVGSjLR.mjs → logs-CQ2T46dr.mjs} +2 -2
  29. package/dist/project-config.mjs +1 -1
  30. package/dist/scaffold/CLAUDE.md +442 -80
  31. package/dist/scaffold/package.json +6 -3
  32. package/dist/scaffold/server.mjs +11 -4
  33. package/dist/scaffold/tsconfig.json +0 -1
  34. package/dist/{secret-BuMuFR4B.mjs → secret-Ct34kdgU.mjs} +2 -2
  35. package/dist/{storage-DzRZ-eCw.mjs → storage-i_79ZwAR.mjs} +2 -2
  36. package/dist/{studio-BCNUpDgP.mjs → studio-CzTzPqe1.mjs} +4 -4
  37. package/dist/templates/briefing-desk/agent.test.ts +350 -0
  38. package/dist/templates/briefing-desk/agent.ts +30 -0
  39. package/dist/templates/briefing-desk/shared.ts +200 -0
  40. package/dist/templates/briefing-desk/system-prompt.md +39 -0
  41. package/dist/templates/briefing-desk/tools/briefing_so_far.ts +35 -0
  42. package/dist/templates/briefing-desk/tools/research_topic.ts +88 -0
  43. package/dist/templates/briefing-desk/tools/verify_claim.ts +77 -0
  44. package/dist/templates/call-audit/agent.eval.test.ts +474 -0
  45. package/dist/templates/call-audit/agent.test.ts +57 -204
  46. package/dist/templates/call-audit/agent.ts +32 -19
  47. package/dist/templates/call-audit/client.tsx +17 -54
  48. package/dist/templates/call-audit/workflows/audit.ts +11 -18
  49. package/dist/templates/call-audit/workflows/ingest.ts +106 -114
  50. package/dist/templates/call-audit/workflows/media.ts +2 -12
  51. package/dist/templates/call-audit/workflows/summarize.ts +47 -52
  52. package/dist/templates/call-audit/workflows/sync-api.ts +7 -7
  53. package/dist/templates/code-interpreter/agent.eval.test.ts +165 -0
  54. package/dist/templates/dispatch-center/agent.eval.test.ts +349 -0
  55. package/dist/templates/dispatch-center/agent.test.ts +149 -25
  56. package/dist/templates/dispatch-center/client.tsx +239 -129
  57. package/dist/templates/dispatch-center/shared.ts +99 -1
  58. package/dist/templates/dispatch-center/system-prompt.md +3 -1
  59. package/dist/templates/dispatch-center/tools/incident_add_note.ts +16 -13
  60. package/dist/templates/dispatch-center/tools/incident_create.ts +19 -1
  61. package/dist/templates/dispatch-center/tools/incident_escalate.ts +68 -59
  62. package/dist/templates/dispatch-center/tools/incident_triage.ts +57 -43
  63. package/dist/templates/dispatch-center/tools/incident_update_status.ts +49 -40
  64. package/dist/templates/dispatch-center/tools/ops_run_scenario.ts +8 -2
  65. package/dist/templates/dispatch-center/tools/resources_dispatch.ts +69 -52
  66. package/dist/templates/dispatch-center/tools/resources_update_status.ts +45 -41
  67. package/dist/templates/embedded-assets/agent.eval.test.ts +138 -0
  68. package/dist/templates/embedded-assets/agent.test.ts +17 -14
  69. package/dist/templates/health-assistant/agent.eval.test.ts +167 -0
  70. package/dist/templates/health-assistant/agent.test.ts +22 -4
  71. package/dist/templates/infocom-adventure/agent.eval.test.ts +158 -0
  72. package/dist/templates/infocom-adventure/agent.test.ts +53 -24
  73. package/dist/templates/infocom-adventure/agent.ts +21 -0
  74. package/dist/templates/infocom-adventure/client.tsx +246 -164
  75. package/dist/templates/infocom-adventure/shared.ts +20 -9
  76. package/dist/templates/infocom-adventure/system-prompt.md +1 -1
  77. package/dist/templates/infocom-adventure/tools/game_state_move.ts +3 -2
  78. package/dist/templates/link-digest/agent.eval.test.ts +195 -0
  79. package/dist/templates/link-digest/agent.test.ts +24 -19
  80. package/dist/templates/link-digest/client.tsx +47 -61
  81. package/dist/templates/link-digest/workflows/digest.ts +19 -31
  82. package/dist/templates/math-buddy/agent.eval.test.ts +146 -0
  83. package/dist/templates/night-owl/agent.eval.test.ts +272 -0
  84. package/dist/templates/night-owl/agent.test.ts +70 -19
  85. package/dist/templates/night-owl/agent.ts +5 -0
  86. package/dist/templates/night-owl/client.tsx +56 -56
  87. package/dist/templates/night-owl/shared.ts +24 -0
  88. package/dist/templates/night-owl/tools/recommend.ts +18 -6
  89. package/dist/templates/personal-finance/agent.eval.test.ts +168 -0
  90. package/dist/templates/personal-finance/system-prompt.md +4 -0
  91. package/dist/templates/pipeline-simple/agent.eval.test.ts +78 -0
  92. package/dist/templates/pipeline-simple/agent.ts +2 -2
  93. package/dist/templates/pizza-ordering/agent.eval.test.ts +171 -0
  94. package/dist/templates/pizza-ordering/agent.test.ts +42 -27
  95. package/dist/templates/pizza-ordering/client.tsx +9 -26
  96. package/dist/templates/pizza-ordering/shared.ts +20 -1
  97. package/dist/templates/pizza-ordering/system-prompt.md +6 -0
  98. package/dist/templates/plan-and-execute/agent.eval.test.ts +209 -0
  99. package/dist/templates/plan-and-execute/agent.test.ts +99 -58
  100. package/dist/templates/plan-and-execute/agent.ts +1 -1
  101. package/dist/templates/plan-and-execute/client.tsx +12 -15
  102. package/dist/templates/plan-and-execute/shared.ts +71 -2
  103. package/dist/templates/plan-and-execute/tools/plan_status.ts +18 -6
  104. package/dist/templates/plan-and-execute/tools/revise_plan.ts +18 -10
  105. package/dist/templates/plan-and-execute/tools/start_plan.ts +13 -2
  106. package/dist/templates/plan-and-execute/tools/work_next_step.ts +70 -22
  107. package/dist/templates/podcast-digest/agent.eval.test.ts +411 -0
  108. package/dist/templates/podcast-digest/agent.test.ts +717 -0
  109. package/dist/templates/podcast-digest/agent.ts +139 -0
  110. package/dist/templates/podcast-digest/client.tsx +154 -0
  111. package/dist/templates/podcast-digest/workflows/digest.ts +444 -0
  112. package/dist/templates/podcast-digest/workflows/feeds.ts +507 -0
  113. package/dist/templates/podcast-digest/workflows/slack.ts +88 -0
  114. package/dist/templates/recap-workflow/agent.eval.test.ts +366 -0
  115. package/dist/templates/recap-workflow/agent.test.ts +97 -94
  116. package/dist/templates/recap-workflow/tools/recap_progress.ts +9 -12
  117. package/dist/templates/recap-workflow/tools/recap_status.ts +8 -9
  118. package/dist/templates/recap-workflow/tools/request_recap.ts +2 -1
  119. package/dist/templates/recap-workflow/workflows/recap.ts +36 -40
  120. package/dist/templates/redline/agent.eval.test.ts +209 -0
  121. package/dist/templates/redline/agent.test.ts +17 -15
  122. package/dist/templates/redline/client.tsx +12 -12
  123. package/dist/templates/redline/workflows/redline.ts +19 -31
  124. package/dist/templates/research-workflow/agent.eval.test.ts +329 -0
  125. package/dist/templates/research-workflow/agent.test.ts +60 -59
  126. package/dist/templates/research-workflow/tools/research_progress.ts +9 -12
  127. package/dist/templates/research-workflow/tools/research_status.ts +9 -11
  128. package/dist/templates/research-workflow/workflows/research.ts +44 -61
  129. package/dist/templates/retail/address.ts +87 -1
  130. package/dist/templates/retail/agent.eval.test.ts +314 -0
  131. package/dist/templates/retail/agent.test.ts +195 -112
  132. package/dist/templates/retail/agent.ts +35 -1
  133. package/dist/templates/retail/cancel.ts +116 -0
  134. package/dist/templates/retail/client.tsx +265 -117
  135. package/dist/templates/retail/payment.ts +107 -0
  136. package/dist/templates/retail/pending.test.ts +196 -0
  137. package/dist/templates/retail/pending.ts +137 -0
  138. package/dist/templates/retail/registry.test.ts +150 -7
  139. package/dist/templates/retail/returns.ts +102 -0
  140. package/dist/templates/retail/shared.test.ts +42 -0
  141. package/dist/templates/retail/shared.ts +35 -0
  142. package/dist/templates/retail/store.test.ts +84 -15
  143. package/dist/templates/retail/store.ts +231 -48
  144. package/dist/templates/retail/swap.test.ts +4 -4
  145. package/dist/templates/retail/swap.ts +248 -15
  146. package/dist/templates/retail/system-prompt.md +69 -28
  147. package/dist/templates/retail/tools/cancel_change.ts +33 -0
  148. package/dist/templates/retail/tools/cancel_pending_order.ts +16 -60
  149. package/dist/templates/retail/tools/confirm_change.ts +42 -0
  150. package/dist/templates/retail/tools/exchange_delivered_order_items.ts +22 -67
  151. package/dist/templates/retail/tools/find_user_id_by_email.ts +8 -5
  152. package/dist/templates/retail/tools/find_user_id_by_name_zip.ts +4 -5
  153. package/dist/templates/retail/tools/get_item_details.ts +3 -4
  154. package/dist/templates/retail/tools/get_order_details.ts +3 -4
  155. package/dist/templates/retail/tools/get_product_details.ts +3 -4
  156. package/dist/templates/retail/tools/get_user_details.ts +2 -2
  157. package/dist/templates/retail/tools/list_all_product_types.ts +5 -5
  158. package/dist/templates/retail/tools/modify_pending_order_address.ts +13 -25
  159. package/dist/templates/retail/tools/modify_pending_order_items.ts +23 -62
  160. package/dist/templates/retail/tools/modify_pending_order_payment.ts +16 -78
  161. package/dist/templates/retail/tools/modify_user_address.ts +13 -16
  162. package/dist/templates/retail/tools/return_delivered_order_items.ts +17 -72
  163. package/dist/templates/retail/tools/transfer_to_human_agents.ts +12 -6
  164. package/dist/templates/simple/agent.eval.test.ts +54 -0
  165. package/dist/templates/solo-rpg/agent.eval.test.ts +320 -0
  166. package/dist/templates/solo-rpg/agent.test.ts +227 -48
  167. package/dist/templates/solo-rpg/client.tsx +38 -37
  168. package/dist/templates/solo-rpg/shared.ts +145 -19
  169. package/dist/templates/solo-rpg/system-prompt.md +3 -2
  170. package/dist/templates/solo-rpg/tools/action_roll.ts +82 -63
  171. package/dist/templates/solo-rpg/tools/burn_momentum.ts +85 -50
  172. package/dist/templates/solo-rpg/tools/check_state.ts +24 -7
  173. package/dist/templates/solo-rpg/tools/load_game.ts +13 -1
  174. package/dist/templates/solo-rpg/tools/save_game.ts +16 -7
  175. package/dist/templates/solo-rpg/tools/setup_character.ts +22 -2
  176. package/dist/templates/solo-rpg/tools/update_state.ts +113 -100
  177. package/dist/templates/spoken-summary/agent.eval.test.ts +342 -0
  178. package/dist/templates/spoken-summary/agent.test.ts +68 -97
  179. package/dist/templates/spoken-summary/agent.ts +30 -17
  180. package/dist/templates/spoken-summary/client.tsx +10 -50
  181. package/dist/templates/spoken-summary/workflows/summarize.ts +17 -22
  182. package/dist/templates/spoken-summary/workflows/transcribe.ts +19 -26
  183. package/dist/templates/support-line/agent.eval.test.ts +273 -0
  184. package/dist/templates/support-line/agent.test.ts +11 -16
  185. package/dist/templates/support-line/agent.ts +1 -1
  186. package/dist/templates/support-line/client.tsx +9 -9
  187. package/dist/templates/support-line/nodes.ts +100 -0
  188. package/dist/templates/support-line/procedure.ts +407 -0
  189. package/dist/templates/support-line/system-prompt.md +2 -1
  190. package/dist/templates/support-line/tools/answer_question.ts +66 -4
  191. package/dist/templates/transcription-workflow/agent.eval.test.ts +234 -0
  192. package/dist/templates/transcription-workflow/agent.test.ts +94 -194
  193. package/dist/templates/transcription-workflow/agent.ts +1 -1
  194. package/dist/templates/transcription-workflow/client.tsx +17 -42
  195. package/dist/templates/transcription-workflow/workflows/batch.ts +19 -22
  196. package/dist/templates/transcription-workflow/workflows/normalize.ts +90 -186
  197. package/dist/templates/transcription-workflow/workflows/stitch.ts +0 -11
  198. package/dist/templates/transcription-workflow/workflows/stream.ts +4 -5
  199. package/dist/templates/transcription-workflow/workflows/sync-api.ts +6 -6
  200. package/dist/templates/transcription-workflow/workflows/transcribe.ts +32 -26
  201. package/dist/templates/transcription-workflow/workflows/wav.ts +0 -31
  202. package/dist/templates/travel-concierge/agent.eval.test.ts +323 -0
  203. package/dist/templates/travel-concierge/agent.test.ts +174 -43
  204. package/dist/templates/travel-concierge/agent.ts +18 -9
  205. package/dist/templates/travel-concierge/client.tsx +11 -23
  206. package/dist/templates/travel-concierge/routing.ts +34 -15
  207. package/dist/templates/travel-concierge/shared.ts +180 -12
  208. package/dist/templates/travel-concierge/system-prompt.md +7 -1
  209. package/dist/templates/travel-concierge/tools/book_car_rental.ts +8 -5
  210. package/dist/templates/travel-concierge/tools/book_excursion.ts +8 -5
  211. package/dist/templates/travel-concierge/tools/book_hotel.ts +8 -5
  212. package/dist/templates/travel-concierge/tools/cancel_ticket.ts +8 -5
  213. package/dist/templates/travel-concierge/tools/search_car_rentals.ts +9 -5
  214. package/dist/templates/travel-concierge/tools/search_excursions.ts +9 -5
  215. package/dist/templates/travel-concierge/tools/search_flights.ts +9 -6
  216. package/dist/templates/travel-concierge/tools/search_hotels.ts +9 -5
  217. package/dist/templates/travel-concierge/tools/update_ticket.ts +8 -5
  218. package/dist/templates/web-researcher/agent.eval.test.ts +121 -0
  219. package/dist/templates/web-researcher/system-prompt.md +15 -4
  220. package/dist/{test-9kPKJI-w.mjs → test-BvyT6sAc.mjs} +24 -10
  221. package/dist/test.d.ts +29 -5
  222. package/dist/{worker-bundler-CGD4r8Kc.mjs → worker-bundler-CCVEDjm1.mjs} +241 -3
  223. package/dist/worker-bundler.mjs +1 -1
  224. package/dist/{workflow-CFpxOFfQ.mjs → workflow-BflATMmU.mjs} +47 -12
  225. package/dist/workflow-bundler.d.ts +6 -1
  226. package/dist/workflow.d.ts +1 -1
  227. package/package.json +5 -4
  228. package/dist/eject-31gjtaHF.mjs +0 -116
  229. package/dist/eject.d.ts +0 -60
  230. package/dist/templates/call-audit/workflows/temp-media.ts +0 -138
  231. package/dist/templates/infocom-adventure/tools/game_state_history.ts +0 -14
  232. package/dist/templates/support-line/graph.ts +0 -224
  233. package/dist/{_config-D_s09e7g.mjs → _config-CmJOFsAP.mjs} +1 -1
  234. /package/dist/templates/plan-and-execute/{graph.ts → procedure.ts} +0 -0
@@ -29,7 +29,7 @@
29
29
  * guest's BAKED image instead of being inlined. Step bundle: 12 MB → ~7 KB.
30
30
  * - **`bundleFinalOutput: false`** — skips wrapping the workflow-mode code in a
31
31
  * runtime host, which is exactly what `workflowEntrypoint(code)` supplies
32
- * itself at the other end. Flow bundle: 3.7 MB → ~69 KB.
32
+ * itself at the other end. Dialog bundle: 3.7 MB → ~69 KB.
33
33
  *
34
34
  * So `workflowCode` is passed to `workflowEntrypoint()` in the guest and
35
35
  * `stepCode` is evaluated there to register its step functions.
@@ -108,6 +108,11 @@ export type WorkflowBundleOutput = {
108
108
  * section for why it is this list and not a content sniff.
109
109
  */
110
110
  inputFiles: readonly string[];
111
+ /**
112
+ * Replay-safety findings, as lines to print. See {@link replayWarnings} for
113
+ * why they are warnings rather than a failed build.
114
+ */
115
+ warnings: readonly string[];
111
116
  };
112
117
  /**
113
118
  * Attach the compiler's `workflowId`/`stepId` to the agent bundle's copy of
@@ -25,7 +25,7 @@
25
25
  * slug, and PRINTING — which is most of why the verbs exist separately from the
26
26
  * client's methods.
27
27
  */
28
- import type { WorkflowRunSnapshot, WorkflowSummary } from "@alexkroman1/aai";
28
+ import type { WorkflowRunSnapshot, WorkflowSummary } from "@alexkroman1/aai/workflow-api";
29
29
  import { type CommandResult } from "./_output.ts";
30
30
  /**
31
31
  * One run, as the API reports it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexkroman1/aai-cli",
3
- "version": "6.11.0",
3
+ "version": "8.0.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "aai": "bin.mjs"
@@ -44,8 +44,9 @@
44
44
  "p-timeout": "^7.0.1",
45
45
  "vite": "^8.2.1",
46
46
  "zod": "^4.4.3",
47
- "@alexkroman1/aai": "6.11.0",
48
- "@alexkroman1/aai-ui": "6.11.0"
47
+ "@alexkroman1/aai-runtime": "8.0.0",
48
+ "@alexkroman1/aai": "8.0.0",
49
+ "@alexkroman1/aai-ui": "8.0.0"
49
50
  },
50
51
  "devDependencies": {
51
52
  "playwright": "^1.62.1",
@@ -53,7 +54,7 @@
53
54
  "verdaccio": "^6.9.2",
54
55
  "vitest": "^4.1.10",
55
56
  "workflow": "4.8.2",
56
- "aai-templates": "0.3.6"
57
+ "aai-templates": "0.3.8"
57
58
  },
58
59
  "peerDependencies": {
59
60
  "vitest": "^4.1.10"
@@ -1,116 +0,0 @@
1
- #!/usr/bin/env node
2
- import { a as ok, t as CliError } from "./_output-CKkmWs7i.mjs";
3
- import { n as log } from "./_ui-u7T4YooX.mjs";
4
- import { l as readJson, o as errorMessage, p as writeJson, s as fileExists } from "./_utils-B8QmtFhK.mjs";
5
- import { scaffoldDir } from "./_templates-Dxb_P2Wz.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 the `prestart`/`start` pair: 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 SCRIPTS are the exception it cannot copy, since a project's package.json
25
- * is its own — so `PRESTART_SCRIPT`/`START_SCRIPT` are written here and pinned
26
- * against the scaffold's manifest by `eject.test.ts`. Both matter: the
27
- * entrypoint boots the BUILT worker, so an ejected project with no `prestart`
28
- * exits at once naming the missing artifact.
29
- */
30
- /** The file `npm start` runs. Named once — the scaffold ships it under this name. */
31
- const SERVER_ENTRY = "server.mjs";
32
- /** The `scripts.start` value that runs {@link SERVER_ENTRY}. */
33
- const START_SCRIPT = `node ${SERVER_ENTRY}`;
34
- /**
35
- * The `scripts.prestart` value, which npm runs before `start`.
36
- *
37
- * {@link SERVER_ENTRY} boots the BUILT worker (`.aai/worker.mjs`), because a
38
- * tool is discovered by the bundler enumerating `tools/` and an un-bundled
39
- * loader would serve an agent with no tools at all — so an entrypoint with no
40
- * build in front of it is not a working project. `--skip-tests` because this
41
- * runs on the way to serving traffic: `npm test` is where a suite belongs, and
42
- * a failing test must not be what stops a container from starting. The
43
- * typecheck stays, since the bundlers strip types unchecked and self-hosting
44
- * has no other gate.
45
- *
46
- * Kept in step with the scaffold's own `package.json`, which the two together
47
- * are the only definition of — `eject.test.ts` asserts they agree.
48
- */
49
- const PRESTART_SCRIPT = "aai build --skip-tests";
50
- /**
51
- * Add `scripts.start` — and the `prestart` that builds what it boots — unless
52
- * the project already declares a `start` of its own.
53
- *
54
- * An existing `start` is left alone even under `--force`: `--force` is about
55
- * replacing the entrypoint file, and silently rewriting the command a project
56
- * boots with is a different, larger act. `prestart` is part of the same act
57
- * rather than a separate one, so it is written only alongside a `start` we
58
- * wrote — bolting a build onto someone else's start command changes what that
59
- * command does, which is precisely what the rule above refuses. The mismatch is
60
- * reported instead, naming both halves, so the choice stays the author's.
61
- */
62
- async function ensureStartScript(cwd) {
63
- const manifestPath = path.join(cwd, "package.json");
64
- const manifest = await readJson(manifestPath);
65
- if (!manifest) {
66
- log.warn(`No package.json here — add "prestart": "${PRESTART_SCRIPT}" and "start": "${START_SCRIPT}" yourself to get \`npm start\`.`);
67
- return false;
68
- }
69
- const existing = manifest.scripts?.start;
70
- if (existing === START_SCRIPT && manifest.scripts?.prestart === "aai build --skip-tests") return false;
71
- if (existing !== void 0 && existing !== START_SCRIPT) {
72
- log.warn(`Kept your existing "start" script (${existing}) — run \`${PRESTART_SCRIPT}\` then \`${START_SCRIPT}\`.`);
73
- return false;
74
- }
75
- manifest.scripts = {
76
- ...manifest.scripts,
77
- prestart: PRESTART_SCRIPT,
78
- start: START_SCRIPT
79
- };
80
- await writeJson(manifestPath, manifest);
81
- return true;
82
- }
83
- /**
84
- * A missing scaffold source means a broken install (or an `AAI_TEMPLATES_DIR`
85
- * pointed somewhere wrong), not anything the user did — so the message names
86
- * the file and where it was looked for.
87
- *
88
- * Built here and thrown by the caller, the shape `build.ts` uses for the same
89
- * reason: `useErrorCause` reads a `throw new Error` inside a `catch` as
90
- * dropping the cause, and cannot see that `CliError` takes its options fourth.
91
- */
92
- function scaffoldMissingError(source, err) {
93
- return new CliError("scaffold_missing", `Could not read the scaffold's ${SERVER_ENTRY} at ${source}: ${errorMessage(err)}`, "Reinstall @alexkroman1/aai-cli.", { cause: err });
94
- }
95
- async function executeEject(opts) {
96
- const { cwd, force } = opts;
97
- const target = path.join(cwd, SERVER_ENTRY);
98
- const overwritten = await fileExists(target);
99
- 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.`);
100
- const source = path.join(scaffoldDir(), SERVER_ENTRY);
101
- try {
102
- await fs.copyFile(source, target);
103
- } catch (err) {
104
- throw scaffoldMissingError(source, err);
105
- }
106
- const addedScripts = await ensureStartScript(cwd);
107
- log.success(`Wrote ${SERVER_ENTRY}${overwritten ? " (replaced)" : ""}`);
108
- log.info(`Next: npm start — it builds first (\`${PRESTART_SCRIPT}\`), then serves on 127.0.0.1:3000 (PORT and HOST override that)`);
109
- return ok({
110
- file: target,
111
- overwritten,
112
- addedScripts
113
- });
114
- }
115
- //#endregion
116
- export { executeEject };
package/dist/eject.d.ts DELETED
@@ -1,60 +0,0 @@
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 the `prestart`/`start` pair: 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
- * The SCRIPTS are the exception it cannot copy, since a project's package.json
17
- * is its own — so `PRESTART_SCRIPT`/`START_SCRIPT` are written here and pinned
18
- * against the scaffold's manifest by `eject.test.ts`. Both matter: the
19
- * entrypoint boots the BUILT worker, so an ejected project with no `prestart`
20
- * exits at once naming the missing artifact.
21
- */
22
- import { type CommandResult } from "./_output.ts";
23
- /** The file `npm start` runs. Named once — the scaffold ships it under this name. */
24
- export declare const SERVER_ENTRY = "server.mjs";
25
- /** The `scripts.start` value that runs {@link SERVER_ENTRY}. */
26
- export declare const START_SCRIPT = "node server.mjs";
27
- /**
28
- * The `scripts.prestart` value, which npm runs before `start`.
29
- *
30
- * {@link SERVER_ENTRY} boots the BUILT worker (`.aai/worker.mjs`), because a
31
- * tool is discovered by the bundler enumerating `tools/` and an un-bundled
32
- * loader would serve an agent with no tools at all — so an entrypoint with no
33
- * build in front of it is not a working project. `--skip-tests` because this
34
- * runs on the way to serving traffic: `npm test` is where a suite belongs, and
35
- * a failing test must not be what stops a container from starting. The
36
- * typecheck stays, since the bundlers strip types unchecked and self-hosting
37
- * has no other gate.
38
- *
39
- * Kept in step with the scaffold's own `package.json`, which the two together
40
- * are the only definition of — `eject.test.ts` asserts they agree.
41
- */
42
- export declare const PRESTART_SCRIPT = "aai build --skip-tests";
43
- type EjectData = {
44
- /** Absolute path of the entrypoint written. */
45
- file: string;
46
- /** True when an existing `server.mjs` was replaced (`--force`). */
47
- overwritten: boolean;
48
- /**
49
- * True when this run wrote `scripts.prestart`/`scripts.start` into
50
- * package.json. Also true for a project ejected by an older CLI, whose
51
- * `start` is already correct and whose `prestart` is missing — the entrypoint
52
- * this run just wrote needs the build in front of it.
53
- */
54
- addedScripts: boolean;
55
- };
56
- export declare function executeEject(opts: {
57
- cwd: string;
58
- force?: boolean | undefined;
59
- }): Promise<CommandResult<EjectData>>;
60
- export {};
@@ -1,138 +0,0 @@
1
- // Copyright 2026 the AAI authors. MIT license.
2
- /**
3
- * Moving bytes between the upload store and a local file, which is what an
4
- * ffmpeg step spends most of its lines on.
5
- *
6
- * No directive, so it sits under `workflows/` untransformed and is called FROM
7
- * steps, inheriting their environment. It exists because both ffmpeg steps in
8
- * this template need the same three things and the third one is the one that is
9
- * easy to get wrong.
10
- *
11
- * ## Why a temp file at all
12
- *
13
- * `@alexkroman1/aai/ffmpeg` takes bytes as happily as a path, and for a short
14
- * clip bytes are the better call. This desk uses paths, for two reasons that are
15
- * both properties of real recordings rather than preferences:
16
- *
17
- * - **A pipe cannot seek.** An `.m4a` off a phone usually carries its `moov`
18
- * index at the END of the file, so ffmpeg reading it from `pipe:0` fails with
19
- * `moov atom not found`. That is the flagship input.
20
- * - **Piped output is capped**, at `DEFAULT_MAX_FFMPEG_OUTPUT_BYTES` (64 MiB),
21
- * which is about half an hour of this desk's 16 kHz mono PCM. The desk exists
22
- * for the two-hour call.
23
- *
24
- * ## A temp file may not outlive its step
25
- *
26
- * A step is journaled by its RETURN VALUE and may be dispatched into a different
27
- * process than its neighbours, so a path in a return value is a path that is
28
- * replayed after the file behind it is gone — and the failure mode is a resumed
29
- * run reading a directory that another run is using. {@link withTempDir} makes
30
- * the lifetime a lexical scope: the directory is created on entry, removed on
31
- * exit, and what crosses the step boundary is an upload id.
32
- */
33
-
34
- import { mkdtemp, open, rm } from "node:fs/promises";
35
- import { tmpdir } from "node:os";
36
- import { join } from "node:path";
37
- import { readUpload } from "@alexkroman1/aai/utils";
38
-
39
- /**
40
- * Bytes moved per `readUpload`, and per write.
41
- *
42
- * Large enough that a two-hour recording is a few hundred round trips rather
43
- * than tens of thousands, and small enough that a step's resident set is a
44
- * constant rather than a function of the recording. The number this must NOT be
45
- * is "the whole file", which is the shape every first draft has.
46
- */
47
- export const WINDOW_BYTES = 8 * 1024 * 1024;
48
-
49
- /**
50
- * Run `work` with a private temp directory, and remove it afterwards.
51
- *
52
- * `join(tmpdir(), …)` rather than a `/tmp` literal, which is this repo's rule
53
- * (`guard-invariants` rule 11) and not merely portability theatre: on Windows a
54
- * literal `/tmp/x` is DRIVE-RELATIVE, so it resolves somewhere that does not
55
- * exist and every write fails with ENOENT. A step runs in a Linux guest when it
56
- * is deployed and on the developer's own machine under `aai dev`, which is the
57
- * half that makes it matter.
58
- *
59
- * The removal is in a `finally`, so it also runs on the failure paths — a guest's
60
- * disk is small, and a step that leaves a copy of every recording it touched
61
- * fills it. `force` so a run that never created its output does not fail HERE and
62
- * replace the real error with this one.
63
- */
64
- export async function withTempDir<T>(work: (dir: string) => Promise<T>): Promise<T> {
65
- const dir = await mkdtemp(join(tmpdir(), "aai-call-audit-"));
66
- try {
67
- return await work(dir);
68
- } finally {
69
- await rm(dir, { recursive: true, force: true });
70
- }
71
- }
72
-
73
- /**
74
- * Write an upload to a local path, a window at a time.
75
- *
76
- * A `for` loop rather than a fan-out deliberately: the bytes land in one file at
77
- * one offset each, so concurrency buys nothing and costs exactly the memory the
78
- * windows are here to bound.
79
- *
80
- * `windowBytes` defaults to {@link WINDOW_BYTES}; see {@link fileChunks} for why
81
- * it is a parameter at all.
82
- */
83
- export async function materializeUpload(
84
- uploadId: string,
85
- size: number,
86
- path: string,
87
- windowBytes: number = WINDOW_BYTES,
88
- ): Promise<void> {
89
- const handle = await open(path, "w");
90
- try {
91
- for (let at = 0; at < size; at += windowBytes) {
92
- const slice = await readUpload(uploadId, {
93
- start: at,
94
- end: Math.min(at + windowBytes, size),
95
- });
96
- await handle.write(slice.bytes);
97
- }
98
- } finally {
99
- await handle.close();
100
- }
101
- }
102
-
103
- /**
104
- * A local file as the stream `writeUpload` takes.
105
- *
106
- * A generator rather than `readFile`, for the same reason the windows above
107
- * exist: the normalized PCM is the largest thing this desk touches, and handing
108
- * the store an `AsyncIterable` is what keeps it off the heap.
109
- *
110
- * **The `.slice()` is load-bearing.** One buffer is reused across reads, so
111
- * yielding a view of it hands the consumer memory the next read overwrites — a
112
- * bug whose symptom is a stored file made of the LAST chunk repeated, and which
113
- * does not reproduce whenever the consumer happens to copy before the next
114
- * iteration.
115
- *
116
- * `windowBytes` is a parameter with a default for exactly that reason, and it is
117
- * the one testability seam in this template. The aliasing bug above only manifests
118
- * across MULTIPLE reads, so at the real 8 MiB window a spec would have to write a
119
- * 16 MB file to reach it — and a first draft of that spec used 200 KB, passed with
120
- * the `.slice()` deleted, and would have shipped a test proving nothing. A small
121
- * window makes the multi-chunk path a few kilobytes instead.
122
- */
123
- export async function* fileChunks(
124
- path: string,
125
- windowBytes: number = WINDOW_BYTES,
126
- ): AsyncIterable<Uint8Array> {
127
- const handle = await open(path, "r");
128
- try {
129
- const buffer = new Uint8Array(windowBytes);
130
- for (;;) {
131
- const { bytesRead } = await handle.read(buffer, 0, buffer.length, null);
132
- if (bytesRead === 0) return;
133
- yield buffer.subarray(0, bytesRead).slice();
134
- }
135
- } finally {
136
- await handle.close();
137
- }
138
- }
@@ -1,14 +0,0 @@
1
- import { z } from "zod";
2
- import { gameSlot, REPORTED_HISTORY, recordCommand } from "../shared.ts";
3
-
4
- export default gameSlot.updateTool({
5
- description: "Log a player command to the history and increment the move counter.",
6
- inputSchema: z.object({
7
- value: z.string().describe("Command text to log"),
8
- }),
9
- execute(args, game) {
10
- recordCommand(game, args.value);
11
- game.moves++;
12
- return { moves: game.moves, recentHistory: game.history.slice(-REPORTED_HISTORY) };
13
- },
14
- });
@@ -1,224 +0,0 @@
1
- /**
2
- * The corrective-RAG loop, node by node.
3
- *
4
- * This is the port of the self-RAG / CRAG graph (see `prompts.ts` for the
5
- * attribution). Their control flow is edges between nodes; here it is a `while`
6
- * loop in one tool body, and the node names survive in {@link AnswerTrace.steps}
7
- * so a run is still readable as the graph it came from:
8
- *
9
- * ```text
10
- * retrieve → grade_documents → decide_to_generate
11
- * ├─ no relevant docs → transform_query → retrieve
12
- * └─ generate → grade_generation_v_documents
13
- * ├─ not grounded → generate (once)
14
- * └─ grade_generation_v_question
15
- * ├─ not useful → transform_query
16
- * └─ done
17
- * ```
18
- *
19
- * **The budget is the mechanism, not the prompt.** A graph with a
20
- * `transform_query` edge can cycle, and their notebooks bound it with a recursion
21
- * limit that raises on hit. A caller is holding the line, so the bound here is
22
- * two attempts and one regeneration — {@link MAX_ATTEMPTS} — and running out is
23
- * an ANSWER (`exhausted`, the caller is offered a ticket) rather than an error.
24
- * An agent that cannot say "I don't have that documented" is the failure the
25
- * whole grading apparatus exists to prevent, so it has to be a reachable state.
26
- *
27
- * **Documents are graded CONCURRENTLY.** Their loop is sequential because a
28
- * notebook does not care; four serial grader calls is four round trips of dead
29
- * air on a phone. The grades are independent, so the fan-out is free.
30
- */
31
-
32
- import type { GenerateFn } from "@alexkroman1/aai";
33
- import {
34
- ANSWER_SYSTEM,
35
- ANSWERS_SYSTEM,
36
- binaryScore,
37
- DOC_GRADER_SYSTEM,
38
- GROUNDED_SYSTEM,
39
- REWRITE_SYSTEM,
40
- } from "./prompts.ts";
41
- import type { AnswerTrace, Doc, GradedDoc, TraceStep } from "./shared.ts";
42
- import { formatDoc, retrieve } from "./shared.ts";
43
-
44
- /** Retrieve-and-answer attempts, i.e. one query rewrite. */
45
- export const MAX_ATTEMPTS = 2;
46
- /** Regenerations after a "not grounded" verdict, within one attempt. */
47
- export const MAX_REGENERATIONS = 1;
48
-
49
- function step(trace: AnswerTrace, node: string, detail: string): void {
50
- const entry: TraceStep = { node, detail };
51
- trace.steps.push(entry);
52
- }
53
-
54
- /** `grade_documents` — one closed question per document, all at once. */
55
- async function gradeDocuments(
56
- generate: GenerateFn,
57
- question: string,
58
- docs: Doc[],
59
- ): Promise<GradedDoc[]> {
60
- return await Promise.all(
61
- docs.map(async (doc) => {
62
- const { object } = await generate({
63
- system: DOC_GRADER_SYSTEM,
64
- prompt: `Caller's question: ${question}\n\nDocument:\n${formatDoc(doc)}`,
65
- schema: binaryScore,
66
- });
67
- return {
68
- id: doc.id,
69
- title: doc.title,
70
- relevant: object.score === "yes",
71
- reason: object.reason,
72
- };
73
- }),
74
- );
75
- }
76
-
77
- /** `transform_query` — their question re-writer, aimed at a keyword index. */
78
- async function transformQuery(generate: GenerateFn, question: string): Promise<string> {
79
- const { text } = await generate({
80
- system: REWRITE_SYSTEM,
81
- prompt: `Caller's question: ${question}`,
82
- });
83
- const rewritten = text.trim().replace(/^["']|["']$/g, "");
84
- // A rewriter that returns nothing usable must not empty the query — that
85
- // would retrieve zero documents and read as "we have nothing on this".
86
- return rewritten.length > 0 ? rewritten : question;
87
- }
88
-
89
- /** `generate` — the answer, from the graded-relevant documents only. */
90
- async function generateAnswer(
91
- generate: GenerateFn,
92
- question: string,
93
- docs: Doc[],
94
- ): Promise<string> {
95
- const { text } = await generate({
96
- system: ANSWER_SYSTEM,
97
- prompt: `Documents:\n\n${docs.map(formatDoc).join("\n\n")}\n\nCaller's question: ${question}`,
98
- });
99
- return text.trim();
100
- }
101
-
102
- /** The two generation graders — same closed question, different subject. */
103
- async function grade(
104
- generate: GenerateFn,
105
- system: string,
106
- prompt: string,
107
- ): Promise<{ pass: boolean; reason: string }> {
108
- const { object } = await generate({ system, prompt, schema: binaryScore });
109
- return { pass: object.score === "yes", reason: object.reason };
110
- }
111
-
112
- /**
113
- * Run the graph for one caller question. Never throws for a bad ANSWER — only
114
- * for a broken model call, which is the tool's to report.
115
- */
116
- export async function runCorrectiveRag(
117
- generate: GenerateFn,
118
- question: string,
119
- ): Promise<AnswerTrace> {
120
- const trace: AnswerTrace = {
121
- question,
122
- query: question,
123
- rewrites: 0,
124
- steps: [],
125
- docs: [],
126
- answer: null,
127
- grounded: null,
128
- useful: null,
129
- exhausted: false,
130
- };
131
-
132
- for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
133
- const retrieved = retrieve(trace.query);
134
- step(trace, "retrieve", `${retrieved.length} document(s) for "${trace.query}"`);
135
-
136
- const graded = await gradeDocuments(
137
- generate,
138
- question,
139
- retrieved.map((one) => one.doc),
140
- );
141
- trace.docs = graded;
142
- const relevant = retrieved.filter((one) => graded.find((g) => g.id === one.doc.id)?.relevant);
143
- step(trace, "grade_documents", `${relevant.length} of ${graded.length} relevant`);
144
-
145
- // `decide_to_generate`: nothing relevant means the retrieval was wrong, not
146
- // that the answer is unknown — so rewrite and try once more before giving up.
147
- if (relevant.length === 0) {
148
- if (attempt < MAX_ATTEMPTS) {
149
- trace.query = await transformQuery(generate, question);
150
- trace.rewrites++;
151
- step(trace, "transform_query", `retrying as "${trace.query}"`);
152
- continue;
153
- }
154
- trace.exhausted = true;
155
- step(trace, "decide_to_generate", "no relevant documents, and no attempts left");
156
- return trace;
157
- }
158
-
159
- const docs = relevant.map((one) => one.doc);
160
- const facts = docs.map(formatDoc).join("\n\n");
161
- let answer = await generateAnswer(generate, question, docs);
162
- step(trace, "generate", `answered from ${docs.map((d) => d.id).join(", ")}`);
163
-
164
- // `grade_generation_v_documents`: is it grounded? A regeneration is worth
165
- // one shot — the same documents with the ungrounded attempt now visible.
166
- let grounded = await grade(
167
- generate,
168
- GROUNDED_SYSTEM,
169
- `Facts:\n\n${facts}\n\nAnswer: ${answer}`,
170
- );
171
- for (let redo = 0; !grounded.pass && redo < MAX_REGENERATIONS; redo++) {
172
- step(trace, "grade_generation_v_documents", `not grounded: ${grounded.reason}`);
173
- answer = await generateAnswer(generate, question, docs);
174
- step(trace, "generate", "regenerated");
175
- grounded = await grade(generate, GROUNDED_SYSTEM, `Facts:\n\n${facts}\n\nAnswer: ${answer}`);
176
- }
177
- trace.answer = answer;
178
- trace.grounded = grounded.pass;
179
- step(
180
- trace,
181
- "grade_generation_v_documents",
182
- grounded.pass ? "grounded" : `still not grounded: ${grounded.reason}`,
183
- );
184
- if (!grounded.pass) {
185
- // An ungrounded answer is never spoken. Two regenerations that both
186
- // invented something is a signal about the documents, not the phrasing.
187
- trace.answer = null;
188
- trace.exhausted = true;
189
- return trace;
190
- }
191
-
192
- // `grade_generation_v_question`: grounded is not the same as useful.
193
- const useful = await grade(
194
- generate,
195
- ANSWERS_SYSTEM,
196
- `Question: ${question}\n\nAnswer: ${answer}`,
197
- );
198
- trace.useful = useful.pass;
199
- step(
200
- trace,
201
- "grade_generation_v_question",
202
- useful.pass ? "useful" : `not useful: ${useful.reason}`,
203
- );
204
- if (useful.pass) return trace;
205
-
206
- if (attempt < MAX_ATTEMPTS) {
207
- trace.query = await transformQuery(generate, question);
208
- trace.rewrites++;
209
- step(trace, "transform_query", `retrying as "${trace.query}"`);
210
- trace.answer = null;
211
- trace.grounded = null;
212
- trace.useful = null;
213
- continue;
214
- }
215
- // Out of attempts holding an answer that is grounded but beside the point.
216
- // It is still the best thing we have, so it is returned WITH its verdict —
217
- // the tool tells the model to offer a ticket alongside it.
218
- trace.exhausted = true;
219
- return trace;
220
- }
221
-
222
- trace.exhausted = true;
223
- return trace;
224
- }
@@ -4,8 +4,8 @@ import { c as isEexist, l as readJson, o as errorMessage, p as writeJson } from
4
4
  import { mkdtempSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import fs from "node:fs/promises";
7
- import { tmpdir } from "node:os";
8
7
  import { sleep } from "@alexkroman1/aai/internal";
8
+ import { tmpdir } from "node:os";
9
9
  import envPaths from "env-paths";
10
10
  import { z } from "zod";
11
11
  //#region _config.ts