@ouro.bot/cli 0.1.0-alpha.92 → 0.1.0-alpha.921

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 (717) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -23
  3. package/RepairGuide.ouro/agent.json +5 -0
  4. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  5. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  6. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  7. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  8. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  9. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  12. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  13. package/assets/bluebubbles-host +264 -0
  14. package/assets/sanctuary-host-launcher.sh +16 -0
  15. package/changelog.json +5826 -16
  16. package/deploy/unraid/Dockerfile +58 -0
  17. package/deploy/unraid/README.txt +2997 -0
  18. package/deploy/unraid/audit-container-spec.sh +4 -0
  19. package/deploy/unraid/container-runtime.json +1 -0
  20. package/deploy/unraid/docker-man-template-transaction.mjs +711 -0
  21. package/deploy/unraid/docker-man-template-xml.cjs +105 -0
  22. package/deploy/unraid/migrate-sanctuary-bundle.mjs +60 -0
  23. package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
  24. package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
  25. package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
  26. package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
  27. package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
  28. package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
  29. package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
  30. package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
  31. package/deploy/unraid/sanctuary-authority-installation.json +36 -0
  32. package/deploy/unraid/sanctuary-authority-service.sh +30 -0
  33. package/deploy/unraid/sanctuary-butler-upgrade.mjs +1254 -0
  34. package/deploy/unraid/sanctuary-deployment-target.mjs +710 -0
  35. package/deploy/unraid/sanctuary-replay-gate.mjs +1564 -0
  36. package/deploy/unraid/sanctuary-safe-rename.py +24 -0
  37. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2086 -0
  38. package/deploy/unraid/sanctuary-unit16-run.sh +560 -0
  39. package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
  40. package/deploy/unraid/sanctuary.ouro/agent.json +66 -0
  41. package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
  42. package/deploy/unraid/sanctuary.ouro/awaiting/house-care-sweep.md +17 -0
  43. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
  44. package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
  45. package/deploy/unraid/sanctuary.ouro/mcp/media-mcp.mjs +2231 -0
  46. package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
  47. package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
  48. package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +5 -0
  49. package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +33 -0
  50. package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +27 -0
  51. package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +22 -0
  52. package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
  53. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +232 -0
  54. package/deploy/unraid/sanctuary.xml +30 -0
  55. package/dist/a2a/card.js +57 -0
  56. package/dist/a2a/client.js +250 -0
  57. package/dist/a2a/config.js +50 -0
  58. package/dist/a2a/delegated-command-grants.js +93 -0
  59. package/dist/a2a/delegated-command.js +197 -0
  60. package/dist/a2a/delegation-stores.js +56 -0
  61. package/dist/a2a/did-resolution.js +93 -0
  62. package/dist/a2a/escalation-grants.js +84 -0
  63. package/dist/a2a/escalation-wiring.js +60 -0
  64. package/dist/a2a/identity.js +258 -0
  65. package/dist/a2a/inbound-share.js +110 -0
  66. package/dist/a2a/mission-result-wire.js +196 -0
  67. package/dist/a2a/onboarding.js +133 -0
  68. package/dist/a2a/operator-trust.js +382 -0
  69. package/dist/a2a/outbox-client.js +57 -0
  70. package/dist/a2a/outbox-store.js +188 -0
  71. package/dist/a2a/outbox-wire.js +95 -0
  72. package/dist/a2a/pin-store.js +132 -0
  73. package/dist/a2a/replay-grant-holders.js +33 -0
  74. package/dist/a2a/replay-harness.js +188 -0
  75. package/dist/a2a/resolution-proof.js +53 -0
  76. package/dist/a2a/sealed-chat.js +113 -0
  77. package/dist/a2a/seen-ledger.js +120 -0
  78. package/dist/a2a/server.js +771 -0
  79. package/dist/a2a/task-store.js +69 -0
  80. package/dist/a2a/transport.js +45 -0
  81. package/dist/a2a/trust-commands.js +203 -0
  82. package/dist/a2a/trusted-files.js +185 -0
  83. package/dist/a2a/types.js +3 -0
  84. package/dist/arc/attention-types.js +8 -0
  85. package/dist/arc/cares.js +360 -0
  86. package/dist/arc/episodes.js +118 -0
  87. package/dist/arc/evolution.js +490 -0
  88. package/dist/arc/flight-recorder.js +1034 -0
  89. package/dist/arc/intentions.js +134 -0
  90. package/dist/arc/json-store.js +117 -0
  91. package/dist/arc/obligations.js +386 -0
  92. package/dist/arc/packets.js +336 -0
  93. package/dist/arc/presence.js +185 -0
  94. package/dist/arc/task-lifecycle.js +57 -0
  95. package/dist/commerce/store.js +755 -0
  96. package/dist/commerce/types.js +3 -0
  97. package/dist/heart/active-work.js +798 -40
  98. package/dist/heart/agent-entry.js +252 -3
  99. package/dist/heart/approval-files.js +113 -0
  100. package/dist/heart/approval-store.js +960 -0
  101. package/dist/heart/attachments/image-normalize.js +194 -0
  102. package/dist/heart/attachments/materialize.js +97 -0
  103. package/dist/heart/attachments/originals.js +88 -0
  104. package/dist/heart/attachments/render.js +29 -0
  105. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  106. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  107. package/dist/heart/attachments/sources/index.js +18 -0
  108. package/dist/heart/attachments/sources/telegram.js +71 -0
  109. package/dist/heart/attachments/store.js +132 -0
  110. package/dist/heart/attachments/types.js +93 -0
  111. package/dist/heart/auth/auth-flow.js +495 -0
  112. package/dist/heart/autonomy-budget.js +478 -0
  113. package/dist/heart/awaiting/a2a-await-delivery.js +109 -0
  114. package/dist/heart/awaiting/await-alert.js +152 -0
  115. package/dist/heart/awaiting/await-expiry.js +143 -0
  116. package/dist/heart/awaiting/await-loader.js +91 -0
  117. package/dist/heart/awaiting/await-parser.js +152 -0
  118. package/dist/heart/awaiting/await-runtime-state.js +111 -0
  119. package/dist/heart/awaiting/await-scheduler.js +391 -0
  120. package/dist/heart/background-operations.js +281 -0
  121. package/dist/heart/bluebubbles-host-account.js +78 -0
  122. package/dist/heart/bridges/manager.js +137 -17
  123. package/dist/heart/bridges/store.js +14 -2
  124. package/dist/heart/bundle-state.js +168 -0
  125. package/dist/heart/commitments.js +44 -18
  126. package/dist/heart/config-registry.js +331 -0
  127. package/dist/heart/config.js +174 -131
  128. package/dist/heart/context-loss-gauntlet.js +387 -0
  129. package/dist/heart/context-loss-sentinel.js +1159 -0
  130. package/dist/heart/core.js +2364 -578
  131. package/dist/heart/cross-chat-delivery.js +9 -22
  132. package/dist/heart/daemon/agent-config-check.js +451 -0
  133. package/dist/heart/daemon/agent-discovery.js +283 -3
  134. package/dist/heart/daemon/agent-home.js +319 -0
  135. package/dist/heart/daemon/agent-service.js +542 -0
  136. package/dist/heart/daemon/agentic-repair.js +547 -0
  137. package/dist/heart/daemon/await-private-wake.js +59 -0
  138. package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
  139. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  140. package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
  141. package/dist/heart/daemon/bluebubbles-host.js +273 -0
  142. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  143. package/dist/heart/daemon/cadence.js +180 -0
  144. package/dist/heart/daemon/cli-arg-redaction.js +26 -0
  145. package/dist/heart/daemon/cli-defaults.js +876 -0
  146. package/dist/heart/daemon/cli-desk.js +322 -0
  147. package/dist/heart/daemon/cli-exec.js +9199 -0
  148. package/dist/heart/daemon/cli-help.js +735 -0
  149. package/dist/heart/daemon/cli-parse.js +3211 -0
  150. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  151. package/dist/heart/daemon/cli-render.js +819 -0
  152. package/dist/heart/daemon/cli-types.js +8 -0
  153. package/dist/heart/daemon/connect-bay.js +323 -0
  154. package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
  155. package/dist/heart/daemon/container-healthcheck.js +112 -0
  156. package/dist/heart/daemon/container-runtime.js +97 -0
  157. package/dist/heart/daemon/container-spec-auditor-main.js +171 -0
  158. package/dist/heart/daemon/container-spec-auditor.js +235 -0
  159. package/dist/heart/daemon/daemon-bootstrap-startup.js +115 -0
  160. package/dist/heart/daemon/daemon-cli.js +29 -2350
  161. package/dist/heart/daemon/daemon-entry.js +953 -11
  162. package/dist/heart/daemon/daemon-health.js +186 -0
  163. package/dist/heart/daemon/daemon-rollup.js +57 -0
  164. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  165. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  166. package/dist/heart/daemon/daemon.js +2084 -105
  167. package/dist/heart/daemon/dns-workflow.js +394 -0
  168. package/dist/heart/daemon/doctor-types.js +8 -0
  169. package/dist/heart/daemon/doctor.js +1766 -0
  170. package/dist/heart/daemon/freshness.js +345 -0
  171. package/dist/heart/daemon/habit-private-wake.js +61 -0
  172. package/dist/heart/daemon/health-monitor.js +154 -11
  173. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  174. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  175. package/dist/heart/daemon/http-health-probe.js +80 -0
  176. package/dist/heart/daemon/human-command-screens.js +234 -0
  177. package/dist/heart/daemon/human-readiness.js +114 -0
  178. package/dist/heart/daemon/inner-status.js +78 -0
  179. package/dist/heart/daemon/interactive-repair.js +394 -0
  180. package/dist/heart/daemon/launchd.js +37 -8
  181. package/dist/heart/daemon/log-tailer.js +79 -10
  182. package/dist/heart/daemon/logs-prune.js +132 -0
  183. package/dist/heart/daemon/mcp-canary.js +524 -0
  184. package/dist/heart/daemon/message-router.js +65 -5
  185. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  186. package/dist/heart/daemon/os-cron-deps.js +135 -0
  187. package/dist/heart/daemon/os-cron.js +22 -14
  188. package/dist/heart/daemon/ouro-bot-entry.js +6 -3
  189. package/dist/heart/daemon/ouro-entry.js +5 -2
  190. package/dist/heart/daemon/plugin-cli.js +432 -0
  191. package/dist/heart/daemon/process-manager.js +760 -61
  192. package/dist/heart/daemon/provider-discovery.js +137 -0
  193. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  194. package/dist/heart/daemon/prunable-bundle.js +144 -0
  195. package/dist/heart/daemon/pulse.js +511 -0
  196. package/dist/heart/daemon/readiness-repair.js +365 -0
  197. package/dist/heart/daemon/run-hooks.js +2 -0
  198. package/dist/heart/daemon/runtime-logging.js +47 -14
  199. package/dist/heart/daemon/runtime-metadata.js +2 -30
  200. package/dist/heart/daemon/runtime-mode.js +13 -2
  201. package/dist/heart/daemon/safe-mode.js +161 -0
  202. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2654 -0
  203. package/dist/heart/daemon/sanctuary-acceptance-harness.js +1830 -0
  204. package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
  205. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +955 -0
  206. package/dist/heart/daemon/sanctuary-authority-codec.js +86 -0
  207. package/dist/heart/daemon/sanctuary-authority-epoch.js +281 -0
  208. package/dist/heart/daemon/sanctuary-authority-installation.js +161 -0
  209. package/dist/heart/daemon/sanctuary-authority-ledger.js +241 -0
  210. package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +1267 -0
  211. package/dist/heart/daemon/sanctuary-authority-vault-migration.js +79 -0
  212. package/dist/heart/daemon/sanctuary-bundle-migration.js +730 -0
  213. package/dist/heart/daemon/sanctuary-host-authority.js +1008 -0
  214. package/dist/heart/daemon/sanctuary-host-detached-supervisor.js +493 -0
  215. package/dist/heart/daemon/sanctuary-host-executor.js +670 -0
  216. package/dist/heart/daemon/sanctuary-host-linux-kernel.js +334 -0
  217. package/dist/heart/daemon/sanctuary-host-supervisor-entry.js +207 -0
  218. package/dist/heart/daemon/sanctuary-host-supervisor.js +95 -0
  219. package/dist/heart/daemon/sanctuary-package-management.js +103 -0
  220. package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
  221. package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
  222. package/dist/heart/daemon/sanctuary-telegram-authority-entry.js +475 -0
  223. package/dist/heart/daemon/sanctuary-telegram-authority-gateway.js +585 -0
  224. package/dist/heart/daemon/sanctuary-telegram-authority-service.js +676 -0
  225. package/dist/heart/daemon/sense-manager.js +733 -48
  226. package/dist/heart/daemon/session-id-resolver.js +131 -0
  227. package/dist/heart/daemon/skill-management-installer.js +1 -1
  228. package/dist/heart/daemon/socket-client.js +180 -12
  229. package/dist/heart/daemon/stale-bundle-prune.js +113 -0
  230. package/dist/heart/daemon/startup-tui.js +339 -0
  231. package/dist/heart/daemon/supercronic-supervisor.js +282 -0
  232. package/dist/heart/daemon/task-scheduler.js +117 -39
  233. package/dist/heart/daemon/terminal-ui.js +503 -0
  234. package/dist/heart/daemon/thoughts.js +138 -54
  235. package/dist/heart/daemon/up-progress.js +366 -0
  236. package/dist/heart/daemon/vault-items.js +56 -0
  237. package/dist/heart/delegation.js +1 -4
  238. package/dist/heart/external-events/router.js +1516 -0
  239. package/dist/heart/failure-reports.js +336 -0
  240. package/dist/heart/file-lock.js +109 -0
  241. package/dist/heart/frontend-approval-runtime.js +506 -0
  242. package/dist/heart/frontend-journal.js +215 -0
  243. package/dist/heart/frontend-session-service.js +237 -0
  244. package/dist/heart/frontend-socket-client.js +164 -0
  245. package/dist/heart/frontend-socket.js +400 -0
  246. package/dist/heart/habits/habit-cancel.js +810 -0
  247. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  248. package/dist/heart/habits/habit-migration.js +194 -0
  249. package/dist/heart/habits/habit-parser.js +278 -0
  250. package/dist/heart/habits/habit-runtime-state.js +93 -0
  251. package/dist/heart/habits/habit-scheduler.js +653 -0
  252. package/dist/heart/habits/habit-session-summary.js +318 -0
  253. package/dist/heart/habits/habit-session.js +636 -0
  254. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
  255. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  256. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  257. package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
  258. package/dist/heart/identity.js +230 -59
  259. package/dist/heart/kept-notes.js +289 -0
  260. package/dist/heart/kicks.js +1 -1
  261. package/dist/heart/machine-identity.js +175 -0
  262. package/dist/heart/mail-import-discovery.js +356 -0
  263. package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
  264. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  265. package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
  266. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  267. package/dist/heart/mailbox/mailbox-http-transport.js +272 -0
  268. package/dist/heart/mailbox/mailbox-http.js +99 -0
  269. package/dist/heart/mailbox/mailbox-read.js +39 -0
  270. package/dist/heart/mailbox/mailbox-types.js +27 -0
  271. package/dist/heart/mailbox/mailbox-view.js +197 -0
  272. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  273. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  274. package/dist/heart/mailbox/readers/mail.js +375 -0
  275. package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
  276. package/dist/heart/mailbox/readers/sessions.js +231 -0
  277. package/dist/heart/mailbox/readers/shared.js +111 -0
  278. package/dist/heart/mcp/mcp-server.js +696 -0
  279. package/dist/heart/migrate-config.js +100 -0
  280. package/dist/heart/model-capabilities.js +83 -16
  281. package/dist/heart/orientation-frame.js +345 -0
  282. package/dist/heart/platform.js +81 -0
  283. package/dist/heart/primitives.js +1 -1
  284. package/dist/heart/private-runtime/decision-renderer.js +158 -0
  285. package/dist/heart/private-runtime/index.js +18 -0
  286. package/dist/heart/private-runtime/ledger.js +221 -0
  287. package/dist/heart/private-runtime/policy.js +260 -0
  288. package/dist/heart/private-runtime/types.js +2 -0
  289. package/dist/heart/progress-story.js +1 -1
  290. package/dist/heart/provider-attempt.js +137 -0
  291. package/dist/heart/provider-binding-resolver.js +273 -0
  292. package/dist/heart/provider-credentials.js +449 -0
  293. package/dist/heart/provider-failover.js +311 -0
  294. package/dist/heart/provider-models.js +96 -0
  295. package/dist/heart/provider-ping.js +265 -0
  296. package/dist/heart/provider-readiness-cache.js +119 -0
  297. package/dist/heart/provider-visibility.js +188 -0
  298. package/dist/heart/providers/anthropic-token.js +131 -0
  299. package/dist/heart/providers/anthropic.js +173 -60
  300. package/dist/heart/providers/azure.js +23 -11
  301. package/dist/heart/providers/error-classification.js +127 -0
  302. package/dist/heart/providers/github-copilot.js +38 -39
  303. package/dist/heart/providers/minimax-vlm.js +189 -0
  304. package/dist/heart/providers/minimax.js +26 -8
  305. package/dist/heart/providers/openai-codex-token.js +349 -0
  306. package/dist/heart/providers/openai-codex.js +55 -40
  307. package/dist/heart/providers/openai-compatible.js +177 -0
  308. package/dist/heart/reply-style.js +52 -0
  309. package/dist/heart/run-ledger.js +247 -0
  310. package/dist/heart/runtime-capability-check.js +170 -0
  311. package/dist/heart/runtime-credentials.js +607 -0
  312. package/dist/heart/runtime-cwd.js +87 -0
  313. package/dist/heart/sense-truth.js +24 -4
  314. package/dist/heart/session-activity.js +92 -24
  315. package/dist/heart/session-events.js +1504 -0
  316. package/dist/heart/session-playback-cli-main.js +5 -0
  317. package/dist/heart/session-playback-cli.js +36 -0
  318. package/dist/heart/session-playback.js +231 -0
  319. package/dist/heart/session-redaction-repair-cli-main.js +31 -0
  320. package/dist/heart/session-redaction-repair.js +552 -0
  321. package/dist/heart/session-stats-cli-main.js +5 -0
  322. package/dist/heart/session-stats.js +183 -0
  323. package/dist/heart/session-transcript.js +133 -0
  324. package/dist/heart/shelf-claims.js +78 -0
  325. package/dist/heart/shepherd-config.js +113 -0
  326. package/dist/heart/source-grounding.js +297 -0
  327. package/dist/heart/start-of-turn-packet.js +372 -0
  328. package/dist/heart/steward-policy.js +656 -0
  329. package/dist/heart/streaming.js +609 -207
  330. package/dist/heart/structured-output.js +196 -0
  331. package/dist/heart/sync-classification.js +176 -0
  332. package/dist/heart/sync-health.js +152 -0
  333. package/dist/heart/sync.js +726 -0
  334. package/dist/heart/target-resolution.js +11 -7
  335. package/dist/heart/tempo.js +93 -0
  336. package/dist/heart/temporal-view.js +41 -0
  337. package/dist/heart/timeouts.js +101 -0
  338. package/dist/heart/tool-activity-callbacks.js +59 -0
  339. package/dist/heart/tool-approval.js +382 -0
  340. package/dist/heart/tool-description.js +155 -0
  341. package/dist/heart/tool-friction.js +55 -0
  342. package/dist/heart/tool-loop.js +206 -0
  343. package/dist/heart/turn-context.js +496 -0
  344. package/dist/heart/turn-execution-lease.js +30 -0
  345. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  346. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +3 -2
  347. package/dist/heart/versioning/ouro-path-installer.js +432 -0
  348. package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
  349. package/dist/heart/versioning/ouro-version-manager.js +432 -0
  350. package/dist/heart/versioning/release-sources.js +173 -0
  351. package/dist/heart/versioning/self-update-defaults.js +294 -0
  352. package/dist/heart/versioning/self-update.js +196 -0
  353. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  354. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  355. package/dist/heart/versioning/update-hooks.js +154 -0
  356. package/dist/heart/versioning/update-state.js +126 -0
  357. package/dist/heart/versioning/updater-launchd.js +150 -0
  358. package/dist/heart/versioning/version-intent.js +114 -0
  359. package/dist/heart/work-card.js +380 -0
  360. package/dist/mailbox-ui/assets/index-Cyv4mw3Y.js +1 -0
  361. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  362. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  363. package/dist/mailbox-ui/index.html +16 -0
  364. package/dist/mailroom/attention.js +167 -0
  365. package/dist/mailroom/autonomy.js +209 -0
  366. package/dist/mailroom/blob-store.js +889 -0
  367. package/dist/mailroom/body-cache.js +61 -0
  368. package/dist/mailroom/cache-sync-cli.js +58 -0
  369. package/dist/mailroom/core.js +803 -0
  370. package/dist/mailroom/entry.js +160 -0
  371. package/dist/mailroom/file-store.js +568 -0
  372. package/dist/mailroom/hosted-cache-sync.js +384 -0
  373. package/dist/mailroom/mbox-import.js +393 -0
  374. package/dist/mailroom/migration.js +164 -0
  375. package/dist/mailroom/outbound.js +380 -0
  376. package/dist/mailroom/policy.js +263 -0
  377. package/dist/mailroom/reader.js +292 -0
  378. package/dist/mailroom/search-cache.js +513 -0
  379. package/dist/mailroom/search-relevance.js +319 -0
  380. package/dist/mailroom/smtp-ingress.js +176 -0
  381. package/dist/mailroom/source-state.js +176 -0
  382. package/dist/mailroom/thread.js +109 -0
  383. package/dist/mailroom/travel-extract.js +89 -0
  384. package/dist/mind/bundle-manifest.js +24 -2
  385. package/dist/mind/context.js +307 -139
  386. package/dist/mind/desk-section.js +362 -0
  387. package/dist/mind/diary-integrity.js +60 -0
  388. package/dist/mind/{memory.js → diary.js} +68 -77
  389. package/dist/mind/embedding-provider.js +60 -0
  390. package/dist/mind/file-state.js +179 -0
  391. package/dist/mind/friend-link-codes.js +209 -0
  392. package/dist/mind/friend-merge.js +330 -0
  393. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  394. package/dist/mind/obligation-steering.js +199 -3
  395. package/dist/mind/pending.js +36 -10
  396. package/dist/mind/prompt-budget.js +479 -0
  397. package/dist/mind/prompt-refresh.js +3 -2
  398. package/dist/mind/prompt.js +1085 -198
  399. package/dist/mind/provenance-trust.js +26 -0
  400. package/dist/mind/record-paths.js +312 -0
  401. package/dist/mind/scrutiny.js +173 -0
  402. package/dist/mind/session-transaction.js +564 -0
  403. package/dist/nerves/cli-logging.js +7 -1
  404. package/dist/nerves/coverage/audit-rules.js +15 -6
  405. package/dist/nerves/coverage/audit.js +28 -2
  406. package/dist/nerves/coverage/cli.js +1 -1
  407. package/dist/nerves/coverage/contract.js +5 -5
  408. package/dist/nerves/coverage/file-completeness.js +139 -5
  409. package/dist/nerves/coverage/run-artifacts.js +55 -35
  410. package/dist/nerves/coverage/source-scanner.js +4 -4
  411. package/dist/nerves/event-buffer.js +111 -0
  412. package/dist/nerves/index.js +293 -9
  413. package/dist/nerves/observation.js +20 -0
  414. package/dist/nerves/redact.js +79 -0
  415. package/dist/nerves/review/cli-main.js +5 -0
  416. package/dist/nerves/review/cli.js +156 -0
  417. package/dist/nerves/review/core.js +159 -0
  418. package/dist/nerves/runtime.js +17 -1
  419. package/dist/repertoire/ado-client.js +15 -56
  420. package/dist/repertoire/ado-semantic.js +16 -10
  421. package/dist/repertoire/api-client.js +97 -0
  422. package/dist/repertoire/bitwarden-store.js +1201 -0
  423. package/dist/repertoire/bundle-templates.js +71 -0
  424. package/dist/repertoire/bw-installer.js +231 -0
  425. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  426. package/dist/repertoire/coding/context-pack.js +331 -0
  427. package/dist/repertoire/coding/feedback.js +174 -32
  428. package/dist/repertoire/coding/index.js +15 -3
  429. package/dist/repertoire/coding/manager.js +159 -10
  430. package/dist/repertoire/coding/spawner.js +40 -11
  431. package/dist/repertoire/coding/tools.js +182 -18
  432. package/dist/repertoire/coding/workbench-client.js +272 -0
  433. package/dist/repertoire/coding/workbench-manager.js +346 -0
  434. package/dist/repertoire/commerce-errors.js +109 -0
  435. package/dist/repertoire/commerce-self-test.js +156 -0
  436. package/dist/repertoire/credential-access.js +183 -0
  437. package/dist/repertoire/desk/classifier.js +362 -0
  438. package/dist/repertoire/duffel-client.js +185 -0
  439. package/dist/repertoire/github-client.js +14 -55
  440. package/dist/repertoire/graph-client.js +11 -52
  441. package/dist/repertoire/guardrails.js +968 -20
  442. package/dist/repertoire/house-sweep.js +469 -0
  443. package/dist/repertoire/mcp-client.js +58 -5
  444. package/dist/repertoire/mcp-manager.js +427 -139
  445. package/dist/repertoire/mcp-tools.js +132 -0
  446. package/dist/repertoire/mcp-write-guard.js +46 -0
  447. package/dist/repertoire/plugin-mcp.js +175 -0
  448. package/dist/repertoire/plugins.js +253 -0
  449. package/dist/repertoire/relationship-authorization.js +322 -0
  450. package/dist/repertoire/sanctuary-container-policy.js +46 -0
  451. package/dist/repertoire/shell-sessions.js +134 -0
  452. package/dist/repertoire/skills.js +48 -4
  453. package/dist/repertoire/stripe-client.js +131 -0
  454. package/dist/repertoire/tool-arguments.js +182 -0
  455. package/dist/repertoire/tool-results.js +29 -0
  456. package/dist/repertoire/tools-a2a.js +699 -0
  457. package/dist/repertoire/tools-attachments.js +322 -0
  458. package/dist/repertoire/tools-awaiting.js +872 -0
  459. package/dist/repertoire/tools-base.js +83 -1168
  460. package/dist/repertoire/tools-bluebubbles.js +2 -0
  461. package/dist/repertoire/tools-bridge.js +144 -0
  462. package/dist/repertoire/tools-bundle.js +995 -0
  463. package/dist/repertoire/tools-commerce.js +253 -0
  464. package/dist/repertoire/tools-config.js +186 -0
  465. package/dist/repertoire/tools-continuity.js +575 -0
  466. package/dist/repertoire/tools-credential.js +383 -0
  467. package/dist/repertoire/tools-escalation.js +84 -0
  468. package/dist/repertoire/tools-evolution.js +527 -0
  469. package/dist/repertoire/tools-files.js +344 -0
  470. package/dist/repertoire/tools-flight.js +290 -0
  471. package/dist/repertoire/tools-flow.js +119 -0
  472. package/dist/repertoire/tools-friend-link.js +57 -0
  473. package/dist/repertoire/tools-github.js +3 -8
  474. package/dist/repertoire/tools-habits.js +103 -0
  475. package/dist/repertoire/tools-house-care.js +174 -0
  476. package/dist/repertoire/tools-mail.js +1828 -0
  477. package/dist/repertoire/tools-notes.js +496 -0
  478. package/dist/repertoire/tools-obligations.js +182 -0
  479. package/dist/repertoire/tools-orientation.js +31 -0
  480. package/dist/repertoire/tools-record.js +482 -0
  481. package/dist/repertoire/tools-rsvp.js +139 -0
  482. package/dist/repertoire/tools-runtime.js +238 -0
  483. package/dist/repertoire/tools-sanctuary-host.js +202 -0
  484. package/dist/repertoire/tools-session.js +1133 -0
  485. package/dist/repertoire/tools-shell.js +149 -0
  486. package/dist/repertoire/tools-shepherd.js +262 -0
  487. package/dist/repertoire/tools-steward-policy.js +147 -0
  488. package/dist/repertoire/tools-stripe.js +224 -0
  489. package/dist/repertoire/tools-surface.js +369 -0
  490. package/dist/repertoire/tools-teams.js +12 -39
  491. package/dist/repertoire/tools-telegram-contacts.js +37 -0
  492. package/dist/repertoire/tools-travel.js +125 -0
  493. package/dist/repertoire/tools-trip.js +982 -0
  494. package/dist/repertoire/tools-unraid.js +556 -0
  495. package/dist/repertoire/tools-user-profile.js +146 -0
  496. package/dist/repertoire/tools-vault.js +40 -0
  497. package/dist/repertoire/tools-voice-local.js +198 -0
  498. package/dist/repertoire/tools-voice.js +145 -0
  499. package/dist/repertoire/tools.js +514 -156
  500. package/dist/repertoire/travel-api-client.js +360 -0
  501. package/dist/repertoire/unraid-client.js +155 -0
  502. package/dist/repertoire/unraid-restart.js +339 -0
  503. package/dist/repertoire/user-profile.js +131 -0
  504. package/dist/repertoire/vault-setup.js +246 -0
  505. package/dist/repertoire/vault-unlock.js +686 -0
  506. package/dist/rsvp/aisleplanner-client.js +354 -0
  507. package/dist/rsvp/cli.js +936 -0
  508. package/dist/rsvp/config.js +327 -0
  509. package/dist/rsvp/cutover.js +433 -0
  510. package/dist/rsvp/diagnostics.js +232 -0
  511. package/dist/rsvp/diff-renderer.js +176 -0
  512. package/dist/rsvp/habit-policy.js +110 -0
  513. package/dist/rsvp/habit-stage.js +123 -0
  514. package/dist/rsvp/incident-bundle.js +97 -0
  515. package/dist/rsvp/migration.js +204 -0
  516. package/dist/rsvp/native-habit-runner.js +630 -0
  517. package/dist/rsvp/outbound-state.js +628 -0
  518. package/dist/rsvp/query.js +118 -0
  519. package/dist/rsvp/replay.js +233 -0
  520. package/dist/rsvp/snapshot.js +232 -0
  521. package/dist/rsvp/spend-ledger.js +175 -0
  522. package/dist/scripts/claude-code-hook.js +41 -0
  523. package/dist/scripts/claude-code-stop-hook.js +47 -0
  524. package/dist/senses/a2a-entry.js +132 -0
  525. package/dist/senses/acp-server.js +386 -0
  526. package/dist/senses/attention-queue.js +186 -0
  527. package/dist/senses/await-turn-message.js +65 -0
  528. package/dist/senses/bluebubbles/active-turns.js +216 -0
  529. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  530. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  531. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +379 -41
  532. package/dist/senses/bluebubbles/context-packet.js +207 -0
  533. package/dist/senses/bluebubbles/context-smoke.js +144 -0
  534. package/dist/senses/bluebubbles/entry.js +90 -0
  535. package/dist/senses/bluebubbles/host-account-verifier.js +88 -0
  536. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
  537. package/dist/senses/bluebubbles/index.js +3878 -0
  538. package/dist/senses/bluebubbles/latest-turn.js +311 -0
  539. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  540. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
  541. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
  542. package/dist/senses/bluebubbles/outbound-state.js +308 -0
  543. package/dist/senses/bluebubbles/processed-log.js +133 -0
  544. package/dist/senses/bluebubbles/reaction-policy.js +47 -0
  545. package/dist/senses/bluebubbles/replay.js +284 -0
  546. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  547. package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
  548. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  549. package/dist/senses/bluebubbles/webhook-registration.js +257 -0
  550. package/dist/senses/bluebubbles-meta-guard.js +39 -0
  551. package/dist/senses/cli/bracketed-paste.js +82 -0
  552. package/dist/senses/cli/image-paste.js +287 -0
  553. package/dist/senses/cli/image-ref-navigation.js +75 -0
  554. package/dist/senses/cli/ink-app.js +156 -0
  555. package/dist/senses/cli/inline-diff.js +64 -0
  556. package/dist/senses/cli/input-keys.js +174 -0
  557. package/dist/senses/cli/kill-ring.js +86 -0
  558. package/dist/senses/cli/message-list.js +51 -0
  559. package/dist/senses/cli/ouro-tui.js +607 -0
  560. package/dist/senses/cli/spinner-imperative.js +135 -0
  561. package/dist/senses/cli/spinner.js +101 -0
  562. package/dist/senses/cli/status-line.js +60 -0
  563. package/dist/senses/cli/streaming-markdown.js +526 -0
  564. package/dist/senses/cli/tool-display.js +85 -0
  565. package/dist/senses/cli/tool-render.js +85 -0
  566. package/dist/senses/cli/tui-store.js +241 -0
  567. package/dist/senses/cli/virtual-list.js +35 -0
  568. package/dist/senses/cli-entry.js +60 -8
  569. package/dist/senses/cli.js +601 -304
  570. package/dist/senses/commands.js +66 -3
  571. package/dist/senses/context-packet-ledger.js +371 -0
  572. package/dist/senses/context-packets.js +154 -0
  573. package/dist/senses/habit-lifecycle-guard.js +24 -0
  574. package/dist/senses/habit-turn-message.js +160 -0
  575. package/dist/senses/ingress-evidence.js +2 -0
  576. package/dist/senses/mail-entry.js +66 -0
  577. package/dist/senses/mail.js +524 -0
  578. package/dist/senses/pipeline.js +1158 -204
  579. package/dist/senses/private-runtime-worker.js +859 -0
  580. package/dist/senses/private-runtime.js +1627 -0
  581. package/dist/senses/proactive-content-guard.js +51 -0
  582. package/dist/senses/root-host-approval-port.js +345 -0
  583. package/dist/senses/root-host-approval-runtime.js +393 -0
  584. package/dist/senses/sanctuary-authority-resident.js +102 -0
  585. package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
  586. package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
  587. package/dist/senses/sanctuary-grounding.js +118 -0
  588. package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
  589. package/dist/senses/sanctuary-health-acceptance-probe.js +774 -0
  590. package/dist/senses/sanctuary-health-runner.js +104 -0
  591. package/dist/senses/sanctuary-health.js +422 -0
  592. package/dist/senses/sanctuary-install-state-contract.js +169 -0
  593. package/dist/senses/sanctuary-interactive-control.js +410 -0
  594. package/dist/senses/sanctuary-media-catalog-contract.js +259 -0
  595. package/dist/senses/sanctuary-media-optimization.js +514 -0
  596. package/dist/senses/sanctuary-runtime.js +369 -0
  597. package/dist/senses/sanctuary-sab.js +85 -0
  598. package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
  599. package/dist/senses/shared-turn.js +793 -0
  600. package/dist/senses/shepherd/client.js +196 -0
  601. package/dist/senses/shepherd/cmux.js +352 -0
  602. package/dist/senses/shepherd/herdr.js +315 -0
  603. package/dist/senses/shepherd/host.js +14 -0
  604. package/dist/senses/shepherd/judge.js +137 -0
  605. package/dist/senses/shepherd/owner-notice.js +251 -0
  606. package/dist/senses/shepherd/redact.js +66 -0
  607. package/dist/senses/shepherd/returns.js +79 -0
  608. package/dist/senses/shepherd/sense.js +310 -0
  609. package/dist/senses/shepherd/terminal-process.js +99 -0
  610. package/dist/senses/shepherd-entry.js +78 -0
  611. package/dist/senses/surface-tool.js +109 -0
  612. package/dist/senses/teams-entry.js +68 -8
  613. package/dist/senses/teams.js +598 -233
  614. package/dist/senses/telegram-admission.js +718 -0
  615. package/dist/senses/telegram-approval-runtime.js +793 -0
  616. package/dist/senses/telegram-attachments.js +186 -0
  617. package/dist/senses/telegram-audit-ledger.js +220 -0
  618. package/dist/senses/telegram-authority-transport.js +231 -0
  619. package/dist/senses/telegram-client.js +1749 -0
  620. package/dist/senses/telegram-effect-adapter.js +900 -0
  621. package/dist/senses/telegram-entry.js +83 -0
  622. package/dist/senses/telegram-handoff.js +80 -0
  623. package/dist/senses/telegram.js +2405 -0
  624. package/dist/senses/trust-gate.js +104 -9
  625. package/dist/senses/voice/audio-playback.js +237 -0
  626. package/dist/senses/voice/audio-routing.js +119 -0
  627. package/dist/senses/voice/call-auth.js +250 -0
  628. package/dist/senses/voice/elevenlabs.js +202 -0
  629. package/dist/senses/voice/floor-control.js +431 -0
  630. package/dist/senses/voice/floor-controller.js +115 -0
  631. package/dist/senses/voice/golden-path.js +116 -0
  632. package/dist/senses/voice/index.js +29 -0
  633. package/dist/senses/voice/local-audio-control.js +344 -0
  634. package/dist/senses/voice/local-audio-devices.js +516 -0
  635. package/dist/senses/voice/local-audio-disclosure.js +174 -0
  636. package/dist/senses/voice/local-audio-identity.js +103 -0
  637. package/dist/senses/voice/local-audio-join.js +325 -0
  638. package/dist/senses/voice/local-audio-mute.js +199 -0
  639. package/dist/senses/voice/local-audio-notify.js +121 -0
  640. package/dist/senses/voice/local-audio-prompts.js +116 -0
  641. package/dist/senses/voice/local-audio-transport.js +427 -0
  642. package/dist/senses/voice/local-audio.js +281 -0
  643. package/dist/senses/voice/local-media-stream.js +145 -0
  644. package/dist/senses/voice/meeting.js +113 -0
  645. package/dist/senses/voice/outbound.js +190 -0
  646. package/dist/senses/voice/phone.js +33 -0
  647. package/dist/senses/voice/playback.js +139 -0
  648. package/dist/senses/voice/process-guards.js +51 -0
  649. package/dist/senses/voice/realtime-eval.js +496 -0
  650. package/dist/senses/voice/realtime-tool-schema.js +195 -0
  651. package/dist/senses/voice/realtime-trace.js +531 -0
  652. package/dist/senses/voice/transcript.js +70 -0
  653. package/dist/senses/voice/turn.js +191 -0
  654. package/dist/senses/voice/twilio-phone-runtime.js +836 -0
  655. package/dist/senses/voice/twilio-phone.js +5454 -0
  656. package/dist/senses/voice/types.js +2 -0
  657. package/dist/senses/voice/whisper.js +161 -0
  658. package/dist/senses/voice-entry.js +83 -0
  659. package/dist/senses/voice-realtime-eval-command.js +99 -0
  660. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  661. package/dist/senses/voice-twilio-entry.js +87 -0
  662. package/dist/trips/core.js +138 -0
  663. package/dist/trips/store.js +265 -0
  664. package/dist/util/frontmatter.js +69 -0
  665. package/npm-shrinkwrap.json +8100 -0
  666. package/package.json +74 -13
  667. package/skills/agent-commerce.md +113 -0
  668. package/skills/browser-navigation.md +117 -0
  669. package/skills/commerce-setup-guide.md +116 -0
  670. package/skills/commerce-setup.md +84 -0
  671. package/skills/configure-dev-tools.md +99 -0
  672. package/skills/travel-planning.md +138 -0
  673. package/dist/heart/daemon/auth-flow.js +0 -430
  674. package/dist/heart/daemon/ouro-path-installer.js +0 -260
  675. package/dist/heart/daemon/ouro-version-manager.js +0 -171
  676. package/dist/heart/daemon/update-hooks.js +0 -138
  677. package/dist/heart/obligations.js +0 -191
  678. package/dist/heart/safe-workspace.js +0 -362
  679. package/dist/heart/session-recall.js +0 -116
  680. package/dist/mind/friends/channel.js +0 -84
  681. package/dist/mind/friends/group-context.js +0 -144
  682. package/dist/mind/friends/resolver.js +0 -84
  683. package/dist/mind/friends/store-file.js +0 -190
  684. package/dist/mind/friends/store.js +0 -4
  685. package/dist/mind/friends/tokens.js +0 -26
  686. package/dist/mind/friends/trust-explanation.js +0 -74
  687. package/dist/mind/friends/types.js +0 -29
  688. package/dist/repertoire/tasks/board.js +0 -134
  689. package/dist/repertoire/tasks/index.js +0 -224
  690. package/dist/repertoire/tasks/lifecycle.js +0 -80
  691. package/dist/repertoire/tasks/middleware.js +0 -65
  692. package/dist/repertoire/tasks/parser.js +0 -173
  693. package/dist/repertoire/tasks/scanner.js +0 -132
  694. package/dist/repertoire/tasks/transitions.js +0 -144
  695. package/dist/senses/bluebubbles-entry.js +0 -13
  696. package/dist/senses/bluebubbles.js +0 -1181
  697. package/dist/senses/debug-activity.js +0 -154
  698. package/dist/senses/inner-dialog-worker.js +0 -90
  699. package/dist/senses/inner-dialog.js +0 -525
  700. package/subagents/README.md +0 -7
  701. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  702. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  703. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  704. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  705. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  706. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  707. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  708. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  709. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  710. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  711. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  712. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  713. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  714. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  715. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  716. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  717. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,872 @@
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.awaitingToolDefinitions = exports.HOUSE_CARE_AWAIT = void 0;
37
+ exports.readAwaitDefinition = readAwaitDefinition;
38
+ exports.setAwaitToolDeps = setAwaitToolDeps;
39
+ exports.resetAwaitToolDeps = resetAwaitToolDeps;
40
+ exports.readOwnerAskForAwait = readOwnerAskForAwait;
41
+ exports.cancelAwaitTool = cancelAwaitTool;
42
+ exports.cancelStaleAwait = cancelStaleAwait;
43
+ exports.isBrokenBindingReason = isBrokenBindingReason;
44
+ exports.failBrokenAwait = failBrokenAwait;
45
+ exports.inspectRelationshipFollowUp = inspectRelationshipFollowUp;
46
+ exports.inspectPeerAwait = inspectPeerAwait;
47
+ exports.hasActiveRelationshipFollowUp = hasActiveRelationshipFollowUp;
48
+ exports.hasActiveExternalEventAwait = hasActiveExternalEventAwait;
49
+ exports.inspectExternalEventAwait = inspectExternalEventAwait;
50
+ exports.cancelRelationshipFollowUps = cancelRelationshipFollowUps;
51
+ const fs = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ const identity_1 = require("../heart/identity");
54
+ const session_events_1 = require("../heart/session-events");
55
+ const runtime_1 = require("../nerves/runtime");
56
+ const await_parser_1 = require("../heart/awaiting/await-parser");
57
+ const await_alert_1 = require("../heart/awaiting/await-alert");
58
+ const friends_1 = require("@ouro.bot/friends");
59
+ const a2a_await_delivery_1 = require("../heart/awaiting/a2a-await-delivery");
60
+ const pending_1 = require("../mind/pending");
61
+ const router_1 = require("../heart/external-events/router");
62
+ const obligations_1 = require("../arc/obligations");
63
+ const cadence_1 = require("../heart/daemon/cadence");
64
+ /**
65
+ * Bundle-root-relative locations.
66
+ * - `awaiting/<name>.md` — active awaits (status: pending)
67
+ * - `awaiting/.done/<name>.md` — terminal awaits (resolved/expired/canceled)
68
+ */
69
+ function awaitingDir(agentRoot) {
70
+ return path.join(agentRoot, "awaiting");
71
+ }
72
+ function awaitingDoneDir(agentRoot) {
73
+ return path.join(awaitingDir(agentRoot), ".done");
74
+ }
75
+ function awaitFilePath(agentRoot, name) {
76
+ return path.join(awaitingDir(agentRoot), `${name}.md`);
77
+ }
78
+ function awaitDoneFilePath(agentRoot, name) {
79
+ return path.join(awaitingDoneDir(agentRoot), `${name}.md`);
80
+ }
81
+ const VALID_NAME = /^[A-Za-z0-9_-]+$/;
82
+ function validateName(name) {
83
+ if (!name)
84
+ return "name is required";
85
+ if (!VALID_NAME.test(name))
86
+ return "name must be alphanumeric, underscores, or hyphens";
87
+ return null;
88
+ }
89
+ /**
90
+ * The relationship scope a resolve/cancel is judged against. A turn that is ticking an await carries that await's own
91
+ * binding (`awaitTick`), because the pipeline rewrites `currentSession` to the private-runtime session; that binding covers the
92
+ * ticked await only, so a tick can never touch any other await. Every other turn is judged by its current session.
93
+ */
94
+ function relationshipScopeFor(ctx, awaitName) {
95
+ const tick = ctx.awaitTick;
96
+ if (tick) {
97
+ return tick.awaitName === awaitName
98
+ ? { session: { friendId: tick.friendId, channel: tick.channel, key: tick.key }, requestId: tick.requestId ?? undefined }
99
+ : { session: undefined, requestId: undefined };
100
+ }
101
+ return { session: ctx.currentSession, requestId: ctx.relationshipAuthorization?.requestId };
102
+ }
103
+ function readAwaitDoneDefinition(agentRoot, name) {
104
+ const filePath = awaitDoneFilePath(agentRoot, name);
105
+ try {
106
+ return (0, await_parser_1.parseAwaitFile)(fs.readFileSync(filePath, "utf-8"), filePath);
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }
112
+ function readAwaitDefinition(agentRoot, name) {
113
+ const filePath = awaitFilePath(agentRoot, name);
114
+ try {
115
+ const content = fs.readFileSync(filePath, "utf-8");
116
+ return (0, await_parser_1.parseAwaitFile)(content, filePath);
117
+ }
118
+ catch {
119
+ return null;
120
+ }
121
+ }
122
+ /**
123
+ * Default delivery deps for the await alert path used from the tool.
124
+ * Mirrors the proactive-outreach pattern: queue to the private-runtime pending
125
+ * dir when no live deliverer is registered.
126
+ */
127
+ function defaultDeliveryDeps(agentName) {
128
+ const pendingDir = (0, pending_1.getPrivateRuntimePendingDir)(agentName);
129
+ return {
130
+ agentName,
131
+ queuePending: (message) => {
132
+ // Mirror the write-as-pending convention from tools-session.
133
+ fs.mkdirSync(pendingDir, { recursive: true });
134
+ const filename = `${message.timestamp}-${Math.random().toString(36).slice(2, 10)}.json`;
135
+ fs.writeFileSync(path.join(pendingDir, filename), JSON.stringify({ ...message, content: (0, session_events_1.capStructuredRecordString)(message.content) }, null, 2), "utf-8");
136
+ },
137
+ };
138
+ }
139
+ let injected = {};
140
+ function setAwaitToolDeps(deps) {
141
+ injected = deps;
142
+ }
143
+ function resetAwaitToolDeps() {
144
+ injected = {};
145
+ }
146
+ function resolveDeliveryDeps(agentName) {
147
+ const deps = injected.buildDeliveryDeps ? injected.buildDeliveryDeps(agentName) : defaultDeliveryDeps(agentName);
148
+ return { ...deps, deliverers: { a2a: (0, a2a_await_delivery_1.createA2AAwaitOwnerDeliverer)(agentName), ...deps.deliverers } };
149
+ }
150
+ const ASK_OWNER_MIN_CHOICES = 2;
151
+ const ASK_OWNER_MAX_CHOICES = 4;
152
+ function oneLine(value) {
153
+ return value.replace(/\s+/gu, " ").trim();
154
+ }
155
+ /**
156
+ * Validates an ask_owner request. The question and choices are collapsed to single lines because they are archived as
157
+ * frontmatter, and choices may not contain "|" because the archive joins them with " | ".
158
+ */
159
+ function parseAskOwner(question, choices) {
160
+ const cleanQuestion = typeof question === "string" ? oneLine(question) : "";
161
+ if (!cleanQuestion)
162
+ return { ok: false, error: "question is required for ask_owner: put the decision to the owner in plain words" };
163
+ if (!Array.isArray(choices) || choices.length < ASK_OWNER_MIN_CHOICES || choices.length > ASK_OWNER_MAX_CHOICES) {
164
+ return { ok: false, error: `ask_owner needs ${ASK_OWNER_MIN_CHOICES} to ${ASK_OWNER_MAX_CHOICES} choices` };
165
+ }
166
+ const cleanChoices = choices.map((choice) => typeof choice === "string" ? oneLine(choice) : "");
167
+ if (cleanChoices.some((choice) => !choice))
168
+ return { ok: false, error: "every ask_owner choice must be a non-empty string" };
169
+ if (cleanChoices.some((choice) => choice.includes("|")))
170
+ return { ok: false, error: 'ask_owner choices must not contain "|"' };
171
+ return { ok: true, question: cleanQuestion, choices: cleanChoices };
172
+ }
173
+ function formatOwnerQuestion(question, choices) {
174
+ return `${question}\n\n${choices.map((choice) => `- ${choice}`).join("\n")}`;
175
+ }
176
+ function failedAskOwner(agentName, name, error) {
177
+ const detail = error instanceof Error ? error.message : String(error);
178
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "repertoire", event: "repertoire.await_ask_owner_error", message: "ask_owner could not reach the owner", meta: { agent: agentName, name, error: detail } });
179
+ return JSON.stringify({ error: `the owner message could not be sent (${detail}); the await is still pending, so ask_owner can be retried` });
180
+ }
181
+ /** At most this many ask_owner closures per requester in a rolling day, so one requester cannot make the Butler pester the owner. */
182
+ const ASK_OWNER_DAILY_LIMIT = 3;
183
+ const ASK_OWNER_WINDOW_MS = 24 * 60 * 60 * 1000;
184
+ /** Across every requester who is not the owner, so many requesters together cannot flood the owner either. */
185
+ const ASK_OWNER_NON_OWNER_DAILY_LIMIT = 6;
186
+ function askLedgerPath(agentRoot) {
187
+ return path.join(awaitingDir(agentRoot), ".asks.jsonl");
188
+ }
189
+ /** Every ask_owner closure is appended here, because the archive is overwritten when an await name is reused. */
190
+ function recordAsk(agentRoot, entry) {
191
+ fs.mkdirSync(awaitingDir(agentRoot), { recursive: true });
192
+ fs.appendFileSync(askLedgerPath(agentRoot), `${JSON.stringify(entry)}\n`, "utf-8");
193
+ }
194
+ /**
195
+ * The most recent time the owner was asked about this await instance, read from the runtime ask ledger (never from model text).
196
+ * An instance is the await name filed at `createdAt`; an ask recorded before that belongs to an earlier use of the name.
197
+ */
198
+ function readOwnerAskForAwait(agentRoot, name, createdAt) {
199
+ let raw;
200
+ try {
201
+ raw = fs.readFileSync(askLedgerPath(agentRoot), "utf-8");
202
+ }
203
+ catch {
204
+ return null;
205
+ }
206
+ const createdMs = createdAt ? Date.parse(createdAt) : Number.NaN;
207
+ let found = null;
208
+ for (const line of raw.split("\n")) {
209
+ try {
210
+ const entry = JSON.parse(line);
211
+ if (entry.name !== name || typeof entry.at !== "string")
212
+ continue;
213
+ const atMs = Date.parse(entry.at);
214
+ if (!Number.isFinite(atMs) || (Number.isFinite(createdMs) && atMs < createdMs))
215
+ continue;
216
+ if (!found || atMs >= Date.parse(found.at))
217
+ found = { at: entry.at, question: typeof entry.question === "string" && entry.question.length > 0 ? entry.question : null };
218
+ }
219
+ catch {
220
+ continue;
221
+ }
222
+ }
223
+ return found;
224
+ }
225
+ function recentAskCount(agentRoot, filer, now) {
226
+ let raw;
227
+ try {
228
+ raw = fs.readFileSync(askLedgerPath(agentRoot), "utf-8");
229
+ }
230
+ catch {
231
+ return 0;
232
+ }
233
+ return raw.split("\n").filter((line) => {
234
+ try {
235
+ const entry = JSON.parse(line);
236
+ const who = filer === undefined ? entry.owner === false : (entry.filer ?? null) === filer;
237
+ return who && typeof entry.at === "string" && now - Date.parse(entry.at) < ASK_OWNER_WINDOW_MS;
238
+ }
239
+ catch {
240
+ return false;
241
+ }
242
+ }).length;
243
+ }
244
+ const askOwnerInFlight = new Set();
245
+ /** A friend store that cannot be read makes the filer unknown, which is never the owner; it must not fail the ask. */
246
+ async function lookupFiler(agentRoot, friendId) {
247
+ try {
248
+ const friend = friendId ? await new friends_1.FileFriendStore(path.join(agentRoot, "friends")).get(friendId) : null;
249
+ return { isOwner: Boolean(friend && friend.admissionState === "active" && friend.trustLevel === "family" && friend.capabilityProfileId === "sanctuary-owner"), name: friend?.name ?? null };
250
+ }
251
+ catch {
252
+ return { isOwner: false, name: null };
253
+ }
254
+ }
255
+ function delivered(alert) {
256
+ return alert?.delivery?.status === "delivered_now" || alert?.delivery?.status === "queued_for_later";
257
+ }
258
+ /**
259
+ * The await's condition cannot be met without the owner deciding. The owner is asked once, as the agent, in the
260
+ * owner's own chat, and only then is the await archived as asked_owner. One notice id per await instance ties every
261
+ * path together: the A2A owner delivery, the direct owner message and the replay sink all dedupe on it, so a retry after
262
+ * a crash between send and archive sends nothing twice. An await filed from A2A goes through the A2A owner delivery,
263
+ * which writes the owner notice (or the replay sink during a replay window); the direct notice is only the fallback
264
+ * when that path blocked or failed. When someone other than the owner filed the await, the text says whose request it is
265
+ * about, and a non-A2A filer is also told that the owner was asked (the obligation stays open if that could not be said).
266
+ */
267
+ async function askOwnerTool(name, observation, question, choices, existing, agentRoot, agentName) {
268
+ const parsed = parseAskOwner(question, choices);
269
+ if (!parsed.ok)
270
+ return JSON.stringify({ error: parsed.error });
271
+ const inFlightKey = `${agentRoot}\0${name}`;
272
+ if (askOwnerInFlight.has(inFlightKey))
273
+ return JSON.stringify({ error: `await "${name}" is already being asked; wait for the owner's reply instead of asking again` });
274
+ askOwnerInFlight.add(inFlightKey);
275
+ try {
276
+ const filerId = existing.filed_for_friend_id ?? null;
277
+ const filer = await lookupFiler(agentRoot, filerId);
278
+ if (!filer.isOwner && recentAskCount(agentRoot, filerId, Date.now()) >= ASK_OWNER_DAILY_LIMIT) {
279
+ return JSON.stringify({ error: `ask_owner limit reached: this requester has already had my owner asked ${ASK_OWNER_DAILY_LIMIT} times in the last day; do not retry ask_owner, resolve with verdict 'no' with an observation and keep polling` });
280
+ }
281
+ if (!filer.isOwner && recentAskCount(agentRoot, undefined, Date.now()) >= ASK_OWNER_NON_OWNER_DAILY_LIMIT) {
282
+ return JSON.stringify({ error: `ask_owner limit reached: my owner has already been asked ${ASK_OWNER_NON_OWNER_DAILY_LIMIT} times today on behalf of other requesters; do not retry ask_owner, resolve with verdict 'no' with an observation and keep polling` });
283
+ }
284
+ const isA2A = existing.filed_from === "a2a";
285
+ const noticeId = `await:${name}:asked_owner:${String(existing.created_at)}`;
286
+ const question = formatOwnerQuestion(parsed.question, parsed.choices);
287
+ const ownerText = filer.isOwner ? question : (0, a2a_await_delivery_1.askedOwnerText)(question, filer.name ?? (isA2A ? "a connected agent" : "a friend"));
288
+ let alert = null;
289
+ let sent = false;
290
+ if (isA2A) {
291
+ try {
292
+ alert = await (0, await_alert_1.deliverAwaitAlert)({ awaitFile: { ...existing, alert: "a2a" }, reason: "asked_owner", observation: question, content: question, deliveryId: noticeId, agentRoot, agentName, deliveryDeps: resolveDeliveryDeps(agentName) });
293
+ }
294
+ catch (error) {
295
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "repertoire", event: "repertoire.await_alert_error", message: "await alert delivery threw", meta: { agent: agentName, name, error: error instanceof Error ? error.message : String(error) } });
296
+ }
297
+ sent = delivered(alert);
298
+ }
299
+ if (!sent) {
300
+ try {
301
+ await (injected.notifyOwner ? injected.notifyOwner(agentName) : (0, a2a_await_delivery_1.defaultNotifyOwner)(agentName))({ noticeId, text: ownerText });
302
+ }
303
+ catch (error) {
304
+ return failedAskOwner(agentName, name, error);
305
+ }
306
+ }
307
+ let friendNotice = null;
308
+ const tellsFriend = !isA2A && !filer.isOwner && Boolean(filerId);
309
+ if (tellsFriend) {
310
+ try {
311
+ friendNotice = await (0, await_alert_1.deliverAwaitAlert)({ awaitFile: existing, reason: "asked_owner", observation: observation.trim(), content: `About "${existing.condition ?? name}": I have asked the owner how to proceed and will let you know what they decide.`, deliveryId: `${noticeId}:filer`, agentRoot, agentName, deliveryDeps: resolveDeliveryDeps(agentName) });
312
+ }
313
+ catch (error) {
314
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "repertoire", event: "repertoire.await_alert_error", message: "await alert delivery threw", meta: { agent: agentName, name, error: error instanceof Error ? error.message : String(error) } });
315
+ }
316
+ }
317
+ const askedAt = new Date().toISOString();
318
+ const archive = archiveAwait(agentRoot, name, {
319
+ status: "asked_owner",
320
+ asked_at: askedAt,
321
+ ask_question: parsed.question,
322
+ ask_choices: parsed.choices.join(" | "),
323
+ resolution_observation: observation.trim(),
324
+ });
325
+ /* v8 ignore next -- defensive: archiveAwait only fails on the file-disappears-mid-call race already covered by v8 ignore inside archiveAwait @preserve */
326
+ if (!archive.ok)
327
+ return JSON.stringify({ error: archive.error });
328
+ recordAsk(agentRoot, { filer: filerId, owner: filer.isOwner, name, at: askedAt, question: parsed.question });
329
+ if (!tellsFriend || delivered(friendNotice))
330
+ fulfillAwaitObligation(agentRoot, archive.file);
331
+ (0, runtime_1.emitNervesEvent)({
332
+ component: "repertoire",
333
+ event: "repertoire.await_asked_owner",
334
+ message: "await closed by asking the owner",
335
+ meta: { agent: agentName, name, choices: parsed.choices.length },
336
+ });
337
+ const summary = (result) => result ? { attempted: result.attempted, status: result.delivery?.status ?? null, skipped: result.skipped ?? null } : null;
338
+ return JSON.stringify({
339
+ verdict: "ask_owner",
340
+ asked: true,
341
+ archived: awaitDoneFilePath(agentRoot, name),
342
+ alert: summary(alert),
343
+ ...(tellsFriend ? { filerNotice: summary(friendNotice) } : {}),
344
+ });
345
+ }
346
+ finally {
347
+ askOwnerInFlight.delete(inFlightKey);
348
+ }
349
+ }
350
+ function fileAwait(args, agentRoot, agentName, sessionFriendId, sessionChannel, sessionKey, requestId) {
351
+ const nameError = validateName(args.name);
352
+ if (nameError)
353
+ return JSON.stringify({ error: nameError });
354
+ if (!args.condition || !args.condition.trim()) {
355
+ return JSON.stringify({ error: "condition is required" });
356
+ }
357
+ if (!args.cadence || !args.cadence.trim()) {
358
+ return JSON.stringify({ error: "cadence is required" });
359
+ }
360
+ // Any ISO timestamp with a zone is accepted and stored in canonical form ("2026-10-12T12:09:00Z" becomes "...:00.000Z"); the alpha.910 replay refused four valid forms in a row.
361
+ if (args.wake_at && (!/(?:Z|[+-]\d\d:?\d\d)$/i.test(args.wake_at) || !Number.isFinite(Date.parse(args.wake_at)))) {
362
+ return JSON.stringify({ error: "wake_at must be an ISO timestamp with a time zone, like 2026-10-12T12:09:00Z" });
363
+ }
364
+ const wakeAt = args.wake_at ? new Date(args.wake_at).toISOString() : null;
365
+ const filePath = awaitFilePath(agentRoot, args.name);
366
+ if (fs.existsSync(filePath)) {
367
+ return JSON.stringify({ error: `await "${args.name}" already exists` });
368
+ }
369
+ const mode = args.mode === "quick" ? "quick" : "full";
370
+ const alert = sessionChannel === "external-event" ? null : args.alert ?? sessionChannel ?? null;
371
+ const frontmatter = {
372
+ condition: (0, session_events_1.capStructuredRecordString)(args.condition.trim()),
373
+ cadence: (0, session_events_1.capStructuredRecordString)(args.cadence.trim()),
374
+ alert,
375
+ mode,
376
+ max_age: typeof args.max_age === "string" ? (0, session_events_1.capStructuredRecordString)(args.max_age) : null,
377
+ wake_at: wakeAt,
378
+ status: "pending",
379
+ created_at: new Date().toISOString(),
380
+ filed_from: sessionChannel ?? "unknown",
381
+ filed_for_friend_id: sessionFriendId ?? null,
382
+ filed_from_key: sessionKey,
383
+ request_id: requestId,
384
+ };
385
+ let obligationId = null;
386
+ if (requestId && sessionFriendId && sessionChannel && sessionKey) {
387
+ const obligation = (0, obligations_1.createObligation)(agentRoot, {
388
+ origin: { friendId: sessionFriendId, channel: sessionChannel, key: sessionKey },
389
+ owedTo: { friendId: sessionFriendId, channel: sessionChannel, key: sessionKey },
390
+ requestId,
391
+ content: args.condition.trim(),
392
+ });
393
+ (0, obligations_1.advanceObligation)(agentRoot, obligation.id, {
394
+ currentSurface: { kind: "session", label: `${sessionChannel}/${sessionKey}` },
395
+ currentArtifact: `awaiting/${args.name}.md`,
396
+ nextAction: args.condition.trim(),
397
+ });
398
+ obligationId = obligation.id;
399
+ frontmatter.obligation_id = obligation.id;
400
+ }
401
+ const rendered = (0, await_parser_1.renderAwaitFile)(frontmatter, (0, session_events_1.capStructuredRecordString)(args.body ?? ""));
402
+ fs.mkdirSync(awaitingDir(agentRoot), { recursive: true });
403
+ try {
404
+ fs.writeFileSync(filePath, rendered, "utf-8");
405
+ }
406
+ catch (error) {
407
+ if (obligationId)
408
+ (0, obligations_1.fulfillObligation)(agentRoot, obligationId);
409
+ throw error;
410
+ }
411
+ (0, runtime_1.emitNervesEvent)({
412
+ component: "repertoire",
413
+ event: "repertoire.await_filed",
414
+ message: "filed new await",
415
+ meta: { agent: agentName, name: args.name, cadence: args.cadence, alert },
416
+ });
417
+ return JSON.stringify({ filed: args.name, path: filePath });
418
+ }
419
+ function archiveAwait(agentRoot, name, updates) {
420
+ const source = awaitFilePath(agentRoot, name);
421
+ /* v8 ignore start -- defensive: callers (resolve/cancel) already verify the file exists via readAwaitDefinition; this guards the file-disappears-between-calls race @preserve */
422
+ if (!fs.existsSync(source)) {
423
+ return { ok: false, error: `await "${name}" not found in awaiting/` };
424
+ }
425
+ /* v8 ignore stop */
426
+ const content = fs.readFileSync(source, "utf-8");
427
+ const current = (0, await_parser_1.parseAwaitFile)(content, source);
428
+ // merge frontmatter from the parsed file with updates
429
+ const merged = {
430
+ condition: current.condition,
431
+ cadence: current.cadence,
432
+ alert: current.alert,
433
+ mode: current.mode,
434
+ max_age: current.max_age,
435
+ wake_at: current.wake_at ?? null,
436
+ status: current.status,
437
+ created_at: current.created_at,
438
+ filed_from: current.filed_from,
439
+ filed_for_friend_id: current.filed_for_friend_id,
440
+ filed_from_key: current.filed_from_key,
441
+ request_id: current.request_id,
442
+ obligation_id: current.obligation_id,
443
+ ...updates,
444
+ };
445
+ const cappedMerged = Object.fromEntries(Object.entries(merged).map(([key, value]) => [
446
+ key,
447
+ typeof value === "string" ? (0, session_events_1.capStructuredRecordString)(value) : value,
448
+ ]));
449
+ const rendered = (0, await_parser_1.renderAwaitFile)(cappedMerged, (0, session_events_1.capStructuredRecordString)(current.body));
450
+ fs.mkdirSync(awaitingDoneDir(agentRoot), { recursive: true });
451
+ fs.writeFileSync(awaitDoneFilePath(agentRoot, name), rendered, "utf-8");
452
+ fs.unlinkSync(source);
453
+ // re-parse the archived file so callers see merged fields (e.g. resolution_observation)
454
+ const archivedContent = fs.readFileSync(awaitDoneFilePath(agentRoot, name), "utf-8");
455
+ const archived = (0, await_parser_1.parseAwaitFile)(archivedContent, awaitDoneFilePath(agentRoot, name));
456
+ return { ok: true, file: archived };
457
+ }
458
+ function fulfillAwaitObligation(agentRoot, awaitFile) {
459
+ if (awaitFile.obligation_id)
460
+ (0, obligations_1.fulfillObligation)(agentRoot, awaitFile.obligation_id);
461
+ }
462
+ /** The package-managed daily sweep must stay a byte-exact pending file in awaiting/, so it can only ever be resolved 'no'. */
463
+ exports.HOUSE_CARE_AWAIT = "house-care-sweep";
464
+ const isHouseCareAwait = (name) => String(name ?? "").replace(/\.md$/u, "") === exports.HOUSE_CARE_AWAIT;
465
+ async function resolveAwaitTool(name, verdict, observation, agentRoot, agentName, ask) {
466
+ const nameError = validateName(name);
467
+ if (nameError)
468
+ return JSON.stringify({ error: nameError });
469
+ const existing = readAwaitDefinition(agentRoot, name);
470
+ if (!existing) {
471
+ if (verdict === "ask_owner" && readAwaitDoneDefinition(agentRoot, name)?.status === "asked_owner") {
472
+ return JSON.stringify({ error: `await "${name}" has already asked the owner and is closed; wait for the owner's reply instead of asking again` });
473
+ }
474
+ return JSON.stringify({ error: `await "${name}" not found in awaiting/` });
475
+ }
476
+ if (existing.status !== "pending") {
477
+ return JSON.stringify({ error: `await "${name}" is not pending (status: ${existing.status})` });
478
+ }
479
+ if (verdict !== "yes" && verdict !== "no" && verdict !== "ask_owner") {
480
+ return JSON.stringify({ error: `verdict must be exactly "yes", "no", or "ask_owner" (got ${JSON.stringify(verdict)}); use "no" with an observation while still waiting` });
481
+ }
482
+ if (!observation || !observation.trim()) {
483
+ return JSON.stringify({ error: "observation is required" });
484
+ }
485
+ if (verdict === "ask_owner")
486
+ return askOwnerTool(name, observation, ask?.question, ask?.choices, existing, agentRoot, agentName);
487
+ if (verdict === "no") {
488
+ // Update runtime state via recordAwaitCheck-style write
489
+ const { recordAwaitCheck } = await Promise.resolve().then(() => __importStar(require("../heart/awaiting/await-runtime-state")));
490
+ recordAwaitCheck(agentRoot, name, observation.trim(), new Date().toISOString());
491
+ (0, runtime_1.emitNervesEvent)({
492
+ component: "repertoire",
493
+ event: "repertoire.await_check_no",
494
+ message: "await checked, not yet ready",
495
+ meta: { agent: agentName, name },
496
+ });
497
+ return JSON.stringify({ verdict: "no", recorded: true });
498
+ }
499
+ // Request-bound returns stay active through Telegram prepare/send authorization.
500
+ let alert = null;
501
+ if (existing.request_id && existing.filed_from !== "external-event") {
502
+ try {
503
+ alert = await (0, await_alert_1.deliverAwaitAlert)({ awaitFile: existing, reason: "resolved", observation: observation.trim(), agentRoot, agentName, deliveryDeps: resolveDeliveryDeps(agentName) });
504
+ }
505
+ catch (error) {
506
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "repertoire", event: "repertoire.await_alert_error", message: "await alert delivery threw", meta: { agent: agentName, name, error: error instanceof Error ? error.message : String(error) } });
507
+ }
508
+ if (alert?.delivery?.status !== "delivered_now") {
509
+ return JSON.stringify({ verdict: "yes", archived: null, alert: alert ? { attempted: alert.attempted, status: alert.delivery?.status ?? null, skipped: alert.skipped ?? null } : null, advancedExternalEvents: [] });
510
+ }
511
+ }
512
+ const advancedEvents = existing.filed_from === "external-event" && existing.filed_from_key && existing.wake_at
513
+ ? (() => {
514
+ if (!hasActiveExternalEventAwait(agentName, { recordPath: existing.filed_from_key, awaitName: name, wakeAt: existing.wake_at }))
515
+ throw new Error("External event await authority changed before resolution");
516
+ const record = (0, router_1.readExternalEventRecord)(existing.filed_from_key);
517
+ if (record.agent !== agentName || record.recordPath !== existing.filed_from_key || record.executionState !== "handled"
518
+ || record.disposition?.awaitId !== name || record.disposition.nextWake.kind !== "at" || record.disposition.nextWake.at !== existing.wake_at) {
519
+ throw new Error("External event await authority changed before resolution");
520
+ }
521
+ return [(0, router_1.advanceExternalEventFromAwait)(record.recordPath, { awaitId: name, expectedVersion: record.version, expectedGeneration: record.generation })];
522
+ })()
523
+ : [];
524
+ const archive = archiveAwait(agentRoot, name, {
525
+ status: "resolved",
526
+ resolved_at: new Date().toISOString(),
527
+ resolution_observation: observation.trim(),
528
+ });
529
+ /* v8 ignore next -- defensive: archiveAwait only fails on the file-disappears-mid-call race already covered by v8 ignore inside archiveAwait @preserve */
530
+ if (!archive.ok)
531
+ return JSON.stringify({ error: archive.error });
532
+ fulfillAwaitObligation(agentRoot, archive.file);
533
+ (0, runtime_1.emitNervesEvent)({
534
+ component: "repertoire",
535
+ event: "repertoire.await_resolved",
536
+ message: "await resolved",
537
+ meta: { agent: agentName, name },
538
+ });
539
+ if (!existing.request_id) {
540
+ try {
541
+ alert = await (0, await_alert_1.deliverAwaitAlert)({ awaitFile: archive.file, reason: "resolved", observation: observation.trim(), agentRoot, agentName, deliveryDeps: resolveDeliveryDeps(agentName) });
542
+ }
543
+ catch (error) {
544
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "repertoire", event: "repertoire.await_alert_error", message: "await alert delivery threw", meta: { agent: agentName, name, error: error instanceof Error ? error.message : String(error) } });
545
+ }
546
+ }
547
+ return JSON.stringify({
548
+ verdict: "yes",
549
+ archived: awaitDoneFilePath(agentRoot, name),
550
+ alert: alert ? { attempted: alert.attempted, status: alert.delivery?.status ?? null, skipped: alert.skipped ?? null } : null,
551
+ advancedExternalEvents: advancedEvents.map((event) => event.recordPath),
552
+ });
553
+ }
554
+ function cancelAwaitTool(name, reason, agentRoot, agentName) {
555
+ const nameError = validateName(name);
556
+ if (nameError)
557
+ return JSON.stringify({ error: nameError });
558
+ const existing = readAwaitDefinition(agentRoot, name);
559
+ if (!existing) {
560
+ return JSON.stringify({ error: `await "${name}" not found in awaiting/` });
561
+ }
562
+ if (existing.status !== "pending") {
563
+ return JSON.stringify({ error: `await "${name}" is not pending (status: ${existing.status})` });
564
+ }
565
+ const updates = {
566
+ status: "canceled",
567
+ canceled_at: new Date().toISOString(),
568
+ };
569
+ if (reason && reason.trim()) {
570
+ updates.cancel_reason = reason.trim();
571
+ }
572
+ const archive = archiveAwait(agentRoot, name, updates);
573
+ /* v8 ignore next -- defensive: archiveAwait only fails on the file-disappears-mid-call race already covered by v8 ignore inside archiveAwait @preserve */
574
+ if (!archive.ok)
575
+ return JSON.stringify({ error: archive.error });
576
+ fulfillAwaitObligation(agentRoot, archive.file);
577
+ (0, runtime_1.emitNervesEvent)({
578
+ component: "repertoire",
579
+ event: "repertoire.await_canceled",
580
+ message: "await canceled",
581
+ meta: { agent: agentName, name },
582
+ });
583
+ return JSON.stringify({ canceled: name, archived: awaitDoneFilePath(agentRoot, name) });
584
+ }
585
+ function exactFileIsMissing(filePath) {
586
+ try {
587
+ fs.lstatSync(filePath);
588
+ return false;
589
+ }
590
+ catch (error) {
591
+ if (error.code === "ENOENT")
592
+ return true;
593
+ throw error;
594
+ }
595
+ }
596
+ function cancelStaleAwait(agentRoot, agentName, name, reason) {
597
+ const result = JSON.parse(cancelAwaitTool(name, reason, agentRoot, agentName));
598
+ if (result.canceled !== name)
599
+ throw new Error(`Stale await could not be archived for repair: ${result.error ?? name}`);
600
+ }
601
+ /** Binding losses that mean the await is broken, as opposed to finished (fulfilled, expired). */
602
+ function isBrokenBindingReason(reason) {
603
+ return reason === "request obligation is missing" || reason === "request obligation binding no longer matches";
604
+ }
605
+ /**
606
+ * An await that can never run is ended, not retried: archived as canceled with the reason, logged as an error, and
607
+ * the private runtime is told once that the follow-up it promised will not happen. Without this the await stayed
608
+ * pending and every scheduled wake failed again, silently, for days.
609
+ */
610
+ function failBrokenAwait(agentRoot, agentName, awaitName, reason) {
611
+ cancelStaleAwait(agentRoot, agentName, awaitName, reason);
612
+ (0, runtime_1.emitNervesEvent)({
613
+ level: "error",
614
+ component: "senses",
615
+ event: "senses.relationship_await_failed",
616
+ message: "relationship await could not run and was canceled",
617
+ meta: { agentName, awaitName, reason },
618
+ });
619
+ (0, pending_1.queuePendingMessageOnce)((0, pending_1.getPrivateRuntimePendingDir)(agentName), {
620
+ from: agentName,
621
+ friendId: "self",
622
+ channel: "inner",
623
+ key: "dialog",
624
+ content: `my await "${awaitName}" was canceled because it could not run (${reason}). the follow-up it promised did not happen; i should tell my owner and decide whether to file it again.`,
625
+ timestamp: Date.now(),
626
+ packetId: `await-failed:${awaitName}`,
627
+ });
628
+ }
629
+ function inspectRelationshipFollowUp(agentRoot, input) {
630
+ const awaiting = readAwaitDefinition(agentRoot, input.awaitName);
631
+ if (!awaiting)
632
+ throw new Error(`Await ${input.awaitName} could not be verified`);
633
+ if (!awaiting.obligation_id)
634
+ return { active: false, reason: "request obligation is missing" };
635
+ const obligationPath = path.join(agentRoot, "arc", "obligations", `${awaiting.obligation_id}.json`);
636
+ const obligation = (0, obligations_1.readVerifiedObligations)(agentRoot).find((candidate) => candidate.id === awaiting.obligation_id);
637
+ if (!obligation) {
638
+ if (exactFileIsMissing(obligationPath))
639
+ return { active: false, reason: "request obligation is missing" };
640
+ throw new Error(`Request obligation ${awaiting.obligation_id} exists but could not be verified`);
641
+ }
642
+ if (obligation.status === "fulfilled")
643
+ return { active: false, reason: "request obligation is no longer active" };
644
+ const matches = obligation.requestId === input.requestId
645
+ && obligation.origin.friendId === input.friendId && obligation.origin.channel === input.channel && obligation.origin.key === input.key
646
+ && obligation.owedTo?.friendId === input.friendId && obligation.owedTo.channel === input.channel && obligation.owedTo.key === input.key
647
+ && obligation.currentArtifact === `awaiting/${input.awaitName}.md`
648
+ && awaiting.status === "pending" && awaiting.obligation_id === obligation.id && awaiting.request_id === input.requestId
649
+ && awaiting.filed_for_friend_id === input.friendId && awaiting.filed_from === input.channel && awaiting.filed_from_key === input.key;
650
+ if (!matches)
651
+ return { active: false, reason: "request obligation binding no longer matches" };
652
+ const maxAge = (0, cadence_1.parseCadenceToMs)(awaiting.max_age);
653
+ if (input.allowElapsed !== true && maxAge !== null && awaiting.created_at && (input.now ?? Date.now()) >= Date.parse(awaiting.created_at) + maxAge) {
654
+ return { active: false, reason: "request obligation await expired" };
655
+ }
656
+ return { active: true };
657
+ }
658
+ /**
659
+ * The binding of an await filed in a plain A2A conversation: it has no request id and no obligation, only the peer's friend
660
+ * id and conversation key as provenance. It is live while it is still pending, was filed by that peer in that conversation,
661
+ * and has not outlived its max age.
662
+ */
663
+ function inspectPeerAwait(agentRoot, input) {
664
+ const awaiting = readAwaitDefinition(agentRoot, input.awaitName);
665
+ if (!awaiting)
666
+ throw new Error(`Await ${input.awaitName} could not be verified`);
667
+ const matches = awaiting.status === "pending" && !awaiting.request_id && !awaiting.obligation_id
668
+ && awaiting.filed_for_friend_id === input.friendId && awaiting.filed_from === "a2a" && awaiting.filed_from_key === input.key;
669
+ if (!matches)
670
+ return { active: false, reason: "request obligation binding no longer matches" };
671
+ const maxAge = (0, cadence_1.parseCadenceToMs)(awaiting.max_age);
672
+ if (input.allowElapsed !== true && maxAge !== null && awaiting.created_at && (input.now ?? Date.now()) >= Date.parse(awaiting.created_at) + maxAge) {
673
+ return { active: false, reason: "request obligation await expired" };
674
+ }
675
+ return { active: true };
676
+ }
677
+ function hasActiveRelationshipFollowUp(agentRoot, input) {
678
+ if (input.awaitName)
679
+ return inspectRelationshipFollowUp(agentRoot, { ...input, awaitName: input.awaitName }).active;
680
+ const obligation = (0, obligations_1.readVerifiedPendingObligations)(agentRoot).find((candidate) => candidate.requestId === input.requestId
681
+ && candidate.origin.friendId === input.friendId && candidate.origin.channel === input.channel && candidate.origin.key === input.key
682
+ && candidate.owedTo?.friendId === input.friendId && candidate.owedTo.channel === input.channel && candidate.owedTo.key === input.key
683
+ && candidate.currentArtifact?.startsWith("awaiting/") && candidate.currentArtifact.endsWith(".md")
684
+ && (!input.awaitName || candidate.currentArtifact === `awaiting/${input.awaitName}.md`));
685
+ if (!obligation)
686
+ return false;
687
+ const name = path.basename(obligation.currentArtifact, ".md");
688
+ if (!VALID_NAME.test(name) || obligation.currentArtifact !== `awaiting/${name}.md`)
689
+ return false;
690
+ const awaiting = readAwaitDefinition(agentRoot, name);
691
+ if (!awaiting || awaiting.status !== "pending" || awaiting.obligation_id !== obligation.id || awaiting.request_id !== input.requestId
692
+ || awaiting.filed_for_friend_id !== input.friendId || awaiting.filed_from !== input.channel || awaiting.filed_from_key !== input.key)
693
+ return false;
694
+ const maxAge = (0, cadence_1.parseCadenceToMs)(awaiting.max_age);
695
+ return input.allowElapsed === true || maxAge === null || !awaiting.created_at || (input.now ?? Date.now()) < Date.parse(awaiting.created_at) + maxAge;
696
+ }
697
+ function hasActiveExternalEventAwait(agentName, input, root = (0, router_1.getExternalEventRoot)()) {
698
+ return inspectExternalEventAwait(agentName, input, root).active;
699
+ }
700
+ function inspectExternalEventAwait(agentName, input, root = (0, router_1.getExternalEventRoot)()) {
701
+ const relative = path.relative(path.resolve(root), path.resolve(input.recordPath));
702
+ if (relative.startsWith("..") || path.isAbsolute(relative))
703
+ throw new Error("External event await record is outside the event root");
704
+ let record;
705
+ try {
706
+ record = (0, router_1.readExternalEventRecord)(input.recordPath);
707
+ }
708
+ catch (error) {
709
+ if (error.code === "ENOENT")
710
+ return { active: false, reason: "external event disposition is missing" };
711
+ throw error;
712
+ }
713
+ const active = record.agent === agentName && record.recordPath === input.recordPath && record.executionState === "handled"
714
+ && record.disposition?.awaitId === input.awaitName && record.disposition.nextWake.kind === "at" && record.disposition.nextWake.at === input.wakeAt;
715
+ return active ? { active: true } : { active: false, reason: "external event disposition is no longer active" };
716
+ }
717
+ function cancelRelationshipFollowUps(agentRoot, agentName, input) {
718
+ const obligations = (0, obligations_1.readVerifiedPendingObligations)(agentRoot).filter((candidate) => candidate.owedTo?.friendId === input.friendId
719
+ && candidate.owedTo.channel === input.channel && candidate.owedTo.key === input.key);
720
+ for (const obligation of obligations) {
721
+ const artifact = obligation.currentArtifact;
722
+ const name = artifact?.startsWith("awaiting/") && artifact.endsWith(".md") ? path.basename(artifact, ".md") : null;
723
+ if (name && VALID_NAME.test(name) && artifact === `awaiting/${name}.md` && readAwaitDefinition(agentRoot, name)) {
724
+ cancelAwaitTool(name, "relationship revoked", agentRoot, agentName);
725
+ }
726
+ else {
727
+ (0, obligations_1.fulfillObligation)(agentRoot, obligation.id);
728
+ }
729
+ }
730
+ }
731
+ exports.awaitingToolDefinitions = [
732
+ {
733
+ tool: {
734
+ type: "function",
735
+ function: {
736
+ name: "await_condition",
737
+ description: "File a one-shot waiting condition. The daemon polls on cadence; on each tick I evaluate the condition and call resolve_await. When the condition becomes true, an alert fires via my outward channel.",
738
+ parameters: {
739
+ type: "object",
740
+ properties: {
741
+ name: { type: "string", description: "Filename stem (alphanumeric/underscore/hyphen). Must be unique." },
742
+ condition: { type: "string", description: "Natural-language condition to watch for." },
743
+ cadence: { type: "string", description: "Polling cadence (e.g. '5m', '1h')." },
744
+ alert: { type: "string", description: "Channel to alert on (e.g. 'bluebubbles', 'teams'). Defaults to filing session's channel." },
745
+ mode: { type: "string", description: "'full' or 'quick'. Defaults 'full'." },
746
+ max_age: { type: "string", description: "Optional auto-expiry (e.g. '24h')." },
747
+ wake_at: { type: "string", description: "Optional exact canonical ISO time this Await supports." },
748
+ body: { type: "string", description: "Optional notes: why I filed this, what 'ready' looks like." },
749
+ },
750
+ required: ["name", "condition", "cadence"],
751
+ },
752
+ },
753
+ },
754
+ handler: (a, ctx) => {
755
+ const agentRoot = (0, identity_1.getAgentRoot)();
756
+ const agentName = (0, identity_1.getAgentName)();
757
+ const event = ctx?.currentExternalEvent;
758
+ const eventFriendId = event ? ctx?.context?.friend.id ?? null : null;
759
+ if (event && !eventFriendId)
760
+ return JSON.stringify({ error: "external event await authority has no exact owner relationship" });
761
+ return fileAwait({
762
+ name: a.name,
763
+ condition: a.condition,
764
+ cadence: a.cadence,
765
+ alert: a.alert,
766
+ mode: a.mode,
767
+ max_age: a.max_age,
768
+ wake_at: a.wake_at,
769
+ body: a.body,
770
+ }, agentRoot, agentName, eventFriendId ?? ctx?.currentSession?.friendId ?? null, event ? "external-event" : ctx?.currentSession?.channel ?? null, event ? event.recordPath : ctx?.currentSession?.key ?? null, event ? null : ctx?.relationshipAuthorization?.requestId ?? null);
771
+ },
772
+ riskProfile: { mutates: "durable_state_write", risk: "high", reason: "files a durable await condition" },
773
+ },
774
+ {
775
+ tool: {
776
+ type: "function",
777
+ function: {
778
+ name: "resolve_await",
779
+ description: "Resolve a pending await with a verdict. verdict='yes' archives and fires the alert. verdict='no' records the observation and continues polling; still pending is always 'no'. verdict='ask_owner' (with question and choices) closes the await and asks my owner to decide, exactly once: use it when the condition cannot be met without the owner deciding, for example a confirmed dead download. Never use ask_owner for \"not yet\" or a merely suspected problem; that is 'no'.",
780
+ parameters: {
781
+ type: "object",
782
+ properties: {
783
+ name: { type: "string", description: "Await name (filename stem)." },
784
+ verdict: { type: "string", enum: ["yes", "no", "ask_owner"], description: "Exactly 'yes' if the condition is met. Exactly 'no' for anything else, including still pending, not yet, or unable to tell: send 'no' with an observation and polling continues. 'ask_owner' only when the condition cannot be met without the owner deciding; it needs question and choices." },
785
+ observation: { type: "string", description: "One-line summary of what I saw this tick." },
786
+ question: { type: "string", description: "Only for ask_owner: the decision I need from my owner, in plain words." },
787
+ choices: { type: "array", items: { type: "string" }, minItems: 2, maxItems: 4, description: "Only for ask_owner: 2 to 4 short options the owner can pick from." },
788
+ },
789
+ required: ["name", "verdict", "observation"],
790
+ },
791
+ },
792
+ },
793
+ handler: async (a, ctx) => {
794
+ const agentRoot = (0, identity_1.getAgentRoot)();
795
+ const agentName = (0, identity_1.getAgentName)();
796
+ if (isHouseCareAwait(a.name) && a.verdict !== "no")
797
+ return JSON.stringify({ error: `${exports.HOUSE_CARE_AWAIT} is the package-managed daily house-care sweep and never resolves: finish every tick with verdict 'no' and a one-line observation, and send any owner digest with house_digest_send` });
798
+ if (ctx?.relationshipAuthorization) {
799
+ const awaitName = String(a.name ?? "");
800
+ const { session, requestId } = relationshipScopeFor(ctx, awaitName);
801
+ const existing = readAwaitDefinition(agentRoot, awaitName);
802
+ let binding = null;
803
+ if (session?.channel === "external-event" && existing?.wake_at) {
804
+ binding = inspectExternalEventAwait(agentName, { recordPath: session.key, awaitName, wakeAt: existing.wake_at });
805
+ }
806
+ else if (session?.channel === "a2a" && ctx.awaitTick && !requestId && existing && !existing.request_id
807
+ && existing.filed_for_friend_id === session.friendId && existing.filed_from === "a2a" && existing.filed_from_key === session.key) {
808
+ // A plain peer await is resolved only by its own tick, never from a chat turn.
809
+ binding = inspectPeerAwait(agentRoot, { friendId: session.friendId, key: session.key, awaitName });
810
+ }
811
+ else if (session && requestId) {
812
+ if (existing?.filed_for_friend_id !== session.friendId || existing.filed_from !== session.channel
813
+ || existing.filed_from_key !== session.key || existing.request_id !== requestId) {
814
+ return JSON.stringify({ error: "resolve_await is limited to the current relationship request or bound external event" });
815
+ }
816
+ binding = inspectRelationshipFollowUp(agentRoot, { friendId: session.friendId, channel: session.channel, key: session.key, requestId, awaitName });
817
+ }
818
+ if (binding && !binding.active) {
819
+ if (isBrokenBindingReason(binding.reason))
820
+ failBrokenAwait(agentRoot, agentName, awaitName, binding.reason);
821
+ else
822
+ cancelStaleAwait(agentRoot, agentName, awaitName, binding.reason);
823
+ return JSON.stringify({ error: binding.reason });
824
+ }
825
+ if (!binding?.active)
826
+ return JSON.stringify({ error: "resolve_await is limited to the current relationship request or bound external event" });
827
+ }
828
+ return resolveAwaitTool(a.name, a.verdict, a.observation, agentRoot, agentName, { question: a.question, choices: a.choices });
829
+ },
830
+ riskProfile: {
831
+ mutates: ["durable_state_write", "external_side_effect"],
832
+ risk: "high",
833
+ reason: "records await observations and may deliver an alert",
834
+ },
835
+ },
836
+ {
837
+ tool: {
838
+ type: "function",
839
+ function: {
840
+ name: "cancel_await",
841
+ description: "Cancel a pending await without alerting. Archives with status: canceled.",
842
+ parameters: {
843
+ type: "object",
844
+ properties: {
845
+ name: { type: "string", description: "Await name (filename stem)." },
846
+ reason: { type: "string", description: "Optional cancel reason." },
847
+ },
848
+ required: ["name"],
849
+ },
850
+ },
851
+ },
852
+ handler: (a, ctx) => {
853
+ const agentRoot = (0, identity_1.getAgentRoot)();
854
+ const agentName = (0, identity_1.getAgentName)();
855
+ if (isHouseCareAwait(a.name))
856
+ return JSON.stringify({ error: `${exports.HOUSE_CARE_AWAIT} is the package-managed daily house-care sweep and cannot be cancelled` });
857
+ if (ctx?.relationshipAuthorization) {
858
+ const { session, requestId } = relationshipScopeFor(ctx, String(a.name ?? ""));
859
+ if (!session || !requestId || !hasActiveRelationshipFollowUp(agentRoot, {
860
+ friendId: session.friendId,
861
+ channel: session.channel,
862
+ key: session.key,
863
+ requestId,
864
+ awaitName: String(a.name ?? ""),
865
+ }))
866
+ return JSON.stringify({ error: "cancel_await is limited to the current relationship request" });
867
+ }
868
+ return cancelAwaitTool(a.name, a.reason, agentRoot, agentName);
869
+ },
870
+ riskProfile: { mutates: "durable_state_write", risk: "high", reason: "archives a durable await condition" },
871
+ },
872
+ ];