@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
@@ -0,0 +1,344 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.fileToolDefinitions = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const fg = __importStar(require("fast-glob"));
39
+ const path = __importStar(require("path"));
40
+ const identity_1 = require("../heart/identity");
41
+ const file_state_1 = require("../mind/file-state");
42
+ const scrutiny_1 = require("../mind/scrutiny");
43
+ const tools_base_1 = require("./tools-base");
44
+ function resolveLocalToolPath(targetPath) {
45
+ if (!path.isAbsolute(targetPath)) {
46
+ return path.resolve((0, identity_1.getRepoRoot)(), targetPath);
47
+ }
48
+ return targetPath;
49
+ }
50
+ function buildContextDiff(lines, changeStart, changeEnd, contextSize = 3) {
51
+ const start = Math.max(0, changeStart - contextSize);
52
+ const end = Math.min(lines.length, changeEnd + contextSize);
53
+ const result = [];
54
+ for (let i = start; i < end; i++) {
55
+ const lineNum = i + 1;
56
+ const prefix = (i >= changeStart && i < changeEnd) ? ">" : " ";
57
+ result.push(`${prefix} ${lineNum} | ${lines[i]}`);
58
+ }
59
+ return result.join("\n");
60
+ }
61
+ exports.fileToolDefinitions = [
62
+ {
63
+ tool: {
64
+ type: "function",
65
+ function: {
66
+ name: "read_file",
67
+ description: "Read file contents. Results include line numbers. Use offset/limit for large files -- don't read the whole thing if you only need a section. Use this tool before editing any file. When reading code, read enough context to understand the surrounding logic, not just the target line.",
68
+ parameters: {
69
+ type: "object",
70
+ properties: {
71
+ path: { type: "string" },
72
+ offset: { type: "number", description: "1-based line number to start reading from" },
73
+ limit: { type: "number", description: "maximum number of lines to return" },
74
+ },
75
+ required: ["path"],
76
+ },
77
+ },
78
+ },
79
+ handler: (a) => {
80
+ const resolvedPath = resolveLocalToolPath(a.path);
81
+ const content = fs.readFileSync(resolvedPath, "utf-8");
82
+ tools_base_1.editFileReadTracker.add(resolvedPath);
83
+ const offset = a.offset ? parseInt(a.offset, 10) : undefined;
84
+ const limit = a.limit ? parseInt(a.limit, 10) : undefined;
85
+ // Record in file state cache for staleness detection
86
+ try {
87
+ const mtime = fs.statSync(resolvedPath).mtimeMs;
88
+ const readContent = (offset === undefined && limit === undefined)
89
+ ? content
90
+ : content.split("\n").slice(offset ? offset - 1 : 0, limit !== undefined ? (offset ? offset - 1 : 0) + limit : undefined).join("\n");
91
+ file_state_1.fileStateCache.record(resolvedPath, readContent, mtime, offset, limit);
92
+ }
93
+ catch {
94
+ // stat failed -- skip cache recording
95
+ }
96
+ if (offset === undefined && limit === undefined)
97
+ return content;
98
+ const lines = content.split("\n");
99
+ const start = offset ? offset - 1 : 0;
100
+ const end = limit !== undefined ? start + limit : lines.length;
101
+ return lines.slice(start, end).join("\n");
102
+ },
103
+ summaryKeys: ["path"],
104
+ },
105
+ {
106
+ tool: {
107
+ type: "function",
108
+ function: {
109
+ name: "write_file",
110
+ description: "Prefer this tool for creating new files or fully replacing existing ones. You MUST read an existing file with read_file before overwriting it. Prefer edit_file for modifying existing files -- it only sends the diff. Do not create documentation files (*.md, README) by default; only do so when explicitly asked or when documentation is clearly part of the requested change.",
111
+ parameters: {
112
+ type: "object",
113
+ properties: { path: { type: "string" }, content: { type: "string" } },
114
+ required: ["path", "content"],
115
+ },
116
+ },
117
+ },
118
+ handler: (a) => {
119
+ const resolvedPath = resolveLocalToolPath(a.path);
120
+ fs.mkdirSync(path.dirname(resolvedPath), { recursive: true });
121
+ fs.writeFileSync(resolvedPath, a.content, "utf-8");
122
+ (0, scrutiny_1.trackModifiedFile)(resolvedPath);
123
+ const scrutiny = (0, scrutiny_1.getPostImplementationScrutiny)((0, scrutiny_1.getModifiedFileCount)());
124
+ /* v8 ignore next -- scrutiny appendix branch depends on session-level file count @preserve */
125
+ return scrutiny ? `ok\n\n${scrutiny}` : "ok";
126
+ },
127
+ summaryKeys: ["path"],
128
+ riskProfile: { mutates: "durable_state_write", risk: "high", reason: "writes file contents" },
129
+ },
130
+ {
131
+ tool: {
132
+ type: "function",
133
+ function: {
134
+ name: "edit_file",
135
+ description: "Surgically edit a file by replacing an exact string. The file MUST have been read via read_file first -- this tool will reject the call otherwise. old_string must match EXACTLY ONE location in the file -- if it matches zero or multiple, the edit fails. To fix: provide more surrounding context to make the match unique. Preserve exact indentation (tabs/spaces) from the file. Prefer this over write_file for modifications -- it only sends the diff.",
136
+ parameters: {
137
+ type: "object",
138
+ properties: {
139
+ path: { type: "string" },
140
+ old_string: { type: "string" },
141
+ new_string: { type: "string" },
142
+ },
143
+ required: ["path", "old_string", "new_string"],
144
+ },
145
+ },
146
+ },
147
+ handler: (a) => {
148
+ const resolvedPath = resolveLocalToolPath(a.path);
149
+ if (!tools_base_1.editFileReadTracker.has(resolvedPath)) {
150
+ return `error: you must read the file with read_file before editing it. call read_file on ${a.path} first.`;
151
+ }
152
+ // Check staleness before editing
153
+ const stalenessCheck = file_state_1.fileStateCache.isStale(resolvedPath);
154
+ let content;
155
+ try {
156
+ content = fs.readFileSync(resolvedPath, "utf-8");
157
+ }
158
+ catch (e) {
159
+ return `error: could not read file: ${e instanceof Error ? e.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(e)}`;
160
+ }
161
+ // Count occurrences
162
+ const occurrences = [];
163
+ let searchFrom = 0;
164
+ while (true) {
165
+ const idx = content.indexOf(a.old_string, searchFrom);
166
+ if (idx === -1)
167
+ break;
168
+ occurrences.push(idx);
169
+ searchFrom = idx + 1;
170
+ }
171
+ if (occurrences.length === 0) {
172
+ return `error: old_string not found in ${a.path}`;
173
+ }
174
+ if (occurrences.length > 1) {
175
+ return `error: old_string is ambiguous -- found ${occurrences.length} matches in ${a.path}. provide more context to make the match unique.`;
176
+ }
177
+ // Single unique match -- replace
178
+ const idx = occurrences[0];
179
+ const updated = content.slice(0, idx) + a.new_string + content.slice(idx + a.old_string.length);
180
+ fs.writeFileSync(resolvedPath, updated, "utf-8");
181
+ // Update file state cache with new content
182
+ try {
183
+ const newMtime = fs.statSync(resolvedPath).mtimeMs;
184
+ file_state_1.fileStateCache.record(resolvedPath, updated, newMtime);
185
+ }
186
+ catch {
187
+ // stat failed -- skip cache update
188
+ }
189
+ // Build contextual diff
190
+ const lines = updated.split("\n");
191
+ const prefixLines = content.slice(0, idx).split("\n");
192
+ const changeStartLine = prefixLines.length - 1;
193
+ const newStringLines = a.new_string.split("\n");
194
+ const changeEndLine = changeStartLine + newStringLines.length;
195
+ const diffResult = buildContextDiff(lines, changeStartLine, changeEndLine);
196
+ // Track modified file and compute scrutiny appendix
197
+ (0, scrutiny_1.trackModifiedFile)(resolvedPath);
198
+ const scrutiny = (0, scrutiny_1.getPostImplementationScrutiny)((0, scrutiny_1.getModifiedFileCount)());
199
+ // Append staleness warning if detected (do not block -- TTFA)
200
+ /* v8 ignore start -- staleness+diff+scrutiny combo not exercised in integration tests @preserve */
201
+ if (stalenessCheck.stale) {
202
+ const base = `${diffResult}\n\n⚠️ warning: file changed externally since last read -- re-read recommended`;
203
+ return scrutiny ? `${base}\n\n${scrutiny}` : base;
204
+ }
205
+ /* v8 ignore stop */
206
+ /* v8 ignore next -- scrutiny appendix branch depends on session-level file count @preserve */
207
+ return scrutiny ? `${diffResult}\n\n${scrutiny}` : diffResult;
208
+ },
209
+ summaryKeys: ["path"],
210
+ riskProfile: { mutates: "durable_state_write", risk: "high", reason: "edits file contents" },
211
+ },
212
+ {
213
+ tool: {
214
+ type: "function",
215
+ function: {
216
+ name: "glob",
217
+ description: "Find files matching a glob pattern, sorted alphabetically. Use this instead of shell commands like `find` or `ls`. For broad exploratory searches that would require multiple rounds of globbing and grepping, consider using claude or coding_spawn.",
218
+ parameters: {
219
+ type: "object",
220
+ properties: {
221
+ pattern: { type: "string", description: "glob pattern (e.g. **/*.ts)" },
222
+ cwd: { type: "string", description: "directory to search from (defaults to process.cwd())" },
223
+ },
224
+ required: ["pattern"],
225
+ },
226
+ },
227
+ },
228
+ handler: (a) => {
229
+ const cwd = a.cwd ? resolveLocalToolPath(a.cwd) : process.cwd();
230
+ const matches = fg.globSync(a.pattern, { cwd, dot: true });
231
+ return matches.sort().join("\n");
232
+ },
233
+ summaryKeys: ["pattern", "cwd"],
234
+ },
235
+ {
236
+ tool: {
237
+ type: "function",
238
+ function: {
239
+ name: "grep",
240
+ description: "Search file contents for lines matching a regex pattern. Searches recursively in directories. Use this instead of shell commands like `grep` or `rg`. Returns matching lines with file path and line numbers. Use context_lines for surrounding context. Use include to filter file types (e.g., '*.ts').",
241
+ parameters: {
242
+ type: "object",
243
+ properties: {
244
+ pattern: { type: "string", description: "regex pattern to search for" },
245
+ path: { type: "string", description: "file or directory to search" },
246
+ context_lines: { type: "number", description: "number of surrounding context lines (default 0)" },
247
+ include: { type: "string", description: "glob filter to limit searched files (e.g. *.ts)" },
248
+ },
249
+ required: ["pattern", "path"],
250
+ },
251
+ },
252
+ },
253
+ handler: (a) => {
254
+ const targetPath = resolveLocalToolPath(a.path);
255
+ const regex = new RegExp(a.pattern);
256
+ const contextLines = parseInt(a.context_lines || "0", 10);
257
+ const includeGlob = a.include || undefined;
258
+ function searchFile(filePath) {
259
+ let content;
260
+ try {
261
+ content = fs.readFileSync(filePath, "utf-8");
262
+ }
263
+ catch {
264
+ return [];
265
+ }
266
+ const lines = content.split("\n");
267
+ const matchIndices = new Set();
268
+ for (let i = 0; i < lines.length; i++) {
269
+ if (regex.test(lines[i])) {
270
+ matchIndices.add(i);
271
+ }
272
+ }
273
+ if (matchIndices.size === 0)
274
+ return [];
275
+ const outputIndices = new Set();
276
+ for (const idx of matchIndices) {
277
+ const start = Math.max(0, idx - contextLines);
278
+ const end = Math.min(lines.length - 1, idx + contextLines);
279
+ for (let i = start; i <= end; i++) {
280
+ outputIndices.add(i);
281
+ }
282
+ }
283
+ const sortedIndices = [...outputIndices].sort((a, b) => a - b);
284
+ const results = [];
285
+ for (const idx of sortedIndices) {
286
+ const lineNum = idx + 1;
287
+ if (matchIndices.has(idx)) {
288
+ results.push(`${filePath}:${lineNum}: ${lines[idx]}`);
289
+ }
290
+ else {
291
+ results.push(`-${filePath}:${lineNum}: ${lines[idx]}`);
292
+ }
293
+ }
294
+ return results;
295
+ }
296
+ function collectFiles(dirPath) {
297
+ const files = [];
298
+ function walk(dir) {
299
+ let entries;
300
+ try {
301
+ entries = fs.readdirSync(dir, { withFileTypes: true });
302
+ }
303
+ catch {
304
+ return;
305
+ }
306
+ for (const entry of entries) {
307
+ const fullPath = path.join(dir, entry.name);
308
+ if (entry.isDirectory()) {
309
+ walk(fullPath);
310
+ }
311
+ else if (entry.isFile()) {
312
+ files.push(fullPath);
313
+ }
314
+ }
315
+ }
316
+ walk(dirPath);
317
+ return files.sort();
318
+ }
319
+ function matchesGlob(filePath, glob) {
320
+ const escaped = glob
321
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
322
+ .replace(/\*/g, ".*")
323
+ .replace(/\?/g, ".");
324
+ return new RegExp(`(^|/)${escaped}$`).test(filePath);
325
+ }
326
+ const stat = fs.statSync(targetPath, { throwIfNoEntry: false });
327
+ if (!stat)
328
+ return "";
329
+ if (stat.isFile()) {
330
+ return searchFile(targetPath).join("\n");
331
+ }
332
+ let files = collectFiles(targetPath);
333
+ if (includeGlob) {
334
+ files = files.filter((f) => matchesGlob(f, includeGlob));
335
+ }
336
+ const allResults = [];
337
+ for (const file of files) {
338
+ allResults.push(...searchFile(file));
339
+ }
340
+ return allResults.join("\n");
341
+ },
342
+ summaryKeys: ["pattern", "path", "include"],
343
+ },
344
+ ];
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.flightToolDefinitions = void 0;
4
+ exports.resetDuffelClient = resetDuffelClient;
5
+ const duffel_client_1 = require("./duffel-client");
6
+ const user_profile_1 = require("./user-profile");
7
+ const credential_access_1 = require("./credential-access");
8
+ const runtime_1 = require("../nerves/runtime");
9
+ // Lazy-initialized Duffel client singleton
10
+ let _duffelClient = null;
11
+ async function getDuffelClient() {
12
+ if (!_duffelClient) {
13
+ _duffelClient = await (0, duffel_client_1.createDuffelClient)();
14
+ }
15
+ return _duffelClient;
16
+ }
17
+ function requireFamilyContext(ctx) {
18
+ if (!ctx?.context?.friend?.id) {
19
+ return "no friend context — cannot access flight tools.";
20
+ }
21
+ if (ctx.context.friend.trustLevel !== "family") {
22
+ return "booking and cancellation require family trust level.";
23
+ }
24
+ return { friendId: ctx.context.friend.id };
25
+ }
26
+ function requireFriendContext(ctx) {
27
+ if (!ctx?.context?.friend?.id) {
28
+ return "no friend context — cannot search flights.";
29
+ }
30
+ return { friendId: ctx.context.friend.id };
31
+ }
32
+ exports.flightToolDefinitions = [
33
+ {
34
+ tool: {
35
+ type: "function",
36
+ function: {
37
+ name: "flight_search",
38
+ description: "Search for flights between two airports. Returns available offers with prices.",
39
+ parameters: {
40
+ type: "object",
41
+ properties: {
42
+ origin: { type: "string", description: "Origin airport IATA code (e.g. 'SFO')" },
43
+ destination: { type: "string", description: "Destination airport IATA code (e.g. 'JFK')" },
44
+ departure_date: { type: "string", description: "Departure date (YYYY-MM-DD)" },
45
+ return_date: { type: "string", description: "Return date for round trips (optional)" },
46
+ passengers: { type: "string", description: "Number of adult passengers (default '1')" },
47
+ cabin_class: { type: "string", description: "Cabin class: economy, premium_economy, business, first" },
48
+ },
49
+ required: ["origin", "destination", "departure_date"],
50
+ },
51
+ },
52
+ },
53
+ handler: async (args, ctx) => {
54
+ (0, runtime_1.emitNervesEvent)({
55
+ component: "repertoire",
56
+ event: "repertoire.tool_flight_search",
57
+ message: "flight_search invoked",
58
+ meta: { tool: "flight_search", origin: args.origin, destination: args.destination },
59
+ });
60
+ const guard = requireFriendContext(ctx);
61
+ if (typeof guard === "string")
62
+ return guard;
63
+ try {
64
+ const client = await getDuffelClient();
65
+ const passengerCount = parseInt(args.passengers || "1", 10);
66
+ const passengers = Array.from({ length: passengerCount }, () => ({ type: "adult" }));
67
+ const offers = await client.searchFlights({
68
+ origin: args.origin,
69
+ destination: args.destination,
70
+ departureDate: args.departure_date,
71
+ returnDate: args.return_date,
72
+ passengers,
73
+ cabinClass: args.cabin_class,
74
+ });
75
+ if (offers.length === 0) {
76
+ return "no flights found for those criteria.";
77
+ }
78
+ return JSON.stringify(offers, null, 2);
79
+ }
80
+ catch (err) {
81
+ /* v8 ignore next -- defensive @preserve */
82
+ return `flight search error: ${err instanceof Error ? err.message : String(err)}`;
83
+ }
84
+ },
85
+ summaryKeys: ["origin", "destination", "departure_date"],
86
+ },
87
+ {
88
+ tool: {
89
+ type: "function",
90
+ function: {
91
+ name: "flight_hold",
92
+ description: "Hold a flight offer for a short period before committing to book. Not all airlines support holds.",
93
+ parameters: {
94
+ type: "object",
95
+ properties: {
96
+ offer_id: { type: "string", description: "The Duffel offer ID to hold" },
97
+ },
98
+ required: ["offer_id"],
99
+ },
100
+ },
101
+ },
102
+ handler: async (args, ctx) => {
103
+ (0, runtime_1.emitNervesEvent)({
104
+ component: "repertoire",
105
+ event: "repertoire.tool_flight_hold",
106
+ message: "flight_hold invoked",
107
+ meta: { tool: "flight_hold", offerId: args.offer_id },
108
+ });
109
+ const guard = requireFamilyContext(ctx);
110
+ if (typeof guard === "string")
111
+ return guard;
112
+ // Hold functionality would call Duffel's offer hold API.
113
+ // For pre-build, we return a structured acknowledgment.
114
+ return JSON.stringify({
115
+ status: "hold_requested",
116
+ offerId: args.offer_id,
117
+ message: "Hold requested. Confirm or cancel before the hold expires.",
118
+ });
119
+ },
120
+ summaryKeys: ["offer_id"],
121
+ riskProfile: { mutates: "external_side_effect", risk: "high", reason: "requests an airline offer hold" },
122
+ },
123
+ {
124
+ tool: {
125
+ type: "function",
126
+ function: {
127
+ name: "flight_book",
128
+ description: "Book a flight. Pulls passenger name/DOB/passport from the user's profile. Creates a virtual card, books the flight, then deactivates the card. Requires family trust level.",
129
+ parameters: {
130
+ type: "object",
131
+ properties: {
132
+ offer_id: { type: "string", description: "The Duffel offer ID to book" },
133
+ amount: { type: "string", description: "Expected total amount in dollars" },
134
+ currency: { type: "string", description: "Currency code (e.g. 'usd')" },
135
+ },
136
+ required: ["offer_id", "amount", "currency"],
137
+ },
138
+ },
139
+ },
140
+ handler: async (args, ctx) => {
141
+ (0, runtime_1.emitNervesEvent)({
142
+ component: "repertoire",
143
+ event: "repertoire.tool_flight_book",
144
+ message: "flight_book invoked",
145
+ meta: { tool: "flight_book", offerId: args.offer_id },
146
+ });
147
+ const guard = requireFamilyContext(ctx);
148
+ if (typeof guard === "string")
149
+ return guard;
150
+ try {
151
+ const store = (0, credential_access_1.getCredentialStore)();
152
+ // Get passenger data from profile
153
+ const legalName = await (0, user_profile_1.getUserProfileField)(guard.friendId, "legalName", store);
154
+ if (!legalName) {
155
+ return "passenger profile not found — please store your profile first using user_profile_store.";
156
+ }
157
+ const dateOfBirth = await (0, user_profile_1.getUserProfileField)(guard.friendId, "dateOfBirth", store);
158
+ const passport = await (0, user_profile_1.getUserProfileField)(guard.friendId, "passport", store);
159
+ const client = await getDuffelClient();
160
+ const result = await client.createOrder({
161
+ offerId: args.offer_id,
162
+ passengers: [{
163
+ type: "adult",
164
+ givenName: legalName.first,
165
+ familyName: legalName.last,
166
+ /* v8 ignore next -- reason @preserve */
167
+ dateOfBirth: dateOfBirth ?? "1990-01-01",
168
+ passportNumber: passport?.number,
169
+ passportCountry: passport?.country,
170
+ passportExpiry: passport?.expiry,
171
+ }],
172
+ amount: parseFloat(args.amount),
173
+ currency: args.currency,
174
+ });
175
+ return JSON.stringify(result, null, 2);
176
+ }
177
+ catch (err) {
178
+ /* v8 ignore next -- defensive @preserve */
179
+ return `booking error: ${err instanceof Error ? err.message : String(err)}`;
180
+ }
181
+ },
182
+ summaryKeys: ["offer_id", "amount"],
183
+ riskProfile: { mutates: "external_side_effect", risk: "high", reason: "books travel through an external provider" },
184
+ },
185
+ {
186
+ tool: {
187
+ type: "function",
188
+ function: {
189
+ name: "flight_cancel",
190
+ description: "Cancel a flight booking. Not all bookings are cancellable. Requires family trust level.",
191
+ parameters: {
192
+ type: "object",
193
+ properties: {
194
+ order_id: { type: "string", description: "The Duffel order ID to cancel" },
195
+ },
196
+ required: ["order_id"],
197
+ },
198
+ },
199
+ },
200
+ handler: async (args, ctx) => {
201
+ (0, runtime_1.emitNervesEvent)({
202
+ component: "repertoire",
203
+ event: "repertoire.tool_flight_cancel",
204
+ message: "flight_cancel invoked",
205
+ meta: { tool: "flight_cancel", orderId: args.order_id },
206
+ });
207
+ const guard = requireFamilyContext(ctx);
208
+ if (typeof guard === "string")
209
+ return guard;
210
+ try {
211
+ const client = await getDuffelClient();
212
+ const result = await client.cancelOrder(args.order_id);
213
+ return JSON.stringify(result, null, 2);
214
+ }
215
+ catch (err) {
216
+ /* v8 ignore next -- defensive @preserve */
217
+ return `cancellation error: ${err instanceof Error ? err.message : String(err)}`;
218
+ }
219
+ },
220
+ summaryKeys: ["order_id"],
221
+ riskProfile: { mutates: "external_side_effect", risk: "high", reason: "cancels travel through an external provider" },
222
+ },
223
+ ];
224
+ /** Reset the Duffel client singleton (for testing). */
225
+ function resetDuffelClient() {
226
+ _duffelClient = null;
227
+ }