@ouro.bot/cli 0.1.0-alpha.62 → 0.1.0-alpha.636

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 (430) hide show
  1. package/README.md +127 -23
  2. package/RepairGuide.ouro/agent.json +5 -0
  3. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  4. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  5. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  6. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  7. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  8. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  9. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  12. package/changelog.json +4070 -13
  13. package/dist/arc/attention-types.js +8 -0
  14. package/dist/arc/cares.js +144 -0
  15. package/dist/arc/episodes.js +118 -0
  16. package/dist/arc/intentions.js +134 -0
  17. package/dist/arc/json-store.js +117 -0
  18. package/dist/arc/obligations.js +266 -0
  19. package/dist/arc/packets.js +194 -0
  20. package/dist/arc/presence.js +185 -0
  21. package/dist/arc/task-lifecycle.js +57 -0
  22. package/dist/heart/active-work.js +831 -43
  23. package/dist/heart/agent-entry.js +69 -3
  24. package/dist/heart/attachments/image-normalize.js +194 -0
  25. package/dist/heart/attachments/materialize.js +97 -0
  26. package/dist/heart/attachments/originals.js +88 -0
  27. package/dist/heart/attachments/render.js +29 -0
  28. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  29. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  30. package/dist/heart/attachments/sources/index.js +16 -0
  31. package/dist/heart/attachments/store.js +103 -0
  32. package/dist/heart/attachments/types.js +93 -0
  33. package/dist/heart/auth/auth-flow.js +479 -0
  34. package/dist/heart/awaiting/await-alert.js +146 -0
  35. package/dist/heart/awaiting/await-expiry.js +108 -0
  36. package/dist/heart/awaiting/await-loader.js +91 -0
  37. package/dist/heart/awaiting/await-parser.js +141 -0
  38. package/dist/heart/awaiting/await-runtime-state.js +100 -0
  39. package/dist/heart/awaiting/await-scheduler.js +377 -0
  40. package/dist/heart/background-operations.js +281 -0
  41. package/dist/heart/bridges/manager.js +137 -17
  42. package/dist/heart/bridges/store.js +14 -2
  43. package/dist/heart/bundle-state.js +168 -0
  44. package/dist/heart/commitments.js +135 -0
  45. package/dist/heart/config-registry.js +322 -0
  46. package/dist/heart/config.js +114 -119
  47. package/dist/heart/core.js +914 -248
  48. package/dist/heart/cross-chat-delivery.js +3 -18
  49. package/dist/heart/daemon/agent-config-check.js +419 -0
  50. package/dist/heart/daemon/agent-discovery.js +102 -3
  51. package/dist/heart/daemon/agent-service.js +522 -0
  52. package/dist/heart/daemon/agentic-repair.js +547 -0
  53. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  54. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  55. package/dist/heart/daemon/cadence.js +70 -0
  56. package/dist/heart/daemon/cli-defaults.js +776 -0
  57. package/dist/heart/daemon/cli-desk.js +322 -0
  58. package/dist/heart/daemon/cli-exec.js +7468 -0
  59. package/dist/heart/daemon/cli-help.js +505 -0
  60. package/dist/heart/daemon/cli-parse.js +1554 -0
  61. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  62. package/dist/heart/daemon/cli-render.js +763 -0
  63. package/dist/heart/daemon/cli-types.js +8 -0
  64. package/dist/heart/daemon/connect-bay.js +323 -0
  65. package/dist/heart/daemon/daemon-cli.js +29 -1700
  66. package/dist/heart/daemon/daemon-entry.js +485 -2
  67. package/dist/heart/daemon/daemon-health.js +176 -0
  68. package/dist/heart/daemon/daemon-rollup.js +57 -0
  69. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  70. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  71. package/dist/heart/daemon/daemon.js +905 -71
  72. package/dist/heart/daemon/dns-workflow.js +394 -0
  73. package/dist/heart/daemon/doctor-types.js +8 -0
  74. package/dist/heart/daemon/doctor.js +873 -0
  75. package/dist/heart/daemon/health-monitor.js +122 -1
  76. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  77. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  78. package/dist/heart/daemon/http-health-probe.js +80 -0
  79. package/dist/heart/daemon/human-command-screens.js +234 -0
  80. package/dist/heart/daemon/human-readiness.js +114 -0
  81. package/dist/heart/daemon/inner-status.js +89 -0
  82. package/dist/heart/daemon/interactive-repair.js +394 -0
  83. package/dist/heart/daemon/launchd.js +37 -8
  84. package/dist/heart/daemon/log-tailer.js +79 -10
  85. package/dist/heart/daemon/logs-prune.js +110 -0
  86. package/dist/heart/daemon/mcp-canary.js +297 -0
  87. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  88. package/dist/heart/daemon/os-cron-deps.js +135 -0
  89. package/dist/heart/daemon/os-cron.js +14 -12
  90. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  91. package/dist/heart/daemon/ouro-entry.js +3 -1
  92. package/dist/heart/daemon/plugin-cli.js +432 -0
  93. package/dist/heart/daemon/process-manager.js +463 -34
  94. package/dist/heart/daemon/provider-discovery.js +137 -0
  95. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  96. package/dist/heart/daemon/pulse.js +475 -0
  97. package/dist/heart/daemon/readiness-repair.js +365 -0
  98. package/dist/heart/daemon/run-hooks.js +2 -0
  99. package/dist/heart/daemon/runtime-logging.js +11 -3
  100. package/dist/heart/daemon/runtime-metadata.js +2 -30
  101. package/dist/heart/daemon/safe-mode.js +161 -0
  102. package/dist/heart/daemon/sense-manager.js +493 -38
  103. package/dist/heart/daemon/session-id-resolver.js +131 -0
  104. package/dist/heart/daemon/skill-management-installer.js +22 -9
  105. package/dist/heart/daemon/socket-client.js +158 -11
  106. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  107. package/dist/heart/daemon/startup-tui.js +330 -0
  108. package/dist/heart/daemon/task-scheduler.js +117 -39
  109. package/dist/heart/daemon/terminal-ui.js +499 -0
  110. package/dist/heart/daemon/thoughts.js +229 -17
  111. package/dist/heart/daemon/up-progress.js +366 -0
  112. package/dist/heart/daemon/vault-items.js +56 -0
  113. package/dist/heart/delegation.js +1 -4
  114. package/dist/heart/habits/habit-migration.js +189 -0
  115. package/dist/heart/habits/habit-parser.js +140 -0
  116. package/dist/heart/habits/habit-runtime-state.js +100 -0
  117. package/dist/heart/habits/habit-scheduler.js +372 -0
  118. package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -56
  119. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  120. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  121. package/dist/heart/{daemon → hatch}/specialist-tools.js +37 -14
  122. package/dist/heart/identity.js +168 -57
  123. package/dist/heart/kept-notes.js +357 -0
  124. package/dist/heart/kicks.js +1 -1
  125. package/dist/heart/machine-identity.js +161 -0
  126. package/dist/heart/mail-import-discovery.js +353 -0
  127. package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
  128. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  129. package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
  130. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  131. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  132. package/dist/heart/mailbox/mailbox-http.js +99 -0
  133. package/dist/heart/mailbox/mailbox-read.js +31 -0
  134. package/dist/heart/mailbox/mailbox-types.js +27 -0
  135. package/dist/heart/mailbox/mailbox-view.js +197 -0
  136. package/dist/heart/mailbox/readers/agent-machine.js +418 -0
  137. package/dist/heart/mailbox/readers/continuity-readers.js +319 -0
  138. package/dist/heart/mailbox/readers/mail.js +375 -0
  139. package/dist/heart/mailbox/readers/runtime-readers.js +756 -0
  140. package/dist/heart/mailbox/readers/sessions.js +232 -0
  141. package/dist/heart/mailbox/readers/shared.js +111 -0
  142. package/dist/heart/mcp/mcp-server.js +656 -0
  143. package/dist/heart/migrate-config.js +100 -0
  144. package/dist/heart/model-capabilities.js +19 -0
  145. package/dist/heart/orientation-frame.js +217 -0
  146. package/dist/heart/platform.js +81 -0
  147. package/dist/heart/provider-attempt.js +134 -0
  148. package/dist/heart/provider-binding-resolver.js +272 -0
  149. package/dist/heart/provider-credentials.js +425 -0
  150. package/dist/heart/provider-failover.js +301 -0
  151. package/dist/heart/provider-models.js +81 -0
  152. package/dist/heart/provider-ping.js +262 -0
  153. package/dist/heart/provider-readiness-cache.js +40 -0
  154. package/dist/heart/provider-visibility.js +188 -0
  155. package/dist/heart/providers/anthropic-token.js +131 -0
  156. package/dist/heart/providers/anthropic.js +139 -52
  157. package/dist/heart/providers/azure.js +23 -11
  158. package/dist/heart/providers/error-classification.js +127 -0
  159. package/dist/heart/providers/github-copilot.js +145 -0
  160. package/dist/heart/providers/minimax-vlm.js +189 -0
  161. package/dist/heart/providers/minimax.js +26 -8
  162. package/dist/heart/providers/openai-codex.js +55 -40
  163. package/dist/heart/runtime-capability-check.js +170 -0
  164. package/dist/heart/runtime-credentials.js +367 -0
  165. package/dist/heart/runtime-cwd.js +87 -0
  166. package/dist/heart/sense-truth.js +13 -4
  167. package/dist/heart/session-activity.js +48 -24
  168. package/dist/heart/session-events.js +1163 -0
  169. package/dist/heart/session-playback-cli-main.js +5 -0
  170. package/dist/heart/session-playback-cli.js +36 -0
  171. package/dist/heart/session-playback.js +231 -0
  172. package/dist/heart/session-stats-cli-main.js +5 -0
  173. package/dist/heart/session-stats.js +182 -0
  174. package/dist/heart/session-transcript.js +133 -0
  175. package/dist/heart/start-of-turn-packet.js +345 -0
  176. package/dist/heart/streaming.js +44 -27
  177. package/dist/heart/structured-output.js +196 -0
  178. package/dist/heart/sync-classification.js +176 -0
  179. package/dist/heart/sync.js +449 -0
  180. package/dist/heart/target-resolution.js +9 -5
  181. package/dist/heart/tempo.js +93 -0
  182. package/dist/heart/temporal-view.js +41 -0
  183. package/dist/heart/timeouts.js +101 -0
  184. package/dist/heart/tool-activity-callbacks.js +59 -0
  185. package/dist/heart/tool-description.js +143 -0
  186. package/dist/heart/tool-friction.js +55 -0
  187. package/dist/heart/tool-loop.js +200 -0
  188. package/dist/heart/turn-context.js +389 -0
  189. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  190. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  191. package/dist/heart/versioning/ouro-path-installer.js +426 -0
  192. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  193. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  194. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  195. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  196. package/dist/mailbox-ui/assets/index-9-AxCxuB.js +61 -0
  197. package/dist/mailbox-ui/assets/index-CWzt267f.css +1 -0
  198. package/dist/mailbox-ui/index.html +15 -0
  199. package/dist/mailroom/attention.js +167 -0
  200. package/dist/mailroom/autonomy.js +209 -0
  201. package/dist/mailroom/blob-store.js +715 -0
  202. package/dist/mailroom/body-cache.js +61 -0
  203. package/dist/mailroom/core.js +788 -0
  204. package/dist/mailroom/entry.js +160 -0
  205. package/dist/mailroom/file-store.js +568 -0
  206. package/dist/mailroom/mbox-import.js +393 -0
  207. package/dist/mailroom/migration.js +164 -0
  208. package/dist/mailroom/outbound.js +380 -0
  209. package/dist/mailroom/policy.js +263 -0
  210. package/dist/mailroom/reader.js +233 -0
  211. package/dist/mailroom/search-cache.js +334 -0
  212. package/dist/mailroom/search-relevance.js +319 -0
  213. package/dist/mailroom/smtp-ingress.js +176 -0
  214. package/dist/mailroom/source-state.js +176 -0
  215. package/dist/mailroom/thread.js +109 -0
  216. package/dist/mailroom/travel-extract.js +89 -0
  217. package/dist/mind/bundle-manifest.js +14 -1
  218. package/dist/mind/context.js +251 -101
  219. package/dist/mind/desk-section.js +310 -0
  220. package/dist/mind/diary-integrity.js +60 -0
  221. package/dist/mind/{memory.js → diary.js} +68 -76
  222. package/dist/mind/embedding-provider.js +60 -0
  223. package/dist/mind/file-state.js +179 -0
  224. package/dist/mind/friends/channel.js +39 -0
  225. package/dist/mind/friends/resolver.js +54 -2
  226. package/dist/mind/friends/store-file.js +48 -4
  227. package/dist/mind/friends/types.js +2 -2
  228. package/dist/mind/journal-index.js +162 -0
  229. package/dist/mind/note-search.js +268 -0
  230. package/dist/mind/obligation-steering.js +221 -0
  231. package/dist/mind/pending.js +6 -1
  232. package/dist/mind/prompt-refresh.js +3 -2
  233. package/dist/mind/prompt.js +1058 -146
  234. package/dist/mind/provenance-trust.js +26 -0
  235. package/dist/mind/scrutiny.js +173 -0
  236. package/dist/nerves/cli-logging.js +7 -1
  237. package/dist/nerves/coverage/audit-rules.js +15 -6
  238. package/dist/nerves/coverage/audit.js +28 -2
  239. package/dist/nerves/coverage/cli.js +1 -1
  240. package/dist/nerves/coverage/contract.js +5 -5
  241. package/dist/nerves/coverage/file-completeness.js +139 -5
  242. package/dist/nerves/event-buffer.js +111 -0
  243. package/dist/nerves/index.js +224 -4
  244. package/dist/nerves/observation.js +20 -0
  245. package/dist/nerves/redact.js +79 -0
  246. package/dist/nerves/review/cli-main.js +5 -0
  247. package/dist/nerves/review/cli.js +156 -0
  248. package/dist/nerves/review/core.js +152 -0
  249. package/dist/nerves/runtime.js +5 -1
  250. package/dist/repertoire/ado-client.js +15 -56
  251. package/dist/repertoire/ado-semantic.js +16 -10
  252. package/dist/repertoire/api-client.js +97 -0
  253. package/dist/repertoire/bitwarden-store.js +997 -0
  254. package/dist/repertoire/bundle-templates.js +72 -0
  255. package/dist/repertoire/bw-installer.js +180 -0
  256. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  257. package/dist/repertoire/coding/context-pack.js +331 -0
  258. package/dist/repertoire/coding/feedback.js +197 -30
  259. package/dist/repertoire/coding/manager.js +163 -10
  260. package/dist/repertoire/coding/spawner.js +55 -9
  261. package/dist/repertoire/coding/tools.js +177 -7
  262. package/dist/repertoire/commerce-errors.js +109 -0
  263. package/dist/repertoire/commerce-self-test.js +156 -0
  264. package/dist/repertoire/credential-access.js +178 -0
  265. package/dist/repertoire/desk/classifier.js +362 -0
  266. package/dist/repertoire/duffel-client.js +185 -0
  267. package/dist/repertoire/github-client.js +14 -55
  268. package/dist/repertoire/graph-client.js +11 -52
  269. package/dist/repertoire/guardrails.js +385 -0
  270. package/dist/repertoire/mcp-client.js +295 -0
  271. package/dist/repertoire/mcp-manager.js +403 -0
  272. package/dist/repertoire/mcp-tools.js +83 -0
  273. package/dist/repertoire/plugin-mcp.js +175 -0
  274. package/dist/repertoire/plugins.js +253 -0
  275. package/dist/repertoire/shell-sessions.js +133 -0
  276. package/dist/repertoire/skills.js +48 -4
  277. package/dist/repertoire/stripe-client.js +131 -0
  278. package/dist/repertoire/tool-results.js +29 -0
  279. package/dist/repertoire/tools-attachments.js +317 -0
  280. package/dist/repertoire/tools-awaiting.js +372 -0
  281. package/dist/repertoire/tools-base.js +57 -1082
  282. package/dist/repertoire/tools-bluebubbles.js +2 -0
  283. package/dist/repertoire/tools-bridge.js +144 -0
  284. package/dist/repertoire/tools-bundle.js +993 -0
  285. package/dist/repertoire/tools-config.js +186 -0
  286. package/dist/repertoire/tools-continuity.js +252 -0
  287. package/dist/repertoire/tools-credential.js +383 -0
  288. package/dist/repertoire/tools-files.js +344 -0
  289. package/dist/repertoire/tools-flight.js +227 -0
  290. package/dist/repertoire/tools-flow.js +119 -0
  291. package/dist/repertoire/tools-github.js +3 -8
  292. package/dist/repertoire/tools-mail.js +1975 -0
  293. package/dist/repertoire/tools-notes.js +438 -0
  294. package/dist/repertoire/tools-obligations.js +143 -0
  295. package/dist/repertoire/tools-orientation.js +31 -0
  296. package/dist/repertoire/tools-record.js +464 -0
  297. package/dist/repertoire/tools-runtime.js +150 -0
  298. package/dist/repertoire/tools-session.js +756 -0
  299. package/dist/repertoire/tools-shell.js +120 -0
  300. package/dist/repertoire/tools-stripe.js +182 -0
  301. package/dist/repertoire/tools-surface.js +316 -0
  302. package/dist/repertoire/tools-teams.js +12 -39
  303. package/dist/repertoire/tools-travel.js +125 -0
  304. package/dist/repertoire/tools-trip.js +982 -0
  305. package/dist/repertoire/tools-user-profile.js +146 -0
  306. package/dist/repertoire/tools-vault.js +40 -0
  307. package/dist/repertoire/tools-voice.js +145 -0
  308. package/dist/repertoire/tools.js +215 -103
  309. package/dist/repertoire/travel-api-client.js +360 -0
  310. package/dist/repertoire/user-profile.js +131 -0
  311. package/dist/repertoire/vault-setup.js +246 -0
  312. package/dist/repertoire/vault-unlock.js +594 -0
  313. package/dist/scripts/claude-code-hook.js +41 -0
  314. package/dist/scripts/claude-code-stop-hook.js +47 -0
  315. package/dist/senses/attention-queue.js +116 -0
  316. package/dist/senses/await-turn-message.js +58 -0
  317. package/dist/senses/bluebubbles/active-turns.js +216 -0
  318. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  319. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  320. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  321. package/dist/senses/bluebubbles/entry.js +77 -0
  322. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  323. package/dist/senses/bluebubbles/index.js +2599 -0
  324. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  325. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  326. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  327. package/dist/senses/bluebubbles/processed-log.js +133 -0
  328. package/dist/senses/bluebubbles/replay.js +137 -0
  329. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  330. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  331. package/dist/senses/bluebubbles-meta-guard.js +40 -0
  332. package/dist/senses/cli/bracketed-paste.js +82 -0
  333. package/dist/senses/cli/image-paste.js +287 -0
  334. package/dist/senses/cli/image-ref-navigation.js +75 -0
  335. package/dist/senses/cli/ink-app.js +156 -0
  336. package/dist/senses/cli/inline-diff.js +64 -0
  337. package/dist/senses/cli/input-keys.js +174 -0
  338. package/dist/senses/cli/kill-ring.js +86 -0
  339. package/dist/senses/cli/message-list.js +51 -0
  340. package/dist/senses/cli/ouro-tui.js +607 -0
  341. package/dist/senses/cli/spinner-imperative.js +135 -0
  342. package/dist/senses/cli/spinner.js +101 -0
  343. package/dist/senses/cli/status-line.js +60 -0
  344. package/dist/senses/cli/streaming-markdown.js +526 -0
  345. package/dist/senses/cli/tool-display.js +85 -0
  346. package/dist/senses/cli/tool-render.js +85 -0
  347. package/dist/senses/cli/tui-store.js +240 -0
  348. package/dist/senses/cli/virtual-list.js +35 -0
  349. package/dist/senses/cli-entry.js +60 -8
  350. package/dist/senses/cli-layout.js +100 -0
  351. package/dist/senses/cli.js +517 -204
  352. package/dist/senses/commands.js +66 -3
  353. package/dist/senses/habit-turn-message.js +108 -0
  354. package/dist/senses/inner-dialog-worker.js +254 -22
  355. package/dist/senses/inner-dialog.js +488 -39
  356. package/dist/senses/mail-entry.js +66 -0
  357. package/dist/senses/mail.js +379 -0
  358. package/dist/senses/pipeline.js +666 -181
  359. package/dist/senses/proactive-content-guard.js +51 -0
  360. package/dist/senses/shared-turn.js +393 -0
  361. package/dist/senses/surface-tool.js +70 -0
  362. package/dist/senses/teams-entry.js +60 -8
  363. package/dist/senses/teams.js +388 -98
  364. package/dist/senses/trust-gate.js +100 -5
  365. package/dist/senses/voice/audio-playback.js +237 -0
  366. package/dist/senses/voice/audio-routing.js +119 -0
  367. package/dist/senses/voice/elevenlabs.js +202 -0
  368. package/dist/senses/voice/floor-control.js +431 -0
  369. package/dist/senses/voice/floor-controller.js +115 -0
  370. package/dist/senses/voice/golden-path.js +116 -0
  371. package/dist/senses/voice/index.js +29 -0
  372. package/dist/senses/voice/meeting.js +113 -0
  373. package/dist/senses/voice/outbound.js +190 -0
  374. package/dist/senses/voice/phone.js +33 -0
  375. package/dist/senses/voice/playback.js +139 -0
  376. package/dist/senses/voice/realtime-eval.js +496 -0
  377. package/dist/senses/voice/realtime-trace.js +531 -0
  378. package/dist/senses/voice/transcript.js +70 -0
  379. package/dist/senses/voice/turn.js +191 -0
  380. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  381. package/dist/senses/voice/twilio-phone.js +5079 -0
  382. package/dist/senses/voice/types.js +2 -0
  383. package/dist/senses/voice/whisper.js +161 -0
  384. package/dist/senses/voice-entry.js +81 -0
  385. package/dist/senses/voice-realtime-eval-command.js +99 -0
  386. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  387. package/dist/senses/voice-twilio-entry.js +87 -0
  388. package/dist/trips/core.js +138 -0
  389. package/dist/trips/store.js +265 -0
  390. package/dist/util/frontmatter.js +53 -0
  391. package/package.json +42 -8
  392. package/skills/agent-commerce.md +106 -0
  393. package/skills/browser-navigation.md +117 -0
  394. package/skills/commerce-setup-guide.md +116 -0
  395. package/skills/commerce-setup.md +84 -0
  396. package/skills/configure-dev-tools.md +99 -0
  397. package/skills/travel-planning.md +138 -0
  398. package/dist/heart/daemon/auth-flow.js +0 -351
  399. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  400. package/dist/heart/safe-workspace.js +0 -228
  401. package/dist/heart/session-recall.js +0 -116
  402. package/dist/mind/associative-recall.js +0 -209
  403. package/dist/repertoire/tasks/board.js +0 -134
  404. package/dist/repertoire/tasks/index.js +0 -224
  405. package/dist/repertoire/tasks/lifecycle.js +0 -80
  406. package/dist/repertoire/tasks/middleware.js +0 -65
  407. package/dist/repertoire/tasks/parser.js +0 -173
  408. package/dist/repertoire/tasks/scanner.js +0 -132
  409. package/dist/repertoire/tasks/transitions.js +0 -144
  410. package/dist/senses/bluebubbles-entry.js +0 -13
  411. package/dist/senses/bluebubbles.js +0 -1177
  412. package/dist/senses/debug-activity.js +0 -148
  413. package/subagents/README.md +0 -7
  414. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  415. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  416. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  417. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  418. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  419. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  420. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  421. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  422. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  423. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  424. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  425. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  426. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  427. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  428. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  429. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  430. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -36,8 +36,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.spawnCodingProcess = spawnCodingProcess;
37
37
  const child_process_1 = require("child_process");
38
38
  const fs = __importStar(require("fs"));
39
+ const os = __importStar(require("os"));
40
+ const path = __importStar(require("path"));
39
41
  const runtime_1 = require("../../nerves/runtime");
40
- function buildCommandArgs(runner, workdir) {
42
+ function buildCommandArgs(runner, workdir, parentAgent) {
41
43
  if (runner === "claude") {
42
44
  return {
43
45
  command: "claude",
@@ -53,25 +55,65 @@ function buildCommandArgs(runner, workdir) {
53
55
  ],
54
56
  };
55
57
  }
58
+ const agent = parentAgent ?? "unknown";
59
+ // Use absolute path to ouro-entry.js so MCP works in both dev and installed mode
60
+ // __dirname at runtime is dist/repertoire/coding/ — go up 2 levels to dist/
61
+ const distRoot = path.resolve(__dirname, "..", "..");
62
+ const ouroEntryPath = path.join(distRoot, "heart", "daemon", "ouro-entry.js");
56
63
  return {
57
64
  command: "codex",
58
- args: ["exec", "--skip-git-repo-check", "--cd", workdir],
65
+ args: [
66
+ "exec",
67
+ "--skip-git-repo-check",
68
+ "--cd",
69
+ workdir,
70
+ "--ephemeral",
71
+ "--json",
72
+ "-c",
73
+ `mcp_servers.ouro.command=node`,
74
+ "-c",
75
+ `mcp_servers.ouro.args=["${ouroEntryPath}","mcp-serve","--agent","${agent}"]`,
76
+ ],
59
77
  };
60
78
  }
79
+ function buildSpawnEnv(baseEnv, homeDir) {
80
+ const binDir = path.join(homeDir, ".ouro-cli", "bin");
81
+ const existingPath = baseEnv.PATH ?? "";
82
+ const pathEntries = existingPath.split(path.delimiter).filter((entry) => entry.length > 0);
83
+ if (!pathEntries.includes(binDir)) {
84
+ pathEntries.unshift(binDir);
85
+ }
86
+ return {
87
+ ...baseEnv,
88
+ PATH: pathEntries.join(path.delimiter),
89
+ };
90
+ }
91
+ function appendFileSection(sections, label, filePath, deps) {
92
+ if (!filePath || !deps.existsSync(filePath))
93
+ return;
94
+ const content = deps.readFileSync(filePath, "utf-8").trim();
95
+ if (content.length === 0)
96
+ return;
97
+ sections.push(`${label} (${filePath}):\n${content}`);
98
+ }
61
99
  function buildPrompt(request, deps) {
62
100
  const sections = [];
101
+ sections.push([
102
+ "Execution contract:",
103
+ "- You are a subordinate coding session launched by a parent Ouro agent.",
104
+ "- Execute the concrete request in the supplied workdir directly.",
105
+ "- Do not switch into planning/doing workflows, approval gates, or repo-management rituals unless the request explicitly asks for them.",
106
+ "- Treat the request, scope file, and state file as the authoritative briefing for this session.",
107
+ "- Prefer direct execution and verification over narration.",
108
+ ].join("\n"));
63
109
  sections.push([
64
110
  "Coding session metadata:",
65
111
  `sessionId: ${request.sessionId ?? "pending"}`,
66
112
  `parentAgent: ${request.parentAgent ?? "unknown"}`,
67
113
  `taskRef: ${request.taskRef ?? "unassigned"}`,
68
114
  ].join("\n"));
69
- if (request.stateFile && deps.existsSync(request.stateFile)) {
70
- const stateContent = deps.readFileSync(request.stateFile, "utf-8").trim();
71
- if (stateContent.length > 0) {
72
- sections.push(`State file (${request.stateFile}):\n${stateContent}`);
73
- }
74
- }
115
+ appendFileSection(sections, "Scope file", request.scopeFile, deps);
116
+ appendFileSection(sections, "State file", request.stateFile, deps);
75
117
  sections.push(request.prompt);
76
118
  return sections.join("\n\n---\n\n");
77
119
  }
@@ -79,8 +121,11 @@ function spawnCodingProcess(request, deps = {}) {
79
121
  const spawnFn = deps.spawnFn ?? ((command, args, options) => (0, child_process_1.spawn)(command, args, options));
80
122
  const existsSync = deps.existsSync ?? fs.existsSync;
81
123
  const readFileSync = deps.readFileSync ?? fs.readFileSync;
124
+ const homeDir = deps.homeDir ?? os.homedir();
125
+ const baseEnv = deps.baseEnv ?? process.env;
82
126
  const prompt = buildPrompt(request, { existsSync, readFileSync });
83
- const { command, args } = buildCommandArgs(request.runner, request.workdir);
127
+ const { command, args } = buildCommandArgs(request.runner, request.workdir, request.parentAgent);
128
+ const env = buildSpawnEnv(baseEnv, homeDir);
84
129
  (0, runtime_1.emitNervesEvent)({
85
130
  component: "repertoire",
86
131
  event: "repertoire.coding_spawn_start",
@@ -89,6 +134,7 @@ function spawnCodingProcess(request, deps = {}) {
89
134
  });
90
135
  const proc = spawnFn(command, args, {
91
136
  cwd: request.workdir,
137
+ env,
92
138
  stdio: ["pipe", "pipe", "pipe"],
93
139
  });
94
140
  proc.stdin.end(`${prompt}\n`);
@@ -1,8 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.codingToolDefinitions = void 0;
4
+ exports.countFilesInSessionOutput = countFilesInSessionOutput;
4
5
  const index_1 = require("./index");
6
+ const context_pack_1 = require("./context-pack");
7
+ const identity_1 = require("../../heart/identity");
8
+ const obligations_1 = require("../../arc/obligations");
5
9
  const runtime_1 = require("../../nerves/runtime");
10
+ const scrutiny_1 = require("../../mind/scrutiny");
6
11
  const RUNNERS = ["claude", "codex"];
7
12
  function requireArg(args, key) {
8
13
  const value = args[key];
@@ -29,11 +34,112 @@ function emitCodingToolEvent(toolName) {
29
34
  meta: { toolName },
30
35
  });
31
36
  }
37
+ /**
38
+ * Count distinct file paths mentioned in a coding session's stdout output.
39
+ * Looks for path-like tokens (containing / and a file extension).
40
+ * Returns the count of unique paths found.
41
+ */
42
+ function countFilesInSessionOutput(session) {
43
+ const text = `${session.stdoutTail}\n${session.stderrTail}`;
44
+ // Match path-like tokens: contain at least one / and a file extension
45
+ const pathPattern = /(?:^|\s)((?:\/|\.\/|\.\.\/)?(?:[\w.@-]+\/)+[\w.-]+\.[\w]+)/gm;
46
+ const paths = new Set();
47
+ let match;
48
+ while ((match = pathPattern.exec(text)) !== null) {
49
+ paths.add(match[1]);
50
+ }
51
+ return paths.size;
52
+ }
53
+ /**
54
+ * If a coding session is completed, append scrutiny to the result.
55
+ * Returns the original result with scrutiny appended, or unchanged if
56
+ * the session is not completed or has no file changes.
57
+ */
58
+ function appendCompletionScrutiny(result, session) {
59
+ if (session.status !== "completed")
60
+ return result;
61
+ const fileCount = countFilesInSessionOutput(session);
62
+ const scrutiny = (0, scrutiny_1.getCodingCompletionScrutiny)(fileCount);
63
+ return scrutiny ? `${result}\n\n${scrutiny}` : result;
64
+ }
65
+ function sameOriginSession(left, right) {
66
+ if (!left && !right)
67
+ return true;
68
+ if (!left || !right)
69
+ return false;
70
+ return left.friendId === right.friendId && left.channel === right.channel && left.key === right.key;
71
+ }
72
+ function matchesReusableCodingSession(session, request) {
73
+ if (session.status !== "spawning" && session.status !== "running" && session.status !== "waiting_input" && session.status !== "stalled") {
74
+ return false;
75
+ }
76
+ const scopeMatches = request.scopeFile ? session.scopeFile === request.scopeFile : true;
77
+ const stateMatches = request.stateFile ? session.stateFile === request.stateFile : true;
78
+ return (session.runner === request.runner &&
79
+ session.workdir === request.workdir &&
80
+ session.taskRef === request.taskRef &&
81
+ scopeMatches &&
82
+ stateMatches &&
83
+ session.obligationId === request.obligationId &&
84
+ sameOriginSession(request.originSession, session.originSession));
85
+ }
86
+ function latestSessionFirst(left, right) {
87
+ const lastActivityDelta = Date.parse(right.lastActivityAt) - Date.parse(left.lastActivityAt);
88
+ if (lastActivityDelta !== 0)
89
+ return lastActivityDelta;
90
+ return right.id.localeCompare(left.id);
91
+ }
92
+ function findReusableCodingSession(sessions, request) {
93
+ const matches = sessions.filter((session) => matchesReusableCodingSession(session, request)).sort(latestSessionFirst);
94
+ return matches[0] ?? null;
95
+ }
96
+ function isLiveCodingStatus(status) {
97
+ return status === "spawning" || status === "running" || status === "waiting_input" || status === "stalled";
98
+ }
99
+ function rankCodingStatusSession(session, currentSession) {
100
+ return sameOriginSession({
101
+ friendId: currentSession.friendId,
102
+ channel: currentSession.channel,
103
+ key: currentSession.key,
104
+ }, session.originSession)
105
+ ? 0
106
+ : 1;
107
+ }
108
+ function selectCodingStatusSessions(sessions, currentSession) {
109
+ if (sessions.length === 0)
110
+ return [];
111
+ if (!currentSession) {
112
+ return sessions;
113
+ }
114
+ const activeSessions = sessions.filter((session) => isLiveCodingStatus(session.status)).sort(latestSessionFirst);
115
+ if (activeSessions.length > 0) {
116
+ return activeSessions.sort((left, right) => {
117
+ const rankDelta = rankCodingStatusSession(left, currentSession) - rankCodingStatusSession(right, currentSession);
118
+ if (rankDelta !== 0)
119
+ return rankDelta;
120
+ return latestSessionFirst(left, right);
121
+ });
122
+ }
123
+ const matchingClosedSessions = sessions
124
+ .filter((session) => sameOriginSession({
125
+ friendId: currentSession.friendId,
126
+ channel: currentSession.channel,
127
+ key: currentSession.key,
128
+ }, session.originSession))
129
+ .sort(latestSessionFirst);
130
+ if (matchingClosedSessions.length > 0) {
131
+ return matchingClosedSessions;
132
+ }
133
+ return [...sessions].sort(latestSessionFirst);
134
+ }
135
+ function buildCodingObligationContent(taskRef) {
136
+ return `finish ${taskRef} and bring the result back`;
137
+ }
32
138
  const codingSpawnTool = {
33
139
  type: "function",
34
140
  function: {
35
141
  name: "coding_spawn",
36
- description: "spawn a coding session using claude/codex and explicit task-threaded guidance",
142
+ description: "Spawn a coding session using claude or codex with task-threaded guidance. The coding session runs as a separate process with its own context. Give it a COMPLETE, SELF-CONTAINED task description -- it cannot see this conversation, doesn't know what you've tried, doesn't understand the broader context. Include: what to do, why, what files are involved, what 'done' looks like. Never delegate understanding -- don't write 'based on the conversation, fix the bug.' Write the specific file paths, line numbers, and what to change. Include any required verification steps or tests in the task description so the coding session knows how to prove the work is done.",
37
143
  parameters: {
38
144
  type: "object",
39
145
  properties: {
@@ -52,7 +158,7 @@ const codingStatusTool = {
52
158
  type: "function",
53
159
  function: {
54
160
  name: "coding_status",
55
- description: "inspect coding sessions; omit sessionId to list all active/known sessions",
161
+ description: "Inspect coding sessions. Omit sessionId to list all active/known sessions with their status. Use this to check progress before asking the human for a status update.",
56
162
  parameters: {
57
163
  type: "object",
58
164
  properties: {
@@ -65,7 +171,7 @@ const codingTailTool = {
65
171
  type: "function",
66
172
  function: {
67
173
  name: "coding_tail",
68
- description: "show recent stdout/stderr tail for a coding session in a readable format",
174
+ description: "Show recent stdout/stderr output from a coding session. Use this to understand what the session is doing or why it might be stuck. Read the actual output before reporting status -- don't guess.",
69
175
  parameters: {
70
176
  type: "object",
71
177
  properties: {
@@ -130,6 +236,17 @@ exports.codingToolDefinitions = [
130
236
  prompt,
131
237
  taskRef,
132
238
  };
239
+ if (ctx?.currentSession && ctx.currentSession.channel !== "inner") {
240
+ request.originSession = {
241
+ friendId: ctx.currentSession.friendId,
242
+ channel: ctx.currentSession.channel,
243
+ key: ctx.currentSession.key,
244
+ };
245
+ const obligation = (0, obligations_1.findPendingObligationForOrigin)((0, identity_1.getAgentRoot)(), request.originSession);
246
+ if (obligation) {
247
+ request.obligationId = obligation.id;
248
+ }
249
+ }
133
250
  const scopeFile = optionalArg(args, "scopeFile");
134
251
  if (scopeFile)
135
252
  request.scopeFile = scopeFile;
@@ -137,7 +254,48 @@ exports.codingToolDefinitions = [
137
254
  if (stateFile)
138
255
  request.stateFile = stateFile;
139
256
  const manager = (0, index_1.getCodingSessionManager)();
257
+ const existingSessions = manager.listSessions();
258
+ const existingSession = findReusableCodingSession(existingSessions, request);
259
+ if (existingSession) {
260
+ (0, runtime_1.emitNervesEvent)({
261
+ component: "repertoire",
262
+ event: "repertoire.coding_session_reused",
263
+ message: "reused active coding session",
264
+ meta: { id: existingSession.id, runner: existingSession.runner, taskRef: existingSession.taskRef },
265
+ });
266
+ if (ctx?.codingFeedback) {
267
+ (0, index_1.attachCodingSessionFeedback)(manager, existingSession, ctx.codingFeedback);
268
+ }
269
+ return JSON.stringify({ ...existingSession, reused: true });
270
+ }
271
+ if (request.originSession && !request.obligationId) {
272
+ const created = (0, obligations_1.createObligation)((0, identity_1.getAgentRoot)(), {
273
+ origin: request.originSession,
274
+ content: buildCodingObligationContent(taskRef),
275
+ });
276
+ request.obligationId = created.id;
277
+ }
278
+ if (!request.scopeFile || !request.stateFile) {
279
+ const generated = (0, context_pack_1.prepareCodingContextPack)({
280
+ request: { ...request },
281
+ existingSessions,
282
+ activeWorkFrame: ctx?.activeWorkFrame,
283
+ });
284
+ if (!request.scopeFile)
285
+ request.scopeFile = generated.scopeFile;
286
+ if (!request.stateFile)
287
+ request.stateFile = generated.stateFile;
288
+ }
140
289
  const session = await manager.spawnSession(request);
290
+ if (session.obligationId) {
291
+ (0, obligations_1.advanceObligation)((0, identity_1.getAgentRoot)(), session.obligationId, {
292
+ status: "investigating",
293
+ currentSurface: { kind: "coding", label: `${session.runner} ${session.id}` },
294
+ latestNote: session.originSession
295
+ ? `coding session started for ${session.originSession.channel}/${session.originSession.key}`
296
+ : "coding session started",
297
+ });
298
+ }
141
299
  if (args.runner === "codex" && args.taskRef) {
142
300
  (0, runtime_1.emitNervesEvent)({
143
301
  component: "repertoire",
@@ -151,21 +309,28 @@ exports.codingToolDefinitions = [
151
309
  }
152
310
  return JSON.stringify(session);
153
311
  },
312
+ summaryKeys: ["runner", "workdir", "taskRef"],
313
+ riskProfile: {
314
+ mutates: ["durable_state_write", "external_side_effect"],
315
+ risk: "high",
316
+ reason: "spawns a separate coding process and may create obligations",
317
+ },
154
318
  },
155
319
  {
156
320
  tool: codingStatusTool,
157
- handler: (args) => {
321
+ handler: (args, ctx) => {
158
322
  emitCodingToolEvent("coding_status");
159
323
  const manager = (0, index_1.getCodingSessionManager)();
160
324
  const sessionId = requireArg(args, "sessionId");
161
325
  if (!sessionId) {
162
- return JSON.stringify(manager.listSessions());
326
+ return JSON.stringify(selectCodingStatusSessions(manager.listSessions(), ctx?.currentSession));
163
327
  }
164
328
  const session = manager.getSession(sessionId);
165
329
  if (!session)
166
330
  return `session not found: ${sessionId}`;
167
- return JSON.stringify(session);
331
+ return appendCompletionScrutiny(JSON.stringify(session), session);
168
332
  },
333
+ summaryKeys: ["sessionId"],
169
334
  },
170
335
  {
171
336
  tool: codingTailTool,
@@ -177,8 +342,9 @@ exports.codingToolDefinitions = [
177
342
  const session = (0, index_1.getCodingSessionManager)().getSession(sessionId);
178
343
  if (!session)
179
344
  return `session not found: ${sessionId}`;
180
- return (0, index_1.formatCodingTail)(session);
345
+ return appendCompletionScrutiny((0, index_1.formatCodingTail)(session), session);
181
346
  },
347
+ summaryKeys: ["sessionId"],
182
348
  },
183
349
  {
184
350
  tool: codingSendInputTool,
@@ -192,6 +358,8 @@ exports.codingToolDefinitions = [
192
358
  return "input is required";
193
359
  return JSON.stringify((0, index_1.getCodingSessionManager)().sendInput(sessionId, input));
194
360
  },
361
+ summaryKeys: ["sessionId", "input"],
362
+ riskProfile: { mutates: "external_side_effect", risk: "high", reason: "sends input to a live coding process" },
195
363
  },
196
364
  {
197
365
  tool: codingKillTool,
@@ -202,5 +370,7 @@ exports.codingToolDefinitions = [
202
370
  return "sessionId is required";
203
371
  return JSON.stringify((0, index_1.getCodingSessionManager)().killSession(sessionId));
204
372
  },
373
+ summaryKeys: ["sessionId"],
374
+ riskProfile: { mutates: "external_side_effect", risk: "high", reason: "terminates a live coding process" },
205
375
  },
206
376
  ];
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ /**
3
+ * Commerce-specific error types and helpers.
4
+ *
5
+ * These errors carry structured `code` and `meta` fields for nerves event
6
+ * compatibility and provide patterns for common commerce failure modes:
7
+ * retry, price change detection, and partial failure reporting.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ProfileError = exports.BookingError = exports.PaymentError = exports.CommerceError = void 0;
11
+ exports.retryOnce = retryOnce;
12
+ exports.priceChangeGuard = priceChangeGuard;
13
+ exports.partialFailureReport = partialFailureReport;
14
+ // ---------------------------------------------------------------------------
15
+ // Error types
16
+ // ---------------------------------------------------------------------------
17
+ class CommerceError extends Error {
18
+ code;
19
+ meta;
20
+ constructor(message, code, meta = {}) {
21
+ super(message);
22
+ this.name = "CommerceError";
23
+ this.code = code;
24
+ this.meta = meta;
25
+ }
26
+ }
27
+ exports.CommerceError = CommerceError;
28
+ class PaymentError extends CommerceError {
29
+ constructor(message, code, meta = {}) {
30
+ super(message, code, meta);
31
+ this.name = "PaymentError";
32
+ }
33
+ }
34
+ exports.PaymentError = PaymentError;
35
+ class BookingError extends CommerceError {
36
+ constructor(message, code, meta = {}) {
37
+ super(message, code, meta);
38
+ this.name = "BookingError";
39
+ }
40
+ }
41
+ exports.BookingError = BookingError;
42
+ class ProfileError extends CommerceError {
43
+ constructor(message, code, meta = {}) {
44
+ super(message, code, meta);
45
+ this.name = "ProfileError";
46
+ }
47
+ }
48
+ exports.ProfileError = ProfileError;
49
+ // ---------------------------------------------------------------------------
50
+ // Transient error detection
51
+ // ---------------------------------------------------------------------------
52
+ const TRANSIENT_CODES = new Set(["COMMERCE_TRANSIENT", "COMMERCE_TIMEOUT", "COMMERCE_NETWORK"]);
53
+ function isTransient(err) {
54
+ return err instanceof CommerceError && TRANSIENT_CODES.has(err.code);
55
+ }
56
+ // ---------------------------------------------------------------------------
57
+ // Helpers
58
+ // ---------------------------------------------------------------------------
59
+ /**
60
+ * Retry a function once on transient failure, then throw.
61
+ * Non-transient errors are thrown immediately without retry.
62
+ */
63
+ async function retryOnce(fn) {
64
+ try {
65
+ return await fn();
66
+ }
67
+ catch (err) {
68
+ if (!isTransient(err))
69
+ throw err;
70
+ // One retry
71
+ return fn();
72
+ }
73
+ }
74
+ /**
75
+ * Throw PaymentError if the actual price differs from the approved price
76
+ * by more than 5%. Used to protect against price changes between search
77
+ * and booking.
78
+ */
79
+ function priceChangeGuard(approved, actual) {
80
+ if (approved === 0 && actual === 0)
81
+ return;
82
+ if (approved === 0) {
83
+ throw new PaymentError(`price changed from $0 to $${actual} — cannot verify percentage change`, "PAYMENT_PRICE_CHANGED", { approved, actual });
84
+ }
85
+ const delta = Math.abs(actual - approved) / approved;
86
+ if (delta > 0.05) {
87
+ throw new PaymentError(`price changed by ${(delta * 100).toFixed(1)}% (approved: $${approved}, actual: $${actual})`, "PAYMENT_PRICE_CHANGED", { approved, actual, deltaPercent: delta * 100 });
88
+ }
89
+ }
90
+ /**
91
+ * Format a human-readable status report for multi-service booking attempts.
92
+ * Each entry has a service name, status, and optional error message.
93
+ */
94
+ function partialFailureReport(results) {
95
+ if (results.length === 0) {
96
+ return "no services attempted.";
97
+ }
98
+ const lines = results.map((r) => {
99
+ const status = r.status === "success" ? "success" : "failed";
100
+ const detail = r.error ? ` — ${r.error}` : "";
101
+ return ` ${r.service}: ${status}${detail}`;
102
+ });
103
+ const succeeded = results.filter((r) => r.status === "success").length;
104
+ const failed = results.length - succeeded;
105
+ return [
106
+ `booking status: ${succeeded} succeeded, ${failed} failed`,
107
+ ...lines,
108
+ ].join("\n");
109
+ }
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * Commerce self-test — per-service health checks for the agent's
4
+ * commerce infrastructure (Stripe, Duffel, LiteAPI).
5
+ *
6
+ * Used by the setup wizard to verify configuration and provide
7
+ * actionable error messages when services are misconfigured.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.commerceSelfTest = commerceSelfTest;
11
+ const stripe_client_1 = require("./stripe-client");
12
+ const duffel_client_1 = require("./duffel-client");
13
+ const credential_access_1 = require("./credential-access");
14
+ const runtime_1 = require("../nerves/runtime");
15
+ // ---------------------------------------------------------------------------
16
+ // Per-service tests
17
+ // ---------------------------------------------------------------------------
18
+ async function testStripe() {
19
+ try {
20
+ const client = await (0, stripe_client_1.createStripeClient)();
21
+ // Create a test card and immediately deactivate it
22
+ const card = await client.createVirtualCard({
23
+ type: "single_use",
24
+ spendLimit: 1,
25
+ currency: "usd",
26
+ });
27
+ await client.deactivateCard(card.cardId);
28
+ return { status: "ok", message: "Stripe Issuing working. Test card created and deactivated." };
29
+ }
30
+ catch (err) {
31
+ /* v8 ignore next -- reason @preserve */
32
+ const reason = err instanceof Error ? err.message : String(err);
33
+ if (reason.includes("no credential found") || reason.includes("restrictedKey")) {
34
+ return {
35
+ status: "error",
36
+ message: `Stripe key missing. Add your restricted key at https://dashboard.stripe.com/apikeys and store it in the vault as stripe.com/restrictedKey.`,
37
+ };
38
+ }
39
+ if (reason.includes("401") || reason.includes("Invalid API Key")) {
40
+ return {
41
+ status: "error",
42
+ message: `Stripe key returned 401. Verify it at https://dashboard.stripe.com/apikeys.`,
43
+ };
44
+ }
45
+ return {
46
+ status: "error",
47
+ message: `Stripe error: ${reason}`,
48
+ };
49
+ }
50
+ }
51
+ async function testDuffel() {
52
+ try {
53
+ const client = await (0, duffel_client_1.createDuffelClient)();
54
+ await client.searchFlights({
55
+ origin: "SFO",
56
+ destination: "JFK",
57
+ departureDate: new Date(Date.now() + 30 * 86400000).toISOString().split("T")[0],
58
+ passengers: [{ type: "adult" }],
59
+ });
60
+ return { status: "ok", message: "Duffel Flights working. Test search completed." };
61
+ }
62
+ catch (err) {
63
+ /* v8 ignore next -- reason @preserve */
64
+ const reason = err instanceof Error ? err.message : String(err);
65
+ if (reason.includes("no credential found") || reason.includes("apiKey")) {
66
+ return {
67
+ status: "error",
68
+ message: `Duffel key missing. Add your API key from https://app.duffel.com/tokens and store it in the vault as duffel.com/apiKey.`,
69
+ };
70
+ }
71
+ if (reason.includes("401") || reason.includes("Unauthorized")) {
72
+ return {
73
+ status: "error",
74
+ message: `Your Duffel key returned 401. Verify it at https://app.duffel.com/tokens.`,
75
+ };
76
+ }
77
+ return {
78
+ status: "error",
79
+ message: `Duffel error: ${reason}`,
80
+ };
81
+ }
82
+ }
83
+ async function testLiteApi() {
84
+ try {
85
+ const store = (0, credential_access_1.getCredentialStore)();
86
+ await store.getRawSecret("liteapi.travel", "apiKey");
87
+ // If we can retrieve the key, the config is present.
88
+ // LiteAPI is accessed via MCP, so we can't do a direct API call here.
89
+ // The actual health check happens when the MCP server starts.
90
+ return { status: "ok", message: "LiteAPI key found in vault. MCP server will use vault:liteapi.travel/apiKey." };
91
+ }
92
+ catch (err) {
93
+ /* v8 ignore next -- reason @preserve */
94
+ const reason = err instanceof Error ? err.message : String(err);
95
+ if (reason.includes("no credential found")) {
96
+ return {
97
+ status: "error",
98
+ message: `LiteAPI key missing. Get your API key from https://dashboard.liteapi.travel and store it in the vault as liteapi.travel/apiKey.`,
99
+ };
100
+ }
101
+ return {
102
+ status: "error",
103
+ message: `LiteAPI error: ${reason}`,
104
+ };
105
+ }
106
+ }
107
+ // ---------------------------------------------------------------------------
108
+ // Main self-test
109
+ // ---------------------------------------------------------------------------
110
+ async function commerceSelfTest() {
111
+ (0, runtime_1.emitNervesEvent)({
112
+ component: "repertoire",
113
+ event: "repertoire.commerce_self_test_start",
114
+ message: "starting commerce self-test",
115
+ meta: {},
116
+ });
117
+ const [stripe, duffel, liteapi] = await Promise.all([
118
+ testStripe(),
119
+ testDuffel(),
120
+ testLiteApi(),
121
+ ]);
122
+ const services = { stripe, duffel, liteapi };
123
+ const okCount = Object.values(services).filter((s) => s.status === "ok").length;
124
+ const total = Object.keys(services).length;
125
+ let overall;
126
+ if (okCount === total) {
127
+ overall = "healthy";
128
+ }
129
+ else if (okCount > 0) {
130
+ overall = "partial";
131
+ }
132
+ else {
133
+ overall = "unhealthy";
134
+ }
135
+ const lines = [];
136
+ if (stripe.status === "ok")
137
+ lines.push("Stripe: working");
138
+ else
139
+ lines.push(`Stripe: ${stripe.message}`);
140
+ if (duffel.status === "ok")
141
+ lines.push("Duffel: working");
142
+ else
143
+ lines.push(`Duffel: ${duffel.message}`);
144
+ if (liteapi.status === "ok")
145
+ lines.push("LiteAPI: working");
146
+ else
147
+ lines.push(`LiteAPI: ${liteapi.message}`);
148
+ const summary = `Commerce health: ${okCount}/${total} services ok.\n${lines.join("\n")}`;
149
+ (0, runtime_1.emitNervesEvent)({
150
+ component: "repertoire",
151
+ event: "repertoire.commerce_self_test_end",
152
+ message: "commerce self-test complete",
153
+ meta: { overall, okCount, total },
154
+ });
155
+ return { overall, services, summary };
156
+ }