@ouro.bot/cli 0.1.0-alpha.56 → 0.1.0-alpha.560

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 (392) 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 +3596 -0
  13. package/dist/arc/attention-types.js +8 -0
  14. package/dist/arc/cares.js +140 -0
  15. package/dist/arc/episodes.js +117 -0
  16. package/dist/arc/intentions.js +133 -0
  17. package/dist/arc/json-store.js +117 -0
  18. package/dist/arc/obligations.js +237 -0
  19. package/dist/arc/packets.js +193 -0
  20. package/dist/arc/presence.js +185 -0
  21. package/dist/arc/task-lifecycle.js +65 -0
  22. package/dist/heart/active-work.js +837 -26
  23. package/dist/heart/agent-entry.js +58 -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/adapter.js +2 -0
  29. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  30. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  31. package/dist/heart/attachments/sources/index.js +16 -0
  32. package/dist/heart/attachments/store.js +103 -0
  33. package/dist/heart/attachments/types.js +93 -0
  34. package/dist/heart/auth/auth-flow.js +479 -0
  35. package/dist/heart/background-operations.js +281 -0
  36. package/dist/heart/bundle-state.js +168 -0
  37. package/dist/heart/commitments.js +111 -0
  38. package/dist/heart/config-registry.js +322 -0
  39. package/dist/heart/config.js +114 -118
  40. package/dist/heart/core.js +913 -246
  41. package/dist/heart/cross-chat-delivery.js +3 -18
  42. package/dist/heart/daemon/agent-config-check.js +419 -0
  43. package/dist/heart/daemon/agent-discovery.js +102 -3
  44. package/dist/heart/daemon/agent-service.js +522 -0
  45. package/dist/heart/daemon/agentic-repair.js +547 -0
  46. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  47. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  48. package/dist/heart/daemon/cadence.js +70 -0
  49. package/dist/heart/daemon/cli-defaults.js +776 -0
  50. package/dist/heart/daemon/cli-exec.js +7457 -0
  51. package/dist/heart/daemon/cli-help.js +498 -0
  52. package/dist/heart/daemon/cli-parse.js +1592 -0
  53. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  54. package/dist/heart/daemon/cli-render.js +763 -0
  55. package/dist/heart/daemon/cli-types.js +8 -0
  56. package/dist/heart/daemon/connect-bay.js +323 -0
  57. package/dist/heart/daemon/daemon-cli.js +29 -1698
  58. package/dist/heart/daemon/daemon-entry.js +387 -2
  59. package/dist/heart/daemon/daemon-health.js +176 -0
  60. package/dist/heart/daemon/daemon-rollup.js +57 -0
  61. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  62. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  63. package/dist/heart/daemon/daemon.js +796 -71
  64. package/dist/heart/daemon/dns-workflow.js +394 -0
  65. package/dist/heart/daemon/doctor-types.js +8 -0
  66. package/dist/heart/daemon/doctor.js +826 -0
  67. package/dist/heart/daemon/health-monitor.js +122 -1
  68. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  69. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  70. package/dist/heart/daemon/http-health-probe.js +80 -0
  71. package/dist/heart/daemon/human-command-screens.js +234 -0
  72. package/dist/heart/daemon/human-readiness.js +114 -0
  73. package/dist/heart/daemon/inner-status.js +89 -0
  74. package/dist/heart/daemon/interactive-repair.js +394 -0
  75. package/dist/heart/daemon/launchd.js +37 -8
  76. package/dist/heart/daemon/log-tailer.js +82 -12
  77. package/dist/heart/daemon/logs-prune.js +110 -0
  78. package/dist/heart/daemon/mcp-canary.js +297 -0
  79. package/dist/heart/daemon/message-router.js +2 -2
  80. package/dist/heart/daemon/os-cron-deps.js +135 -0
  81. package/dist/heart/daemon/os-cron.js +14 -12
  82. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  83. package/dist/heart/daemon/ouro-entry.js +3 -1
  84. package/dist/heart/daemon/process-manager.js +375 -33
  85. package/dist/heart/daemon/provider-discovery.js +137 -0
  86. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  87. package/dist/heart/daemon/pulse.js +475 -0
  88. package/dist/heart/daemon/readiness-repair.js +365 -0
  89. package/dist/heart/daemon/run-hooks.js +2 -0
  90. package/dist/heart/daemon/runtime-logging.js +67 -16
  91. package/dist/heart/daemon/runtime-metadata.js +3 -31
  92. package/dist/heart/daemon/safe-mode.js +161 -0
  93. package/dist/heart/daemon/sense-manager.js +389 -38
  94. package/dist/heart/daemon/session-id-resolver.js +131 -0
  95. package/dist/heart/daemon/skill-management-installer.js +94 -0
  96. package/dist/heart/daemon/socket-client.js +158 -11
  97. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  98. package/dist/heart/daemon/startup-tui.js +330 -0
  99. package/dist/heart/daemon/task-scheduler.js +3 -25
  100. package/dist/heart/daemon/terminal-ui.js +499 -0
  101. package/dist/heart/daemon/thoughts.js +162 -17
  102. package/dist/heart/daemon/up-progress.js +366 -0
  103. package/dist/heart/daemon/vault-items.js +56 -0
  104. package/dist/heart/delegation.js +1 -1
  105. package/dist/heart/habits/habit-migration.js +189 -0
  106. package/dist/heart/habits/habit-parser.js +140 -0
  107. package/dist/heart/habits/habit-runtime-state.js +100 -0
  108. package/dist/heart/habits/habit-scheduler.js +372 -0
  109. package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -56
  110. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  111. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  112. package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
  113. package/dist/heart/identity.js +203 -57
  114. package/dist/heart/kept-notes.js +357 -0
  115. package/dist/heart/kicks.js +1 -1
  116. package/dist/heart/machine-identity.js +161 -0
  117. package/dist/heart/mail-import-discovery.js +353 -0
  118. package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
  119. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  120. package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
  121. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  122. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  123. package/dist/heart/mailbox/mailbox-http.js +99 -0
  124. package/dist/heart/mailbox/mailbox-read.js +31 -0
  125. package/dist/heart/mailbox/mailbox-types.js +27 -0
  126. package/dist/heart/mailbox/mailbox-view.js +195 -0
  127. package/dist/heart/mailbox/readers/agent-machine.js +382 -0
  128. package/dist/heart/mailbox/readers/continuity-readers.js +338 -0
  129. package/dist/heart/mailbox/readers/mail.js +362 -0
  130. package/dist/heart/mailbox/readers/runtime-readers.js +651 -0
  131. package/dist/heart/mailbox/readers/sessions.js +232 -0
  132. package/dist/heart/mailbox/readers/shared.js +111 -0
  133. package/dist/heart/mcp/mcp-server.js +683 -0
  134. package/dist/heart/migrate-config.js +100 -0
  135. package/dist/heart/model-capabilities.js +19 -0
  136. package/dist/heart/platform.js +81 -0
  137. package/dist/heart/provider-attempt.js +134 -0
  138. package/dist/heart/provider-binding-resolver.js +267 -0
  139. package/dist/heart/provider-credentials.js +425 -0
  140. package/dist/heart/provider-failover.js +301 -0
  141. package/dist/heart/provider-models.js +81 -0
  142. package/dist/heart/provider-ping.js +262 -0
  143. package/dist/heart/provider-readiness-cache.js +40 -0
  144. package/dist/heart/provider-visibility.js +188 -0
  145. package/dist/heart/providers/anthropic-token.js +131 -0
  146. package/dist/heart/providers/anthropic.js +139 -52
  147. package/dist/heart/providers/azure.js +97 -13
  148. package/dist/heart/providers/error-classification.js +127 -0
  149. package/dist/heart/providers/github-copilot.js +145 -0
  150. package/dist/heart/providers/minimax-vlm.js +189 -0
  151. package/dist/heart/providers/minimax.js +26 -8
  152. package/dist/heart/providers/openai-codex.js +55 -40
  153. package/dist/heart/runtime-capability-check.js +170 -0
  154. package/dist/heart/runtime-credentials.js +367 -0
  155. package/dist/heart/runtime-cwd.js +87 -0
  156. package/dist/heart/sense-truth.js +13 -4
  157. package/dist/heart/session-activity.js +43 -22
  158. package/dist/heart/session-events.js +1149 -0
  159. package/dist/heart/session-playback-cli-main.js +5 -0
  160. package/dist/heart/session-playback-cli.js +36 -0
  161. package/dist/heart/session-playback.js +231 -0
  162. package/dist/heart/session-stats-cli-main.js +5 -0
  163. package/dist/heart/session-stats.js +182 -0
  164. package/dist/heart/session-transcript.js +243 -0
  165. package/dist/heart/start-of-turn-packet.js +345 -0
  166. package/dist/heart/streaming.js +44 -27
  167. package/dist/heart/sync-classification.js +176 -0
  168. package/dist/heart/sync.js +449 -0
  169. package/dist/heart/target-resolution.js +9 -5
  170. package/dist/heart/tempo.js +93 -0
  171. package/dist/heart/temporal-view.js +41 -0
  172. package/dist/heart/timeouts.js +101 -0
  173. package/dist/heart/tool-activity-callbacks.js +59 -0
  174. package/dist/heart/tool-description.js +139 -0
  175. package/dist/heart/tool-friction.js +55 -0
  176. package/dist/heart/tool-loop.js +200 -0
  177. package/dist/heart/turn-context.js +389 -0
  178. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  179. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  180. package/dist/heart/versioning/ouro-path-installer.js +426 -0
  181. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  182. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  183. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  184. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  185. package/dist/mailbox-ui/assets/index-B-461hes.js +61 -0
  186. package/dist/mailbox-ui/assets/index-BPr5vNuM.css +1 -0
  187. package/dist/mailbox-ui/index.html +15 -0
  188. package/dist/mailroom/attention.js +167 -0
  189. package/dist/mailroom/autonomy.js +209 -0
  190. package/dist/mailroom/blob-store.js +674 -0
  191. package/dist/mailroom/body-cache.js +61 -0
  192. package/dist/mailroom/core.js +720 -0
  193. package/dist/mailroom/entry.js +160 -0
  194. package/dist/mailroom/file-store.js +430 -0
  195. package/dist/mailroom/mbox-import.js +383 -0
  196. package/dist/mailroom/outbound.js +380 -0
  197. package/dist/mailroom/policy.js +263 -0
  198. package/dist/mailroom/reader.js +233 -0
  199. package/dist/mailroom/search-cache.js +256 -0
  200. package/dist/mailroom/search-relevance.js +319 -0
  201. package/dist/mailroom/smtp-ingress.js +176 -0
  202. package/dist/mailroom/source-state.js +176 -0
  203. package/dist/mailroom/thread.js +109 -0
  204. package/dist/mailroom/travel-extract.js +89 -0
  205. package/dist/mind/bundle-manifest.js +7 -1
  206. package/dist/mind/context.js +165 -101
  207. package/dist/mind/diary-integrity.js +60 -0
  208. package/dist/mind/{memory.js → diary.js} +62 -75
  209. package/dist/mind/embedding-provider.js +60 -0
  210. package/dist/mind/file-state.js +179 -0
  211. package/dist/mind/friends/channel.js +39 -0
  212. package/dist/mind/friends/resolver.js +54 -2
  213. package/dist/mind/friends/store-file.js +39 -3
  214. package/dist/mind/friends/types.js +2 -2
  215. package/dist/mind/journal-index.js +161 -0
  216. package/dist/mind/note-search.js +268 -0
  217. package/dist/mind/obligation-steering.js +221 -0
  218. package/dist/mind/pending.js +4 -0
  219. package/dist/mind/prompt-refresh.js +3 -2
  220. package/dist/mind/prompt.js +1011 -123
  221. package/dist/mind/provenance-trust.js +26 -0
  222. package/dist/mind/scrutiny.js +173 -0
  223. package/dist/nerves/cli-logging.js +7 -1
  224. package/dist/nerves/coverage/audit-rules.js +15 -6
  225. package/dist/nerves/coverage/audit.js +28 -2
  226. package/dist/nerves/coverage/cli.js +1 -1
  227. package/dist/nerves/coverage/contract.js +5 -5
  228. package/dist/nerves/coverage/file-completeness.js +129 -5
  229. package/dist/nerves/coverage/run-artifacts.js +1 -1
  230. package/dist/nerves/event-buffer.js +111 -0
  231. package/dist/nerves/index.js +224 -4
  232. package/dist/nerves/observation.js +20 -0
  233. package/dist/nerves/redact.js +79 -0
  234. package/dist/nerves/review/cli-main.js +5 -0
  235. package/dist/nerves/review/cli.js +156 -0
  236. package/dist/nerves/review/core.js +152 -0
  237. package/dist/nerves/runtime.js +5 -1
  238. package/dist/repertoire/ado-client.js +15 -56
  239. package/dist/repertoire/ado-semantic.js +11 -10
  240. package/dist/repertoire/api-client.js +97 -0
  241. package/dist/repertoire/bitwarden-store.js +963 -0
  242. package/dist/repertoire/bundle-templates.js +72 -0
  243. package/dist/repertoire/bw-installer.js +180 -0
  244. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  245. package/dist/repertoire/coding/context-pack.js +330 -0
  246. package/dist/repertoire/coding/feedback.js +197 -30
  247. package/dist/repertoire/coding/manager.js +158 -9
  248. package/dist/repertoire/coding/spawner.js +55 -9
  249. package/dist/repertoire/coding/tools.js +170 -7
  250. package/dist/repertoire/commerce-errors.js +109 -0
  251. package/dist/repertoire/commerce-self-test.js +156 -0
  252. package/dist/repertoire/credential-access.js +178 -0
  253. package/dist/repertoire/duffel-client.js +185 -0
  254. package/dist/repertoire/github-client.js +14 -55
  255. package/dist/repertoire/graph-client.js +11 -52
  256. package/dist/repertoire/guardrails.js +396 -0
  257. package/dist/repertoire/mcp-client.js +295 -0
  258. package/dist/repertoire/mcp-manager.js +362 -0
  259. package/dist/repertoire/mcp-tools.js +63 -0
  260. package/dist/repertoire/shell-sessions.js +133 -0
  261. package/dist/repertoire/skills.js +15 -24
  262. package/dist/repertoire/stripe-client.js +131 -0
  263. package/dist/repertoire/tasks/board.js +31 -5
  264. package/dist/repertoire/tasks/fix.js +182 -0
  265. package/dist/repertoire/tasks/index.js +16 -4
  266. package/dist/repertoire/tasks/lifecycle.js +2 -2
  267. package/dist/repertoire/tasks/parser.js +3 -2
  268. package/dist/repertoire/tasks/scanner.js +194 -37
  269. package/dist/repertoire/tasks/transitions.js +16 -78
  270. package/dist/repertoire/tool-results.js +29 -0
  271. package/dist/repertoire/tools-attachments.js +317 -0
  272. package/dist/repertoire/tools-base.js +47 -1075
  273. package/dist/repertoire/tools-bluebubbles.js +1 -0
  274. package/dist/repertoire/tools-bridge.js +142 -0
  275. package/dist/repertoire/tools-bundle.js +984 -0
  276. package/dist/repertoire/tools-config.js +185 -0
  277. package/dist/repertoire/tools-continuity.js +248 -0
  278. package/dist/repertoire/tools-credential.js +381 -0
  279. package/dist/repertoire/tools-files.js +342 -0
  280. package/dist/repertoire/tools-flight.js +224 -0
  281. package/dist/repertoire/tools-flow.js +119 -0
  282. package/dist/repertoire/tools-github.js +1 -7
  283. package/dist/repertoire/tools-mail.js +1857 -0
  284. package/dist/repertoire/tools-notes.js +421 -0
  285. package/dist/repertoire/tools-session.js +750 -0
  286. package/dist/repertoire/tools-shell.js +120 -0
  287. package/dist/repertoire/tools-stripe.js +180 -0
  288. package/dist/repertoire/tools-surface.js +243 -0
  289. package/dist/repertoire/tools-teams.js +9 -39
  290. package/dist/repertoire/tools-travel.js +125 -0
  291. package/dist/repertoire/tools-trip.js +604 -0
  292. package/dist/repertoire/tools-user-profile.js +144 -0
  293. package/dist/repertoire/tools-vault.js +40 -0
  294. package/dist/repertoire/tools.js +108 -100
  295. package/dist/repertoire/travel-api-client.js +360 -0
  296. package/dist/repertoire/user-profile.js +131 -0
  297. package/dist/repertoire/vault-setup.js +246 -0
  298. package/dist/repertoire/vault-unlock.js +594 -0
  299. package/dist/scripts/claude-code-hook.js +41 -0
  300. package/dist/scripts/claude-code-stop-hook.js +47 -0
  301. package/dist/senses/attention-queue.js +116 -0
  302. package/dist/senses/bluebubbles/active-turns.js +216 -0
  303. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  304. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  305. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  306. package/dist/senses/bluebubbles/entry.js +77 -0
  307. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  308. package/dist/senses/bluebubbles/index.js +2305 -0
  309. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  310. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  311. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  312. package/dist/senses/bluebubbles/processed-log.js +133 -0
  313. package/dist/senses/bluebubbles/replay.js +137 -0
  314. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  315. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  316. package/dist/senses/cli/bracketed-paste.js +82 -0
  317. package/dist/senses/cli/image-paste.js +287 -0
  318. package/dist/senses/cli/image-ref-navigation.js +75 -0
  319. package/dist/senses/cli/ink-app.js +156 -0
  320. package/dist/senses/cli/inline-diff.js +64 -0
  321. package/dist/senses/cli/input-keys.js +174 -0
  322. package/dist/senses/cli/kill-ring.js +86 -0
  323. package/dist/senses/cli/message-list.js +51 -0
  324. package/dist/senses/cli/ouro-tui.js +607 -0
  325. package/dist/senses/cli/spinner-imperative.js +135 -0
  326. package/dist/senses/cli/spinner.js +101 -0
  327. package/dist/senses/cli/status-line.js +60 -0
  328. package/dist/senses/cli/streaming-markdown.js +526 -0
  329. package/dist/senses/cli/tool-display.js +85 -0
  330. package/dist/senses/cli/tool-render.js +85 -0
  331. package/dist/senses/cli/tui-store.js +240 -0
  332. package/dist/senses/cli/virtual-list.js +35 -0
  333. package/dist/senses/cli-entry.js +60 -8
  334. package/dist/senses/cli-layout.js +187 -0
  335. package/dist/senses/cli.js +520 -209
  336. package/dist/senses/commands.js +66 -3
  337. package/dist/senses/habit-turn-message.js +108 -0
  338. package/dist/senses/inner-dialog-worker.js +175 -21
  339. package/dist/senses/inner-dialog.js +330 -27
  340. package/dist/senses/mail-entry.js +66 -0
  341. package/dist/senses/mail.js +379 -0
  342. package/dist/senses/pipeline.js +549 -181
  343. package/dist/senses/proactive-content-guard.js +51 -0
  344. package/dist/senses/shared-turn.js +248 -0
  345. package/dist/senses/surface-tool.js +68 -0
  346. package/dist/senses/teams-entry.js +60 -8
  347. package/dist/senses/teams.js +387 -98
  348. package/dist/senses/trust-gate.js +100 -5
  349. package/dist/senses/voice/elevenlabs.js +125 -0
  350. package/dist/senses/voice/index.js +22 -0
  351. package/dist/senses/voice/transcript.js +70 -0
  352. package/dist/senses/voice/turn.js +85 -0
  353. package/dist/senses/voice/types.js +2 -0
  354. package/dist/senses/voice/whisper.js +133 -0
  355. package/dist/senses/voice-entry.js +80 -0
  356. package/dist/trips/core.js +138 -0
  357. package/dist/trips/store.js +146 -0
  358. package/package.json +38 -7
  359. package/skills/agent-commerce.md +106 -0
  360. package/skills/browser-navigation.md +117 -0
  361. package/skills/commerce-setup-guide.md +116 -0
  362. package/skills/commerce-setup.md +84 -0
  363. package/skills/configure-dev-tools.md +101 -0
  364. package/skills/travel-planning.md +138 -0
  365. package/dist/heart/daemon/auth-flow.js +0 -351
  366. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  367. package/dist/heart/daemon/subagent-installer.js +0 -166
  368. package/dist/heart/session-recall.js +0 -116
  369. package/dist/mind/associative-recall.js +0 -209
  370. package/dist/senses/bluebubbles-entry.js +0 -13
  371. package/dist/senses/bluebubbles.js +0 -1177
  372. package/dist/senses/debug-activity.js +0 -148
  373. package/subagents/README.md +0 -86
  374. package/subagents/work-doer.md +0 -237
  375. package/subagents/work-merger.md +0 -618
  376. package/subagents/work-planner.md +0 -390
  377. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  378. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  379. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  380. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  381. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  382. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  383. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  384. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  385. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  386. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  387. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  388. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  389. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  390. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  391. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  392. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,604 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tripToolDefinitions = void 0;
4
+ const types_1 = require("../mind/friends/types");
5
+ const runtime_1 = require("../nerves/runtime");
6
+ const store_1 = require("../trips/store");
7
+ const core_1 = require("../trips/core");
8
+ const identity_1 = require("../heart/identity");
9
+ function trustAllowsTripAccess(ctx) {
10
+ const trustLevel = ctx?.context?.friend?.trustLevel;
11
+ return trustLevel === undefined || (0, types_1.isTrustedLevel)(trustLevel);
12
+ }
13
+ function isRecord(value) {
14
+ return !!value && typeof value === "object" && !Array.isArray(value);
15
+ }
16
+ function parseJsonArg(raw, label) {
17
+ if (typeof raw !== "string")
18
+ throw new Error(`${label} must be a JSON string`);
19
+ try {
20
+ return JSON.parse(raw);
21
+ }
22
+ catch (error) {
23
+ throw new Error(`${label} is not valid JSON: ${error instanceof Error ? error.message : /* v8 ignore next -- JSON.parse only throws SyntaxError */ String(error)}`);
24
+ }
25
+ }
26
+ function validateTripRecord(value) {
27
+ if (!isRecord(value))
28
+ throw new Error("record must be a TripRecord object");
29
+ // Minimal structural validation — the agent is constructing the value but
30
+ // we still guard against the obvious shape mistakes that would break decrypt.
31
+ for (const field of ["tripId", "agentId", "ownerEmail", "name", "status", "createdAt", "updatedAt"]) {
32
+ if (typeof value[field] !== "string" || value[field].length === 0) {
33
+ throw new Error(`record.${field} must be a non-empty string`);
34
+ }
35
+ }
36
+ if (!Array.isArray(value.travellers))
37
+ throw new Error("record.travellers must be an array");
38
+ if (!Array.isArray(value.legs))
39
+ throw new Error("record.legs must be an array");
40
+ for (const leg of value.legs) {
41
+ if (!isRecord(leg))
42
+ throw new Error("each leg must be an object");
43
+ if (typeof leg.legId !== "string" || leg.legId.length === 0)
44
+ throw new Error("each leg requires a legId");
45
+ if (typeof leg.kind !== "string")
46
+ throw new Error("each leg requires a kind");
47
+ if (typeof leg.status !== "string")
48
+ throw new Error("each leg requires a status");
49
+ if (!Array.isArray(leg.evidence))
50
+ throw new Error(`leg ${leg.legId} requires an evidence array`);
51
+ for (const ev of leg.evidence) {
52
+ if (!isRecord(ev))
53
+ throw new Error(`leg ${leg.legId}: each evidence entry must be an object`);
54
+ if (typeof ev.messageId !== "string" || ev.messageId.length === 0)
55
+ throw new Error(`leg ${leg.legId}: evidence.messageId must be a non-empty string`);
56
+ if (typeof ev.discoveryMethod !== "string" || ev.discoveryMethod.length === 0)
57
+ throw new Error(`leg ${leg.legId}: evidence.discoveryMethod must be a non-empty string`);
58
+ }
59
+ }
60
+ return value;
61
+ }
62
+ function validateTripEvidence(value) {
63
+ if (!isRecord(value))
64
+ throw new Error("evidence must be a TripEvidence object");
65
+ for (const field of ["messageId", "reason", "recordedAt", "discoveryMethod"]) {
66
+ if (typeof value[field] !== "string" || value[field].length === 0) {
67
+ throw new Error(`evidence.${field} must be a non-empty string`);
68
+ }
69
+ }
70
+ return value;
71
+ }
72
+ function renderTripSummary(trip) {
73
+ const dateRange = trip.startDate && trip.endDate
74
+ ? `${trip.startDate} → ${trip.endDate}`
75
+ : trip.startDate ?? trip.endDate ?? "(no dates)";
76
+ const lines = [
77
+ `- ${trip.tripId} :: "${trip.name}" [${trip.status}; ${dateRange}; legs: ${trip.legs.length}]`,
78
+ ` travellers: ${trip.travellers.map((p) => p.name).join(", ") || "(none)"}`,
79
+ ];
80
+ if (trip.notes)
81
+ lines.push(` notes: ${trip.notes}`);
82
+ return lines.join("\n");
83
+ }
84
+ function compact(parts) {
85
+ return parts
86
+ .map((part) => part?.trim())
87
+ .filter((part) => !!part)
88
+ .join(" ");
89
+ }
90
+ function routeLabel(origin, destination) {
91
+ if (origin && destination)
92
+ return `${origin} -> ${destination}`;
93
+ return origin ?? destination;
94
+ }
95
+ function tripLegCalendarEntry(trip, leg) {
96
+ switch (leg.kind) {
97
+ case "lodging":
98
+ return {
99
+ tripId: trip.tripId,
100
+ tripName: trip.name,
101
+ legId: leg.legId,
102
+ kind: leg.kind,
103
+ status: leg.status,
104
+ start: leg.checkInDate,
105
+ end: leg.checkOutDate,
106
+ title: leg.vendor ?? "lodging",
107
+ where: leg.city,
108
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
109
+ };
110
+ case "flight": {
111
+ const route = routeLabel(leg.origin, leg.destination);
112
+ return {
113
+ tripId: trip.tripId,
114
+ tripName: trip.name,
115
+ legId: leg.legId,
116
+ kind: leg.kind,
117
+ status: leg.status,
118
+ start: leg.departureAt,
119
+ end: leg.arrivalAt,
120
+ title: compact([leg.vendor ?? "flight", leg.flightNumber, route]),
121
+ where: route,
122
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
123
+ };
124
+ }
125
+ case "train": {
126
+ const route = routeLabel(leg.originStation, leg.destinationStation);
127
+ return {
128
+ tripId: trip.tripId,
129
+ tripName: trip.name,
130
+ legId: leg.legId,
131
+ kind: leg.kind,
132
+ status: leg.status,
133
+ start: leg.departureAt,
134
+ end: leg.arrivalAt,
135
+ title: compact([leg.vendor ?? "train", leg.trainNumber, route]),
136
+ where: route,
137
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
138
+ };
139
+ }
140
+ case "ground-transport": {
141
+ const route = routeLabel(leg.origin, leg.destination);
142
+ return {
143
+ tripId: trip.tripId,
144
+ tripName: trip.name,
145
+ legId: leg.legId,
146
+ kind: leg.kind,
147
+ status: leg.status,
148
+ start: leg.departureAt,
149
+ end: leg.arrivalAt,
150
+ title: compact([leg.operator ?? leg.vendor ?? "ground transport", route]),
151
+ where: route,
152
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
153
+ };
154
+ }
155
+ case "rental-car": {
156
+ const route = routeLabel(leg.pickupLocation, leg.dropoffLocation);
157
+ return {
158
+ tripId: trip.tripId,
159
+ tripName: trip.name,
160
+ legId: leg.legId,
161
+ kind: leg.kind,
162
+ status: leg.status,
163
+ start: leg.pickupAt,
164
+ end: leg.dropoffAt,
165
+ title: compact([leg.rentalVendor ?? leg.vendor ?? "rental car", route]),
166
+ where: route,
167
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
168
+ };
169
+ }
170
+ case "ferry": {
171
+ const route = routeLabel(leg.originPort, leg.destinationPort);
172
+ return {
173
+ tripId: trip.tripId,
174
+ tripName: trip.name,
175
+ legId: leg.legId,
176
+ kind: leg.kind,
177
+ status: leg.status,
178
+ start: leg.departureAt,
179
+ end: leg.arrivalAt,
180
+ title: compact([leg.operator ?? leg.vendor ?? "ferry", route]),
181
+ where: route,
182
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
183
+ };
184
+ }
185
+ case "event": {
186
+ const where = [leg.venue, leg.city].filter(Boolean).join(", ") || undefined;
187
+ return {
188
+ tripId: trip.tripId,
189
+ tripName: trip.name,
190
+ legId: leg.legId,
191
+ kind: leg.kind,
192
+ status: leg.status,
193
+ start: leg.startsAt,
194
+ end: leg.endsAt,
195
+ title: leg.vendor ?? "event",
196
+ where,
197
+ evidenceIds: leg.evidence.map((entry) => entry.messageId),
198
+ };
199
+ }
200
+ }
201
+ }
202
+ function calendarEntryRange(entry) {
203
+ if (entry.start && entry.end && entry.start !== entry.end)
204
+ return `${entry.start} -> ${entry.end}`;
205
+ return entry.start ?? entry.end ?? "(undated)";
206
+ }
207
+ function renderTripCalendar(trips, includeUndated) {
208
+ const entries = trips
209
+ .flatMap((trip) => trip.legs.map((leg) => tripLegCalendarEntry(trip, leg)))
210
+ .filter((entry) => includeUndated || entry.start || entry.end)
211
+ .sort((left, right) => {
212
+ const leftKey = left.start ?? left.end ?? "9999-99-99T99:99:99.999Z";
213
+ const rightKey = right.start ?? right.end ?? "9999-99-99T99:99:99.999Z";
214
+ return leftKey.localeCompare(rightKey) || left.tripName.localeCompare(right.tripName) || left.legId.localeCompare(right.legId);
215
+ });
216
+ if (entries.length === 0)
217
+ return includeUndated ? "no calendar entries on the trip ledger yet." : "no dated calendar entries on the trip ledger yet.";
218
+ const noun = entries.length === 1 ? "entry" : "entries";
219
+ const lines = [`${entries.length} trip calendar ${noun}:`];
220
+ for (const entry of entries) {
221
+ lines.push(`- ${calendarEntryRange(entry)} | ${entry.kind} | ${entry.status} | ${entry.title}`);
222
+ lines.push(` trip: ${entry.tripName} (${entry.tripId}); leg: ${entry.legId}`);
223
+ if (entry.where)
224
+ lines.push(` where: ${entry.where}`);
225
+ if (entry.evidenceIds.length > 0)
226
+ lines.push(` evidence: ${entry.evidenceIds.join(", ")}`);
227
+ }
228
+ return lines.join("\n");
229
+ }
230
+ exports.tripToolDefinitions = [
231
+ {
232
+ tool: {
233
+ type: "function",
234
+ function: {
235
+ name: "trip_ensure_ledger",
236
+ description: "Idempotently ensure this agent has a trip ledger keypair. Safe to call multiple times. Required once before any other trip_ tool.",
237
+ parameters: { type: "object", properties: {} },
238
+ },
239
+ },
240
+ handler: async (_args, ctx) => {
241
+ if (!trustAllowsTripAccess(ctx))
242
+ return "trip ledger is private; this tool is only available in trusted contexts.";
243
+ const result = (0, store_1.ensureAgentTripLedger)({ agentName: (0, identity_1.getAgentName)() });
244
+ const verb = result.added ? "created" : "already present";
245
+ return `trip ledger ${verb}: ledgerId=${result.ledger.ledgerId}, keyId=${result.ledger.keyId}, createdAt=${result.ledger.createdAt}`;
246
+ },
247
+ summaryKeys: [],
248
+ },
249
+ {
250
+ tool: {
251
+ type: "function",
252
+ function: {
253
+ name: "trip_status",
254
+ description: "List the agent's trip ids in sorted order. Cheap overview before opening individual trips.",
255
+ parameters: { type: "object", properties: {} },
256
+ },
257
+ },
258
+ handler: async (_args, ctx) => {
259
+ if (!trustAllowsTripAccess(ctx))
260
+ return "trip ledger is private; this tool is only available in trusted contexts.";
261
+ const tripIds = (0, store_1.listTripIds)((0, identity_1.getAgentName)());
262
+ if (tripIds.length === 0)
263
+ return "no trips on the ledger yet.";
264
+ return `${tripIds.length} trip(s):\n${tripIds.map((id) => `- ${id}`).join("\n")}`;
265
+ },
266
+ summaryKeys: [],
267
+ },
268
+ {
269
+ tool: {
270
+ type: "function",
271
+ function: {
272
+ name: "trip_get",
273
+ description: "Read one trip record by id. Returns a structured summary plus the raw JSON for further reasoning.",
274
+ parameters: {
275
+ type: "object",
276
+ properties: {
277
+ tripId: { type: "string", description: "Canonical trip id (trip_<slug>_<fingerprint>)." },
278
+ },
279
+ required: ["tripId"],
280
+ },
281
+ },
282
+ },
283
+ handler: async (args, ctx) => {
284
+ if (!trustAllowsTripAccess(ctx))
285
+ return "trip ledger is private; this tool is only available in trusted contexts.";
286
+ const tripId = args.tripId;
287
+ if (typeof tripId !== "string" || tripId.length === 0)
288
+ return "tripId is required.";
289
+ try {
290
+ const trip = (0, store_1.readTripRecord)((0, identity_1.getAgentName)(), tripId);
291
+ return [
292
+ renderTripSummary(trip),
293
+ "",
294
+ "raw record (JSON):",
295
+ JSON.stringify(trip, null, 2),
296
+ ].join("\n");
297
+ }
298
+ catch (error) {
299
+ if (error instanceof store_1.TripNotFoundError)
300
+ return error.message;
301
+ throw error;
302
+ }
303
+ },
304
+ summaryKeys: ["tripId"],
305
+ },
306
+ {
307
+ tool: {
308
+ type: "function",
309
+ function: {
310
+ name: "trip_upsert",
311
+ description: "Create or replace a TripRecord. Pass the full record as a JSON string in `record`. Every leg requires a legId and an evidence array (each evidence entry requires messageId + discoveryMethod). Returns the persisted tripId.",
312
+ parameters: {
313
+ type: "object",
314
+ properties: {
315
+ record: { type: "string", description: "Full TripRecord JSON. Must include tripId, agentId, ownerEmail, name, status, travellers[], legs[], createdAt, updatedAt." },
316
+ },
317
+ required: ["record"],
318
+ },
319
+ },
320
+ },
321
+ handler: async (args, ctx) => {
322
+ if (!trustAllowsTripAccess(ctx))
323
+ return "trip ledger is private; this tool is only available in trusted contexts.";
324
+ try {
325
+ const parsed = parseJsonArg(args.record, "record");
326
+ const trip = validateTripRecord(parsed);
327
+ (0, store_1.ensureAgentTripLedger)({ agentName: (0, identity_1.getAgentName)() });
328
+ (0, store_1.upsertTripRecord)((0, identity_1.getAgentName)(), trip);
329
+ return `trip upserted: ${trip.tripId} (${trip.legs.length} leg(s), status=${trip.status})`;
330
+ }
331
+ catch (error) {
332
+ return `upsert failed: ${error instanceof Error ? error.message : /* v8 ignore next -- non-Error throw is unreachable from validateTripRecord/parseJsonArg */ String(error)}`;
333
+ }
334
+ },
335
+ summaryKeys: [],
336
+ },
337
+ {
338
+ tool: {
339
+ type: "function",
340
+ function: {
341
+ name: "trip_attach_evidence",
342
+ description: "Append a TripEvidence record to a specific leg's evidence array. Pass tripId, legId, and the evidence as a JSON string. Useful when extracting a fact from a single mail message and attaching it to an existing leg without re-uploading the whole record.",
343
+ parameters: {
344
+ type: "object",
345
+ properties: {
346
+ tripId: { type: "string", description: "Canonical trip id." },
347
+ legId: { type: "string", description: "Leg id within the trip." },
348
+ evidence: { type: "string", description: "TripEvidence JSON: { messageId, reason, recordedAt, discoveryMethod, excerpt? }." },
349
+ },
350
+ required: ["tripId", "legId", "evidence"],
351
+ },
352
+ },
353
+ },
354
+ handler: async (args, ctx) => {
355
+ if (!trustAllowsTripAccess(ctx))
356
+ return "trip ledger is private; this tool is only available in trusted contexts.";
357
+ const tripId = args.tripId;
358
+ const legId = args.legId;
359
+ if (typeof tripId !== "string" || tripId.length === 0)
360
+ return "tripId is required.";
361
+ if (typeof legId !== "string" || legId.length === 0)
362
+ return "legId is required.";
363
+ try {
364
+ const evidence = validateTripEvidence(parseJsonArg(args.evidence, "evidence"));
365
+ const trip = (0, store_1.readTripRecord)((0, identity_1.getAgentName)(), tripId);
366
+ const legIndex = trip.legs.findIndex((leg) => leg.legId === legId);
367
+ if (legIndex === -1)
368
+ return `leg ${legId} not found in trip ${tripId}.`;
369
+ const leg = trip.legs[legIndex];
370
+ const updatedLeg = {
371
+ ...leg,
372
+ evidence: [...leg.evidence, evidence],
373
+ updatedAt: evidence.recordedAt,
374
+ };
375
+ const updated = {
376
+ ...trip,
377
+ legs: [...trip.legs.slice(0, legIndex), updatedLeg, ...trip.legs.slice(legIndex + 1)],
378
+ updatedAt: evidence.recordedAt,
379
+ };
380
+ (0, store_1.upsertTripRecord)((0, identity_1.getAgentName)(), updated);
381
+ (0, runtime_1.emitNervesEvent)({
382
+ component: "trips",
383
+ event: "trips.evidence_attached",
384
+ message: "trip evidence attached to leg",
385
+ meta: { agentId: (0, identity_1.getAgentName)(), tripId, legId, discoveryMethod: evidence.discoveryMethod, messageId: evidence.messageId },
386
+ });
387
+ return `evidence attached to leg ${legId} in ${tripId}; leg now carries ${updatedLeg.evidence.length} evidence entries.`;
388
+ }
389
+ catch (error) {
390
+ if (error instanceof store_1.TripNotFoundError)
391
+ return error.message;
392
+ return `attach failed: ${error instanceof Error ? error.message : /* v8 ignore next -- non-Error throw is unreachable from validateTripEvidence/parseJsonArg/store */ String(error)}`;
393
+ }
394
+ },
395
+ summaryKeys: ["tripId", "legId"],
396
+ },
397
+ {
398
+ tool: {
399
+ type: "function",
400
+ function: {
401
+ name: "trip_update_leg",
402
+ description: "Update specific fields of an existing leg in a trip. Pass tripId, legId, and a JSON object of field updates (e.g. {status:\"cancelled\", confirmationCode:\"PNR123\"}). Existing evidence is preserved unless explicitly overwritten. Use this instead of trip_upsert when you only need to change one leg without re-emitting the whole record. The leg's `kind` cannot be changed (changing kind means a new leg).",
403
+ parameters: {
404
+ type: "object",
405
+ properties: {
406
+ tripId: { type: "string", description: "Canonical trip id." },
407
+ legId: { type: "string", description: "Leg id within the trip." },
408
+ updates: { type: "string", description: "JSON object of leg fields to update. Cannot include `legId` or `kind`. Common fields: status, confirmationCode, vendor, amount, checkInDate, checkOutDate, departureTime, arrivalTime, etc." },
409
+ updatedAt: { type: "string", description: "ISO timestamp for the update. Used both for the leg's updatedAt and the trip's updatedAt." },
410
+ },
411
+ required: ["tripId", "legId", "updates", "updatedAt"],
412
+ },
413
+ },
414
+ },
415
+ handler: async (args, ctx) => {
416
+ if (!trustAllowsTripAccess(ctx))
417
+ return "trip ledger is private; this tool is only available in trusted contexts.";
418
+ const tripId = args.tripId;
419
+ const legId = args.legId;
420
+ const updatedAt = args.updatedAt;
421
+ if (typeof tripId !== "string" || tripId.length === 0)
422
+ return "tripId is required.";
423
+ if (typeof legId !== "string" || legId.length === 0)
424
+ return "legId is required.";
425
+ if (typeof updatedAt !== "string" || updatedAt.length === 0)
426
+ return "updatedAt is required.";
427
+ try {
428
+ const updates = parseJsonArg(args.updates, "updates");
429
+ if (!isRecord(updates))
430
+ return "updates must be a JSON object.";
431
+ // Reject identity-changing fields — those would silently break referential integrity.
432
+ if ("legId" in updates)
433
+ return "updates cannot change legId; create a new leg instead.";
434
+ if ("kind" in updates)
435
+ return "updates cannot change kind; create a new leg instead.";
436
+ if (Object.keys(updates).length === 0)
437
+ return "updates cannot be empty — pass at least one field.";
438
+ const trip = (0, store_1.readTripRecord)((0, identity_1.getAgentName)(), tripId);
439
+ const legIndex = trip.legs.findIndex((leg) => leg.legId === legId);
440
+ if (legIndex === -1)
441
+ return `leg ${legId} not found in trip ${tripId}.`;
442
+ const leg = trip.legs[legIndex];
443
+ const updatedLeg = {
444
+ ...leg,
445
+ ...updates,
446
+ legId: leg.legId,
447
+ kind: leg.kind,
448
+ updatedAt,
449
+ };
450
+ const updated = {
451
+ ...trip,
452
+ legs: [...trip.legs.slice(0, legIndex), updatedLeg, ...trip.legs.slice(legIndex + 1)],
453
+ updatedAt,
454
+ };
455
+ (0, store_1.upsertTripRecord)((0, identity_1.getAgentName)(), updated);
456
+ (0, runtime_1.emitNervesEvent)({
457
+ component: "trips",
458
+ event: "trips.leg_updated",
459
+ message: "trip leg fields updated",
460
+ meta: { agentId: (0, identity_1.getAgentName)(), tripId, legId, fields: Object.keys(updates) },
461
+ });
462
+ const fieldList = Object.keys(updates).join(", ");
463
+ return `leg ${legId} updated in ${tripId}: ${fieldList}.`;
464
+ }
465
+ catch (error) {
466
+ if (error instanceof store_1.TripNotFoundError)
467
+ return error.message;
468
+ return `update failed: ${error instanceof Error ? error.message : /* v8 ignore next -- non-Error throw is unreachable from parseJsonArg/store */ String(error)}`;
469
+ }
470
+ },
471
+ summaryKeys: ["tripId", "legId"],
472
+ },
473
+ {
474
+ tool: {
475
+ type: "function",
476
+ function: {
477
+ name: "trip_remove_leg",
478
+ description: "Remove a leg from a trip. Use when a leg was added by mistake or the booking was cancelled. Updates the trip's updatedAt. Rejects when the leg id is unknown so accidental no-op removals are visible.",
479
+ parameters: {
480
+ type: "object",
481
+ properties: {
482
+ tripId: { type: "string", description: "Canonical trip id." },
483
+ legId: { type: "string", description: "Leg id within the trip to drop." },
484
+ updatedAt: { type: "string", description: "ISO timestamp for the trip's updatedAt." },
485
+ reason: { type: "string", description: "Why the leg is being removed. Logged in nerves for audit." },
486
+ },
487
+ required: ["tripId", "legId", "updatedAt"],
488
+ },
489
+ },
490
+ },
491
+ handler: async (args, ctx) => {
492
+ if (!trustAllowsTripAccess(ctx))
493
+ return "trip ledger is private; this tool is only available in trusted contexts.";
494
+ const tripId = args.tripId;
495
+ const legId = args.legId;
496
+ const updatedAt = args.updatedAt;
497
+ if (typeof tripId !== "string" || tripId.length === 0)
498
+ return "tripId is required.";
499
+ if (typeof legId !== "string" || legId.length === 0)
500
+ return "legId is required.";
501
+ if (typeof updatedAt !== "string" || updatedAt.length === 0)
502
+ return "updatedAt is required.";
503
+ try {
504
+ const trip = (0, store_1.readTripRecord)((0, identity_1.getAgentName)(), tripId);
505
+ const legIndex = trip.legs.findIndex((leg) => leg.legId === legId);
506
+ if (legIndex === -1)
507
+ return `leg ${legId} not found in trip ${tripId}.`;
508
+ const droppedLeg = trip.legs[legIndex];
509
+ const updated = {
510
+ ...trip,
511
+ legs: [...trip.legs.slice(0, legIndex), ...trip.legs.slice(legIndex + 1)],
512
+ updatedAt,
513
+ };
514
+ (0, store_1.upsertTripRecord)((0, identity_1.getAgentName)(), updated);
515
+ (0, runtime_1.emitNervesEvent)({
516
+ component: "trips",
517
+ event: "trips.leg_removed",
518
+ message: "trip leg removed from ledger",
519
+ meta: {
520
+ agentId: (0, identity_1.getAgentName)(),
521
+ tripId,
522
+ legId,
523
+ kind: droppedLeg.kind,
524
+ /* v8 ignore next -- defensive: reason typing always string in normal call sites @preserve */
525
+ reason: typeof args.reason === "string" ? args.reason : undefined,
526
+ },
527
+ });
528
+ /* v8 ignore next -- pluralization branch: tests don't exhaustively cover both 1-leg and N-leg removal outcomes @preserve */
529
+ return `leg ${legId} removed from ${tripId}. trip now has ${updated.legs.length} leg${updated.legs.length === 1 ? "" : "s"}.`;
530
+ } /* v8 ignore start -- error-classification branches: TripNotFoundError vs unexpected store failure; the latter is covered by trip-store unit tests rather than tool-level fixtures @preserve */
531
+ catch (error) {
532
+ if (error instanceof store_1.TripNotFoundError)
533
+ return error.message;
534
+ return `remove failed: ${error instanceof Error ? error.message : String(error)}`;
535
+ } /* v8 ignore stop */
536
+ },
537
+ summaryKeys: ["tripId", "legId", "reason"],
538
+ },
539
+ {
540
+ tool: {
541
+ type: "function",
542
+ function: {
543
+ name: "trip_calendar",
544
+ description: "Render a chronological calendar/agenda projection from the trip ledger. Use this before answering current itinerary, travel gap, or what-changed questions; friend notes and old handoffs may be stale. Also use this after extracting mail-backed trip facts so the agent can track dates across lodging, travel, events, and local transport.",
545
+ parameters: {
546
+ type: "object",
547
+ properties: {
548
+ tripId: { type: "string", description: "Optional canonical trip id. Omit to render all trips on the ledger." },
549
+ includeUndated: { type: "string", enum: ["true", "false"], description: "Set true to include legs that have no start/end dates yet. Defaults to false." },
550
+ },
551
+ },
552
+ },
553
+ },
554
+ handler: async (args, ctx) => {
555
+ if (!trustAllowsTripAccess(ctx))
556
+ return "trip ledger is private; this tool is only available in trusted contexts.";
557
+ const includeUndated = args.includeUndated === "true";
558
+ const tripId = typeof args.tripId === "string" ? args.tripId.trim() : "";
559
+ try {
560
+ const trips = tripId
561
+ ? [(0, store_1.readTripRecord)((0, identity_1.getAgentName)(), tripId)]
562
+ : (0, store_1.listTripIds)((0, identity_1.getAgentName)()).map((id) => (0, store_1.readTripRecord)((0, identity_1.getAgentName)(), id));
563
+ if (trips.length === 0)
564
+ return "no trips on the ledger yet.";
565
+ return renderTripCalendar(trips, includeUndated);
566
+ }
567
+ catch (error) {
568
+ if (error instanceof store_1.TripNotFoundError)
569
+ return error.message;
570
+ throw error;
571
+ }
572
+ },
573
+ summaryKeys: ["tripId"],
574
+ },
575
+ {
576
+ tool: {
577
+ type: "function",
578
+ function: {
579
+ name: "trip_new_id",
580
+ description: "Compute a deterministic trip id from agentId + name + createdAt. Useful before constructing a new TripRecord so the id is stable and reproducible.",
581
+ parameters: {
582
+ type: "object",
583
+ properties: {
584
+ name: { type: "string", description: "Human-friendly trip name (e.g. \"Europe summer 2026\")." },
585
+ createdAt: { type: "string", description: "ISO timestamp the trip was first conceived. Pass `now` if just creating it." },
586
+ },
587
+ required: ["name", "createdAt"],
588
+ },
589
+ },
590
+ },
591
+ handler: async (args, ctx) => {
592
+ if (!trustAllowsTripAccess(ctx))
593
+ return "trip ledger is private; this tool is only available in trusted contexts.";
594
+ const name = args.name;
595
+ const createdAt = args.createdAt;
596
+ if (typeof name !== "string" || name.length === 0)
597
+ return "name is required.";
598
+ if (typeof createdAt !== "string" || createdAt.length === 0)
599
+ return "createdAt is required.";
600
+ return (0, core_1.newTripId)((0, identity_1.getAgentName)(), name, createdAt);
601
+ },
602
+ summaryKeys: ["name"],
603
+ },
604
+ ];