@ouro.bot/cli 0.1.0-alpha.66 → 0.1.0-alpha.660

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