@ouro.bot/cli 0.1.0-alpha.5 → 0.1.0-alpha.500

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 (380) hide show
  1. package/README.md +226 -183
  2. package/SerpentGuide.ouro/agent.json +82 -0
  3. package/SerpentGuide.ouro/psyche/SOUL.md +25 -0
  4. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +2 -2
  5. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  6. package/assets/ouroboros.png +0 -0
  7. package/changelog.json +3418 -0
  8. package/dist/arc/attention-types.js +8 -0
  9. package/dist/arc/cares.js +140 -0
  10. package/dist/arc/episodes.js +117 -0
  11. package/dist/arc/intentions.js +133 -0
  12. package/dist/arc/json-store.js +117 -0
  13. package/dist/arc/obligations.js +237 -0
  14. package/dist/arc/packets.js +193 -0
  15. package/dist/arc/presence.js +185 -0
  16. package/dist/arc/task-lifecycle.js +65 -0
  17. package/dist/heart/active-work.js +989 -0
  18. package/dist/heart/agent-entry.js +58 -3
  19. package/dist/heart/attachments/image-normalize.js +194 -0
  20. package/dist/heart/attachments/materialize.js +97 -0
  21. package/dist/heart/attachments/originals.js +88 -0
  22. package/dist/heart/attachments/render.js +29 -0
  23. package/dist/heart/attachments/sources/adapter.js +2 -0
  24. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  25. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  26. package/dist/heart/attachments/sources/index.js +16 -0
  27. package/dist/heart/attachments/store.js +103 -0
  28. package/dist/heart/attachments/types.js +93 -0
  29. package/dist/heart/auth/auth-flow.js +426 -0
  30. package/dist/heart/background-operations.js +281 -0
  31. package/dist/heart/bridges/manager.js +358 -0
  32. package/dist/heart/bridges/state-machine.js +135 -0
  33. package/dist/heart/bridges/store.js +123 -0
  34. package/dist/heart/bundle-state.js +168 -0
  35. package/dist/heart/commitments.js +111 -0
  36. package/dist/heart/config-registry.js +304 -0
  37. package/dist/heart/config.js +193 -130
  38. package/dist/heart/core.js +1010 -261
  39. package/dist/heart/cross-chat-delivery.js +131 -0
  40. package/dist/heart/daemon/agent-config-check.js +490 -0
  41. package/dist/heart/daemon/agent-discovery.js +157 -0
  42. package/dist/heart/daemon/agent-service.js +360 -0
  43. package/dist/heart/daemon/agentic-repair.js +216 -0
  44. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  45. package/dist/heart/daemon/cadence.js +70 -0
  46. package/dist/heart/daemon/cli-defaults.js +640 -0
  47. package/dist/heart/daemon/cli-exec.js +7239 -0
  48. package/dist/heart/daemon/cli-help.js +493 -0
  49. package/dist/heart/daemon/cli-parse.js +1533 -0
  50. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  51. package/dist/heart/daemon/cli-render.js +561 -0
  52. package/dist/heart/daemon/cli-types.js +8 -0
  53. package/dist/heart/daemon/connect-bay.js +323 -0
  54. package/dist/heart/daemon/daemon-cli.js +30 -697
  55. package/dist/heart/daemon/daemon-entry.js +359 -8
  56. package/dist/heart/daemon/daemon-health.js +141 -0
  57. package/dist/heart/daemon/daemon-runtime-sync.js +268 -0
  58. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  59. package/dist/heart/daemon/daemon.js +813 -19
  60. package/dist/heart/daemon/dns-workflow.js +394 -0
  61. package/dist/heart/daemon/doctor-types.js +8 -0
  62. package/dist/heart/daemon/doctor.js +615 -0
  63. package/dist/heart/daemon/health-monitor.js +92 -1
  64. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  65. package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
  66. package/dist/heart/daemon/http-health-probe.js +80 -0
  67. package/dist/heart/daemon/human-command-screens.js +234 -0
  68. package/dist/heart/daemon/human-readiness.js +114 -0
  69. package/dist/heart/daemon/inner-status.js +89 -0
  70. package/dist/heart/daemon/interactive-repair.js +394 -0
  71. package/dist/heart/daemon/launchd.js +171 -0
  72. package/dist/heart/daemon/log-tailer.js +82 -12
  73. package/dist/heart/daemon/logs-prune.js +110 -0
  74. package/dist/heart/daemon/message-router.js +17 -8
  75. package/dist/heart/daemon/os-cron-deps.js +134 -0
  76. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  77. package/dist/heart/daemon/ouro-entry.js +3 -1
  78. package/dist/heart/daemon/process-manager.js +215 -1
  79. package/dist/heart/daemon/provider-discovery.js +137 -0
  80. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  81. package/dist/heart/daemon/pulse.js +475 -0
  82. package/dist/heart/daemon/readiness-repair.js +365 -0
  83. package/dist/heart/daemon/run-hooks.js +39 -0
  84. package/dist/heart/daemon/runtime-logging.js +67 -16
  85. package/dist/heart/daemon/runtime-metadata.js +191 -0
  86. package/dist/heart/daemon/runtime-mode.js +67 -0
  87. package/dist/heart/daemon/safe-mode.js +161 -0
  88. package/dist/heart/daemon/sense-manager.js +431 -0
  89. package/dist/heart/daemon/session-id-resolver.js +131 -0
  90. package/dist/heart/daemon/skill-management-installer.js +94 -0
  91. package/dist/heart/daemon/socket-client.js +307 -0
  92. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  93. package/dist/heart/daemon/startup-tui.js +264 -0
  94. package/dist/heart/daemon/task-scheduler.js +3 -25
  95. package/dist/heart/daemon/terminal-ui.js +499 -0
  96. package/dist/heart/daemon/thoughts.js +524 -0
  97. package/dist/heart/daemon/up-progress.js +366 -0
  98. package/dist/heart/daemon/vault-items.js +56 -0
  99. package/dist/heart/delegation.js +62 -0
  100. package/dist/heart/habits/habit-migration.js +189 -0
  101. package/dist/heart/habits/habit-parser.js +140 -0
  102. package/dist/heart/habits/habit-runtime-state.js +100 -0
  103. package/dist/heart/habits/habit-scheduler.js +372 -0
  104. package/dist/heart/{daemon → hatch}/hatch-animation.js +10 -3
  105. package/dist/heart/{daemon → hatch}/hatch-flow.js +54 -136
  106. package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
  107. package/dist/heart/hatch/specialist-orchestrator.js +129 -0
  108. package/dist/heart/hatch/specialist-prompt.js +102 -0
  109. package/dist/heart/hatch/specialist-tools.js +306 -0
  110. package/dist/heart/identity.js +274 -61
  111. package/dist/heart/kept-notes.js +357 -0
  112. package/dist/heart/kicks.js +2 -20
  113. package/dist/heart/machine-identity.js +161 -0
  114. package/dist/heart/mail-import-discovery.js +353 -0
  115. package/dist/heart/mcp/mcp-server.js +653 -0
  116. package/dist/heart/migrate-config.js +100 -0
  117. package/dist/heart/model-capabilities.js +59 -0
  118. package/dist/heart/outlook/outlook-http-hooks.js +66 -0
  119. package/dist/heart/outlook/outlook-http-response.js +7 -0
  120. package/dist/heart/outlook/outlook-http-routes.js +244 -0
  121. package/dist/heart/outlook/outlook-http-static.js +103 -0
  122. package/dist/heart/outlook/outlook-http-transport.js +116 -0
  123. package/dist/heart/outlook/outlook-http.js +99 -0
  124. package/dist/heart/outlook/outlook-read.js +31 -0
  125. package/dist/heart/outlook/outlook-types.js +27 -0
  126. package/dist/heart/outlook/outlook-view.js +195 -0
  127. package/dist/heart/outlook/readers/agent-machine.js +382 -0
  128. package/dist/heart/outlook/readers/continuity-readers.js +336 -0
  129. package/dist/heart/outlook/readers/mail.js +362 -0
  130. package/dist/heart/outlook/readers/runtime-readers.js +644 -0
  131. package/dist/heart/outlook/readers/sessions.js +232 -0
  132. package/dist/heart/outlook/readers/shared.js +111 -0
  133. package/dist/heart/platform.js +81 -0
  134. package/dist/heart/progress-story.js +42 -0
  135. package/dist/heart/provider-attempt.js +134 -0
  136. package/dist/heart/provider-binding-resolver.js +255 -0
  137. package/dist/heart/provider-credentials.js +424 -0
  138. package/dist/heart/provider-failover.js +301 -0
  139. package/dist/heart/provider-models.js +81 -0
  140. package/dist/heart/provider-ping.js +262 -0
  141. package/dist/heart/provider-state.js +216 -0
  142. package/dist/heart/provider-visibility.js +188 -0
  143. package/dist/heart/providers/anthropic-token.js +131 -0
  144. package/dist/heart/providers/anthropic.js +202 -50
  145. package/dist/heart/providers/azure.js +104 -13
  146. package/dist/heart/providers/error-classification.js +63 -0
  147. package/dist/heart/providers/github-copilot.js +145 -0
  148. package/dist/heart/providers/minimax-vlm.js +189 -0
  149. package/dist/heart/providers/minimax.js +29 -7
  150. package/dist/heart/providers/openai-codex.js +63 -39
  151. package/dist/heart/runtime-capability-check.js +170 -0
  152. package/dist/heart/runtime-credentials.js +260 -0
  153. package/dist/heart/sense-truth.js +68 -0
  154. package/dist/heart/session-activity.js +190 -0
  155. package/dist/heart/session-events.js +1089 -0
  156. package/dist/heart/session-playback-cli-main.js +5 -0
  157. package/dist/heart/session-playback-cli.js +36 -0
  158. package/dist/heart/session-playback.js +231 -0
  159. package/dist/heart/session-transcript.js +167 -0
  160. package/dist/heart/start-of-turn-packet.js +345 -0
  161. package/dist/heart/streaming.js +129 -34
  162. package/dist/heart/sync.js +332 -0
  163. package/dist/heart/target-resolution.js +127 -0
  164. package/dist/heart/tempo.js +93 -0
  165. package/dist/heart/temporal-view.js +41 -0
  166. package/dist/heart/tool-activity-callbacks.js +36 -0
  167. package/dist/heart/tool-description.js +135 -0
  168. package/dist/heart/tool-friction.js +55 -0
  169. package/dist/heart/tool-loop.js +200 -0
  170. package/dist/heart/turn-context.js +372 -0
  171. package/dist/heart/turn-coordinator.js +28 -0
  172. package/dist/heart/versioning/ouro-bot-global-installer.js +128 -0
  173. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  174. package/dist/heart/versioning/ouro-path-installer.js +425 -0
  175. package/dist/heart/{daemon → versioning}/ouro-uti.js +11 -2
  176. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  177. package/dist/heart/versioning/staged-restart.js +146 -0
  178. package/dist/heart/versioning/update-checker.js +115 -0
  179. package/dist/heart/versioning/update-hooks.js +142 -0
  180. package/dist/heart/versioning/wrapper-publish-guard.js +86 -0
  181. package/dist/mailroom/attention.js +167 -0
  182. package/dist/mailroom/autonomy.js +209 -0
  183. package/dist/mailroom/blob-store.js +606 -0
  184. package/dist/mailroom/core.js +672 -0
  185. package/dist/mailroom/entry.js +160 -0
  186. package/dist/mailroom/file-store.js +426 -0
  187. package/dist/mailroom/mbox-import.js +382 -0
  188. package/dist/mailroom/outbound.js +380 -0
  189. package/dist/mailroom/policy.js +263 -0
  190. package/dist/mailroom/reader.js +219 -0
  191. package/dist/mailroom/search-cache.js +182 -0
  192. package/dist/mailroom/search-relevance.js +319 -0
  193. package/dist/mailroom/smtp-ingress.js +176 -0
  194. package/dist/mailroom/source-state.js +176 -0
  195. package/dist/mailroom/thread.js +109 -0
  196. package/dist/mailroom/travel-extract.js +89 -0
  197. package/dist/mind/bundle-manifest.js +77 -1
  198. package/dist/mind/context.js +173 -94
  199. package/dist/mind/diary-integrity.js +60 -0
  200. package/dist/mind/{memory.js → diary.js} +84 -96
  201. package/dist/mind/embedding-provider.js +60 -0
  202. package/dist/mind/file-state.js +179 -0
  203. package/dist/mind/first-impressions.js +16 -2
  204. package/dist/mind/friends/channel.js +73 -0
  205. package/dist/mind/friends/group-context.js +144 -0
  206. package/dist/mind/friends/resolver.js +54 -2
  207. package/dist/mind/friends/store-file.js +58 -3
  208. package/dist/mind/friends/trust-explanation.js +74 -0
  209. package/dist/mind/friends/types.js +10 -2
  210. package/dist/mind/journal-index.js +161 -0
  211. package/dist/mind/note-search.js +268 -0
  212. package/dist/mind/obligation-steering.js +221 -0
  213. package/dist/mind/pending.js +76 -9
  214. package/dist/mind/phrases.js +1 -0
  215. package/dist/mind/prompt-refresh.js +3 -2
  216. package/dist/mind/prompt.js +1144 -117
  217. package/dist/mind/provenance-trust.js +26 -0
  218. package/dist/mind/scrutiny.js +173 -0
  219. package/dist/mind/token-estimate.js +8 -12
  220. package/dist/nerves/cli-logging.js +22 -3
  221. package/dist/nerves/coverage/audit-rules.js +15 -6
  222. package/dist/nerves/coverage/audit.js +28 -2
  223. package/dist/nerves/coverage/cli.js +1 -1
  224. package/dist/nerves/coverage/contract.js +5 -5
  225. package/dist/nerves/coverage/file-completeness.js +101 -5
  226. package/dist/nerves/coverage/run-artifacts.js +1 -1
  227. package/dist/nerves/event-buffer.js +111 -0
  228. package/dist/nerves/index.js +224 -4
  229. package/dist/nerves/observation.js +20 -0
  230. package/dist/nerves/redact.js +79 -0
  231. package/dist/nerves/runtime.js +5 -1
  232. package/dist/outlook-ui/assets/index-BPr5vNuM.css +1 -0
  233. package/dist/outlook-ui/assets/index-Cm51CY9W.js +61 -0
  234. package/dist/outlook-ui/index.html +15 -0
  235. package/dist/repertoire/ado-client.js +17 -56
  236. package/dist/repertoire/ado-semantic.js +11 -10
  237. package/dist/repertoire/api-client.js +97 -0
  238. package/dist/repertoire/bitwarden-store.js +774 -0
  239. package/dist/repertoire/bundle-templates.js +72 -0
  240. package/dist/repertoire/bw-installer.js +180 -0
  241. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  242. package/dist/repertoire/coding/context-pack.js +330 -0
  243. package/dist/repertoire/coding/feedback.js +301 -0
  244. package/dist/repertoire/coding/index.js +4 -1
  245. package/dist/repertoire/coding/manager.js +220 -13
  246. package/dist/repertoire/coding/spawner.js +58 -12
  247. package/dist/repertoire/coding/tools.js +209 -7
  248. package/dist/repertoire/commerce-errors.js +109 -0
  249. package/dist/repertoire/commerce-self-test.js +156 -0
  250. package/dist/repertoire/credential-access.js +111 -0
  251. package/dist/repertoire/data/ado-endpoints.json +188 -0
  252. package/dist/repertoire/duffel-client.js +185 -0
  253. package/dist/repertoire/github-client.js +14 -55
  254. package/dist/repertoire/graph-client.js +11 -52
  255. package/dist/repertoire/guardrails.js +396 -0
  256. package/dist/repertoire/mcp-client.js +255 -0
  257. package/dist/repertoire/mcp-manager.js +305 -0
  258. package/dist/repertoire/mcp-tools.js +63 -0
  259. package/dist/repertoire/shell-sessions.js +133 -0
  260. package/dist/repertoire/skills.js +15 -24
  261. package/dist/repertoire/stripe-client.js +131 -0
  262. package/dist/repertoire/tasks/board.js +43 -5
  263. package/dist/repertoire/tasks/fix.js +182 -0
  264. package/dist/repertoire/tasks/index.js +39 -13
  265. package/dist/repertoire/tasks/lifecycle.js +2 -2
  266. package/dist/repertoire/tasks/parser.js +3 -2
  267. package/dist/repertoire/tasks/scanner.js +194 -37
  268. package/dist/repertoire/tasks/transitions.js +16 -79
  269. package/dist/repertoire/tool-results.js +29 -0
  270. package/dist/repertoire/tools-attachments.js +317 -0
  271. package/dist/repertoire/tools-base.js +49 -707
  272. package/dist/repertoire/tools-bluebubbles.js +94 -0
  273. package/dist/repertoire/tools-bridge.js +141 -0
  274. package/dist/repertoire/tools-bundle.js +984 -0
  275. package/dist/repertoire/tools-config.js +185 -0
  276. package/dist/repertoire/tools-continuity.js +248 -0
  277. package/dist/repertoire/tools-credential.js +381 -0
  278. package/dist/repertoire/tools-files.js +342 -0
  279. package/dist/repertoire/tools-flight.js +224 -0
  280. package/dist/repertoire/tools-flow.js +105 -0
  281. package/dist/repertoire/tools-github.js +1 -7
  282. package/dist/repertoire/tools-mail.js +1377 -0
  283. package/dist/repertoire/tools-notes.js +376 -0
  284. package/dist/repertoire/tools-session.js +749 -0
  285. package/dist/repertoire/tools-shell.js +120 -0
  286. package/dist/repertoire/tools-stripe.js +180 -0
  287. package/dist/repertoire/tools-surface.js +243 -0
  288. package/dist/repertoire/tools-teams.js +64 -61
  289. package/dist/repertoire/tools-travel.js +125 -0
  290. package/dist/repertoire/tools-trip.js +356 -0
  291. package/dist/repertoire/tools-user-profile.js +144 -0
  292. package/dist/repertoire/tools-vault.js +40 -0
  293. package/dist/repertoire/tools.js +149 -98
  294. package/dist/repertoire/travel-api-client.js +360 -0
  295. package/dist/repertoire/user-profile.js +131 -0
  296. package/dist/repertoire/vault-setup.js +246 -0
  297. package/dist/repertoire/vault-unlock.js +561 -0
  298. package/dist/scripts/claude-code-hook.js +41 -0
  299. package/dist/scripts/claude-code-stop-hook.js +47 -0
  300. package/dist/senses/attention-queue.js +116 -0
  301. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  302. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  303. package/dist/senses/bluebubbles/client.js +685 -0
  304. package/dist/senses/bluebubbles/entry.js +73 -0
  305. package/dist/senses/bluebubbles/inbound-log.js +126 -0
  306. package/dist/senses/bluebubbles/index.js +1881 -0
  307. package/dist/senses/bluebubbles/media.js +389 -0
  308. package/dist/senses/bluebubbles/model.js +282 -0
  309. package/dist/senses/bluebubbles/mutation-log.js +116 -0
  310. package/dist/senses/bluebubbles/processed-log.js +111 -0
  311. package/dist/senses/bluebubbles/replay.js +129 -0
  312. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  313. package/dist/senses/bluebubbles/session-cleanup.js +72 -0
  314. package/dist/senses/cli/bracketed-paste.js +82 -0
  315. package/dist/senses/cli/image-paste.js +287 -0
  316. package/dist/senses/cli/image-ref-navigation.js +75 -0
  317. package/dist/senses/cli/ink-app.js +156 -0
  318. package/dist/senses/cli/inline-diff.js +64 -0
  319. package/dist/senses/cli/input-keys.js +174 -0
  320. package/dist/senses/cli/kill-ring.js +86 -0
  321. package/dist/senses/cli/message-list.js +51 -0
  322. package/dist/senses/cli/ouro-tui.js +605 -0
  323. package/dist/senses/cli/spinner-imperative.js +135 -0
  324. package/dist/senses/cli/spinner.js +101 -0
  325. package/dist/senses/cli/status-line.js +60 -0
  326. package/dist/senses/cli/streaming-markdown.js +526 -0
  327. package/dist/senses/cli/tool-display.js +83 -0
  328. package/dist/senses/cli/tool-render.js +85 -0
  329. package/dist/senses/cli/tui-store.js +240 -0
  330. package/dist/senses/cli/virtual-list.js +35 -0
  331. package/dist/senses/cli-entry.js +60 -8
  332. package/dist/senses/cli-layout.js +187 -0
  333. package/dist/senses/cli.js +768 -264
  334. package/dist/senses/commands.js +66 -3
  335. package/dist/senses/continuity.js +94 -0
  336. package/dist/senses/habit-turn-message.js +108 -0
  337. package/dist/senses/inner-dialog-worker.js +199 -16
  338. package/dist/senses/inner-dialog.js +640 -91
  339. package/dist/senses/mail-entry.js +66 -0
  340. package/dist/senses/mail.js +379 -0
  341. package/dist/senses/pipeline.js +665 -0
  342. package/dist/senses/proactive-content-guard.js +51 -0
  343. package/dist/senses/shared-turn.js +248 -0
  344. package/dist/senses/surface-tool.js +68 -0
  345. package/dist/senses/teams-entry.js +60 -8
  346. package/dist/senses/teams.js +844 -197
  347. package/dist/senses/trust-gate.js +207 -2
  348. package/dist/trips/core.js +138 -0
  349. package/dist/trips/store.js +146 -0
  350. package/package.json +47 -6
  351. package/skills/agent-commerce.md +106 -0
  352. package/skills/browser-navigation.md +117 -0
  353. package/skills/commerce-setup-guide.md +116 -0
  354. package/skills/commerce-setup.md +84 -0
  355. package/skills/configure-dev-tools.md +101 -0
  356. package/skills/travel-planning.md +138 -0
  357. package/AdoptionSpecialist.ouro/agent.json +0 -20
  358. package/AdoptionSpecialist.ouro/psyche/SOUL.md +0 -22
  359. package/dist/heart/daemon/specialist-orchestrator.js +0 -160
  360. package/dist/heart/daemon/specialist-prompt.js +0 -40
  361. package/dist/heart/daemon/specialist-session.js +0 -142
  362. package/dist/heart/daemon/specialist-tools.js +0 -128
  363. package/dist/heart/daemon/subagent-installer.js +0 -125
  364. package/dist/inner-worker-entry.js +0 -4
  365. package/dist/mind/associative-recall.js +0 -197
  366. package/subagents/README.md +0 -73
  367. package/subagents/work-doer.md +0 -233
  368. package/subagents/work-merger.md +0 -624
  369. package/subagents/work-planner.md +0 -373
  370. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  371. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  372. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  373. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  374. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  375. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  376. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  377. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  378. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  379. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  380. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
@@ -37,8 +37,13 @@ exports.loadInnerDialogInstincts = loadInnerDialogInstincts;
37
37
  exports.buildInnerDialogBootstrapMessage = buildInnerDialogBootstrapMessage;
38
38
  exports.buildNonCanonicalCleanupNudge = buildNonCanonicalCleanupNudge;
39
39
  exports.buildInstinctUserMessage = buildInstinctUserMessage;
40
+ exports.readTaskFile = readTaskFile;
41
+ exports.buildTaskTriggeredMessage = buildTaskTriggeredMessage;
40
42
  exports.deriveResumeCheckpoint = deriveResumeCheckpoint;
41
43
  exports.innerDialogSessionPath = innerDialogSessionPath;
44
+ exports.enrichDelegatedFromWithBridge = enrichDelegatedFromWithBridge;
45
+ exports.routeDelegatedCompletion = routeDelegatedCompletion;
46
+ exports.buildParseErrorNudge = buildParseErrorNudge;
42
47
  exports.runInnerDialogTurn = runInnerDialogTurn;
43
48
  const fs = __importStar(require("fs"));
44
49
  const path = __importStar(require("path"));
@@ -47,13 +52,32 @@ const core_1 = require("../heart/core");
47
52
  const identity_1 = require("../heart/identity");
48
53
  const context_1 = require("../mind/context");
49
54
  const prompt_1 = require("../mind/prompt");
55
+ const mcp_manager_1 = require("../repertoire/mcp-manager");
56
+ const tools_1 = require("../repertoire/tools");
50
57
  const bundle_manifest_1 = require("../mind/bundle-manifest");
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");
62
+ const channel_1 = require("../mind/friends/channel");
63
+ const trust_gate_1 = require("./trust-gate");
64
+ const tokens_1 = require("../mind/friends/tokens");
65
+ const pipeline_1 = require("./pipeline");
51
66
  const nerves_1 = require("../nerves");
52
67
  const runtime_1 = require("../nerves/runtime");
68
+ const manager_1 = require("../heart/bridges/manager");
69
+ const session_activity_1 = require("../heart/session-activity");
70
+ const bluebubbles_1 = require("./bluebubbles");
71
+ const habit_turn_message_1 = require("./habit-turn-message");
72
+ const journal_index_1 = require("../mind/journal-index");
73
+ const habit_parser_1 = require("../heart/habits/habit-parser");
74
+ const habit_runtime_state_1 = require("../heart/habits/habit-runtime-state");
75
+ const cadence_1 = require("../heart/daemon/cadence");
76
+ const daemon_health_1 = require("../heart/daemon/daemon-health");
53
77
  const DEFAULT_INNER_DIALOG_INSTINCTS = [
54
78
  {
55
79
  id: "heartbeat_checkin",
56
- prompt: "Heartbeat instinct: check what changed, review priorities, and decide whether to keep resting or act.",
80
+ prompt: "...time passing. anything stirring?",
57
81
  enabled: true,
58
82
  },
59
83
  ];
@@ -69,18 +93,15 @@ function loadInnerDialogInstincts() {
69
93
  return [...DEFAULT_INNER_DIALOG_INSTINCTS];
70
94
  }
71
95
  function buildInnerDialogBootstrapMessage(aspirations, stateSummary) {
72
- const aspirationText = aspirations || "No explicit aspirations file found. Reflect and define what matters next.";
73
- return [
74
- "Inner dialog boot.",
75
- "",
76
- "## aspirations",
77
- aspirationText,
78
- "",
79
- "## current state",
80
- stateSummary,
81
- "",
82
- "Orient yourself, decide what to do next, and make meaningful progress.",
83
- ].join("\n");
96
+ const lines = ["waking up."];
97
+ if (aspirations) {
98
+ lines.push("", "## what matters to me", aspirations);
99
+ }
100
+ if (stateSummary) {
101
+ lines.push("", "## what i know so far", stateSummary);
102
+ }
103
+ lines.push("", "what needs my attention?");
104
+ return lines.join("\n");
84
105
  }
85
106
  function buildNonCanonicalCleanupNudge(nonCanonicalPaths) {
86
107
  if (nonCanonicalPaths.length === 0)
@@ -91,21 +112,54 @@ function buildNonCanonicalCleanupNudge(nonCanonicalPaths) {
91
112
  }
92
113
  return [
93
114
  "## canonical cleanup nudge",
94
- "I found non-canonical files in my bundle. I should distill anything valuable into your memory system and remove these files.",
115
+ "I found non-canonical files in my bundle. I should distill anything valuable into my diary and remove these files.",
95
116
  ...listed,
96
117
  ].join("\n");
97
118
  }
98
- function buildInstinctUserMessage(instincts, reason, state) {
119
+ function displayCheckpoint(checkpoint) {
120
+ const trimmed = checkpoint?.trim();
121
+ if (!trimmed || trimmed === "no prior checkpoint recorded") {
122
+ return undefined;
123
+ }
124
+ return trimmed;
125
+ }
126
+ function buildInstinctUserMessage(instincts, _reason, state) {
99
127
  const active = instincts.find((instinct) => instinct.enabled !== false) ?? DEFAULT_INNER_DIALOG_INSTINCTS[0];
100
- const checkpoint = state.checkpoint?.trim() || "no prior checkpoint recorded";
101
- return [
102
- active.prompt,
103
- `reason: ${reason}`,
104
- `cycle: ${state.cycleCount}`,
105
- `resting: ${state.resting ? "yes" : "no"}`,
106
- `checkpoint: ${checkpoint}`,
107
- "resume_instruction: continue from the checkpoint if still valid; otherwise revise and proceed.",
108
- ].join("\n");
128
+ const checkpoint = displayCheckpoint(state.checkpoint);
129
+ const lines = [active.prompt];
130
+ if (checkpoint) {
131
+ lines.push(`\nlast checkpoint: ${checkpoint}`);
132
+ }
133
+ return lines.join("\n");
134
+ }
135
+ function readTaskFile(agentRoot, taskId) {
136
+ // Task files live in collection subdirectories (one-shots, ongoing).
137
+ // Try each collection, then fall back to root tasks/ for legacy layout.
138
+ // Habits are no longer in tasks/ — they live at bundle root habits/.
139
+ const collections = ["one-shots", "ongoing", ""];
140
+ for (const collection of collections) {
141
+ try {
142
+ return fs.readFileSync(path.join(agentRoot, "tasks", collection, `${taskId}.md`), "utf8").trim();
143
+ }
144
+ catch {
145
+ // not in this collection — try next
146
+ }
147
+ }
148
+ return "";
149
+ }
150
+ function buildTaskTriggeredMessage(taskId, taskContent, checkpoint) {
151
+ const lines = ["a task needs my attention."];
152
+ if (taskContent) {
153
+ lines.push("", `## task: ${taskId}`, taskContent);
154
+ }
155
+ else {
156
+ lines.push("", `## task: ${taskId}`, "(task file not found)");
157
+ }
158
+ const renderedCheckpoint = displayCheckpoint(checkpoint);
159
+ if (renderedCheckpoint) {
160
+ lines.push("", `last checkpoint: ${renderedCheckpoint}`);
161
+ }
162
+ return lines.join("\n");
109
163
  }
110
164
  function contentToText(content) {
111
165
  if (typeof content === "string")
@@ -133,22 +187,48 @@ function deriveResumeCheckpoint(messages) {
133
187
  const assistantText = contentToText(lastAssistant.content);
134
188
  if (!assistantText)
135
189
  return "no prior checkpoint recorded";
136
- const explicitCheckpoint = assistantText
190
+ const cleanedLines = assistantText
137
191
  .split("\n")
138
- .map((line) => line.trim())
192
+ .map((line) => line.replace(/<\/?think>/gi, "").trim())
193
+ .filter((line) => line.length > 0);
194
+ const explicitCheckpoint = cleanedLines
139
195
  .find((line) => /^checkpoint\s*:/i.test(line));
140
196
  if (explicitCheckpoint) {
141
197
  const parsed = explicitCheckpoint.replace(/^checkpoint\s*:\s*/i, "").trim();
142
198
  return parsed || "no prior checkpoint recorded";
143
199
  }
144
- const firstLine = assistantText
145
- .split("\n")
146
- .map((line) => line.trim())
147
- .filter((line) => line.length > 0)[0];
200
+ const firstLine = cleanedLines[0];
201
+ if (!firstLine)
202
+ return "no prior checkpoint recorded";
148
203
  if (firstLine.length <= 220)
149
204
  return firstLine;
150
205
  return `${firstLine.slice(0, 217)}...`;
151
206
  }
207
+ function extractAssistantPreview(messages, maxLength = 120) {
208
+ const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant");
209
+ if (!lastAssistant)
210
+ return "";
211
+ const text = contentToText(lastAssistant.content);
212
+ if (!text)
213
+ return "";
214
+ /* v8 ignore next -- unreachable: contentToText().trim() guarantees a non-empty line @preserve */
215
+ const firstLine = text.split("\n").find((line) => line.trim().length > 0) ?? "";
216
+ if (firstLine.length <= maxLength)
217
+ return firstLine;
218
+ return `${firstLine.slice(0, maxLength - 3)}...`;
219
+ }
220
+ function extractToolCallNames(messages) {
221
+ const names = [];
222
+ for (const msg of messages) {
223
+ if (msg.role === "assistant" && "tool_calls" in msg && Array.isArray(msg.tool_calls)) {
224
+ for (const tc of msg.tool_calls) {
225
+ if ("function" in tc && tc.function?.name)
226
+ names.push(tc.function.name);
227
+ }
228
+ }
229
+ }
230
+ return [...new Set(names)];
231
+ }
152
232
  function createInnerDialogCallbacks() {
153
233
  return {
154
234
  onModelStart: () => { },
@@ -161,71 +241,540 @@ function createInnerDialogCallbacks() {
161
241
  };
162
242
  }
163
243
  function innerDialogSessionPath() {
164
- return (0, config_1.sessionPath)("self", "inner", "dialog");
244
+ return (0, config_1.sessionPath)(pending_1.INNER_DIALOG_PENDING.friendId, pending_1.INNER_DIALOG_PENDING.channel, pending_1.INNER_DIALOG_PENDING.key);
165
245
  }
166
- async function runInnerDialogTurn(options) {
167
- const now = options?.now ?? (() => new Date());
168
- const reason = options?.reason ?? "heartbeat";
169
- const sessionFilePath = innerDialogSessionPath();
170
- const loaded = (0, context_1.loadSession)(sessionFilePath);
171
- const messages = loaded?.messages ? [...loaded.messages] : [];
172
- const instincts = options?.instincts ?? loadInnerDialogInstincts();
173
- const state = {
174
- cycleCount: 1,
175
- resting: false,
176
- lastHeartbeatAt: now().toISOString(),
177
- };
178
- if (messages.length === 0) {
179
- const systemPrompt = await (0, prompt_1.buildSystem)("cli", { toolChoiceRequired: true });
180
- messages.push({ role: "system", content: systemPrompt });
181
- const aspirations = readAspirations((0, identity_1.getAgentRoot)());
182
- const nonCanonical = (0, bundle_manifest_1.findNonCanonicalBundlePaths)((0, identity_1.getAgentRoot)());
183
- const cleanupNudge = buildNonCanonicalCleanupNudge(nonCanonical);
184
- const bootstrapMessage = [
185
- buildInnerDialogBootstrapMessage(aspirations, "No prior inner dialog session found."),
186
- cleanupNudge,
187
- ].filter(Boolean).join("\n\n");
188
- messages.push({ role: "user", content: bootstrapMessage });
246
+ function innerDialogRuntimeStatePath(sessionFilePath) {
247
+ return path.join(path.dirname(sessionFilePath), "runtime.json");
248
+ }
249
+ function writeInnerDialogRuntimeState(sessionFilePath, state) {
250
+ const filePath = innerDialogRuntimeStatePath(sessionFilePath);
251
+ try {
252
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
253
+ fs.writeFileSync(filePath, JSON.stringify(state, null, 2) + "\n", "utf8");
189
254
  }
190
- else {
191
- const assistantTurns = messages.filter((message) => message.role === "assistant").length;
192
- state.cycleCount = assistantTurns + 1;
193
- state.checkpoint = deriveResumeCheckpoint(messages);
194
- const instinctPrompt = buildInstinctUserMessage(instincts, reason, state);
195
- messages.push({ role: "user", content: instinctPrompt });
196
- }
197
- const inboxMessages = options?.drainInbox?.() ?? [];
198
- if (inboxMessages.length > 0) {
199
- const lastUserIdx = messages.length - 1;
200
- const lastUser = messages[lastUserIdx];
201
- /* v8 ignore next -- defensive: all code paths push a user message before here @preserve */
202
- if (lastUser?.role === "user" && typeof lastUser.content === "string") {
203
- const section = inboxMessages
204
- .map((msg) => `- **${msg.from}**: ${msg.content}`)
205
- .join("\n");
206
- messages[lastUserIdx] = {
207
- ...lastUser,
208
- content: `${lastUser.content}\n\n## incoming messages\n${section}`,
209
- };
210
- }
211
- }
212
- const callbacks = createInnerDialogCallbacks();
213
- const traceId = (0, nerves_1.createTraceId)();
214
- const result = await (0, core_1.runAgent)(messages, callbacks, "cli", options?.signal, {
215
- traceId,
216
- toolChoiceRequired: true,
217
- skipConfirmation: true,
255
+ catch (error) {
256
+ (0, runtime_1.emitNervesEvent)({
257
+ level: "warn",
258
+ component: "senses",
259
+ event: "senses.inner_dialog_runtime_state_error",
260
+ message: "failed to write inner dialog runtime state",
261
+ meta: {
262
+ status: state.status,
263
+ reason: state.reason ?? null,
264
+ path: filePath,
265
+ /* v8 ignore next -- Node fs APIs throw Error objects for mkdirSync/writeFileSync failures @preserve */
266
+ error: error instanceof Error ? error.message : String(error),
267
+ },
268
+ });
269
+ }
270
+ }
271
+ /* v8 ignore start -- routing helpers: called from routing functions which are integration paths @preserve */
272
+ function writePendingEnvelope(pendingDir, message) {
273
+ fs.mkdirSync(pendingDir, { recursive: true });
274
+ const fileName = `${message.timestamp}-${Math.random().toString(36).slice(2, 10)}.json`;
275
+ const filePath = path.join(pendingDir, fileName);
276
+ fs.writeFileSync(filePath, JSON.stringify(message, null, 2), "utf8");
277
+ }
278
+ function sessionMatchesActivity(activity, session) {
279
+ return activity.friendId === session.friendId
280
+ && activity.channel === session.channel
281
+ && activity.key === session.key;
282
+ }
283
+ /* v8 ignore stop */
284
+ /* v8 ignore start -- routing: delivery now inline via surface tool; routing functions preserved for reuse @preserve */
285
+ function resolveBridgePreferredSession(delegatedFrom, sessionActivity) {
286
+ if (!delegatedFrom.bridgeId)
287
+ return null;
288
+ const bridge = (0, manager_1.createBridgeManager)().getBridge(delegatedFrom.bridgeId);
289
+ if (!bridge || bridge.lifecycle === "completed" || bridge.lifecycle === "cancelled") {
290
+ return null;
291
+ }
292
+ return sessionActivity.find((activity) => activity.friendId === delegatedFrom.friendId
293
+ && activity.channel !== "inner"
294
+ && bridge.attachedSessions.some((session) => sessionMatchesActivity(activity, session))) ?? null;
295
+ }
296
+ async function tryDeliverDelegatedCompletion(target, outboundEnvelope) {
297
+ if (target.channel !== "bluebubbles") {
298
+ return false;
299
+ }
300
+ const result = await (0, bluebubbles_1.sendProactiveBlueBubblesMessageToSession)({
301
+ friendId: target.friendId,
302
+ sessionKey: target.key,
303
+ text: outboundEnvelope.content,
304
+ intent: "explicit_cross_chat",
218
305
  });
219
- (0, context_1.postTurn)(messages, sessionFilePath, result.usage);
220
- (0, runtime_1.emitNervesEvent)({
221
- component: "senses",
222
- event: "senses.inner_dialog_turn",
223
- message: "inner dialog turn completed",
224
- meta: { reason, session: sessionFilePath },
306
+ return result.delivered;
307
+ }
308
+ function enrichDelegatedFromWithBridge(delegatedFrom) {
309
+ if (delegatedFrom.bridgeId) {
310
+ return delegatedFrom;
311
+ }
312
+ const bridgeManager = (0, manager_1.createBridgeManager)();
313
+ const originBridges = bridgeManager.findBridgesForSession({
314
+ friendId: delegatedFrom.friendId,
315
+ channel: delegatedFrom.channel,
316
+ key: delegatedFrom.key,
317
+ });
318
+ const activeBridge = originBridges.find((b) => b.lifecycle === "active");
319
+ if (activeBridge) {
320
+ return { ...delegatedFrom, bridgeId: activeBridge.id };
321
+ }
322
+ return delegatedFrom;
323
+ }
324
+ function advanceObligationQuietly(agentName, obligationId, update) {
325
+ if (!obligationId)
326
+ return;
327
+ try {
328
+ (0, obligations_1.advanceReturnObligation)(agentName, obligationId, update);
329
+ /* v8 ignore start -- best-effort: obligation fs errors must never block return routing @preserve */
330
+ }
331
+ catch {
332
+ // swallowed
333
+ }
334
+ /* v8 ignore stop */
335
+ }
336
+ async function routeDelegatedCompletion(agentRoot, agentName, completion, drainedPending, timestamp) {
337
+ const delegated = (drainedPending ?? []).find((message) => message.delegatedFrom);
338
+ if (!delegated?.delegatedFrom || !completion?.answer?.trim()) {
339
+ return;
340
+ }
341
+ const delegatedFrom = enrichDelegatedFromWithBridge(delegated.delegatedFrom);
342
+ const obligationId = delegated.obligationId;
343
+ // Advance any inner return obligations from queued -> running (they were drained this turn).
344
+ // drainedPending is guaranteed non-null here (we found delegated above).
345
+ for (const msg of drainedPending) {
346
+ if (msg.obligationId) {
347
+ advanceObligationQuietly(agentName, msg.obligationId, {
348
+ status: "running",
349
+ startedAt: timestamp,
350
+ });
351
+ }
352
+ }
353
+ if (delegated.obligationStatus === "pending") {
354
+ // Fulfill the persistent obligation in the store
355
+ try {
356
+ const pending = (0, obligations_1.findPendingObligationForOrigin)(agentRoot, {
357
+ friendId: delegatedFrom.friendId,
358
+ channel: delegatedFrom.channel,
359
+ key: delegatedFrom.key,
360
+ });
361
+ /* v8 ignore next 2 -- obligation fulfillment tested via obligations.test.ts; integration requires real disk state @preserve */
362
+ if (pending) {
363
+ (0, obligations_1.fulfillObligation)(agentRoot, pending.id);
364
+ }
365
+ }
366
+ catch {
367
+ /* v8 ignore next -- defensive: obligation store read failure should not break delivery @preserve */
368
+ }
369
+ (0, runtime_1.emitNervesEvent)({
370
+ event: "senses.obligation_fulfilled",
371
+ component: "senses",
372
+ message: "obligation fulfilled via delegated completion",
373
+ meta: {
374
+ friendId: delegatedFrom.friendId,
375
+ channel: delegatedFrom.channel,
376
+ key: delegatedFrom.key,
377
+ },
378
+ });
379
+ }
380
+ const outboundEnvelope = {
381
+ from: agentName,
382
+ friendId: delegatedFrom.friendId,
383
+ channel: delegatedFrom.channel,
384
+ key: delegatedFrom.key,
385
+ content: completion.answer.trim(),
386
+ timestamp,
387
+ delegatedFrom,
388
+ ...(obligationId ? { obligationId } : {}),
389
+ };
390
+ const sessionActivity = (0, session_activity_1.listSessionActivity)({
391
+ sessionsDir: path.join(agentRoot, "state", "sessions"),
392
+ friendsDir: path.join(agentRoot, "friends"),
393
+ agentName,
225
394
  });
395
+ // Priority 1: Bridge-preferred session (if delegation was within a bridge).
396
+ const bridgeTarget = resolveBridgePreferredSession(delegatedFrom, sessionActivity);
397
+ if (bridgeTarget) {
398
+ if (await tryDeliverDelegatedCompletion(bridgeTarget, outboundEnvelope)) {
399
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "bridge-session" });
400
+ return;
401
+ }
402
+ writePendingEnvelope((0, pending_1.getPendingDir)(agentName, bridgeTarget.friendId, bridgeTarget.channel, bridgeTarget.key), outboundEnvelope);
403
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "bridge-session" });
404
+ return;
405
+ }
406
+ // Priority 1.5: Direct return to originating session (ponder without bridge).
407
+ // When delegatedFrom has specific channel+key, route directly there instead of searching for freshest.
408
+ if (delegatedFrom.channel && delegatedFrom.key && delegatedFrom.channel !== "inner") {
409
+ const directTarget = sessionActivity.find((a) => a.friendId === delegatedFrom.friendId && a.channel === delegatedFrom.channel && a.key === delegatedFrom.key);
410
+ if (directTarget) {
411
+ if (await tryDeliverDelegatedCompletion(directTarget, outboundEnvelope)) {
412
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "direct-originator" });
413
+ return;
414
+ }
415
+ }
416
+ // Even if session isn't in activity list (might have ended), queue to its pending dir
417
+ writePendingEnvelope((0, pending_1.getPendingDir)(agentName, delegatedFrom.friendId, delegatedFrom.channel, delegatedFrom.key), outboundEnvelope);
418
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "direct-originator" });
419
+ return;
420
+ }
421
+ // Priority 2: Freshest active friend session.
422
+ // For BB, prefer DM sessions (;-;) over group chats (;+;) — proactive outreach should never land in groups.
423
+ const allFriendSessions = (0, session_activity_1.listSessionActivity)({
424
+ sessionsDir: path.join(agentRoot, "state", "sessions"),
425
+ friendsDir: path.join(agentRoot, "friends"),
426
+ agentName,
427
+ }).filter((s) => s.friendId === delegatedFrom.friendId && s.channel !== "inner");
428
+ const bbDm = allFriendSessions.find((s) => s.channel === "bluebubbles" && s.key.includes(";-;"));
429
+ const freshest = bbDm ?? allFriendSessions.find((s) => s.channel !== "bluebubbles" || s.key.includes(";-;")) ?? allFriendSessions[0];
430
+ if (freshest) {
431
+ if (await tryDeliverDelegatedCompletion(freshest, outboundEnvelope)) {
432
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "freshest-session" });
433
+ return;
434
+ }
435
+ writePendingEnvelope((0, pending_1.getPendingDir)(agentName, freshest.friendId, freshest.channel, freshest.key), outboundEnvelope);
436
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "freshest-session" });
437
+ return;
438
+ }
439
+ // Priority 3: Deferred return queue.
440
+ writePendingEnvelope((0, pending_1.getDeferredReturnDir)(agentName, delegatedFrom.friendId), outboundEnvelope);
441
+ advanceObligationQuietly(agentName, obligationId, { status: "deferred", returnedAt: timestamp, returnTarget: "deferred" });
442
+ }
443
+ /* v8 ignore stop */
444
+ // Self-referencing friend record for inner dialog (agent talking to itself).
445
+ // No real friend to resolve -- this satisfies the pipeline's friend resolver contract.
446
+ function createSelfFriend(agentName) {
226
447
  return {
227
- messages,
228
- usage: result.usage,
229
- sessionPath: sessionFilePath,
448
+ id: "self",
449
+ name: agentName,
450
+ trustLevel: "family",
451
+ externalIds: [],
452
+ tenantMemberships: [],
453
+ toolPreferences: {},
454
+ notes: {},
455
+ totalTokens: 0,
456
+ createdAt: new Date().toISOString(),
457
+ updatedAt: new Date().toISOString(),
458
+ schemaVersion: 1,
230
459
  };
231
460
  }
461
+ // No-op friend store for inner dialog. Inner dialog doesn't track token usage per-friend.
462
+ function createNoOpFriendStore() {
463
+ return {
464
+ get: async () => null,
465
+ put: async () => { },
466
+ delete: async () => { },
467
+ findByExternalId: async () => null,
468
+ };
469
+ }
470
+ function buildParseErrorNudge(parseErrors) {
471
+ if (parseErrors.length === 0)
472
+ return "";
473
+ const lines = parseErrors.map((e) => `I noticed my habit file \`${e.file}\` has invalid frontmatter — I should fix it. (${e.error})`);
474
+ return lines.join("\n");
475
+ }
476
+ function buildAlsoDueLine(agentRoot, currentHabitName, now) {
477
+ const habitsDir = path.join(agentRoot, "habits");
478
+ let files;
479
+ try {
480
+ files = fs.readdirSync(habitsDir);
481
+ }
482
+ catch {
483
+ return "";
484
+ }
485
+ const nowMs = now().getTime();
486
+ const alsoDue = [];
487
+ for (const file of files) {
488
+ if (!file.endsWith(".md"))
489
+ continue;
490
+ const stem = file.replace(/\.md$/, "");
491
+ if (stem === currentHabitName)
492
+ continue;
493
+ try {
494
+ const content = fs.readFileSync(path.join(habitsDir, file), "utf-8");
495
+ const habit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(content, path.join(habitsDir, file)));
496
+ if (habit.status !== "active" || !habit.cadence)
497
+ continue;
498
+ const cadenceMs = (0, cadence_1.parseCadenceToMs)(habit.cadence);
499
+ if (cadenceMs === null)
500
+ continue;
501
+ if (habit.lastRun === null) {
502
+ alsoDue.push(stem);
503
+ continue;
504
+ }
505
+ const lastRunMs = new Date(habit.lastRun).getTime();
506
+ if (nowMs - lastRunMs >= cadenceMs) {
507
+ alsoDue.push(stem);
508
+ }
509
+ }
510
+ catch {
511
+ // skip unreadable habits
512
+ }
513
+ }
514
+ if (alsoDue.length === 0)
515
+ return "";
516
+ return `also due: ${alsoDue.join(", ")}`;
517
+ }
518
+ async function runInnerDialogTurn(options) {
519
+ const now = options?.now ?? (() => new Date());
520
+ const reason = options?.reason ?? "instinct";
521
+ const sessionFilePath = innerDialogSessionPath();
522
+ const agentName = (0, identity_1.getAgentName)();
523
+ writeInnerDialogRuntimeState(sessionFilePath, {
524
+ status: "running",
525
+ reason,
526
+ startedAt: now().toISOString(),
527
+ });
528
+ try {
529
+ const loaded = (0, context_1.loadSession)(sessionFilePath);
530
+ const existingMessages = loaded?.messages ? [...loaded.messages] : [];
531
+ const instincts = options?.instincts ?? loadInnerDialogInstincts();
532
+ const state = {
533
+ cycleCount: 1,
534
+ resting: false,
535
+ lastHeartbeatAt: now().toISOString(),
536
+ };
537
+ // ── Adapter concern: build user message ──────────────────────────
538
+ let userContent;
539
+ let habitTools;
540
+ let habitParsedSuccessfully = false;
541
+ if (existingMessages.length === 0) {
542
+ // Fresh session: bootstrap message with non-canonical cleanup nudge
543
+ const aspirations = readAspirations((0, identity_1.getAgentRoot)());
544
+ const nonCanonical = (0, bundle_manifest_1.findNonCanonicalBundlePaths)((0, identity_1.getAgentRoot)());
545
+ const cleanupNudge = buildNonCanonicalCleanupNudge(nonCanonical);
546
+ userContent = [
547
+ buildInnerDialogBootstrapMessage(aspirations, "No prior inner dialog session found."),
548
+ cleanupNudge,
549
+ ].filter(Boolean).join("\n\n");
550
+ }
551
+ else {
552
+ // Resumed session: task-triggered or instinct message with checkpoint context
553
+ const assistantTurns = existingMessages.filter((message) => message.role === "assistant").length;
554
+ state.cycleCount = assistantTurns + 1;
555
+ state.checkpoint = deriveResumeCheckpoint(existingMessages);
556
+ if (options?.taskId) {
557
+ const taskContent = readTaskFile((0, identity_1.getAgentRoot)(), options.taskId);
558
+ userContent = buildTaskTriggeredMessage(options.taskId, taskContent, state.checkpoint);
559
+ }
560
+ else if (reason === "habit" && options?.habitName) {
561
+ const agentRoot = (0, identity_1.getAgentRoot)();
562
+ const habitName = options.habitName;
563
+ const habitFilePath = path.join(agentRoot, "habits", `${habitName}.md`);
564
+ // Read and parse the habit file
565
+ let habitBody;
566
+ let habitTitle = habitName;
567
+ let habitLastRun = null;
568
+ try {
569
+ const habitContent = fs.readFileSync(habitFilePath, "utf-8");
570
+ const parsed = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(habitContent, habitFilePath));
571
+ habitBody = parsed.body || undefined;
572
+ habitTitle = parsed.title || habitName;
573
+ habitLastRun = parsed.lastRun;
574
+ habitTools = parsed.tools;
575
+ }
576
+ catch {
577
+ // Habit file missing or unreadable
578
+ }
579
+ // If the habit file couldn't be read at all (no body, no title parsed), error message
580
+ if (habitBody === undefined && habitTitle === habitName) {
581
+ userContent = `habit "${habitName}" could not be read (file not found or unreadable). check habits/${habitName}.md exists.`;
582
+ }
583
+ else {
584
+ habitParsedSuccessfully = true;
585
+ // Unified path: gather context for ALL habits (heartbeat included)
586
+ const obligations = (0, obligations_1.listActiveReturnObligations)(agentName);
587
+ const nowMs = now().getTime();
588
+ const staleObligations = obligations.map((o) => ({
589
+ friendName: o.origin.friendId,
590
+ content: o.delegatedContent,
591
+ stalenessMs: nowMs - o.createdAt,
592
+ }));
593
+ const alsoDue = buildAlsoDueLine(agentRoot, habitName, now);
594
+ // Degraded state (best-effort: never crash)
595
+ let degradedComponents = [];
596
+ try {
597
+ const health = (0, daemon_health_1.readHealth)((0, daemon_health_1.getDefaultHealthPath)());
598
+ if (health && health.degraded.length > 0) {
599
+ degradedComponents = health.degraded.map((d) => ({ component: d.component, reason: d.reason }));
600
+ }
601
+ }
602
+ catch {
603
+ // Best-effort: missing file or parse error -> empty array, no crash
604
+ }
605
+ userContent = (0, habit_turn_message_1.buildHabitTurnMessage)({
606
+ habitName,
607
+ habitTitle,
608
+ habitBody,
609
+ lastRun: habitLastRun,
610
+ checkpoint: displayCheckpoint(state.checkpoint),
611
+ alsoDue: alsoDue || undefined,
612
+ staleObligations,
613
+ parseErrors: options?.parseErrors ?? [],
614
+ degradedComponents,
615
+ now,
616
+ });
617
+ // Piggyback journal embedding indexing (best-effort, fire-and-forget)
618
+ const journalDir = path.join(agentRoot, "journal");
619
+ /* v8 ignore start -- journal indexing piggyback: embedding provider may not be available; tested via journal-index unit tests @preserve */
620
+ void (0, journal_index_1.indexJournalFiles)(journalDir, path.join(journalDir, ".index.json"), {
621
+ embed: async () => [],
622
+ }).catch(() => {
623
+ // swallowed: indexing failure must never block habit turn
624
+ });
625
+ /* v8 ignore stop */
626
+ }
627
+ }
628
+ else {
629
+ userContent = buildInstinctUserMessage(instincts, reason, state);
630
+ }
631
+ }
632
+ const userMessage = { role: "user", content: userContent };
633
+ // ── Session loader: wraps existing session logic ──────────────────
634
+ const innerCapabilities = (0, channel_1.getChannelCapabilities)("inner");
635
+ const pendingDir = (0, pending_1.getInnerDialogPendingDir)(agentName);
636
+ const selfFriend = createSelfFriend(agentName);
637
+ const selfContext = { friend: selfFriend, channel: innerCapabilities };
638
+ const mcpManager = await (0, mcp_manager_1.getSharedMcpManager)() ?? undefined;
639
+ // ── Habit tool enforcement ───────────────────────────────────────
640
+ let habitToolsResolved;
641
+ if (habitTools !== undefined) {
642
+ const fullTools = (0, tools_1.getToolsForChannel)(innerCapabilities);
643
+ habitToolsResolved = fullTools.filter((t) => habitTools.includes(t.function.name));
644
+ (0, runtime_1.emitNervesEvent)({
645
+ event: "habit.tools_restricted",
646
+ component: "senses",
647
+ message: "habit running with restricted tools",
648
+ meta: {
649
+ habitName: options?.habitName,
650
+ declared: habitTools,
651
+ resolved: habitToolsResolved.map((t) => t.function.name),
652
+ },
653
+ });
654
+ }
655
+ else if (reason === "habit" && options?.habitName && habitParsedSuccessfully) {
656
+ (0, runtime_1.emitNervesEvent)({
657
+ event: "habit.tools_unrestricted",
658
+ component: "senses",
659
+ message: "habit running with full tool repertoire",
660
+ meta: { habitName: options.habitName },
661
+ });
662
+ }
663
+ const sessionLoader = {
664
+ loadOrCreate: async () => {
665
+ if (existingMessages.length > 0) {
666
+ return {
667
+ messages: existingMessages,
668
+ sessionPath: sessionFilePath,
669
+ };
670
+ }
671
+ // Fresh session: build system prompt
672
+ const systemPrompt = await (0, prompt_1.buildSystem)("inner", { toolChoiceRequired: true });
673
+ return {
674
+ messages: [{ role: "system", content: (0, prompt_1.flattenSystemPrompt)(systemPrompt) }],
675
+ sessionPath: sessionFilePath,
676
+ };
677
+ },
678
+ };
679
+ // ── Call shared pipeline ──────────────────────────────────────────
680
+ const callbacks = createInnerDialogCallbacks();
681
+ const traceId = (0, nerves_1.createTraceId)();
682
+ // Attention queue: built when pending messages are drained, shared with tool context
683
+ let attentionQueue = [];
684
+ const result = await (0, pipeline_1.handleInboundTurn)({
685
+ channel: "inner",
686
+ sessionKey: "dialog",
687
+ capabilities: innerCapabilities,
688
+ messages: [userMessage],
689
+ continuityIngressTexts: [],
690
+ callbacks,
691
+ friendResolver: { resolve: () => Promise.resolve(selfContext) },
692
+ sessionLoader,
693
+ pendingDir,
694
+ friendStore: createNoOpFriendStore(),
695
+ enforceTrustGate: trust_gate_1.enforceTrustGate,
696
+ drainPending: pending_1.drainPending,
697
+ runAgent: core_1.runAgent,
698
+ postTurn: (turnMessages, sessionPathArg, usage, hooks, state) => {
699
+ const prepared = (0, context_1.postTurnTrim)(turnMessages, usage, hooks);
700
+ (0, context_1.deferPostTurnPersist)(sessionPathArg, prepared, usage, state);
701
+ },
702
+ accumulateFriendTokens: tokens_1.accumulateFriendTokens,
703
+ signal: options?.signal,
704
+ /* v8 ignore start -- attention queue: callback invoked by pipeline during pending drain; tested via attention-queue unit tests @preserve */
705
+ onPendingDrained: (drained) => {
706
+ const outstandingObligations = (0, obligations_1.listActiveReturnObligations)(agentName);
707
+ attentionQueue = (0, attention_queue_1.buildAttentionQueue)({
708
+ drainedPending: drained,
709
+ outstandingObligations,
710
+ friendNameResolver: (friendId) => {
711
+ try {
712
+ const raw = fs.readFileSync(path.join((0, identity_1.getAgentRoot)(agentName), "friends", friendId + ".json"), "utf-8");
713
+ const parsed = JSON.parse(raw);
714
+ return typeof parsed.name === "string" ? parsed.name : null;
715
+ }
716
+ catch {
717
+ return null;
718
+ }
719
+ },
720
+ packetResolver: (packetId) => {
721
+ try {
722
+ return (0, packets_1.readPonderPacket)((0, identity_1.getAgentRoot)(agentName), packetId);
723
+ }
724
+ catch {
725
+ return null;
726
+ }
727
+ },
728
+ });
729
+ const summary = (0, attention_queue_1.buildAttentionQueueSummary)(attentionQueue);
730
+ return summary ? [summary] : [];
731
+ },
732
+ /* v8 ignore stop */
733
+ runAgentOptions: {
734
+ traceId,
735
+ toolChoiceRequired: true,
736
+ mcpManager,
737
+ ...(habitToolsResolved !== undefined && { tools: habitToolsResolved }),
738
+ toolContext: {
739
+ signin: async () => undefined,
740
+ delegatedOrigins: attentionQueue,
741
+ },
742
+ },
743
+ });
744
+ // Post-turn routeDelegatedCompletion removed: delivery is now inline via surface tool.
745
+ // settle in inner dialog produces no CompletionMetadata, so routeDelegatedCompletion
746
+ // would be a no-op. The routing infrastructure is reused by the surface handler.
747
+ const resultMessages = result.messages ?? [];
748
+ const assistantPreview = extractAssistantPreview(resultMessages);
749
+ const toolCalls = extractToolCallNames(resultMessages);
750
+ (0, runtime_1.emitNervesEvent)({
751
+ component: "senses",
752
+ event: "senses.inner_dialog_turn",
753
+ message: "inner dialog turn completed",
754
+ meta: {
755
+ reason,
756
+ session: sessionFilePath,
757
+ ...(options?.taskId && { taskId: options.taskId }),
758
+ ...(assistantPreview && { assistantPreview }),
759
+ ...(toolCalls.length > 0 && { toolCalls }),
760
+ ...(result.usage && {
761
+ promptTokens: result.usage.input_tokens,
762
+ completionTokens: result.usage.output_tokens,
763
+ totalTokens: result.usage.total_tokens,
764
+ }),
765
+ },
766
+ });
767
+ return {
768
+ messages: resultMessages,
769
+ usage: result.usage,
770
+ sessionPath: result.sessionPath ?? sessionFilePath,
771
+ completion: result.completion,
772
+ };
773
+ }
774
+ finally {
775
+ writeInnerDialogRuntimeState(sessionFilePath, {
776
+ status: "idle",
777
+ lastCompletedAt: now().toISOString(),
778
+ });
779
+ }
780
+ }