@ouro.bot/cli 0.1.0-alpha.67 → 0.1.0-alpha.670

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 (457) hide show
  1. package/README.md +127 -23
  2. package/RepairGuide.ouro/agent.json +5 -0
  3. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  4. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  5. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  6. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  7. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  8. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  9. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  12. package/changelog.json +4271 -16
  13. package/dist/a2a/card.js +56 -0
  14. package/dist/a2a/client.js +143 -0
  15. package/dist/a2a/config.js +50 -0
  16. package/dist/a2a/onboarding.js +111 -0
  17. package/dist/a2a/server.js +498 -0
  18. package/dist/a2a/task-store.js +69 -0
  19. package/dist/a2a/types.js +3 -0
  20. package/dist/arc/attention-types.js +8 -0
  21. package/dist/arc/cares.js +144 -0
  22. package/dist/arc/episodes.js +118 -0
  23. package/dist/arc/evolution.js +487 -0
  24. package/dist/arc/flight-recorder.js +810 -0
  25. package/dist/arc/intentions.js +134 -0
  26. package/dist/arc/json-store.js +117 -0
  27. package/dist/arc/obligations.js +326 -0
  28. package/dist/arc/packets.js +288 -0
  29. package/dist/arc/presence.js +185 -0
  30. package/dist/arc/task-lifecycle.js +57 -0
  31. package/dist/commerce/store.js +755 -0
  32. package/dist/commerce/types.js +3 -0
  33. package/dist/heart/active-work.js +860 -43
  34. package/dist/heart/agent-entry.js +69 -3
  35. package/dist/heart/attachments/image-normalize.js +194 -0
  36. package/dist/heart/attachments/materialize.js +97 -0
  37. package/dist/heart/attachments/originals.js +88 -0
  38. package/dist/heart/attachments/render.js +29 -0
  39. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  40. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  41. package/dist/heart/attachments/sources/index.js +16 -0
  42. package/dist/heart/attachments/store.js +103 -0
  43. package/dist/heart/attachments/types.js +93 -0
  44. package/dist/heart/auth/auth-flow.js +479 -0
  45. package/dist/heart/awaiting/await-alert.js +146 -0
  46. package/dist/heart/awaiting/await-expiry.js +108 -0
  47. package/dist/heart/awaiting/await-loader.js +91 -0
  48. package/dist/heart/awaiting/await-parser.js +141 -0
  49. package/dist/heart/awaiting/await-runtime-state.js +100 -0
  50. package/dist/heart/awaiting/await-scheduler.js +378 -0
  51. package/dist/heart/background-operations.js +281 -0
  52. package/dist/heart/bridges/manager.js +137 -17
  53. package/dist/heart/bridges/store.js +14 -2
  54. package/dist/heart/bundle-state.js +168 -0
  55. package/dist/heart/commitments.js +135 -0
  56. package/dist/heart/config-registry.js +331 -0
  57. package/dist/heart/config.js +118 -119
  58. package/dist/heart/context-loss-gauntlet.js +354 -0
  59. package/dist/heart/context-loss-sentinel.js +907 -0
  60. package/dist/heart/core.js +1288 -249
  61. package/dist/heart/cross-chat-delivery.js +8 -22
  62. package/dist/heart/daemon/agent-config-check.js +427 -0
  63. package/dist/heart/daemon/agent-discovery.js +102 -3
  64. package/dist/heart/daemon/agent-service.js +523 -0
  65. package/dist/heart/daemon/agentic-repair.js +547 -0
  66. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  67. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  68. package/dist/heart/daemon/cadence.js +70 -0
  69. package/dist/heart/daemon/cli-defaults.js +780 -0
  70. package/dist/heart/daemon/cli-desk.js +322 -0
  71. package/dist/heart/daemon/cli-exec.js +7981 -0
  72. package/dist/heart/daemon/cli-help.js +576 -0
  73. package/dist/heart/daemon/cli-parse.js +1850 -0
  74. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  75. package/dist/heart/daemon/cli-render.js +763 -0
  76. package/dist/heart/daemon/cli-types.js +8 -0
  77. package/dist/heart/daemon/connect-bay.js +323 -0
  78. package/dist/heart/daemon/daemon-cli.js +29 -1750
  79. package/dist/heart/daemon/daemon-entry.js +533 -3
  80. package/dist/heart/daemon/daemon-health.js +176 -0
  81. package/dist/heart/daemon/daemon-rollup.js +57 -0
  82. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  83. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  84. package/dist/heart/daemon/daemon.js +950 -76
  85. package/dist/heart/daemon/dns-workflow.js +394 -0
  86. package/dist/heart/daemon/doctor-types.js +8 -0
  87. package/dist/heart/daemon/doctor.js +873 -0
  88. package/dist/heart/daemon/health-monitor.js +125 -1
  89. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  90. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  91. package/dist/heart/daemon/http-health-probe.js +80 -0
  92. package/dist/heart/daemon/human-command-screens.js +234 -0
  93. package/dist/heart/daemon/human-readiness.js +114 -0
  94. package/dist/heart/daemon/inner-status.js +78 -0
  95. package/dist/heart/daemon/interactive-repair.js +394 -0
  96. package/dist/heart/daemon/launchd.js +37 -8
  97. package/dist/heart/daemon/log-tailer.js +79 -10
  98. package/dist/heart/daemon/logs-prune.js +110 -0
  99. package/dist/heart/daemon/mcp-canary.js +297 -0
  100. package/dist/heart/daemon/message-router.js +6 -2
  101. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  102. package/dist/heart/daemon/os-cron-deps.js +135 -0
  103. package/dist/heart/daemon/os-cron.js +14 -12
  104. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  105. package/dist/heart/daemon/ouro-entry.js +3 -1
  106. package/dist/heart/daemon/plugin-cli.js +432 -0
  107. package/dist/heart/daemon/process-manager.js +511 -40
  108. package/dist/heart/daemon/provider-discovery.js +137 -0
  109. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  110. package/dist/heart/daemon/pulse.js +475 -0
  111. package/dist/heart/daemon/readiness-repair.js +365 -0
  112. package/dist/heart/daemon/run-hooks.js +2 -0
  113. package/dist/heart/daemon/runtime-logging.js +41 -14
  114. package/dist/heart/daemon/runtime-metadata.js +2 -30
  115. package/dist/heart/daemon/safe-mode.js +161 -0
  116. package/dist/heart/daemon/sense-manager.js +564 -38
  117. package/dist/heart/daemon/session-id-resolver.js +131 -0
  118. package/dist/heart/daemon/skill-management-installer.js +1 -1
  119. package/dist/heart/daemon/socket-client.js +158 -11
  120. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  121. package/dist/heart/daemon/startup-tui.js +330 -0
  122. package/dist/heart/daemon/task-scheduler.js +117 -39
  123. package/dist/heart/daemon/terminal-ui.js +499 -0
  124. package/dist/heart/daemon/thoughts.js +229 -17
  125. package/dist/heart/daemon/up-progress.js +366 -0
  126. package/dist/heart/daemon/vault-items.js +56 -0
  127. package/dist/heart/delegation.js +1 -4
  128. package/dist/heart/habits/habit-migration.js +189 -0
  129. package/dist/heart/habits/habit-parser.js +211 -0
  130. package/dist/heart/habits/habit-runtime-state.js +114 -0
  131. package/dist/heart/habits/habit-scheduler.js +391 -0
  132. package/dist/heart/habits/habit-session-summary.js +318 -0
  133. package/dist/heart/habits/habit-session.js +618 -0
  134. package/dist/heart/{daemon → hatch}/hatch-flow.js +42 -56
  135. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  136. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  137. package/dist/heart/{daemon → hatch}/specialist-tools.js +45 -18
  138. package/dist/heart/identity.js +174 -57
  139. package/dist/heart/kept-notes.js +289 -0
  140. package/dist/heart/kicks.js +1 -1
  141. package/dist/heart/machine-identity.js +161 -0
  142. package/dist/heart/mail-import-discovery.js +353 -0
  143. package/dist/heart/mailbox/mailbox-http-hooks.js +96 -0
  144. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  145. package/dist/heart/mailbox/mailbox-http-routes.js +375 -0
  146. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  147. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  148. package/dist/heart/mailbox/mailbox-http.js +99 -0
  149. package/dist/heart/mailbox/mailbox-read.js +37 -0
  150. package/dist/heart/mailbox/mailbox-types.js +27 -0
  151. package/dist/heart/mailbox/mailbox-view.js +197 -0
  152. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  153. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  154. package/dist/heart/mailbox/readers/mail.js +375 -0
  155. package/dist/heart/mailbox/readers/runtime-readers.js +815 -0
  156. package/dist/heart/mailbox/readers/sessions.js +232 -0
  157. package/dist/heart/mailbox/readers/shared.js +111 -0
  158. package/dist/heart/mcp/mcp-server.js +696 -0
  159. package/dist/heart/migrate-config.js +100 -0
  160. package/dist/heart/model-capabilities.js +19 -0
  161. package/dist/heart/orientation-frame.js +217 -0
  162. package/dist/heart/platform.js +81 -0
  163. package/dist/heart/provider-attempt.js +134 -0
  164. package/dist/heart/provider-binding-resolver.js +273 -0
  165. package/dist/heart/provider-credentials.js +425 -0
  166. package/dist/heart/provider-failover.js +311 -0
  167. package/dist/heart/provider-models.js +81 -0
  168. package/dist/heart/provider-ping.js +262 -0
  169. package/dist/heart/provider-readiness-cache.js +119 -0
  170. package/dist/heart/provider-visibility.js +188 -0
  171. package/dist/heart/providers/anthropic-token.js +131 -0
  172. package/dist/heart/providers/anthropic.js +139 -52
  173. package/dist/heart/providers/azure.js +23 -11
  174. package/dist/heart/providers/error-classification.js +127 -0
  175. package/dist/heart/providers/github-copilot.js +145 -0
  176. package/dist/heart/providers/minimax-vlm.js +189 -0
  177. package/dist/heart/providers/minimax.js +26 -8
  178. package/dist/heart/providers/openai-codex-token.js +349 -0
  179. package/dist/heart/providers/openai-codex.js +55 -40
  180. package/dist/heart/runtime-capability-check.js +170 -0
  181. package/dist/heart/runtime-credentials.js +367 -0
  182. package/dist/heart/runtime-cwd.js +87 -0
  183. package/dist/heart/sense-truth.js +17 -4
  184. package/dist/heart/session-activity.js +48 -24
  185. package/dist/heart/session-events.js +1133 -0
  186. package/dist/heart/session-playback-cli-main.js +5 -0
  187. package/dist/heart/session-playback-cli.js +36 -0
  188. package/dist/heart/session-playback.js +231 -0
  189. package/dist/heart/session-stats-cli-main.js +5 -0
  190. package/dist/heart/session-stats.js +182 -0
  191. package/dist/heart/session-transcript.js +133 -0
  192. package/dist/heart/start-of-turn-packet.js +357 -0
  193. package/dist/heart/streaming.js +44 -27
  194. package/dist/heart/structured-output.js +196 -0
  195. package/dist/heart/sync-classification.js +176 -0
  196. package/dist/heart/sync.js +449 -0
  197. package/dist/heart/target-resolution.js +11 -7
  198. package/dist/heart/tempo.js +93 -0
  199. package/dist/heart/temporal-view.js +41 -0
  200. package/dist/heart/timeouts.js +101 -0
  201. package/dist/heart/tool-activity-callbacks.js +59 -0
  202. package/dist/heart/tool-description.js +155 -0
  203. package/dist/heart/tool-friction.js +55 -0
  204. package/dist/heart/tool-loop.js +200 -0
  205. package/dist/heart/turn-context.js +450 -0
  206. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  207. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  208. package/dist/heart/versioning/ouro-path-installer.js +426 -0
  209. package/dist/heart/versioning/ouro-version-manager.js +409 -0
  210. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  211. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  212. package/dist/heart/versioning/update-hooks.js +154 -0
  213. package/dist/heart/work-card.js +390 -0
  214. package/dist/mailbox-ui/assets/index-CaTIFDmv.js +1 -0
  215. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  216. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  217. package/dist/mailbox-ui/index.html +16 -0
  218. package/dist/mailroom/attention.js +167 -0
  219. package/dist/mailroom/autonomy.js +209 -0
  220. package/dist/mailroom/blob-store.js +715 -0
  221. package/dist/mailroom/body-cache.js +61 -0
  222. package/dist/mailroom/core.js +788 -0
  223. package/dist/mailroom/entry.js +160 -0
  224. package/dist/mailroom/file-store.js +568 -0
  225. package/dist/mailroom/mbox-import.js +393 -0
  226. package/dist/mailroom/migration.js +164 -0
  227. package/dist/mailroom/outbound.js +380 -0
  228. package/dist/mailroom/policy.js +263 -0
  229. package/dist/mailroom/reader.js +233 -0
  230. package/dist/mailroom/search-cache.js +334 -0
  231. package/dist/mailroom/search-relevance.js +319 -0
  232. package/dist/mailroom/smtp-ingress.js +176 -0
  233. package/dist/mailroom/source-state.js +176 -0
  234. package/dist/mailroom/thread.js +109 -0
  235. package/dist/mailroom/travel-extract.js +89 -0
  236. package/dist/mind/bundle-manifest.js +24 -2
  237. package/dist/mind/context.js +250 -101
  238. package/dist/mind/desk-section.js +362 -0
  239. package/dist/mind/diary-integrity.js +60 -0
  240. package/dist/mind/{memory.js → diary.js} +68 -77
  241. package/dist/mind/embedding-provider.js +60 -0
  242. package/dist/mind/file-state.js +179 -0
  243. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  244. package/dist/mind/obligation-steering.js +221 -0
  245. package/dist/mind/pending.js +6 -1
  246. package/dist/mind/prompt-refresh.js +3 -2
  247. package/dist/mind/prompt.js +1020 -148
  248. package/dist/mind/provenance-trust.js +26 -0
  249. package/dist/mind/record-paths.js +312 -0
  250. package/dist/mind/scrutiny.js +173 -0
  251. package/dist/nerves/cli-logging.js +7 -1
  252. package/dist/nerves/coverage/audit-rules.js +15 -6
  253. package/dist/nerves/coverage/audit.js +28 -2
  254. package/dist/nerves/coverage/cli.js +1 -1
  255. package/dist/nerves/coverage/contract.js +5 -5
  256. package/dist/nerves/coverage/file-completeness.js +139 -5
  257. package/dist/nerves/event-buffer.js +111 -0
  258. package/dist/nerves/index.js +224 -4
  259. package/dist/nerves/observation.js +20 -0
  260. package/dist/nerves/redact.js +79 -0
  261. package/dist/nerves/review/cli-main.js +5 -0
  262. package/dist/nerves/review/cli.js +156 -0
  263. package/dist/nerves/review/core.js +152 -0
  264. package/dist/nerves/runtime.js +5 -1
  265. package/dist/repertoire/ado-client.js +15 -56
  266. package/dist/repertoire/ado-semantic.js +16 -10
  267. package/dist/repertoire/api-client.js +97 -0
  268. package/dist/repertoire/bitwarden-store.js +1042 -0
  269. package/dist/repertoire/bundle-templates.js +71 -0
  270. package/dist/repertoire/bw-installer.js +180 -0
  271. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  272. package/dist/repertoire/coding/context-pack.js +331 -0
  273. package/dist/repertoire/coding/feedback.js +197 -30
  274. package/dist/repertoire/coding/manager.js +166 -10
  275. package/dist/repertoire/coding/spawner.js +55 -9
  276. package/dist/repertoire/coding/tools.js +219 -7
  277. package/dist/repertoire/commerce-errors.js +109 -0
  278. package/dist/repertoire/commerce-self-test.js +156 -0
  279. package/dist/repertoire/credential-access.js +178 -0
  280. package/dist/repertoire/desk/classifier.js +362 -0
  281. package/dist/repertoire/duffel-client.js +185 -0
  282. package/dist/repertoire/github-client.js +14 -55
  283. package/dist/repertoire/graph-client.js +11 -52
  284. package/dist/repertoire/guardrails.js +161 -27
  285. package/dist/repertoire/mcp-client.js +295 -0
  286. package/dist/repertoire/mcp-manager.js +434 -0
  287. package/dist/repertoire/mcp-tools.js +83 -0
  288. package/dist/repertoire/plugin-mcp.js +175 -0
  289. package/dist/repertoire/plugins.js +253 -0
  290. package/dist/repertoire/shell-sessions.js +133 -0
  291. package/dist/repertoire/skills.js +48 -4
  292. package/dist/repertoire/stripe-client.js +131 -0
  293. package/dist/repertoire/tool-results.js +29 -0
  294. package/dist/repertoire/tools-a2a.js +282 -0
  295. package/dist/repertoire/tools-attachments.js +317 -0
  296. package/dist/repertoire/tools-awaiting.js +372 -0
  297. package/dist/repertoire/tools-base.js +63 -1082
  298. package/dist/repertoire/tools-bluebubbles.js +2 -0
  299. package/dist/repertoire/tools-bridge.js +144 -0
  300. package/dist/repertoire/tools-bundle.js +993 -0
  301. package/dist/repertoire/tools-commerce.js +253 -0
  302. package/dist/repertoire/tools-config.js +186 -0
  303. package/dist/repertoire/tools-continuity.js +252 -0
  304. package/dist/repertoire/tools-credential.js +383 -0
  305. package/dist/repertoire/tools-evolution.js +527 -0
  306. package/dist/repertoire/tools-files.js +344 -0
  307. package/dist/repertoire/tools-flight.js +290 -0
  308. package/dist/repertoire/tools-flow.js +119 -0
  309. package/dist/repertoire/tools-github.js +3 -8
  310. package/dist/repertoire/tools-mail.js +1975 -0
  311. package/dist/repertoire/tools-notes.js +468 -0
  312. package/dist/repertoire/tools-obligations.js +143 -0
  313. package/dist/repertoire/tools-orientation.js +31 -0
  314. package/dist/repertoire/tools-record.js +482 -0
  315. package/dist/repertoire/tools-runtime.js +150 -0
  316. package/dist/repertoire/tools-session.js +906 -0
  317. package/dist/repertoire/tools-shell.js +120 -0
  318. package/dist/repertoire/tools-stripe.js +224 -0
  319. package/dist/repertoire/tools-surface.js +355 -0
  320. package/dist/repertoire/tools-teams.js +12 -39
  321. package/dist/repertoire/tools-travel.js +125 -0
  322. package/dist/repertoire/tools-trip.js +982 -0
  323. package/dist/repertoire/tools-user-profile.js +146 -0
  324. package/dist/repertoire/tools-vault.js +40 -0
  325. package/dist/repertoire/tools-voice.js +145 -0
  326. package/dist/repertoire/tools.js +250 -79
  327. package/dist/repertoire/travel-api-client.js +360 -0
  328. package/dist/repertoire/user-profile.js +131 -0
  329. package/dist/repertoire/vault-setup.js +246 -0
  330. package/dist/repertoire/vault-unlock.js +594 -0
  331. package/dist/scripts/claude-code-hook.js +41 -0
  332. package/dist/scripts/claude-code-stop-hook.js +47 -0
  333. package/dist/senses/a2a-entry.js +78 -0
  334. package/dist/senses/attention-queue.js +186 -0
  335. package/dist/senses/await-turn-message.js +58 -0
  336. package/dist/senses/bluebubbles/active-turns.js +216 -0
  337. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  338. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  339. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  340. package/dist/senses/bluebubbles/entry.js +77 -0
  341. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  342. package/dist/senses/bluebubbles/index.js +2732 -0
  343. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  344. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  345. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  346. package/dist/senses/bluebubbles/processed-log.js +133 -0
  347. package/dist/senses/bluebubbles/replay.js +137 -0
  348. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  349. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  350. package/dist/senses/bluebubbles-meta-guard.js +40 -0
  351. package/dist/senses/cli/bracketed-paste.js +82 -0
  352. package/dist/senses/cli/image-paste.js +287 -0
  353. package/dist/senses/cli/image-ref-navigation.js +75 -0
  354. package/dist/senses/cli/ink-app.js +156 -0
  355. package/dist/senses/cli/inline-diff.js +64 -0
  356. package/dist/senses/cli/input-keys.js +174 -0
  357. package/dist/senses/cli/kill-ring.js +86 -0
  358. package/dist/senses/cli/message-list.js +51 -0
  359. package/dist/senses/cli/ouro-tui.js +607 -0
  360. package/dist/senses/cli/spinner-imperative.js +135 -0
  361. package/dist/senses/cli/spinner.js +101 -0
  362. package/dist/senses/cli/status-line.js +60 -0
  363. package/dist/senses/cli/streaming-markdown.js +526 -0
  364. package/dist/senses/cli/tool-display.js +85 -0
  365. package/dist/senses/cli/tool-render.js +85 -0
  366. package/dist/senses/cli/tui-store.js +240 -0
  367. package/dist/senses/cli/virtual-list.js +35 -0
  368. package/dist/senses/cli-entry.js +60 -8
  369. package/dist/senses/cli-layout.js +100 -0
  370. package/dist/senses/cli.js +522 -212
  371. package/dist/senses/commands.js +66 -3
  372. package/dist/senses/habit-turn-message.js +160 -0
  373. package/dist/senses/inner-dialog-worker.js +499 -22
  374. package/dist/senses/inner-dialog.js +544 -47
  375. package/dist/senses/mail-entry.js +66 -0
  376. package/dist/senses/mail.js +379 -0
  377. package/dist/senses/pipeline.js +870 -179
  378. package/dist/senses/proactive-content-guard.js +51 -0
  379. package/dist/senses/shared-turn.js +416 -0
  380. package/dist/senses/surface-tool.js +109 -0
  381. package/dist/senses/teams-entry.js +60 -8
  382. package/dist/senses/teams.js +400 -112
  383. package/dist/senses/trust-gate.js +102 -7
  384. package/dist/senses/voice/audio-playback.js +237 -0
  385. package/dist/senses/voice/audio-routing.js +119 -0
  386. package/dist/senses/voice/elevenlabs.js +202 -0
  387. package/dist/senses/voice/floor-control.js +431 -0
  388. package/dist/senses/voice/floor-controller.js +115 -0
  389. package/dist/senses/voice/golden-path.js +116 -0
  390. package/dist/senses/voice/index.js +29 -0
  391. package/dist/senses/voice/meeting.js +113 -0
  392. package/dist/senses/voice/outbound.js +190 -0
  393. package/dist/senses/voice/phone.js +33 -0
  394. package/dist/senses/voice/playback.js +139 -0
  395. package/dist/senses/voice/realtime-eval.js +496 -0
  396. package/dist/senses/voice/realtime-trace.js +531 -0
  397. package/dist/senses/voice/transcript.js +70 -0
  398. package/dist/senses/voice/turn.js +191 -0
  399. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  400. package/dist/senses/voice/twilio-phone.js +5077 -0
  401. package/dist/senses/voice/types.js +2 -0
  402. package/dist/senses/voice/whisper.js +161 -0
  403. package/dist/senses/voice-entry.js +81 -0
  404. package/dist/senses/voice-realtime-eval-command.js +99 -0
  405. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  406. package/dist/senses/voice-twilio-entry.js +87 -0
  407. package/dist/trips/core.js +138 -0
  408. package/dist/trips/store.js +265 -0
  409. package/dist/util/frontmatter.js +69 -0
  410. package/package.json +57 -12
  411. package/skills/agent-commerce.md +113 -0
  412. package/skills/browser-navigation.md +117 -0
  413. package/skills/commerce-setup-guide.md +116 -0
  414. package/skills/commerce-setup.md +84 -0
  415. package/skills/configure-dev-tools.md +99 -0
  416. package/skills/travel-planning.md +138 -0
  417. package/dist/heart/daemon/auth-flow.js +0 -351
  418. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  419. package/dist/heart/daemon/update-hooks.js +0 -138
  420. package/dist/heart/safe-workspace.js +0 -228
  421. package/dist/heart/session-recall.js +0 -116
  422. package/dist/mind/friends/channel.js +0 -84
  423. package/dist/mind/friends/group-context.js +0 -144
  424. package/dist/mind/friends/resolver.js +0 -84
  425. package/dist/mind/friends/store-file.js +0 -190
  426. package/dist/mind/friends/store.js +0 -4
  427. package/dist/mind/friends/tokens.js +0 -26
  428. package/dist/mind/friends/trust-explanation.js +0 -74
  429. package/dist/mind/friends/types.js +0 -29
  430. package/dist/repertoire/tasks/board.js +0 -134
  431. package/dist/repertoire/tasks/index.js +0 -224
  432. package/dist/repertoire/tasks/lifecycle.js +0 -80
  433. package/dist/repertoire/tasks/middleware.js +0 -65
  434. package/dist/repertoire/tasks/parser.js +0 -173
  435. package/dist/repertoire/tasks/scanner.js +0 -132
  436. package/dist/repertoire/tasks/transitions.js +0 -144
  437. package/dist/senses/bluebubbles-entry.js +0 -13
  438. package/dist/senses/bluebubbles.js +0 -1177
  439. package/dist/senses/debug-activity.js +0 -148
  440. package/subagents/README.md +0 -7
  441. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  442. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  443. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  444. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  445. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  446. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  447. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  448. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  449. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  450. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  451. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  452. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  453. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  454. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  455. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  456. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  457. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -41,6 +41,10 @@ exports.readTaskFile = readTaskFile;
41
41
  exports.buildTaskTriggeredMessage = buildTaskTriggeredMessage;
42
42
  exports.deriveResumeCheckpoint = deriveResumeCheckpoint;
43
43
  exports.innerDialogSessionPath = innerDialogSessionPath;
44
+ exports.enrichDelegatedFromWithBridge = enrichDelegatedFromWithBridge;
45
+ exports.routeDelegatedCompletion = routeDelegatedCompletion;
46
+ exports.buildParseErrorNudge = buildParseErrorNudge;
47
+ exports.buildHeldReturnWakeMessage = buildHeldReturnWakeMessage;
44
48
  exports.runInnerDialogTurn = runInnerDialogTurn;
45
49
  const fs = __importStar(require("fs"));
46
50
  const path = __importStar(require("path"));
@@ -49,17 +53,31 @@ const core_1 = require("../heart/core");
49
53
  const identity_1 = require("../heart/identity");
50
54
  const context_1 = require("../mind/context");
51
55
  const prompt_1 = require("../mind/prompt");
56
+ const mcp_manager_1 = require("../repertoire/mcp-manager");
57
+ const tools_1 = require("../repertoire/tools");
52
58
  const bundle_manifest_1 = require("../mind/bundle-manifest");
53
59
  const pending_1 = require("../mind/pending");
54
- const channel_1 = require("../mind/friends/channel");
60
+ const obligations_1 = require("../arc/obligations");
61
+ const attention_queue_1 = require("./attention-queue");
62
+ const packets_1 = require("../arc/packets");
63
+ const friends_1 = require("@ouro.bot/friends");
55
64
  const trust_gate_1 = require("./trust-gate");
56
- const tokens_1 = require("../mind/friends/tokens");
57
65
  const pipeline_1 = require("./pipeline");
58
66
  const nerves_1 = require("../nerves");
59
67
  const runtime_1 = require("../nerves/runtime");
60
68
  const manager_1 = require("../heart/bridges/manager");
61
69
  const session_activity_1 = require("../heart/session-activity");
62
70
  const bluebubbles_1 = require("./bluebubbles");
71
+ const habit_turn_message_1 = require("./habit-turn-message");
72
+ const await_turn_message_1 = require("./await-turn-message");
73
+ const await_parser_1 = require("../heart/awaiting/await-parser");
74
+ const await_runtime_state_1 = require("../heart/awaiting/await-runtime-state");
75
+ const habit_parser_1 = require("../heart/habits/habit-parser");
76
+ const habit_runtime_state_1 = require("../heart/habits/habit-runtime-state");
77
+ const cadence_1 = require("../heart/daemon/cadence");
78
+ const daemon_health_1 = require("../heart/daemon/daemon-health");
79
+ const flight_recorder_1 = require("../arc/flight-recorder");
80
+ const desk_section_1 = require("../mind/desk-section");
63
81
  const DEFAULT_INNER_DIALOG_INSTINCTS = [
64
82
  {
65
83
  id: "heartbeat_checkin",
@@ -98,23 +116,31 @@ function buildNonCanonicalCleanupNudge(nonCanonicalPaths) {
98
116
  }
99
117
  return [
100
118
  "## canonical cleanup nudge",
101
- "I found non-canonical files in my bundle. I should distill anything valuable into your memory system and remove these files.",
119
+ "I found non-canonical files in my bundle. I should distill anything valuable into my diary and remove these files.",
102
120
  ...listed,
103
121
  ].join("\n");
104
122
  }
123
+ function displayCheckpoint(checkpoint) {
124
+ const trimmed = checkpoint?.trim();
125
+ if (!trimmed || trimmed === "no prior checkpoint recorded") {
126
+ return undefined;
127
+ }
128
+ return trimmed;
129
+ }
105
130
  function buildInstinctUserMessage(instincts, _reason, state) {
106
131
  const active = instincts.find((instinct) => instinct.enabled !== false) ?? DEFAULT_INNER_DIALOG_INSTINCTS[0];
107
- const checkpoint = state.checkpoint?.trim();
132
+ const checkpoint = displayCheckpoint(state.checkpoint);
108
133
  const lines = [active.prompt];
109
134
  if (checkpoint) {
110
- lines.push(`\nlast i remember: ${checkpoint}`);
135
+ lines.push(`\nlast checkpoint: ${checkpoint}`);
111
136
  }
112
137
  return lines.join("\n");
113
138
  }
114
139
  function readTaskFile(agentRoot, taskId) {
115
- // Task files live in collection subdirectories (one-shots, ongoing, habits).
140
+ // Task files live in collection subdirectories (one-shots, ongoing).
116
141
  // Try each collection, then fall back to root tasks/ for legacy layout.
117
- const collections = ["one-shots", "ongoing", "habits", ""];
142
+ // Habits are no longer in tasks/ — they live at bundle root habits/.
143
+ const collections = ["one-shots", "ongoing", ""];
118
144
  for (const collection of collections) {
119
145
  try {
120
146
  return fs.readFileSync(path.join(agentRoot, "tasks", collection, `${taskId}.md`), "utf8").trim();
@@ -133,8 +159,9 @@ function buildTaskTriggeredMessage(taskId, taskContent, checkpoint) {
133
159
  else {
134
160
  lines.push("", `## task: ${taskId}`, "(task file not found)");
135
161
  }
136
- if (checkpoint) {
137
- lines.push("", `last i remember: ${checkpoint}`);
162
+ const renderedCheckpoint = displayCheckpoint(checkpoint);
163
+ if (renderedCheckpoint) {
164
+ lines.push("", `last checkpoint: ${renderedCheckpoint}`);
138
165
  }
139
166
  return lines.join("\n");
140
167
  }
@@ -157,31 +184,129 @@ function contentToText(content) {
157
184
  .join("\n");
158
185
  return text.trim();
159
186
  }
160
- function deriveResumeCheckpoint(messages) {
161
- const lastAssistant = [...messages].reverse().find((message) => message.role === "assistant");
162
- if (!lastAssistant)
163
- return "no prior checkpoint recorded";
164
- const assistantText = contentToText(lastAssistant.content);
187
+ function checkpointTextFromAssistantContent(content) {
188
+ const assistantText = contentToText(content);
165
189
  if (!assistantText)
166
- return "no prior checkpoint recorded";
167
- const explicitCheckpoint = assistantText
190
+ return null;
191
+ const cleanedLines = assistantText
168
192
  .split("\n")
169
- .map((line) => line.trim())
193
+ .map((line) => line.replace(/<\/?think>/gi, "").trim())
194
+ .filter((line) => line.length > 0);
195
+ const explicitCheckpoint = cleanedLines
170
196
  .find((line) => /^checkpoint\s*:/i.test(line));
171
197
  if (explicitCheckpoint) {
172
198
  const parsed = explicitCheckpoint.replace(/^checkpoint\s*:\s*/i, "").trim();
173
- return parsed || "no prior checkpoint recorded";
199
+ return parsed || null;
174
200
  }
175
- const firstLine = assistantText
176
- .split("\n")
177
- .map((line) => line.trim())
178
- .find((line) => line.length > 0);
179
- /* v8 ignore next -- unreachable: contentToText().trim() guarantees a non-empty line @preserve */
180
- if (!firstLine)
181
- return "no prior checkpoint recorded";
182
- if (firstLine.length <= 220)
183
- return firstLine;
184
- return `${firstLine.slice(0, 217)}...`;
201
+ const firstLine = cleanedLines[0];
202
+ return firstLine ?? null;
203
+ }
204
+ function truncateCheckpointText(text) {
205
+ if (text.length <= 220)
206
+ return text;
207
+ return `${text.slice(0, 217)}...`;
208
+ }
209
+ function parseToolArguments(argumentsValue) {
210
+ if (!argumentsValue)
211
+ return {};
212
+ try {
213
+ const parsed = JSON.parse(argumentsValue);
214
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
215
+ ? parsed
216
+ : {};
217
+ }
218
+ catch {
219
+ return {};
220
+ }
221
+ }
222
+ function toolArgumentText(args, keys) {
223
+ for (const key of keys) {
224
+ const value = args[key];
225
+ if (typeof value === "string" && value.trim()) {
226
+ return value.trim();
227
+ }
228
+ }
229
+ return "";
230
+ }
231
+ function summarizeToolAction(name, argumentsValue) {
232
+ if (!name)
233
+ return null;
234
+ const args = parseToolArguments(argumentsValue);
235
+ if (name === "surface") {
236
+ const message = toolArgumentText(args, ["message", "text", "content"]);
237
+ return message ? `surfaced: ${message}` : null;
238
+ }
239
+ if (name === "ponder") {
240
+ const thought = toolArgumentText(args, ["summary", "question", "topic", "prompt"]);
241
+ return thought ? `pondered: ${thought}` : null;
242
+ }
243
+ if (name === "diary_write") {
244
+ const note = toolArgumentText(args, ["text", "content", "note", "entry"]);
245
+ return note ? `diary: ${note}` : null;
246
+ }
247
+ if (name === "let_go") {
248
+ const reason = toolArgumentText(args, ["reason", "note", "status"]);
249
+ return reason ? `let go: ${reason}` : null;
250
+ }
251
+ if (name === "rest") {
252
+ const note = toolArgumentText(args, ["note", "status"]);
253
+ return note ? `rested: ${note}` : null;
254
+ }
255
+ return null;
256
+ }
257
+ function extractToolFunction(toolCall) {
258
+ if (!toolCall || typeof toolCall !== "object" || !("function" in toolCall))
259
+ return null;
260
+ const maybeFunction = toolCall.function;
261
+ if (!maybeFunction || typeof maybeFunction !== "object")
262
+ return null;
263
+ const name = "name" in maybeFunction && typeof maybeFunction.name === "string"
264
+ ? maybeFunction.name
265
+ : undefined;
266
+ const argumentsValue = "arguments" in maybeFunction && typeof maybeFunction.arguments === "string"
267
+ ? maybeFunction.arguments
268
+ : undefined;
269
+ return { name, arguments: argumentsValue };
270
+ }
271
+ function checkpointTextFromAssistantToolCalls(message) {
272
+ if (message.role !== "assistant" || !Array.isArray(message.tool_calls))
273
+ return null;
274
+ for (let i = message.tool_calls.length - 1; i >= 0; i--) {
275
+ const toolFunction = extractToolFunction(message.tool_calls[i]);
276
+ const summary = summarizeToolAction(toolFunction?.name, toolFunction?.arguments);
277
+ if (summary)
278
+ return summary;
279
+ }
280
+ return null;
281
+ }
282
+ function latestRestStatus(messages) {
283
+ for (let i = messages.length - 1; i >= 0; i--) {
284
+ const message = messages[i];
285
+ if (message.role !== "assistant" || !Array.isArray(message.tool_calls))
286
+ continue;
287
+ for (let j = message.tool_calls.length - 1; j >= 0; j--) {
288
+ const toolFunction = extractToolFunction(message.tool_calls[j]);
289
+ if (toolFunction?.name !== "rest")
290
+ continue;
291
+ const status = parseToolArguments(toolFunction.arguments).status;
292
+ return typeof status === "string" && status.trim() ? status.trim() : undefined;
293
+ }
294
+ }
295
+ return undefined;
296
+ }
297
+ function deriveResumeCheckpoint(messages) {
298
+ for (let i = messages.length - 1; i >= 0; i--) {
299
+ const message = messages[i];
300
+ if (message.role !== "assistant")
301
+ continue;
302
+ const textCheckpoint = checkpointTextFromAssistantContent(message.content);
303
+ if (textCheckpoint)
304
+ return truncateCheckpointText(textCheckpoint);
305
+ const toolCheckpoint = checkpointTextFromAssistantToolCalls(message);
306
+ if (toolCheckpoint)
307
+ return truncateCheckpointText(toolCheckpoint);
308
+ }
309
+ return "no prior checkpoint recorded";
185
310
  }
186
311
  function extractAssistantPreview(messages, maxLength = 120) {
187
312
  const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant");
@@ -247,6 +372,7 @@ function writeInnerDialogRuntimeState(sessionFilePath, state) {
247
372
  });
248
373
  }
249
374
  }
375
+ /* v8 ignore start -- routing helpers: called from routing functions which are integration paths @preserve */
250
376
  function writePendingEnvelope(pendingDir, message) {
251
377
  fs.mkdirSync(pendingDir, { recursive: true });
252
378
  const fileName = `${message.timestamp}-${Math.random().toString(36).slice(2, 10)}.json`;
@@ -258,6 +384,8 @@ function sessionMatchesActivity(activity, session) {
258
384
  && activity.channel === session.channel
259
385
  && activity.key === session.key;
260
386
  }
387
+ /* v8 ignore stop */
388
+ /* v8 ignore start -- routing: delivery now inline via surface tool; routing functions preserved for reuse @preserve */
261
389
  function resolveBridgePreferredSession(delegatedFrom, sessionActivity) {
262
390
  if (!delegatedFrom.bridgeId)
263
391
  return null;
@@ -277,15 +405,82 @@ async function tryDeliverDelegatedCompletion(target, outboundEnvelope) {
277
405
  friendId: target.friendId,
278
406
  sessionKey: target.key,
279
407
  text: outboundEnvelope.content,
408
+ intent: "explicit_cross_chat",
280
409
  });
281
410
  return result.delivered;
282
411
  }
412
+ function enrichDelegatedFromWithBridge(delegatedFrom) {
413
+ if (delegatedFrom.bridgeId) {
414
+ return delegatedFrom;
415
+ }
416
+ const bridgeManager = (0, manager_1.createBridgeManager)();
417
+ const originBridges = bridgeManager.findBridgesForSession({
418
+ friendId: delegatedFrom.friendId,
419
+ channel: delegatedFrom.channel,
420
+ key: delegatedFrom.key,
421
+ });
422
+ const activeBridge = originBridges.find((b) => b.lifecycle === "active");
423
+ if (activeBridge) {
424
+ return { ...delegatedFrom, bridgeId: activeBridge.id };
425
+ }
426
+ return delegatedFrom;
427
+ }
428
+ function advanceObligationQuietly(agentName, obligationId, update) {
429
+ if (!obligationId)
430
+ return;
431
+ try {
432
+ (0, obligations_1.advanceReturnObligation)(agentName, obligationId, update);
433
+ /* v8 ignore start -- best-effort: obligation fs errors must never block return routing @preserve */
434
+ }
435
+ catch {
436
+ // swallowed
437
+ }
438
+ /* v8 ignore stop */
439
+ }
283
440
  async function routeDelegatedCompletion(agentRoot, agentName, completion, drainedPending, timestamp) {
284
441
  const delegated = (drainedPending ?? []).find((message) => message.delegatedFrom);
285
442
  if (!delegated?.delegatedFrom || !completion?.answer?.trim()) {
286
443
  return;
287
444
  }
288
- const delegatedFrom = delegated.delegatedFrom;
445
+ const delegatedFrom = enrichDelegatedFromWithBridge(delegated.delegatedFrom);
446
+ const obligationId = delegated.obligationId;
447
+ // Advance any inner return obligations from queued -> running (they were drained this turn).
448
+ // drainedPending is guaranteed non-null here (we found delegated above).
449
+ for (const msg of drainedPending) {
450
+ if (msg.obligationId) {
451
+ advanceObligationQuietly(agentName, msg.obligationId, {
452
+ status: "running",
453
+ startedAt: timestamp,
454
+ });
455
+ }
456
+ }
457
+ if (delegated.obligationStatus === "pending") {
458
+ // Fulfill the persistent obligation in the store
459
+ try {
460
+ const pending = (0, obligations_1.findPendingObligationForOrigin)(agentRoot, {
461
+ friendId: delegatedFrom.friendId,
462
+ channel: delegatedFrom.channel,
463
+ key: delegatedFrom.key,
464
+ });
465
+ /* v8 ignore next 2 -- obligation fulfillment tested via obligations.test.ts; integration requires real disk state @preserve */
466
+ if (pending) {
467
+ (0, obligations_1.fulfillObligation)(agentRoot, pending.id);
468
+ }
469
+ }
470
+ catch {
471
+ /* v8 ignore next -- defensive: obligation store read failure should not break delivery @preserve */
472
+ }
473
+ (0, runtime_1.emitNervesEvent)({
474
+ event: "senses.obligation_fulfilled",
475
+ component: "senses",
476
+ message: "obligation fulfilled via delegated completion",
477
+ meta: {
478
+ friendId: delegatedFrom.friendId,
479
+ channel: delegatedFrom.channel,
480
+ key: delegatedFrom.key,
481
+ },
482
+ });
483
+ }
289
484
  const outboundEnvelope = {
290
485
  from: agentName,
291
486
  friendId: delegatedFrom.friendId,
@@ -294,36 +489,62 @@ async function routeDelegatedCompletion(agentRoot, agentName, completion, draine
294
489
  content: completion.answer.trim(),
295
490
  timestamp,
296
491
  delegatedFrom,
492
+ ...(obligationId ? { obligationId } : {}),
297
493
  };
298
494
  const sessionActivity = (0, session_activity_1.listSessionActivity)({
299
495
  sessionsDir: path.join(agentRoot, "state", "sessions"),
300
496
  friendsDir: path.join(agentRoot, "friends"),
301
497
  agentName,
302
498
  });
499
+ // Priority 1: Bridge-preferred session (if delegation was within a bridge).
303
500
  const bridgeTarget = resolveBridgePreferredSession(delegatedFrom, sessionActivity);
304
501
  if (bridgeTarget) {
305
502
  if (await tryDeliverDelegatedCompletion(bridgeTarget, outboundEnvelope)) {
503
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "bridge-session" });
306
504
  return;
307
505
  }
308
506
  writePendingEnvelope((0, pending_1.getPendingDir)(agentName, bridgeTarget.friendId, bridgeTarget.channel, bridgeTarget.key), outboundEnvelope);
507
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "bridge-session" });
508
+ return;
509
+ }
510
+ // Priority 1.5: Direct return to originating session (ponder without bridge).
511
+ // When delegatedFrom has specific channel+key, route directly there instead of searching for freshest.
512
+ if (delegatedFrom.channel && delegatedFrom.key && delegatedFrom.channel !== "inner") {
513
+ const directTarget = sessionActivity.find((a) => a.friendId === delegatedFrom.friendId && a.channel === delegatedFrom.channel && a.key === delegatedFrom.key);
514
+ if (directTarget) {
515
+ if (await tryDeliverDelegatedCompletion(directTarget, outboundEnvelope)) {
516
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "direct-originator" });
517
+ return;
518
+ }
519
+ }
520
+ // Even if session isn't in activity list (might have ended), queue to its pending dir
521
+ writePendingEnvelope((0, pending_1.getPendingDir)(agentName, delegatedFrom.friendId, delegatedFrom.channel, delegatedFrom.key), outboundEnvelope);
522
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "direct-originator" });
309
523
  return;
310
524
  }
311
- const freshest = (0, session_activity_1.findFreshestFriendSession)({
525
+ // Priority 2: Freshest active friend session.
526
+ // For BB, prefer DM sessions (;-;) over group chats (;+;) — proactive outreach should never land in groups.
527
+ const allFriendSessions = (0, session_activity_1.listSessionActivity)({
312
528
  sessionsDir: path.join(agentRoot, "state", "sessions"),
313
529
  friendsDir: path.join(agentRoot, "friends"),
314
530
  agentName,
315
- friendId: delegatedFrom.friendId,
316
- activeOnly: true,
317
- });
318
- if (freshest && freshest.channel !== "inner") {
531
+ }).filter((s) => s.friendId === delegatedFrom.friendId && s.channel !== "inner");
532
+ const bbDm = allFriendSessions.find((s) => s.channel === "bluebubbles" && s.key.includes(";-;"));
533
+ const freshest = bbDm ?? allFriendSessions.find((s) => s.channel !== "bluebubbles" || s.key.includes(";-;")) ?? allFriendSessions[0];
534
+ if (freshest) {
319
535
  if (await tryDeliverDelegatedCompletion(freshest, outboundEnvelope)) {
536
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "freshest-session" });
320
537
  return;
321
538
  }
322
539
  writePendingEnvelope((0, pending_1.getPendingDir)(agentName, freshest.friendId, freshest.channel, freshest.key), outboundEnvelope);
540
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "freshest-session" });
323
541
  return;
324
542
  }
543
+ // Priority 3: Deferred return queue.
325
544
  writePendingEnvelope((0, pending_1.getDeferredReturnDir)(agentName, delegatedFrom.friendId), outboundEnvelope);
545
+ advanceObligationQuietly(agentName, obligationId, { status: "deferred", returnedAt: timestamp, returnTarget: "deferred" });
326
546
  }
547
+ /* v8 ignore stop */
327
548
  // Self-referencing friend record for inner dialog (agent talking to itself).
328
549
  // No real friend to resolve -- this satisfies the pipeline's friend resolver contract.
329
550
  function createSelfFriend(agentName) {
@@ -350,12 +571,81 @@ function createNoOpFriendStore() {
350
571
  findByExternalId: async () => null,
351
572
  };
352
573
  }
574
+ function buildParseErrorNudge(parseErrors) {
575
+ if (parseErrors.length === 0)
576
+ return "";
577
+ const lines = parseErrors.map((e) => `I noticed my habit file \`${e.file}\` has invalid frontmatter — I should fix it. (${e.error})`);
578
+ return lines.join("\n");
579
+ }
580
+ function buildHeldReturnWakeMessage() {
581
+ return [
582
+ "held return work arrived; use the current held-work frame above as the authority for this turn.",
583
+ "Older checkpoints, rest summaries, transcript memories, completed returns, and repeated probes are historical context, not evidence about what is waiting now.",
584
+ "Return only the requested result; do not add commentary about prior attempts, old loops, or completed probes.",
585
+ "Return each listed item with surface(delegationId=...) before resting or settling.",
586
+ ].join("\n");
587
+ }
588
+ function buildAlsoDueLine(agentRoot, currentHabitName, now) {
589
+ const habitsDir = path.join(agentRoot, "habits");
590
+ let files;
591
+ try {
592
+ files = fs.readdirSync(habitsDir);
593
+ }
594
+ catch {
595
+ return "";
596
+ }
597
+ const nowMs = now().getTime();
598
+ const alsoDue = [];
599
+ for (const file of files) {
600
+ if (!file.endsWith(".md"))
601
+ continue;
602
+ const stem = file.replace(/\.md$/, "");
603
+ if (stem === currentHabitName)
604
+ continue;
605
+ try {
606
+ const content = fs.readFileSync(path.join(habitsDir, file), "utf-8");
607
+ const habit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(content, path.join(habitsDir, file)));
608
+ if (habit.status !== "active" || !habit.cadence)
609
+ continue;
610
+ const cadenceMs = (0, cadence_1.parseCadenceToMs)(habit.cadence);
611
+ if (cadenceMs === null)
612
+ continue;
613
+ if (habit.lastRun === null) {
614
+ alsoDue.push(stem);
615
+ continue;
616
+ }
617
+ const lastRunMs = new Date(habit.lastRun).getTime();
618
+ if (nowMs - lastRunMs >= cadenceMs) {
619
+ alsoDue.push(stem);
620
+ }
621
+ }
622
+ catch {
623
+ // skip unreadable habits
624
+ }
625
+ }
626
+ if (alsoDue.length === 0)
627
+ return "";
628
+ return `also due: ${alsoDue.join(", ")}`;
629
+ }
630
+ function buildHabitSurfacePolicy(origin, surface) {
631
+ const lines = ["## habit surface policy"];
632
+ lines.push("this habit runs privately, but it may message outward when it needs input, has a useful answer, is blocked, or should report status.");
633
+ if (surface.family)
634
+ lines.push("- family recipients are allowed by default.");
635
+ if (surface.originator && origin)
636
+ lines.push(`- the originator is allowed: ${origin.friendId} via ${origin.channel}/${origin.key}.`);
637
+ if (surface.originator && !origin)
638
+ lines.push("- originator messaging is enabled, but this habit has no origin metadata.");
639
+ if (surface.extra.length > 0)
640
+ lines.push(`- extra allowed recipients: ${surface.extra.join(", ")}.`);
641
+ lines.push("- use send_message for intentional contact; use surface only for a held return tied to an existing return obligation.");
642
+ return lines.join("\n");
643
+ }
353
644
  async function runInnerDialogTurn(options) {
354
645
  const now = options?.now ?? (() => new Date());
355
- const reason = options?.reason ?? "heartbeat";
356
- const sessionFilePath = innerDialogSessionPath();
646
+ const reason = options?.reason ?? "instinct";
647
+ const sessionFilePath = options?.habitSession?.sessionPath ?? innerDialogSessionPath();
357
648
  const agentName = (0, identity_1.getAgentName)();
358
- const agentRoot = (0, identity_1.getAgentRoot)();
359
649
  writeInnerDialogRuntimeState(sessionFilePath, {
360
650
  status: "running",
361
651
  reason,
@@ -370,9 +660,15 @@ async function runInnerDialogTurn(options) {
370
660
  resting: false,
371
661
  lastHeartbeatAt: now().toISOString(),
372
662
  };
663
+ const pendingDir = options?.habitSession?.pendingDir ?? (0, pending_1.getInnerDialogPendingDir)(agentName);
664
+ const shouldUseHeldReturnWake = !options?.taskId && reason !== "habit" && reason !== "await"
665
+ ? (0, obligations_1.listActiveReturnObligations)(agentName).length > 0
666
+ : false;
373
667
  // ── Adapter concern: build user message ──────────────────────────
374
668
  let userContent;
375
- if (existingMessages.length === 0) {
669
+ let habitTools;
670
+ let habitParsedSuccessfully = false;
671
+ if (existingMessages.length === 0 && !(reason === "habit" && options?.habitName)) {
376
672
  // Fresh session: bootstrap message with non-canonical cleanup nudge
377
673
  const aspirations = readAspirations((0, identity_1.getAgentRoot)());
378
674
  const nonCanonical = (0, bundle_manifest_1.findNonCanonicalBundlePaths)((0, identity_1.getAgentRoot)());
@@ -391,32 +687,189 @@ async function runInnerDialogTurn(options) {
391
687
  const taskContent = readTaskFile((0, identity_1.getAgentRoot)(), options.taskId);
392
688
  userContent = buildTaskTriggeredMessage(options.taskId, taskContent, state.checkpoint);
393
689
  }
690
+ else if (reason === "habit" && options?.habitName) {
691
+ const agentRoot = (0, identity_1.getAgentRoot)();
692
+ const habitName = options.habitName;
693
+ const habitFilePath = path.join(agentRoot, "habits", `${habitName}.md`);
694
+ const preparedHabit = options.preparedHabit?.habit.name === habitName ? options.preparedHabit.habit : null;
695
+ // Read and parse the habit file
696
+ let habitBody;
697
+ let habitTitle = habitName;
698
+ let habitLastRun = null;
699
+ let habitOrigin = null;
700
+ let habitSurface = { family: true, originator: true, extra: [] };
701
+ if (preparedHabit) {
702
+ habitBody = preparedHabit.body || undefined;
703
+ habitTitle = preparedHabit.title || habitName;
704
+ habitLastRun = preparedHabit.lastRun;
705
+ habitTools = preparedHabit.tools;
706
+ habitOrigin = preparedHabit.origin;
707
+ habitSurface = preparedHabit.surface;
708
+ }
709
+ else {
710
+ try {
711
+ const habitContent = fs.readFileSync(habitFilePath, "utf-8");
712
+ const parsed = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(habitContent, habitFilePath));
713
+ habitBody = parsed.body || undefined;
714
+ habitTitle = parsed.title || habitName;
715
+ habitLastRun = parsed.lastRun;
716
+ habitTools = parsed.tools;
717
+ habitOrigin = parsed.origin;
718
+ habitSurface = parsed.surface;
719
+ }
720
+ catch {
721
+ // Habit file missing or unreadable
722
+ }
723
+ }
724
+ // If the habit file couldn't be read at all (no body, no title parsed), error message
725
+ if (habitBody === undefined && habitTitle === habitName) {
726
+ userContent = `habit "${habitName}" could not be read (file not found or unreadable). check habits/${habitName}.md exists.`;
727
+ }
728
+ else {
729
+ habitParsedSuccessfully = true;
730
+ // Unified path: gather context for ALL habits (heartbeat included)
731
+ const obligations = (0, obligations_1.listActiveReturnObligations)(agentName);
732
+ const nowMs = now().getTime();
733
+ const staleObligations = obligations.map((o) => ({
734
+ friendName: o.origin.friendId,
735
+ content: o.delegatedContent,
736
+ stalenessMs: nowMs - o.createdAt,
737
+ }));
738
+ const alsoDue = buildAlsoDueLine(agentRoot, habitName, now);
739
+ const arcResume = (0, flight_recorder_1.formatFlightRecorderResume)((0, flight_recorder_1.readFlightRecorderResume)(agentRoot));
740
+ const deskOrientation = (0, desk_section_1.deskRecordOrientationSection)(agentRoot, now());
741
+ const surfacePolicy = buildHabitSurfacePolicy(habitOrigin, habitSurface);
742
+ // Degraded state (best-effort: never crash)
743
+ let degradedComponents = [];
744
+ try {
745
+ const health = (0, daemon_health_1.readHealth)((0, daemon_health_1.getDefaultHealthPath)());
746
+ if (health && health.degraded.length > 0) {
747
+ degradedComponents = health.degraded.map((d) => ({ component: d.component, reason: d.reason }));
748
+ }
749
+ }
750
+ catch {
751
+ // Best-effort: missing file or parse error -> empty array, no crash
752
+ }
753
+ userContent = (0, habit_turn_message_1.buildHabitTurnMessage)({
754
+ habitName,
755
+ habitTitle,
756
+ habitBody,
757
+ lastRun: habitLastRun,
758
+ checkpoint: displayCheckpoint(state.checkpoint),
759
+ alsoDue: alsoDue || undefined,
760
+ staleObligations,
761
+ parseErrors: options?.parseErrors ?? [],
762
+ degradedComponents,
763
+ arcResume,
764
+ deskOrientation,
765
+ surfacePolicy,
766
+ priorSessionSummary: options.preparedHabit?.habit.name === habitName ? options.preparedHabit.priorSessionSummary : undefined,
767
+ now,
768
+ });
769
+ }
770
+ }
771
+ else if (reason === "await" && options?.awaitName) {
772
+ const agentRoot = (0, identity_1.getAgentRoot)();
773
+ const awaitName = options.awaitName;
774
+ const awaitFilePath = path.join(agentRoot, "awaiting", `${awaitName}.md`);
775
+ let awaitBody;
776
+ let condition = null;
777
+ let lastCheckedAt = null;
778
+ let lastObservation = null;
779
+ let checkedCount = 0;
780
+ let awaitFound = false;
781
+ try {
782
+ const awaitContent = fs.readFileSync(awaitFilePath, "utf-8");
783
+ const parsed = (0, await_runtime_state_1.applyAwaitRuntimeState)(agentRoot, (0, await_parser_1.parseAwaitFile)(awaitContent, awaitFilePath));
784
+ awaitFound = true;
785
+ awaitBody = parsed.body || undefined;
786
+ condition = parsed.condition;
787
+ lastCheckedAt = parsed.last_checked ?? null;
788
+ lastObservation = parsed.last_observation ?? null;
789
+ checkedCount = parsed.checked_count ?? 0;
790
+ }
791
+ catch {
792
+ // file missing — fall through to error message
793
+ }
794
+ if (!awaitFound || !condition) {
795
+ userContent = `await "${awaitName}" could not be read (file not found or no condition). check awaiting/${awaitName}.md.`;
796
+ }
797
+ else {
798
+ userContent = (0, await_turn_message_1.buildAwaitTurnMessage)({
799
+ awaitName,
800
+ condition,
801
+ body: awaitBody,
802
+ lastCheckedAt,
803
+ lastObservation,
804
+ checkedCount,
805
+ checkpoint: displayCheckpoint(state.checkpoint),
806
+ now,
807
+ });
808
+ }
809
+ }
394
810
  else {
395
811
  userContent = buildInstinctUserMessage(instincts, reason, state);
396
812
  }
397
813
  }
814
+ if (shouldUseHeldReturnWake) {
815
+ userContent = buildHeldReturnWakeMessage();
816
+ }
398
817
  const userMessage = { role: "user", content: userContent };
399
818
  // ── Session loader: wraps existing session logic ──────────────────
400
- const innerCapabilities = (0, channel_1.getChannelCapabilities)("inner");
401
- const pendingDir = (0, pending_1.getInnerDialogPendingDir)(agentName);
819
+ const innerCapabilities = (0, friends_1.getChannelCapabilities)("inner");
402
820
  const selfFriend = createSelfFriend(agentName);
403
821
  const selfContext = { friend: selfFriend, channel: innerCapabilities };
822
+ const mcpManager = await (0, mcp_manager_1.getSharedMcpManager)() ?? undefined;
823
+ // ── Habit tool enforcement ───────────────────────────────────────
824
+ let habitToolsResolved;
825
+ if (habitTools !== undefined) {
826
+ const fullTools = (0, tools_1.getToolsForChannel)(innerCapabilities);
827
+ habitToolsResolved = fullTools.filter((t) => habitTools.includes(t.function.name));
828
+ (0, runtime_1.emitNervesEvent)({
829
+ event: "habit.tools_restricted",
830
+ component: "senses",
831
+ message: "habit running with restricted tools",
832
+ meta: {
833
+ habitName: options?.habitName,
834
+ declared: habitTools,
835
+ resolved: habitToolsResolved.map((t) => t.function.name),
836
+ },
837
+ });
838
+ }
839
+ else if (reason === "habit" && options?.habitName && habitParsedSuccessfully) {
840
+ (0, runtime_1.emitNervesEvent)({
841
+ event: "habit.tools_unrestricted",
842
+ component: "senses",
843
+ message: "habit running with full tool repertoire",
844
+ meta: { habitName: options.habitName },
845
+ });
846
+ }
404
847
  const sessionLoader = {
405
848
  loadOrCreate: async () => {
406
849
  if (existingMessages.length > 0) {
407
- return { messages: existingMessages, sessionPath: sessionFilePath };
850
+ return {
851
+ messages: existingMessages,
852
+ sessionPath: sessionFilePath,
853
+ structuredOutputs: loaded?.structuredOutputs,
854
+ };
408
855
  }
409
856
  // Fresh session: build system prompt
410
- const systemPrompt = await (0, prompt_1.buildSystem)("inner", { toolChoiceRequired: true });
857
+ const systemPrompt = await (0, prompt_1.buildSystem)("inner", {
858
+ toolChoiceRequired: true,
859
+ flightRecorderResume: (0, flight_recorder_1.readFlightRecorderResume)((0, identity_1.getAgentRoot)()),
860
+ });
411
861
  return {
412
- messages: [{ role: "system", content: systemPrompt }],
862
+ messages: [{ role: "system", content: (0, prompt_1.flattenSystemPrompt)(systemPrompt) }],
413
863
  sessionPath: sessionFilePath,
864
+ structuredOutputs: [],
414
865
  };
415
866
  },
416
867
  };
417
868
  // ── Call shared pipeline ──────────────────────────────────────────
418
869
  const callbacks = createInnerDialogCallbacks();
419
870
  const traceId = (0, nerves_1.createTraceId)();
871
+ // Attention queue: built when pending messages are drained, shared with tool context
872
+ let attentionQueue = [];
420
873
  const result = await (0, pipeline_1.handleInboundTurn)({
421
874
  channel: "inner",
422
875
  sessionKey: "dialog",
@@ -431,16 +884,58 @@ async function runInnerDialogTurn(options) {
431
884
  enforceTrustGate: trust_gate_1.enforceTrustGate,
432
885
  drainPending: pending_1.drainPending,
433
886
  runAgent: core_1.runAgent,
434
- postTurn: context_1.postTurn,
435
- accumulateFriendTokens: tokens_1.accumulateFriendTokens,
887
+ postTurn: (turnMessages, sessionPathArg, usage, hooks, state) => {
888
+ const prepared = (0, context_1.postTurnTrim)(turnMessages, usage, hooks);
889
+ return (0, context_1.deferPostTurnPersist)(sessionPathArg, prepared, usage, state);
890
+ },
891
+ accumulateFriendTokens: friends_1.accumulateFriendTokens,
436
892
  signal: options?.signal,
893
+ /* v8 ignore start -- attention queue: callback invoked by pipeline during pending drain; tested via attention-queue unit tests @preserve */
894
+ onPendingDrained: (drained) => {
895
+ const outstandingObligations = (0, obligations_1.listActiveReturnObligations)(agentName);
896
+ const builtAttentionQueue = (0, attention_queue_1.buildAttentionQueue)({
897
+ drainedPending: drained,
898
+ outstandingObligations,
899
+ friendNameResolver: (friendId) => {
900
+ try {
901
+ const raw = fs.readFileSync(path.join((0, identity_1.getAgentRoot)(agentName), "friends", friendId + ".json"), "utf-8");
902
+ const parsed = JSON.parse(raw);
903
+ return typeof parsed.name === "string" ? parsed.name : null;
904
+ }
905
+ catch {
906
+ return null;
907
+ }
908
+ },
909
+ packetResolver: (packetId) => {
910
+ try {
911
+ return (0, packets_1.readPonderPacket)((0, identity_1.getAgentRoot)(agentName), packetId);
912
+ }
913
+ catch {
914
+ return null;
915
+ }
916
+ },
917
+ });
918
+ attentionQueue.splice(0, attentionQueue.length, ...builtAttentionQueue);
919
+ const attentionFrame = (0, attention_queue_1.buildAttentionQueueStatusFrame)(attentionQueue);
920
+ return attentionFrame ? [attentionFrame] : [];
921
+ },
922
+ /* v8 ignore stop */
437
923
  runAgentOptions: {
438
924
  traceId,
439
925
  toolChoiceRequired: true,
440
- skipConfirmation: true,
926
+ mcpManager,
927
+ ...(habitToolsResolved !== undefined && { tools: habitToolsResolved }),
928
+ toolContext: {
929
+ signin: async () => undefined,
930
+ delegatedOrigins: attentionQueue,
931
+ ...(options?.habitSession ? { habitSession: options.habitSession } : {}),
932
+ },
933
+ ...(options?.habitSession ? { habitSession: options.habitSession } : {}),
441
934
  },
442
935
  });
443
- await routeDelegatedCompletion(agentRoot, agentName, result.completion, result.drainedPending, now().getTime());
936
+ // Post-turn routeDelegatedCompletion removed: delivery is now inline via surface tool.
937
+ // settle in inner dialog produces no CompletionMetadata, so routeDelegatedCompletion
938
+ // would be a no-op. The routing infrastructure is reused by the surface handler.
444
939
  const resultMessages = result.messages ?? [];
445
940
  const assistantPreview = extractAssistantPreview(resultMessages);
446
941
  const toolCalls = extractToolCallNames(resultMessages);
@@ -466,6 +961,8 @@ async function runInnerDialogTurn(options) {
466
961
  usage: result.usage,
467
962
  sessionPath: result.sessionPath ?? sessionFilePath,
468
963
  completion: result.completion,
964
+ turnOutcome: result.turnOutcome,
965
+ restStatus: latestRestStatus(resultMessages),
469
966
  };
470
967
  }
471
968
  finally {