@ouro.bot/cli 0.1.0-alpha.62 → 0.1.0-alpha.636

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