@ouro.bot/cli 0.1.0-alpha.80 → 0.1.0-alpha.801

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 (613) 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/changelog.json +5123 -16
  15. package/deploy/unraid/Dockerfile +48 -0
  16. package/deploy/unraid/README.txt +3012 -0
  17. package/deploy/unraid/audit-container-spec.sh +4 -0
  18. package/deploy/unraid/container-runtime.json +1 -0
  19. package/deploy/unraid/docker-man-template-transaction.mjs +526 -0
  20. package/deploy/unraid/docker-man-template-xml.cjs +105 -0
  21. package/deploy/unraid/migrate-sanctuary-bundle.mjs +60 -0
  22. package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
  23. package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
  24. package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
  25. package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
  26. package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
  27. package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
  28. package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
  29. package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
  30. package/deploy/unraid/sanctuary-deployment-target.mjs +709 -0
  31. package/deploy/unraid/sanctuary-safe-rename.py +24 -0
  32. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2030 -0
  33. package/deploy/unraid/sanctuary-unit16-run.sh +560 -0
  34. package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
  35. package/deploy/unraid/sanctuary.ouro/agent.json +24 -0
  36. package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
  37. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
  38. package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
  39. package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
  40. package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
  41. package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +5 -0
  42. package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +11 -0
  43. package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +25 -0
  44. package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +11 -0
  45. package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
  46. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +23 -0
  47. package/deploy/unraid/sanctuary.xml +27 -0
  48. package/dist/a2a/card.js +57 -0
  49. package/dist/a2a/client.js +180 -0
  50. package/dist/a2a/config.js +50 -0
  51. package/dist/a2a/delegation-stores.js +56 -0
  52. package/dist/a2a/did-resolution.js +93 -0
  53. package/dist/a2a/identity.js +170 -0
  54. package/dist/a2a/inbound-share.js +107 -0
  55. package/dist/a2a/mission-result-wire.js +196 -0
  56. package/dist/a2a/onboarding.js +115 -0
  57. package/dist/a2a/pin-store.js +132 -0
  58. package/dist/a2a/seen-ledger.js +120 -0
  59. package/dist/a2a/server.js +604 -0
  60. package/dist/a2a/task-store.js +69 -0
  61. package/dist/a2a/transport.js +45 -0
  62. package/dist/a2a/types.js +3 -0
  63. package/dist/arc/attention-types.js +8 -0
  64. package/dist/arc/cares.js +360 -0
  65. package/dist/arc/episodes.js +118 -0
  66. package/dist/arc/evolution.js +490 -0
  67. package/dist/arc/flight-recorder.js +1034 -0
  68. package/dist/arc/intentions.js +134 -0
  69. package/dist/arc/json-store.js +117 -0
  70. package/dist/arc/obligations.js +386 -0
  71. package/dist/arc/packets.js +336 -0
  72. package/dist/arc/presence.js +185 -0
  73. package/dist/arc/task-lifecycle.js +57 -0
  74. package/dist/commerce/store.js +755 -0
  75. package/dist/commerce/types.js +3 -0
  76. package/dist/heart/active-work.js +820 -29
  77. package/dist/heart/agent-entry.js +252 -3
  78. package/dist/heart/approval-files.js +113 -0
  79. package/dist/heart/approval-store.js +950 -0
  80. package/dist/heart/attachments/image-normalize.js +194 -0
  81. package/dist/heart/attachments/materialize.js +97 -0
  82. package/dist/heart/attachments/originals.js +88 -0
  83. package/dist/heart/attachments/render.js +29 -0
  84. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  85. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  86. package/dist/heart/attachments/sources/index.js +18 -0
  87. package/dist/heart/attachments/sources/telegram.js +71 -0
  88. package/dist/heart/attachments/store.js +132 -0
  89. package/dist/heart/attachments/types.js +93 -0
  90. package/dist/heart/auth/auth-flow.js +495 -0
  91. package/dist/heart/autonomy-budget.js +478 -0
  92. package/dist/heart/awaiting/await-alert.js +148 -0
  93. package/dist/heart/awaiting/await-expiry.js +143 -0
  94. package/dist/heart/awaiting/await-loader.js +91 -0
  95. package/dist/heart/awaiting/await-parser.js +149 -0
  96. package/dist/heart/awaiting/await-runtime-state.js +100 -0
  97. package/dist/heart/awaiting/await-scheduler.js +382 -0
  98. package/dist/heart/background-operations.js +281 -0
  99. package/dist/heart/bridges/manager.js +137 -17
  100. package/dist/heart/bridges/store.js +14 -2
  101. package/dist/heart/bundle-state.js +168 -0
  102. package/dist/heart/commitments.js +64 -18
  103. package/dist/heart/config-registry.js +331 -0
  104. package/dist/heart/config.js +142 -129
  105. package/dist/heart/context-loss-gauntlet.js +387 -0
  106. package/dist/heart/context-loss-sentinel.js +1157 -0
  107. package/dist/heart/core.js +2132 -572
  108. package/dist/heart/cross-chat-delivery.js +9 -22
  109. package/dist/heart/daemon/agent-config-check.js +451 -0
  110. package/dist/heart/daemon/agent-discovery.js +185 -3
  111. package/dist/heart/daemon/agent-service.js +542 -0
  112. package/dist/heart/daemon/agentic-repair.js +547 -0
  113. package/dist/heart/daemon/await-private-wake.js +59 -0
  114. package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
  115. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  116. package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
  117. package/dist/heart/daemon/bluebubbles-host.js +273 -0
  118. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  119. package/dist/heart/daemon/cadence.js +180 -0
  120. package/dist/heart/daemon/cli-defaults.js +836 -0
  121. package/dist/heart/daemon/cli-desk.js +322 -0
  122. package/dist/heart/daemon/cli-exec.js +8730 -0
  123. package/dist/heart/daemon/cli-help.js +710 -0
  124. package/dist/heart/daemon/cli-parse.js +2719 -0
  125. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  126. package/dist/heart/daemon/cli-render.js +777 -0
  127. package/dist/heart/daemon/cli-types.js +8 -0
  128. package/dist/heart/daemon/connect-bay.js +323 -0
  129. package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
  130. package/dist/heart/daemon/container-healthcheck.js +112 -0
  131. package/dist/heart/daemon/container-runtime.js +97 -0
  132. package/dist/heart/daemon/container-spec-auditor-main.js +170 -0
  133. package/dist/heart/daemon/container-spec-auditor.js +236 -0
  134. package/dist/heart/daemon/daemon-bootstrap-startup.js +107 -0
  135. package/dist/heart/daemon/daemon-cli.js +29 -2284
  136. package/dist/heart/daemon/daemon-entry.js +920 -11
  137. package/dist/heart/daemon/daemon-health.js +186 -0
  138. package/dist/heart/daemon/daemon-rollup.js +57 -0
  139. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  140. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  141. package/dist/heart/daemon/daemon.js +2010 -88
  142. package/dist/heart/daemon/dns-workflow.js +394 -0
  143. package/dist/heart/daemon/doctor-types.js +8 -0
  144. package/dist/heart/daemon/doctor.js +1755 -0
  145. package/dist/heart/daemon/freshness.js +345 -0
  146. package/dist/heart/daemon/habit-private-wake.js +61 -0
  147. package/dist/heart/daemon/health-monitor.js +142 -11
  148. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  149. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  150. package/dist/heart/daemon/http-health-probe.js +80 -0
  151. package/dist/heart/daemon/human-command-screens.js +234 -0
  152. package/dist/heart/daemon/human-readiness.js +114 -0
  153. package/dist/heart/daemon/inner-status.js +78 -0
  154. package/dist/heart/daemon/interactive-repair.js +394 -0
  155. package/dist/heart/daemon/launchd.js +37 -8
  156. package/dist/heart/daemon/log-tailer.js +79 -10
  157. package/dist/heart/daemon/logs-prune.js +132 -0
  158. package/dist/heart/daemon/mcp-canary.js +524 -0
  159. package/dist/heart/daemon/message-router.js +65 -5
  160. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  161. package/dist/heart/daemon/os-cron-deps.js +135 -0
  162. package/dist/heart/daemon/os-cron.js +22 -14
  163. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  164. package/dist/heart/daemon/ouro-entry.js +3 -1
  165. package/dist/heart/daemon/plugin-cli.js +432 -0
  166. package/dist/heart/daemon/process-manager.js +733 -61
  167. package/dist/heart/daemon/provider-discovery.js +137 -0
  168. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  169. package/dist/heart/daemon/prunable-bundle.js +144 -0
  170. package/dist/heart/daemon/pulse.js +511 -0
  171. package/dist/heart/daemon/readiness-repair.js +365 -0
  172. package/dist/heart/daemon/run-hooks.js +2 -0
  173. package/dist/heart/daemon/runtime-logging.js +47 -14
  174. package/dist/heart/daemon/runtime-metadata.js +2 -30
  175. package/dist/heart/daemon/runtime-mode.js +13 -2
  176. package/dist/heart/daemon/safe-mode.js +161 -0
  177. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2609 -0
  178. package/dist/heart/daemon/sanctuary-acceptance-harness.js +1866 -0
  179. package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
  180. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +976 -0
  181. package/dist/heart/daemon/sanctuary-bundle-migration.js +728 -0
  182. package/dist/heart/daemon/sanctuary-package-management.js +103 -0
  183. package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
  184. package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
  185. package/dist/heart/daemon/sense-manager.js +689 -48
  186. package/dist/heart/daemon/session-id-resolver.js +131 -0
  187. package/dist/heart/daemon/skill-management-installer.js +1 -1
  188. package/dist/heart/daemon/socket-client.js +180 -12
  189. package/dist/heart/daemon/stale-bundle-prune.js +113 -0
  190. package/dist/heart/daemon/startup-tui.js +339 -0
  191. package/dist/heart/daemon/supercronic-supervisor.js +282 -0
  192. package/dist/heart/daemon/task-scheduler.js +117 -39
  193. package/dist/heart/daemon/terminal-ui.js +499 -0
  194. package/dist/heart/daemon/thoughts.js +138 -54
  195. package/dist/heart/daemon/up-progress.js +366 -0
  196. package/dist/heart/daemon/vault-items.js +56 -0
  197. package/dist/heart/delegation.js +1 -4
  198. package/dist/heart/external-events/router.js +1414 -0
  199. package/dist/heart/habits/habit-cancel.js +810 -0
  200. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  201. package/dist/heart/habits/habit-migration.js +194 -0
  202. package/dist/heart/habits/habit-parser.js +278 -0
  203. package/dist/heart/habits/habit-runtime-state.js +93 -0
  204. package/dist/heart/habits/habit-scheduler.js +653 -0
  205. package/dist/heart/habits/habit-session-summary.js +318 -0
  206. package/dist/heart/habits/habit-session.js +636 -0
  207. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
  208. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  209. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  210. package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
  211. package/dist/heart/identity.js +184 -59
  212. package/dist/heart/kept-notes.js +289 -0
  213. package/dist/heart/kicks.js +1 -1
  214. package/dist/heart/machine-identity.js +161 -0
  215. package/dist/heart/mail-import-discovery.js +353 -0
  216. package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
  217. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  218. package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
  219. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  220. package/dist/heart/mailbox/mailbox-http-transport.js +129 -0
  221. package/dist/heart/mailbox/mailbox-http.js +99 -0
  222. package/dist/heart/mailbox/mailbox-read.js +39 -0
  223. package/dist/heart/mailbox/mailbox-types.js +27 -0
  224. package/dist/heart/mailbox/mailbox-view.js +197 -0
  225. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  226. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  227. package/dist/heart/mailbox/readers/mail.js +375 -0
  228. package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
  229. package/dist/heart/mailbox/readers/sessions.js +232 -0
  230. package/dist/heart/mailbox/readers/shared.js +111 -0
  231. package/dist/heart/mcp/mcp-server.js +696 -0
  232. package/dist/heart/migrate-config.js +100 -0
  233. package/dist/heart/model-capabilities.js +11 -0
  234. package/dist/heart/orientation-frame.js +345 -0
  235. package/dist/heart/platform.js +81 -0
  236. package/dist/heart/primitives.js +1 -1
  237. package/dist/heart/private-runtime/decision-renderer.js +158 -0
  238. package/dist/heart/private-runtime/index.js +18 -0
  239. package/dist/heart/private-runtime/ledger.js +221 -0
  240. package/dist/heart/private-runtime/policy.js +252 -0
  241. package/dist/heart/private-runtime/types.js +2 -0
  242. package/dist/heart/progress-story.js +1 -1
  243. package/dist/heart/provider-attempt.js +137 -0
  244. package/dist/heart/provider-binding-resolver.js +273 -0
  245. package/dist/heart/provider-credentials.js +449 -0
  246. package/dist/heart/provider-failover.js +311 -0
  247. package/dist/heart/provider-models.js +96 -0
  248. package/dist/heart/provider-ping.js +265 -0
  249. package/dist/heart/provider-readiness-cache.js +119 -0
  250. package/dist/heart/provider-visibility.js +188 -0
  251. package/dist/heart/providers/anthropic-token.js +131 -0
  252. package/dist/heart/providers/anthropic.js +173 -60
  253. package/dist/heart/providers/azure.js +23 -11
  254. package/dist/heart/providers/error-classification.js +127 -0
  255. package/dist/heart/providers/github-copilot.js +34 -38
  256. package/dist/heart/providers/minimax-vlm.js +189 -0
  257. package/dist/heart/providers/minimax.js +26 -8
  258. package/dist/heart/providers/openai-codex-token.js +349 -0
  259. package/dist/heart/providers/openai-codex.js +55 -40
  260. package/dist/heart/providers/openai-compatible.js +177 -0
  261. package/dist/heart/run-ledger.js +247 -0
  262. package/dist/heart/runtime-capability-check.js +170 -0
  263. package/dist/heart/runtime-credentials.js +607 -0
  264. package/dist/heart/runtime-cwd.js +87 -0
  265. package/dist/heart/sense-truth.js +22 -4
  266. package/dist/heart/session-activity.js +90 -24
  267. package/dist/heart/session-events.js +1318 -0
  268. package/dist/heart/session-playback-cli-main.js +5 -0
  269. package/dist/heart/session-playback-cli.js +36 -0
  270. package/dist/heart/session-playback.js +231 -0
  271. package/dist/heart/session-stats-cli-main.js +5 -0
  272. package/dist/heart/session-stats.js +182 -0
  273. package/dist/heart/session-transcript.js +133 -0
  274. package/dist/heart/start-of-turn-packet.js +372 -0
  275. package/dist/heart/steward-policy.js +302 -0
  276. package/dist/heart/streaming.js +604 -207
  277. package/dist/heart/structured-output.js +196 -0
  278. package/dist/heart/sync-classification.js +176 -0
  279. package/dist/heart/sync.js +449 -0
  280. package/dist/heart/target-resolution.js +11 -7
  281. package/dist/heart/tempo.js +93 -0
  282. package/dist/heart/temporal-view.js +41 -0
  283. package/dist/heart/timeouts.js +101 -0
  284. package/dist/heart/tool-activity-callbacks.js +59 -0
  285. package/dist/heart/tool-approval.js +342 -0
  286. package/dist/heart/tool-description.js +155 -0
  287. package/dist/heart/tool-friction.js +55 -0
  288. package/dist/heart/tool-loop.js +200 -0
  289. package/dist/heart/turn-context.js +481 -0
  290. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  291. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  292. package/dist/heart/versioning/ouro-path-installer.js +432 -0
  293. package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
  294. package/dist/heart/versioning/ouro-version-manager.js +409 -0
  295. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  296. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  297. package/dist/heart/versioning/update-hooks.js +154 -0
  298. package/dist/heart/versioning/version-intent.js +114 -0
  299. package/dist/heart/work-card.js +380 -0
  300. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  301. package/dist/mailbox-ui/assets/index-J8zDwHmE.js +1 -0
  302. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  303. package/dist/mailbox-ui/index.html +16 -0
  304. package/dist/mailroom/attention.js +167 -0
  305. package/dist/mailroom/autonomy.js +209 -0
  306. package/dist/mailroom/blob-store.js +889 -0
  307. package/dist/mailroom/body-cache.js +61 -0
  308. package/dist/mailroom/cache-sync-cli.js +58 -0
  309. package/dist/mailroom/core.js +803 -0
  310. package/dist/mailroom/entry.js +160 -0
  311. package/dist/mailroom/file-store.js +568 -0
  312. package/dist/mailroom/hosted-cache-sync.js +384 -0
  313. package/dist/mailroom/mbox-import.js +393 -0
  314. package/dist/mailroom/migration.js +164 -0
  315. package/dist/mailroom/outbound.js +380 -0
  316. package/dist/mailroom/policy.js +263 -0
  317. package/dist/mailroom/reader.js +292 -0
  318. package/dist/mailroom/search-cache.js +513 -0
  319. package/dist/mailroom/search-relevance.js +319 -0
  320. package/dist/mailroom/smtp-ingress.js +176 -0
  321. package/dist/mailroom/source-state.js +176 -0
  322. package/dist/mailroom/thread.js +109 -0
  323. package/dist/mailroom/travel-extract.js +89 -0
  324. package/dist/mind/bundle-manifest.js +24 -2
  325. package/dist/mind/context.js +278 -111
  326. package/dist/mind/desk-section.js +362 -0
  327. package/dist/mind/diary-integrity.js +60 -0
  328. package/dist/mind/{memory.js → diary.js} +68 -77
  329. package/dist/mind/embedding-provider.js +60 -0
  330. package/dist/mind/file-state.js +179 -0
  331. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  332. package/dist/mind/obligation-steering.js +227 -0
  333. package/dist/mind/pending.js +34 -8
  334. package/dist/mind/prompt-budget.js +479 -0
  335. package/dist/mind/prompt-refresh.js +3 -2
  336. package/dist/mind/prompt.js +1056 -187
  337. package/dist/mind/provenance-trust.js +26 -0
  338. package/dist/mind/record-paths.js +312 -0
  339. package/dist/mind/scrutiny.js +173 -0
  340. package/dist/mind/session-transaction.js +415 -0
  341. package/dist/nerves/cli-logging.js +7 -1
  342. package/dist/nerves/coverage/audit-rules.js +15 -6
  343. package/dist/nerves/coverage/audit.js +28 -2
  344. package/dist/nerves/coverage/cli.js +1 -1
  345. package/dist/nerves/coverage/contract.js +5 -5
  346. package/dist/nerves/coverage/file-completeness.js +139 -5
  347. package/dist/nerves/coverage/run-artifacts.js +55 -35
  348. package/dist/nerves/coverage/source-scanner.js +4 -4
  349. package/dist/nerves/event-buffer.js +111 -0
  350. package/dist/nerves/index.js +293 -9
  351. package/dist/nerves/observation.js +20 -0
  352. package/dist/nerves/redact.js +79 -0
  353. package/dist/nerves/review/cli-main.js +5 -0
  354. package/dist/nerves/review/cli.js +156 -0
  355. package/dist/nerves/review/core.js +159 -0
  356. package/dist/nerves/runtime.js +17 -1
  357. package/dist/repertoire/ado-client.js +15 -56
  358. package/dist/repertoire/ado-semantic.js +16 -10
  359. package/dist/repertoire/api-client.js +97 -0
  360. package/dist/repertoire/bitwarden-store.js +1045 -0
  361. package/dist/repertoire/bundle-templates.js +71 -0
  362. package/dist/repertoire/bw-installer.js +180 -0
  363. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  364. package/dist/repertoire/coding/context-pack.js +331 -0
  365. package/dist/repertoire/coding/feedback.js +218 -30
  366. package/dist/repertoire/coding/index.js +15 -3
  367. package/dist/repertoire/coding/manager.js +166 -10
  368. package/dist/repertoire/coding/spawner.js +58 -11
  369. package/dist/repertoire/coding/tools.js +242 -14
  370. package/dist/repertoire/coding/workbench-client.js +272 -0
  371. package/dist/repertoire/coding/workbench-manager.js +346 -0
  372. package/dist/repertoire/commerce-errors.js +109 -0
  373. package/dist/repertoire/commerce-self-test.js +156 -0
  374. package/dist/repertoire/credential-access.js +178 -0
  375. package/dist/repertoire/desk/classifier.js +362 -0
  376. package/dist/repertoire/duffel-client.js +185 -0
  377. package/dist/repertoire/github-client.js +14 -55
  378. package/dist/repertoire/graph-client.js +11 -52
  379. package/dist/repertoire/guardrails.js +811 -18
  380. package/dist/repertoire/mcp-client.js +44 -3
  381. package/dist/repertoire/mcp-manager.js +259 -20
  382. package/dist/repertoire/mcp-tools.js +83 -0
  383. package/dist/repertoire/plugin-mcp.js +175 -0
  384. package/dist/repertoire/plugins.js +253 -0
  385. package/dist/repertoire/relationship-authorization.js +194 -0
  386. package/dist/repertoire/shell-sessions.js +133 -0
  387. package/dist/repertoire/skills.js +48 -4
  388. package/dist/repertoire/stripe-client.js +131 -0
  389. package/dist/repertoire/tool-arguments.js +148 -0
  390. package/dist/repertoire/tool-results.js +29 -0
  391. package/dist/repertoire/tools-a2a.js +699 -0
  392. package/dist/repertoire/tools-attachments.js +322 -0
  393. package/dist/repertoire/tools-awaiting.js +575 -0
  394. package/dist/repertoire/tools-base.js +82 -1139
  395. package/dist/repertoire/tools-bluebubbles.js +2 -0
  396. package/dist/repertoire/tools-bridge.js +144 -0
  397. package/dist/repertoire/tools-bundle.js +993 -0
  398. package/dist/repertoire/tools-commerce.js +253 -0
  399. package/dist/repertoire/tools-config.js +186 -0
  400. package/dist/repertoire/tools-continuity.js +575 -0
  401. package/dist/repertoire/tools-credential.js +383 -0
  402. package/dist/repertoire/tools-evolution.js +527 -0
  403. package/dist/repertoire/tools-files.js +344 -0
  404. package/dist/repertoire/tools-flight.js +290 -0
  405. package/dist/repertoire/tools-flow.js +119 -0
  406. package/dist/repertoire/tools-github.js +3 -8
  407. package/dist/repertoire/tools-habits.js +103 -0
  408. package/dist/repertoire/tools-mail.js +1828 -0
  409. package/dist/repertoire/tools-notes.js +485 -0
  410. package/dist/repertoire/tools-obligations.js +182 -0
  411. package/dist/repertoire/tools-orientation.js +31 -0
  412. package/dist/repertoire/tools-record.js +482 -0
  413. package/dist/repertoire/tools-rsvp.js +139 -0
  414. package/dist/repertoire/tools-runtime.js +150 -0
  415. package/dist/repertoire/tools-session.js +1108 -0
  416. package/dist/repertoire/tools-shell.js +133 -0
  417. package/dist/repertoire/tools-steward-policy.js +95 -0
  418. package/dist/repertoire/tools-stripe.js +224 -0
  419. package/dist/repertoire/tools-surface.js +369 -0
  420. package/dist/repertoire/tools-teams.js +12 -39
  421. package/dist/repertoire/tools-telegram-contacts.js +37 -0
  422. package/dist/repertoire/tools-travel.js +125 -0
  423. package/dist/repertoire/tools-trip.js +982 -0
  424. package/dist/repertoire/tools-unraid.js +484 -0
  425. package/dist/repertoire/tools-user-profile.js +146 -0
  426. package/dist/repertoire/tools-vault.js +40 -0
  427. package/dist/repertoire/tools-voice.js +145 -0
  428. package/dist/repertoire/tools.js +377 -80
  429. package/dist/repertoire/travel-api-client.js +360 -0
  430. package/dist/repertoire/unraid-client.js +155 -0
  431. package/dist/repertoire/unraid-restart.js +212 -0
  432. package/dist/repertoire/user-profile.js +131 -0
  433. package/dist/repertoire/vault-setup.js +246 -0
  434. package/dist/repertoire/vault-unlock.js +628 -0
  435. package/dist/rsvp/aisleplanner-client.js +354 -0
  436. package/dist/rsvp/cli.js +926 -0
  437. package/dist/rsvp/config.js +327 -0
  438. package/dist/rsvp/cutover.js +433 -0
  439. package/dist/rsvp/diagnostics.js +232 -0
  440. package/dist/rsvp/diff-renderer.js +176 -0
  441. package/dist/rsvp/habit-policy.js +110 -0
  442. package/dist/rsvp/habit-stage.js +123 -0
  443. package/dist/rsvp/incident-bundle.js +97 -0
  444. package/dist/rsvp/migration.js +204 -0
  445. package/dist/rsvp/native-habit-runner.js +630 -0
  446. package/dist/rsvp/outbound-state.js +628 -0
  447. package/dist/rsvp/query.js +118 -0
  448. package/dist/rsvp/replay.js +233 -0
  449. package/dist/rsvp/snapshot.js +232 -0
  450. package/dist/rsvp/spend-ledger.js +175 -0
  451. package/dist/scripts/claude-code-hook.js +41 -0
  452. package/dist/scripts/claude-code-stop-hook.js +47 -0
  453. package/dist/senses/a2a-entry.js +115 -0
  454. package/dist/senses/attention-queue.js +186 -0
  455. package/dist/senses/await-turn-message.js +58 -0
  456. package/dist/senses/bluebubbles/active-turns.js +216 -0
  457. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  458. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  459. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +355 -40
  460. package/dist/senses/bluebubbles/context-packet.js +207 -0
  461. package/dist/senses/bluebubbles/context-smoke.js +144 -0
  462. package/dist/senses/bluebubbles/entry.js +90 -0
  463. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
  464. package/dist/senses/bluebubbles/index.js +3839 -0
  465. package/dist/senses/bluebubbles/latest-turn.js +311 -0
  466. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  467. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
  468. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
  469. package/dist/senses/bluebubbles/outbound-state.js +308 -0
  470. package/dist/senses/bluebubbles/processed-log.js +133 -0
  471. package/dist/senses/bluebubbles/reaction-policy.js +47 -0
  472. package/dist/senses/bluebubbles/replay.js +284 -0
  473. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  474. package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
  475. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  476. package/dist/senses/bluebubbles/webhook-registration.js +228 -0
  477. package/dist/senses/bluebubbles-meta-guard.js +39 -0
  478. package/dist/senses/cli/bracketed-paste.js +82 -0
  479. package/dist/senses/cli/image-paste.js +287 -0
  480. package/dist/senses/cli/image-ref-navigation.js +75 -0
  481. package/dist/senses/cli/ink-app.js +156 -0
  482. package/dist/senses/cli/inline-diff.js +64 -0
  483. package/dist/senses/cli/input-keys.js +174 -0
  484. package/dist/senses/cli/kill-ring.js +86 -0
  485. package/dist/senses/cli/message-list.js +51 -0
  486. package/dist/senses/cli/ouro-tui.js +607 -0
  487. package/dist/senses/cli/spinner-imperative.js +135 -0
  488. package/dist/senses/cli/spinner.js +101 -0
  489. package/dist/senses/cli/status-line.js +60 -0
  490. package/dist/senses/cli/streaming-markdown.js +526 -0
  491. package/dist/senses/cli/tool-display.js +85 -0
  492. package/dist/senses/cli/tool-render.js +85 -0
  493. package/dist/senses/cli/tui-store.js +241 -0
  494. package/dist/senses/cli/virtual-list.js +35 -0
  495. package/dist/senses/cli-entry.js +60 -8
  496. package/dist/senses/cli.js +600 -317
  497. package/dist/senses/commands.js +66 -3
  498. package/dist/senses/context-packet-ledger.js +371 -0
  499. package/dist/senses/context-packets.js +154 -0
  500. package/dist/senses/habit-lifecycle-guard.js +24 -0
  501. package/dist/senses/habit-turn-message.js +160 -0
  502. package/dist/senses/ingress-evidence.js +2 -0
  503. package/dist/senses/mail-entry.js +66 -0
  504. package/dist/senses/mail.js +524 -0
  505. package/dist/senses/pipeline.js +1110 -204
  506. package/dist/senses/private-runtime-worker.js +859 -0
  507. package/dist/senses/private-runtime.js +1496 -0
  508. package/dist/senses/proactive-content-guard.js +51 -0
  509. package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
  510. package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
  511. package/dist/senses/sanctuary-grounding.js +118 -0
  512. package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
  513. package/dist/senses/sanctuary-health-acceptance-probe.js +774 -0
  514. package/dist/senses/sanctuary-health-runner.js +101 -0
  515. package/dist/senses/sanctuary-health.js +408 -0
  516. package/dist/senses/sanctuary-interactive-control.js +306 -0
  517. package/dist/senses/sanctuary-media-catalog-contract.js +235 -0
  518. package/dist/senses/sanctuary-media-optimization.js +514 -0
  519. package/dist/senses/sanctuary-runtime.js +338 -0
  520. package/dist/senses/sanctuary-sab.js +85 -0
  521. package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
  522. package/dist/senses/shared-turn.js +571 -0
  523. package/dist/senses/surface-tool.js +109 -0
  524. package/dist/senses/teams-entry.js +60 -8
  525. package/dist/senses/teams.js +515 -217
  526. package/dist/senses/telegram-admission.js +711 -0
  527. package/dist/senses/telegram-approval-runtime.js +566 -0
  528. package/dist/senses/telegram-attachments.js +182 -0
  529. package/dist/senses/telegram-audit-ledger.js +220 -0
  530. package/dist/senses/telegram-client.js +1677 -0
  531. package/dist/senses/telegram-effect-adapter.js +859 -0
  532. package/dist/senses/telegram-entry.js +83 -0
  533. package/dist/senses/telegram.js +2031 -0
  534. package/dist/senses/trust-gate.js +104 -9
  535. package/dist/senses/voice/audio-playback.js +237 -0
  536. package/dist/senses/voice/audio-routing.js +119 -0
  537. package/dist/senses/voice/elevenlabs.js +202 -0
  538. package/dist/senses/voice/floor-control.js +431 -0
  539. package/dist/senses/voice/floor-controller.js +115 -0
  540. package/dist/senses/voice/golden-path.js +116 -0
  541. package/dist/senses/voice/index.js +29 -0
  542. package/dist/senses/voice/meeting.js +113 -0
  543. package/dist/senses/voice/outbound.js +190 -0
  544. package/dist/senses/voice/phone.js +33 -0
  545. package/dist/senses/voice/playback.js +139 -0
  546. package/dist/senses/voice/realtime-eval.js +496 -0
  547. package/dist/senses/voice/realtime-trace.js +531 -0
  548. package/dist/senses/voice/transcript.js +70 -0
  549. package/dist/senses/voice/turn.js +191 -0
  550. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  551. package/dist/senses/voice/twilio-phone.js +5081 -0
  552. package/dist/senses/voice/types.js +2 -0
  553. package/dist/senses/voice/whisper.js +161 -0
  554. package/dist/senses/voice-entry.js +81 -0
  555. package/dist/senses/voice-realtime-eval-command.js +99 -0
  556. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  557. package/dist/senses/voice-twilio-entry.js +87 -0
  558. package/dist/trips/core.js +138 -0
  559. package/dist/trips/store.js +265 -0
  560. package/dist/util/frontmatter.js +69 -0
  561. package/npm-shrinkwrap.json +8144 -0
  562. package/package.json +72 -13
  563. package/skills/agent-commerce.md +113 -0
  564. package/skills/browser-navigation.md +117 -0
  565. package/skills/commerce-setup-guide.md +116 -0
  566. package/skills/commerce-setup.md +84 -0
  567. package/skills/configure-dev-tools.md +99 -0
  568. package/skills/travel-planning.md +138 -0
  569. package/dist/heart/daemon/auth-flow.js +0 -430
  570. package/dist/heart/daemon/ouro-path-installer.js +0 -260
  571. package/dist/heart/daemon/ouro-version-manager.js +0 -164
  572. package/dist/heart/daemon/update-hooks.js +0 -138
  573. package/dist/heart/obligations.js +0 -141
  574. package/dist/heart/safe-workspace.js +0 -228
  575. package/dist/heart/session-recall.js +0 -116
  576. package/dist/mind/friends/channel.js +0 -84
  577. package/dist/mind/friends/group-context.js +0 -144
  578. package/dist/mind/friends/resolver.js +0 -84
  579. package/dist/mind/friends/store-file.js +0 -190
  580. package/dist/mind/friends/store.js +0 -4
  581. package/dist/mind/friends/tokens.js +0 -26
  582. package/dist/mind/friends/trust-explanation.js +0 -74
  583. package/dist/mind/friends/types.js +0 -29
  584. package/dist/repertoire/tasks/board.js +0 -134
  585. package/dist/repertoire/tasks/index.js +0 -224
  586. package/dist/repertoire/tasks/lifecycle.js +0 -80
  587. package/dist/repertoire/tasks/middleware.js +0 -65
  588. package/dist/repertoire/tasks/parser.js +0 -173
  589. package/dist/repertoire/tasks/scanner.js +0 -132
  590. package/dist/repertoire/tasks/transitions.js +0 -144
  591. package/dist/senses/bluebubbles-entry.js +0 -13
  592. package/dist/senses/bluebubbles.js +0 -1181
  593. package/dist/senses/debug-activity.js +0 -154
  594. package/dist/senses/inner-dialog-worker.js +0 -90
  595. package/dist/senses/inner-dialog.js +0 -525
  596. package/subagents/README.md +0 -7
  597. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  598. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  599. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  600. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  601. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  602. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  603. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  604. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  605. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  606. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  607. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  608. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  609. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  610. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  611. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  612. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  613. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,571 @@
1
+ "use strict";
2
+ // Shared turn runner for non-interactive senses (MCP, future senses).
3
+ // Follows the CLI pattern: resolves context, constructs InboundTurnInput,
4
+ // calls handleInboundTurn, collects response text, detects ponder deferral.
5
+ //
6
+ // Does NOT refactor CLI — CLI is stable with 2280+ tests. This is a new
7
+ // code path for new senses that follows the same pipeline pattern.
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.stripThinkBlocks = stripThinkBlocks;
43
+ exports.extractOutwardSenseDeliveryText = extractOutwardSenseDeliveryText;
44
+ exports.getSenseSessionPath = getSenseSessionPath;
45
+ exports.runSenseTurn = runSenseTurn;
46
+ const os = __importStar(require("os"));
47
+ const path = __importStar(require("path"));
48
+ const fs = __importStar(require("fs"));
49
+ const core_1 = require("../heart/core");
50
+ const identity_1 = require("../heart/identity");
51
+ const config_1 = require("../heart/config");
52
+ const session_events_1 = require("../heart/session-events");
53
+ const context_1 = require("../mind/context");
54
+ const prompt_1 = require("../mind/prompt");
55
+ const friends_1 = require("@ouro.bot/friends");
56
+ const pending_1 = require("../mind/pending");
57
+ const context_2 = require("../mind/context");
58
+ const trust_gate_1 = require("./trust-gate");
59
+ const pipeline_1 = require("./pipeline");
60
+ const mcp_manager_1 = require("../repertoire/mcp-manager");
61
+ const runtime_1 = require("../nerves/runtime");
62
+ const session_transaction_1 = require("../mind/session-transaction");
63
+ const RESPONSE_CAP = 50_000;
64
+ const OUTWARD_DELIVERY_TOOL_ACKS = new Map([
65
+ ["settle", "(delivered)"],
66
+ ["speak", "(spoken)"],
67
+ ]);
68
+ /**
69
+ * Strip MiniMax-style `<think>...</think>` reasoning blocks from a response
70
+ * string. Handles unclosed open tags (treats everything from `<think>` to
71
+ * end of string as reasoning) and multiple blocks in sequence. Returns the
72
+ * trimmed remainder.
73
+ */
74
+ function stripThinkBlocks(input) {
75
+ let out = input;
76
+ // Closed blocks first (greedy match removed by repeatedly slicing the leftmost pair).
77
+ for (;;) {
78
+ const open = out.indexOf("<think>");
79
+ if (open === -1)
80
+ break;
81
+ const close = out.indexOf("</think>", open + "<think>".length);
82
+ if (close === -1) {
83
+ // Unclosed — drop everything from <think> onward.
84
+ out = out.slice(0, open);
85
+ break;
86
+ }
87
+ out = out.slice(0, open) + out.slice(close + "</think>".length);
88
+ }
89
+ return out.trim();
90
+ }
91
+ function assistantContentText(content) {
92
+ if (typeof content !== "string")
93
+ return null;
94
+ const trimmed = content.trim();
95
+ return trimmed ? trimmed : null;
96
+ }
97
+ function parseToolStringArg(toolCall, toolName, argName) {
98
+ if (!toolCall || typeof toolCall !== "object")
99
+ return null;
100
+ const fn = toolCall.function;
101
+ if (fn?.name !== toolName || typeof fn.arguments !== "string")
102
+ return null;
103
+ try {
104
+ const parsed = JSON.parse(fn.arguments);
105
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
106
+ return null;
107
+ const value = parsed[argName];
108
+ if (typeof value !== "string")
109
+ return null;
110
+ const trimmed = value.trim();
111
+ return trimmed ? trimmed : null;
112
+ }
113
+ catch {
114
+ return null;
115
+ }
116
+ }
117
+ function hasDeliveredToolResult(messages, assistantIndex, toolCallId, toolName) {
118
+ if (typeof toolCallId !== "string" || !toolCallId.trim())
119
+ return false;
120
+ const expectedAck = OUTWARD_DELIVERY_TOOL_ACKS.get(toolName);
121
+ for (let index = assistantIndex + 1; index < messages.length; index++) {
122
+ const message = messages[index];
123
+ if (message.role !== "tool")
124
+ return false;
125
+ if (message.tool_call_id === toolCallId
126
+ && typeof message.content === "string"
127
+ && message.content.trim() === expectedAck) {
128
+ return true;
129
+ }
130
+ }
131
+ return false;
132
+ }
133
+ function outwardDeliveryTextFromAssistantTools(messages, assistantIndex) {
134
+ const assistant = messages[assistantIndex];
135
+ const toolCalls = assistant.tool_calls;
136
+ const delivered = [];
137
+ for (let index = 0; index < toolCalls.length; index++) {
138
+ const toolCall = toolCalls[index];
139
+ const toolCallId = toolCall && typeof toolCall === "object"
140
+ ? toolCall.id
141
+ : undefined;
142
+ const settleAnswer = parseToolStringArg(toolCall, "settle", "answer");
143
+ if (settleAnswer && hasDeliveredToolResult(messages, assistantIndex, toolCallId, "settle")) {
144
+ delivered.push(settleAnswer);
145
+ continue;
146
+ }
147
+ const spokenMessage = parseToolStringArg(toolCall, "speak", "message");
148
+ if (spokenMessage && hasDeliveredToolResult(messages, assistantIndex, toolCallId, "speak")) {
149
+ delivered.push(spokenMessage);
150
+ }
151
+ }
152
+ return delivered.length > 0 ? delivered.join("\n") : null;
153
+ }
154
+ /**
155
+ * Recover the text that actually reached a friend in an outward sense turn.
156
+ *
157
+ * Ouro runs outward channels in tool-required mode. That means the visible
158
+ * response may be a `settle({ answer })` or `speak({ message })` tool call
159
+ * whose assistant message has `content: null`. The authoritative delivery
160
+ * signal is the following tool ack:
161
+ *
162
+ * - `(delivered)` for `settle.answer`
163
+ * - `(spoken)` for `speak.message`
164
+ *
165
+ * Private-runtime `(settled)`, malformed tool arguments, rejected tools, and
166
+ * interrupted tool-call sequences are not outward speech. Sense transports
167
+ * that need to replay the turn later (Voice/Twilio TTS, future meeting audio)
168
+ * should use this helper instead of reading `assistant.content` directly.
169
+ */
170
+ function extractOutwardSenseDeliveryText(messages) {
171
+ const assistantIndex = messages.findLastIndex((message) => message.role === "assistant");
172
+ if (assistantIndex < 0)
173
+ return null;
174
+ const assistant = messages[assistantIndex];
175
+ return Array.isArray(assistant.tool_calls) && assistant.tool_calls.length > 0
176
+ ? outwardDeliveryTextFromAssistantTools(messages, assistantIndex)
177
+ : assistantContentText(assistant.content);
178
+ }
179
+ function hasAcceptedOutwardSessionAck(events, assistantIndex, toolCallId, toolName) {
180
+ const expectedAck = OUTWARD_DELIVERY_TOOL_ACKS.get(toolName);
181
+ for (let index = assistantIndex + 1; index < events.length; index++) {
182
+ const candidate = events[index];
183
+ if (candidate.role !== "tool")
184
+ return false;
185
+ if (candidate.toolCallId === toolCallId && typeof candidate.content === "string" && candidate.content.trim() === expectedAck)
186
+ return true;
187
+ }
188
+ return false;
189
+ }
190
+ function newOutwardCoordinates(events, existingEventIds, afterEventId) {
191
+ const boundaryIndex = events.findIndex((event) => event.id === afterEventId);
192
+ if (boundaryIndex < 0)
193
+ return [];
194
+ return events.flatMap((event, eventIndex) => {
195
+ if (eventIndex <= boundaryIndex || existingEventIds.has(event.id) || event.role !== "assistant" || event.provenance?.captureKind === "synthetic")
196
+ return [];
197
+ const outwardTools = event.toolCalls.flatMap((call) => {
198
+ if (call.function.name !== "speak" && call.function.name !== "settle")
199
+ return [];
200
+ if (!hasAcceptedOutwardSessionAck(events, eventIndex, call.id, call.function.name))
201
+ return [];
202
+ const text = stripThinkBlocks(parseToolStringArg(call, call.function.name, call.function.name === "speak" ? "message" : "answer") ?? "");
203
+ return text ? [{ kind: call.function.name, eventId: event.id, text }] : [];
204
+ });
205
+ if (outwardTools.length > 0)
206
+ return outwardTools;
207
+ if (event.toolCalls.length > 0)
208
+ return [];
209
+ const text = stripThinkBlocks(typeof event.content === "string" ? event.content : "");
210
+ return text ? [{ kind: "text", eventId: event.id, text }] : [];
211
+ });
212
+ }
213
+ function newestPlainAssistantText(messages) {
214
+ const message = messages.findLast((candidate) => candidate.role === "assistant"
215
+ && (!("tool_calls" in candidate) || !Array.isArray(candidate.tool_calls) || candidate.tool_calls.length === 0)
216
+ && typeof candidate.content === "string"
217
+ && candidate.content.trim().length > 0);
218
+ return message ? assistantContentText(message.content) : null;
219
+ }
220
+ function causalSessionEventIds(events, existingEventIds, attempts, afterEventId) {
221
+ if (!afterEventId)
222
+ return attempts.flatMap((attempt) => attempt.delivered ? [null] : []);
223
+ const coordinates = newOutwardCoordinates(events, existingEventIds, afterEventId);
224
+ let nextCoordinate = 0;
225
+ return attempts.flatMap((attempt) => {
226
+ if (!attempt.delivered)
227
+ return [];
228
+ const coordinateIndex = coordinates.findIndex((coordinate, index) => index >= nextCoordinate && coordinate.kind === attempt.kind && coordinate.text === attempt.text);
229
+ if (coordinateIndex < 0)
230
+ return [null];
231
+ nextCoordinate = coordinateIndex + 1;
232
+ return [coordinates[coordinateIndex].eventId];
233
+ });
234
+ }
235
+ function currentIngressEventId(events, existingEventIds, userMessage, precommittedIngress, ingressRelations) {
236
+ if (precommittedIngress)
237
+ return precommittedIngress.eventId;
238
+ const reference = ingressRelations?.references[0];
239
+ return events.findLast((event) => (!existingEventIds.has(event.id)
240
+ && event.role === "user"
241
+ && event.content === userMessage
242
+ && event.provenance?.captureKind !== "synthetic"
243
+ && (!reference || event.relations?.references.includes(reference))))?.id;
244
+ }
245
+ function getSenseSessionPath(agentName, friendId, channel, sessionKey, agentRootOverride) {
246
+ return path.join(agentRootOverride ?? (0, identity_1.getAgentRoot)(agentName), "state", "sessions", friendId, channel, `${(0, config_1.sanitizeKey)(sessionKey)}.json`);
247
+ }
248
+ /**
249
+ * Run a single agent turn through the inbound pipeline.
250
+ * Caller provides channel, session key, friend, and message;
251
+ * this function handles all pipeline wiring.
252
+ */
253
+ async function runSenseTurn(options) {
254
+ const { agentName, channel, sessionKey, friendId, userMessage } = options;
255
+ (0, runtime_1.emitNervesEvent)({
256
+ component: "senses",
257
+ event: "senses.shared_turn_start",
258
+ message: "shared turn runner starting",
259
+ meta: { agentName, channel, sessionKey, friendId },
260
+ });
261
+ // Resolve context
262
+ const agentRoot = (0, identity_1.getAgentRoot)(agentName);
263
+ const friendsPath = path.join(agentRoot, "friends");
264
+ const friendStore = new friends_1.FileFriendStore(friendsPath);
265
+ const capabilities = (0, friends_1.getChannelCapabilities)(channel);
266
+ // If friendId looks like a UUID, look up the friend record directly and use its identity.
267
+ // Otherwise, resolve as a local user (same pattern as CLI sense).
268
+ const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-/.test(friendId);
269
+ let resolverParams;
270
+ if (options.identity) {
271
+ resolverParams = {
272
+ provider: options.identity.provider,
273
+ externalId: options.identity.externalId,
274
+ displayName: options.identity.displayName,
275
+ channel,
276
+ ...(options.identity.tenantId ? { tenantId: options.identity.tenantId } : {}),
277
+ };
278
+ }
279
+ else if (isUuid) {
280
+ const existingFriend = await friendStore.get(friendId);
281
+ if (existingFriend) {
282
+ // Use the friend's first external ID for resolver context
283
+ const ext = existingFriend.externalIds?.[0];
284
+ resolverParams = {
285
+ provider: (ext?.provider ?? "local"),
286
+ externalId: ext?.externalId ?? friendId,
287
+ displayName: existingFriend.name ?? friendId,
288
+ channel,
289
+ };
290
+ }
291
+ else {
292
+ resolverParams = { provider: "local", externalId: friendId, displayName: friendId, channel };
293
+ }
294
+ }
295
+ else {
296
+ // Treat as local user identity (username@hostname pattern)
297
+ const username = os.userInfo().username;
298
+ resolverParams = { provider: "local", externalId: username, displayName: username, channel };
299
+ }
300
+ const resolver = new friends_1.FriendResolver(friendStore, resolverParams);
301
+ // Initialize MCP manager so MCP tools appear as first-class tools in the agent's tool list.
302
+ // Runtime MCP servers (e.g. Workbench's ouro_workbench) are passed per-turn for THIS agent only.
303
+ const mcpManager = await (0, mcp_manager_1.getSharedMcpManager)(options.runtimeMcpServers ? { runtimeServers: options.runtimeMcpServers } : undefined) ?? undefined;
304
+ // Session path and loading
305
+ const sessionDir = path.join(agentRoot, "state", "sessions", friendId, channel);
306
+ fs.mkdirSync(sessionDir, { recursive: true });
307
+ const sessPath = getSenseSessionPath(agentName, friendId, channel, sessionKey, agentRoot);
308
+ const runWithLease = options._withSessionTurnLease ?? session_transaction_1.withSessionTurnLease;
309
+ return runWithLease(sessPath, async (sessionTurnLease) => {
310
+ const baseSessionRevision = (0, session_transaction_1.readSessionTransaction)(sessPath, sessionTurnLease).revision;
311
+ const existing = (0, context_1.loadSession)(sessPath);
312
+ if (options.precommittedIngress) {
313
+ const event = existing?.events?.find((candidate) => candidate.id === options.precommittedIngress.eventId);
314
+ const latestUserEvent = existing?.events?.filter((candidate) => candidate.role === "user").at(-1);
315
+ if (!event || event !== latestUserEvent || event.role !== "user" || event.content !== userMessage
316
+ || !event.relations.references.includes(options.precommittedIngress.reference)) {
317
+ throw new Error("shared turn precommitted ingress is missing, mismatched, or no longer current");
318
+ }
319
+ }
320
+ const existingEventIds = new Set(existing?.events?.map((event) => event.id) ?? []);
321
+ let sessionState = existing?.state;
322
+ let persistPromise;
323
+ const sessionMessages = existing?.messages && existing.messages.length > 0
324
+ ? existing.messages
325
+ : [{ role: "system", content: (0, prompt_1.flattenSystemPrompt)(await (0, prompt_1.buildSystem)(channel, {}, undefined)) }];
326
+ const preTurnMessageCount = sessionMessages.length;
327
+ // Pending dir
328
+ const pendingDir = (0, pending_1.getPendingDir)(agentName, friendId, channel, sessionKey);
329
+ // Accumulate outward text through the same callback boundary used by chat
330
+ // channels. `speak` flushes pending text immediately; `settle` is delivered
331
+ // once the turn completes.
332
+ let committedResponseText = "";
333
+ let pendingResponseText = "";
334
+ let terminalDeliveryKind = "text";
335
+ const deliveries = [];
336
+ const deliveryFailures = [];
337
+ const deliveryAttempts = [];
338
+ let providerInvocationCount = 0;
339
+ let toolInvocationCount = 0;
340
+ let hadReasoningChunk = false;
341
+ const commitResponseText = (text) => {
342
+ const cleaned = stripThinkBlocks(text);
343
+ /* v8 ignore next -- deliverPending strips first; this is a defensive direct-call guard @preserve */
344
+ if (!cleaned)
345
+ return;
346
+ committedResponseText = committedResponseText
347
+ ? `${committedResponseText}\n${cleaned}`
348
+ : cleaned;
349
+ };
350
+ const deliveryErrorMessage = (error) => error instanceof Error ? error.message : String(error);
351
+ const deliverPending = async (kind, optionsForDelivery) => {
352
+ const text = stripThinkBlocks(pendingResponseText);
353
+ pendingResponseText = "";
354
+ if (!text)
355
+ return;
356
+ const delivery = { kind, text };
357
+ const attempt = { kind, text, delivered: false };
358
+ deliveryAttempts.push(attempt);
359
+ try {
360
+ await options.deliverySink?.onDelivery(delivery);
361
+ attempt.delivered = true;
362
+ deliveries.push(delivery);
363
+ commitResponseText(text);
364
+ }
365
+ catch (error) {
366
+ const failure = { ...delivery, error: deliveryErrorMessage(error) };
367
+ deliveryFailures.push(failure);
368
+ (0, runtime_1.emitNervesEvent)({
369
+ level: "error",
370
+ component: "senses",
371
+ event: "senses.shared_turn_delivery_error",
372
+ message: "shared turn outward delivery failed",
373
+ meta: { agentName, channel, sessionKey, friendId, kind, error: failure.error, textLength: text.length },
374
+ });
375
+ if (optionsForDelivery.throwOnError)
376
+ throw error;
377
+ commitResponseText(text);
378
+ }
379
+ };
380
+ /* v8 ignore start — callback stubs are exercised through the pipeline integration */
381
+ const callbacks = {
382
+ settleOutputMode: "retractable_buffer",
383
+ onModelStart: () => { providerInvocationCount += 1; if (options.turnMetricsObserver)
384
+ options.turnMetricsObserver.providerInvocationCount += 1; },
385
+ onModelStreamStart: () => { },
386
+ onTextChunk: (chunk) => { pendingResponseText += chunk; },
387
+ onReasoningChunk: () => { hadReasoningChunk = true; },
388
+ onToolStart: () => { toolInvocationCount += 1; if (options.turnMetricsObserver)
389
+ options.turnMetricsObserver.toolInvocationCount += 1; },
390
+ onToolEnd: (name, _summary, success) => {
391
+ if (name === "settle" && success)
392
+ terminalDeliveryKind = "settle";
393
+ },
394
+ onError: () => { },
395
+ onClearText: () => { pendingResponseText = ""; },
396
+ flushNow: () => deliverPending("speak", { throwOnError: true }),
397
+ };
398
+ /* v8 ignore stop */
399
+ // Run the pipeline
400
+ const inboundMessages = [];
401
+ if (!options.precommittedIngress) {
402
+ const userMsg = { role: "user", content: userMessage };
403
+ (0, session_events_1.stampIngressTime)(userMsg);
404
+ if (options.ingressRelations)
405
+ (0, session_events_1.stampIngressRelations)(userMsg, options.ingressRelations);
406
+ inboundMessages.push(userMsg);
407
+ }
408
+ const turnResult = await (0, pipeline_1.handleInboundTurn)({
409
+ channel,
410
+ latencyMode: options.latencyMode,
411
+ sessionKey,
412
+ capabilities,
413
+ messages: inboundMessages,
414
+ callbacks,
415
+ sessionTurnLease,
416
+ /* v8 ignore start — delegation wrappers; pipeline integration tested separately */
417
+ friendResolver: { resolve: () => resolver.resolve() },
418
+ sessionLoader: {
419
+ loadOrCreate: () => Promise.resolve({
420
+ messages: sessionMessages,
421
+ sessionPath: sessPath,
422
+ state: sessionState,
423
+ events: existing?.events,
424
+ structuredOutputs: existing?.structuredOutputs,
425
+ }),
426
+ },
427
+ /* v8 ignore stop */
428
+ pendingDir,
429
+ friendStore,
430
+ provider: resolverParams.provider,
431
+ externalId: resolverParams.externalId,
432
+ tenantId: resolverParams.tenantId,
433
+ enforceTrustGate: trust_gate_1.enforceTrustGate,
434
+ drainPending: pending_1.drainPending,
435
+ runAgentOptions: {
436
+ mcpManager,
437
+ ...(options.approvalCoordinatorFactory ? { approvalCoordinator: options.approvalCoordinatorFactory({ sessionPath: sessPath, baseSessionRevision }) } : {}),
438
+ ...(options.latencyMode === "live" ? { skipKeptNotes: true } : {}),
439
+ ...(options.orientationFrame ? { orientationFrame: options.orientationFrame } : {}),
440
+ toolContext: {
441
+ signin: async () => undefined,
442
+ ...(options.toolContext ? options.toolContext : {}),
443
+ currentUserMessage: userMessage,
444
+ },
445
+ },
446
+ ...(options.prepareRunAgentOptions ? { prepareRunAgentOptions: options.prepareRunAgentOptions } : {}),
447
+ /* v8 ignore start — delegation wrappers; these just forward to the real functions */
448
+ runAgent: (msgs, cb, ch, sig, opts) => (0, core_1.runAgent)(msgs, cb, ch, sig, opts),
449
+ postTurn: (turnMessages, sessionPathArg, usage, hooks, state) => {
450
+ const prepared = (0, context_2.postTurnTrim)(turnMessages, usage, hooks);
451
+ sessionState = state;
452
+ persistPromise = (0, context_2.deferPostTurnPersist)(sessionPathArg, prepared, usage, state);
453
+ },
454
+ /* v8 ignore stop */
455
+ accumulateFriendTokens: friends_1.accumulateFriendTokens,
456
+ });
457
+ if (turnResult.gateResult && !turnResult.gateResult.allowed) {
458
+ const blockedResponse = "autoReply" in turnResult.gateResult
459
+ ? turnResult.gateResult.autoReply
460
+ : `(blocked by trust gate: ${turnResult.gateResult.reason})`;
461
+ return {
462
+ response: blockedResponse,
463
+ ponderDeferred: false,
464
+ deliveries,
465
+ deliveryFailures,
466
+ providerInvocationCount,
467
+ toolInvocationCount,
468
+ sessionPath: sessPath,
469
+ };
470
+ }
471
+ const persistedEvents = persistPromise ? await persistPromise : [];
472
+ const ingressEventId = currentIngressEventId(persistedEvents, existingEventIds, userMessage, options.precommittedIngress, options.ingressRelations);
473
+ const finalDeliveryKind = terminalDeliveryKind;
474
+ const acceptedTerminalOutcome = turnResult.turnOutcome === "settled" || turnResult.turnOutcome === "blocked";
475
+ const failoverText = turnResult.turnOutcome === "errored" ? turnResult.failoverMessage?.trim() : undefined;
476
+ const expectsOutwardResponse = acceptedTerminalOutcome || turnResult.turnOutcome === "command" || Boolean(failoverText);
477
+ const hadPendingCallbackText = stripThinkBlocks(pendingResponseText).length > 0;
478
+ let recoveredTerminalEventId;
479
+ if (acceptedTerminalOutcome) {
480
+ const completionText = turnResult.completion?.answer.trim();
481
+ const currentTurnMessages = Array.isArray(turnResult.messages) ? turnResult.messages.slice(preTurnMessageCount) : [];
482
+ const plainTerminalText = newestPlainAssistantText(currentTurnMessages);
483
+ const acknowledgedDeliveryText = finalDeliveryKind === "settle"
484
+ ? extractOutwardSenseDeliveryText(currentTurnMessages)
485
+ : null;
486
+ const authoritativeText = completionText || acknowledgedDeliveryText || plainTerminalText;
487
+ if (authoritativeText)
488
+ pendingResponseText = authoritativeText;
489
+ else
490
+ pendingResponseText = "";
491
+ if (!hadPendingCallbackText && plainTerminalText)
492
+ recoveredTerminalEventId = causalSessionEventIds(persistedEvents, existingEventIds, [{ kind: "text", text: stripThinkBlocks(plainTerminalText), delivered: true }], ingressEventId)[0] ?? undefined;
493
+ }
494
+ else if (turnResult.turnOutcome === "command") {
495
+ // Slash-command text is emitted directly by the pipeline and has no assistant event.
496
+ }
497
+ else if (failoverText) {
498
+ pendingResponseText = failoverText;
499
+ }
500
+ else {
501
+ pendingResponseText = "";
502
+ }
503
+ await deliverPending(finalDeliveryKind, { throwOnError: false });
504
+ const ponderDeferred = false;
505
+ // Build response
506
+ let finalResponse;
507
+ let responseCausalSessionEventId = recoveredTerminalEventId;
508
+ if (committedResponseText.length === 0) {
509
+ if (!expectsOutwardResponse) {
510
+ finalResponse = "";
511
+ }
512
+ else {
513
+ // The terminal turn had no committed text — check its session transcript for the delivered answer.
514
+ const postTurnSession = (0, context_1.loadSession)(sessPath);
515
+ const emptyFallback = options.emptyResponseFallback?.();
516
+ if (postTurnSession?.messages) {
517
+ const recovered = extractOutwardSenseDeliveryText(postTurnSession.messages.slice(preTurnMessageCount));
518
+ finalResponse = recovered ?? emptyFallback ?? (hadReasoningChunk ? "" : "(agent responded but response was empty)");
519
+ if (recovered)
520
+ responseCausalSessionEventId = causalSessionEventIds(persistedEvents, existingEventIds, [{ kind: finalDeliveryKind, text: stripThinkBlocks(recovered), delivered: true }], ingressEventId)[0] ?? undefined;
521
+ }
522
+ else {
523
+ finalResponse = emptyFallback ?? (hadReasoningChunk ? "" : "(agent responded but response was empty)");
524
+ }
525
+ }
526
+ }
527
+ else {
528
+ finalResponse = committedResponseText;
529
+ }
530
+ // Strip MiniMax-style <think>...</think> blocks from the final response.
531
+ // When a reasoning-style model emits only a think block and no final answer
532
+ // (no settle tool call, no post-think text), the readback path above
533
+ // surfaces the raw saved assistant content — which includes the think tags
534
+ // and renders as empty (or as raw reasoning) on MCP/CLI clients. Strip
535
+ // here so the caller sees the actual delivered text. If only reasoning
536
+ // came through and nothing else, surface a clear diagnostic message
537
+ // instead of a blank response so the operator knows what happened.
538
+ finalResponse = stripThinkBlocks(finalResponse);
539
+ if (finalResponse.length === 0 && expectsOutwardResponse) {
540
+ (0, runtime_1.emitNervesEvent)({
541
+ level: "warn",
542
+ component: "senses",
543
+ event: "senses.shared_turn_only_reasoning",
544
+ message: "agent produced only <think> reasoning with no final answer — likely a model that closed the think tag without continuing",
545
+ meta: { agentName, channel, sessionKey, friendId },
546
+ });
547
+ finalResponse = "(agent produced reasoning but no final answer this turn — try again, or check the session transcript for the trace)";
548
+ }
549
+ // Cap response length
550
+ if (finalResponse.length > RESPONSE_CAP) {
551
+ finalResponse = finalResponse.slice(0, RESPONSE_CAP) + "\n\n[truncated — response exceeded 50K characters]";
552
+ }
553
+ (0, runtime_1.emitNervesEvent)({
554
+ component: "senses",
555
+ event: "senses.shared_turn_end",
556
+ message: "shared turn runner complete",
557
+ meta: { agentName, channel, sessionKey, friendId, ponderDeferred, responseLength: finalResponse.length },
558
+ });
559
+ return {
560
+ response: finalResponse,
561
+ ponderDeferred,
562
+ deliveries,
563
+ deliveryFailures,
564
+ providerInvocationCount,
565
+ toolInvocationCount,
566
+ sessionPath: sessPath,
567
+ ...(deliveries.length > 0 ? { causalSessionEventIds: causalSessionEventIds(persistedEvents, existingEventIds, deliveryAttempts, ingressEventId) } : {}),
568
+ ...(responseCausalSessionEventId ? { responseCausalSessionEventId } : {}),
569
+ };
570
+ });
571
+ }
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleSurface = handleSurface;
4
+ const attention_queue_1 = require("./attention-queue");
5
+ const runtime_1 = require("../nerves/runtime");
6
+ async function handleSurface(input) {
7
+ const { content, delegationId, friendId, deliveryHint, queue, routeToFriend, advanceObligation, completePonderPacket, fulfillHeartObligation, onRouteResult, } = input;
8
+ // Resolve target friend
9
+ let targetFriendId;
10
+ let queueItem;
11
+ const matchesFriend = (item, target) => item.friendId === target || item.friendName.toLowerCase() === target.toLowerCase();
12
+ const inferQueueItem = (target) => {
13
+ if (queue.length === 0)
14
+ return undefined;
15
+ const candidates = target
16
+ ? queue.filter((item) => matchesFriend(item, target))
17
+ : queue;
18
+ if (candidates.length === 1)
19
+ return candidates[0];
20
+ if (candidates.length > 1) {
21
+ return `multiple held thoughts match ${target ?? "this surface call"} — use delegationId to choose one`;
22
+ }
23
+ return undefined;
24
+ };
25
+ if (delegationId) {
26
+ // Look up in attention queue
27
+ const found = queue.find((item) => item.id === delegationId);
28
+ if (!found) {
29
+ return `no delegation found with id ${delegationId} — check your attention queue`;
30
+ }
31
+ targetFriendId = found.friendId;
32
+ queueItem = found;
33
+ }
34
+ else if (friendId) {
35
+ const inferred = inferQueueItem(friendId);
36
+ if (typeof inferred === "string")
37
+ return inferred;
38
+ queueItem = inferred;
39
+ targetFriendId = queueItem?.friendId ?? friendId;
40
+ }
41
+ else {
42
+ const inferred = inferQueueItem();
43
+ if (typeof inferred === "string")
44
+ return inferred;
45
+ if (inferred) {
46
+ queueItem = inferred;
47
+ targetFriendId = inferred.friendId;
48
+ }
49
+ else {
50
+ return "specify who this thought is for — use delegationId to address a held thought, or friendId for spontaneous outreach";
51
+ }
52
+ }
53
+ if (queueItem?.packetId && !delegationId) {
54
+ return `held private return ${queueItem.id} is waiting — call surface with delegationId="${queueItem.id}" so the return is tied to the correct packet`;
55
+ }
56
+ // Route to target
57
+ const result = deliveryHint
58
+ ? await routeToFriend(targetFriendId, content, queueItem, deliveryHint)
59
+ : await routeToFriend(targetFriendId, content, queueItem);
60
+ (0, runtime_1.emitNervesEvent)({
61
+ event: "senses.surface_routed",
62
+ component: "senses",
63
+ message: `surface routed to ${targetFriendId}: ${result.status}`,
64
+ meta: {
65
+ targetFriendId,
66
+ status: result.status,
67
+ hasDelegationId: !!delegationId,
68
+ ...(result.detail ? { detail: result.detail } : {}),
69
+ },
70
+ });
71
+ onRouteResult?.({ targetFriendId, queueItem, result });
72
+ // On successful routing with delegationId:
73
+ // 1. Advance obligation to "returned" (disk FIRST — crash safety)
74
+ // 2. Dequeue from process-local queue (AFTER obligation advance)
75
+ if (queueItem && result.status !== "failed") {
76
+ if (queueItem.obligationId) {
77
+ advanceObligation(queueItem.obligationId, {
78
+ status: "returned",
79
+ returnedAt: Date.now(),
80
+ returnTarget: "surface",
81
+ });
82
+ }
83
+ if (completePonderPacket && queueItem.packetId) {
84
+ try {
85
+ completePonderPacket(queueItem.packetId);
86
+ }
87
+ catch {
88
+ // swallowed — packet completion must never break surface delivery
89
+ }
90
+ }
91
+ // Fulfill the heart obligation for this origin (separate from inner/mind obligation)
92
+ if (fulfillHeartObligation) {
93
+ try {
94
+ fulfillHeartObligation({
95
+ friendId: queueItem.friendId,
96
+ channel: queueItem.channel,
97
+ key: queueItem.key,
98
+ });
99
+ }
100
+ catch {
101
+ // swallowed — heart obligation fulfillment must never break surface delivery
102
+ }
103
+ }
104
+ (0, attention_queue_1.dequeueAttentionItem)(queue, queueItem.id);
105
+ }
106
+ // Return delivery status
107
+ const detail = result.detail ? ` — ${result.detail}` : "";
108
+ return `${result.status}${detail}`;
109
+ }