@ouro.bot/cli 0.1.0-alpha.81 → 0.1.0-alpha.811

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 (623) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -23
  3. package/RepairGuide.ouro/agent.json +5 -0
  4. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  5. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  6. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  7. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  8. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  9. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  12. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  13. package/assets/bluebubbles-host +264 -0
  14. package/changelog.json +5189 -16
  15. package/deploy/unraid/Dockerfile +48 -0
  16. package/deploy/unraid/README.txt +3032 -0
  17. package/deploy/unraid/audit-container-spec.sh +4 -0
  18. package/deploy/unraid/container-runtime.json +1 -0
  19. package/deploy/unraid/docker-man-template-transaction.mjs +526 -0
  20. package/deploy/unraid/docker-man-template-xml.cjs +105 -0
  21. package/deploy/unraid/migrate-sanctuary-bundle.mjs +60 -0
  22. package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
  23. package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
  24. package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
  25. package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
  26. package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
  27. package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
  28. package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
  29. package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
  30. package/deploy/unraid/sanctuary-deployment-target.mjs +709 -0
  31. package/deploy/unraid/sanctuary-safe-rename.py +24 -0
  32. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2031 -0
  33. package/deploy/unraid/sanctuary-unit16-run.sh +560 -0
  34. package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
  35. package/deploy/unraid/sanctuary.ouro/agent.json +24 -0
  36. package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
  37. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
  38. package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
  39. package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
  40. package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
  41. package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +5 -0
  42. package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +11 -0
  43. package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +25 -0
  44. package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +11 -0
  45. package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
  46. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +23 -0
  47. package/deploy/unraid/sanctuary.xml +27 -0
  48. package/dist/a2a/card.js +57 -0
  49. package/dist/a2a/client.js +180 -0
  50. package/dist/a2a/config.js +50 -0
  51. package/dist/a2a/delegation-stores.js +56 -0
  52. package/dist/a2a/did-resolution.js +93 -0
  53. package/dist/a2a/identity.js +170 -0
  54. package/dist/a2a/inbound-share.js +107 -0
  55. package/dist/a2a/mission-result-wire.js +196 -0
  56. package/dist/a2a/onboarding.js +115 -0
  57. package/dist/a2a/pin-store.js +132 -0
  58. package/dist/a2a/seen-ledger.js +120 -0
  59. package/dist/a2a/server.js +604 -0
  60. package/dist/a2a/task-store.js +69 -0
  61. package/dist/a2a/transport.js +45 -0
  62. package/dist/a2a/types.js +3 -0
  63. package/dist/arc/attention-types.js +8 -0
  64. package/dist/arc/cares.js +360 -0
  65. package/dist/arc/episodes.js +118 -0
  66. package/dist/arc/evolution.js +490 -0
  67. package/dist/arc/flight-recorder.js +1034 -0
  68. package/dist/arc/intentions.js +134 -0
  69. package/dist/arc/json-store.js +117 -0
  70. package/dist/arc/obligations.js +386 -0
  71. package/dist/arc/packets.js +336 -0
  72. package/dist/arc/presence.js +185 -0
  73. package/dist/arc/task-lifecycle.js +57 -0
  74. package/dist/commerce/store.js +755 -0
  75. package/dist/commerce/types.js +3 -0
  76. package/dist/heart/active-work.js +820 -29
  77. package/dist/heart/agent-entry.js +252 -3
  78. package/dist/heart/approval-files.js +113 -0
  79. package/dist/heart/approval-store.js +950 -0
  80. package/dist/heart/attachments/image-normalize.js +194 -0
  81. package/dist/heart/attachments/materialize.js +97 -0
  82. package/dist/heart/attachments/originals.js +88 -0
  83. package/dist/heart/attachments/render.js +29 -0
  84. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  85. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  86. package/dist/heart/attachments/sources/index.js +18 -0
  87. package/dist/heart/attachments/sources/telegram.js +71 -0
  88. package/dist/heart/attachments/store.js +132 -0
  89. package/dist/heart/attachments/types.js +93 -0
  90. package/dist/heart/auth/auth-flow.js +495 -0
  91. package/dist/heart/autonomy-budget.js +478 -0
  92. package/dist/heart/awaiting/await-alert.js +148 -0
  93. package/dist/heart/awaiting/await-expiry.js +143 -0
  94. package/dist/heart/awaiting/await-loader.js +91 -0
  95. package/dist/heart/awaiting/await-parser.js +149 -0
  96. package/dist/heart/awaiting/await-runtime-state.js +100 -0
  97. package/dist/heart/awaiting/await-scheduler.js +382 -0
  98. package/dist/heart/background-operations.js +281 -0
  99. package/dist/heart/bridges/manager.js +137 -17
  100. package/dist/heart/bridges/store.js +14 -2
  101. package/dist/heart/bundle-state.js +168 -0
  102. package/dist/heart/commitments.js +64 -18
  103. package/dist/heart/config-registry.js +331 -0
  104. package/dist/heart/config.js +174 -131
  105. package/dist/heart/context-loss-gauntlet.js +387 -0
  106. package/dist/heart/context-loss-sentinel.js +1157 -0
  107. package/dist/heart/core.js +2164 -581
  108. package/dist/heart/cross-chat-delivery.js +9 -22
  109. package/dist/heart/daemon/agent-config-check.js +451 -0
  110. package/dist/heart/daemon/agent-discovery.js +185 -3
  111. package/dist/heart/daemon/agent-service.js +542 -0
  112. package/dist/heart/daemon/agentic-repair.js +547 -0
  113. package/dist/heart/daemon/await-private-wake.js +59 -0
  114. package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
  115. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  116. package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
  117. package/dist/heart/daemon/bluebubbles-host.js +273 -0
  118. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  119. package/dist/heart/daemon/cadence.js +180 -0
  120. package/dist/heart/daemon/cli-defaults.js +854 -0
  121. package/dist/heart/daemon/cli-desk.js +322 -0
  122. package/dist/heart/daemon/cli-exec.js +8822 -0
  123. package/dist/heart/daemon/cli-help.js +716 -0
  124. package/dist/heart/daemon/cli-parse.js +2771 -0
  125. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  126. package/dist/heart/daemon/cli-render.js +777 -0
  127. package/dist/heart/daemon/cli-types.js +8 -0
  128. package/dist/heart/daemon/connect-bay.js +323 -0
  129. package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
  130. package/dist/heart/daemon/container-healthcheck.js +112 -0
  131. package/dist/heart/daemon/container-runtime.js +97 -0
  132. package/dist/heart/daemon/container-spec-auditor-main.js +170 -0
  133. package/dist/heart/daemon/container-spec-auditor.js +236 -0
  134. package/dist/heart/daemon/daemon-bootstrap-startup.js +115 -0
  135. package/dist/heart/daemon/daemon-cli.js +29 -2317
  136. package/dist/heart/daemon/daemon-entry.js +921 -11
  137. package/dist/heart/daemon/daemon-health.js +186 -0
  138. package/dist/heart/daemon/daemon-rollup.js +57 -0
  139. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  140. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  141. package/dist/heart/daemon/daemon.js +2084 -105
  142. package/dist/heart/daemon/dns-workflow.js +394 -0
  143. package/dist/heart/daemon/doctor-types.js +8 -0
  144. package/dist/heart/daemon/doctor.js +1755 -0
  145. package/dist/heart/daemon/freshness.js +345 -0
  146. package/dist/heart/daemon/habit-private-wake.js +61 -0
  147. package/dist/heart/daemon/health-monitor.js +142 -11
  148. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  149. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  150. package/dist/heart/daemon/http-health-probe.js +80 -0
  151. package/dist/heart/daemon/human-command-screens.js +234 -0
  152. package/dist/heart/daemon/human-readiness.js +114 -0
  153. package/dist/heart/daemon/inner-status.js +78 -0
  154. package/dist/heart/daemon/interactive-repair.js +394 -0
  155. package/dist/heart/daemon/launchd.js +37 -8
  156. package/dist/heart/daemon/log-tailer.js +79 -10
  157. package/dist/heart/daemon/logs-prune.js +132 -0
  158. package/dist/heart/daemon/mcp-canary.js +524 -0
  159. package/dist/heart/daemon/message-router.js +65 -5
  160. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  161. package/dist/heart/daemon/os-cron-deps.js +135 -0
  162. package/dist/heart/daemon/os-cron.js +22 -14
  163. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  164. package/dist/heart/daemon/ouro-entry.js +3 -1
  165. package/dist/heart/daemon/plugin-cli.js +432 -0
  166. package/dist/heart/daemon/process-manager.js +733 -61
  167. package/dist/heart/daemon/provider-discovery.js +137 -0
  168. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  169. package/dist/heart/daemon/prunable-bundle.js +144 -0
  170. package/dist/heart/daemon/pulse.js +511 -0
  171. package/dist/heart/daemon/readiness-repair.js +365 -0
  172. package/dist/heart/daemon/run-hooks.js +2 -0
  173. package/dist/heart/daemon/runtime-logging.js +47 -14
  174. package/dist/heart/daemon/runtime-metadata.js +2 -30
  175. package/dist/heart/daemon/runtime-mode.js +13 -2
  176. package/dist/heart/daemon/safe-mode.js +161 -0
  177. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2647 -0
  178. package/dist/heart/daemon/sanctuary-acceptance-harness.js +1904 -0
  179. package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
  180. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +956 -0
  181. package/dist/heart/daemon/sanctuary-bundle-migration.js +728 -0
  182. package/dist/heart/daemon/sanctuary-package-management.js +103 -0
  183. package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
  184. package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
  185. package/dist/heart/daemon/sense-manager.js +689 -48
  186. package/dist/heart/daemon/session-id-resolver.js +131 -0
  187. package/dist/heart/daemon/skill-management-installer.js +1 -1
  188. package/dist/heart/daemon/socket-client.js +180 -12
  189. package/dist/heart/daemon/stale-bundle-prune.js +113 -0
  190. package/dist/heart/daemon/startup-tui.js +339 -0
  191. package/dist/heart/daemon/supercronic-supervisor.js +282 -0
  192. package/dist/heart/daemon/task-scheduler.js +117 -39
  193. package/dist/heart/daemon/terminal-ui.js +499 -0
  194. package/dist/heart/daemon/thoughts.js +138 -54
  195. package/dist/heart/daemon/up-progress.js +366 -0
  196. package/dist/heart/daemon/vault-items.js +56 -0
  197. package/dist/heart/delegation.js +1 -4
  198. package/dist/heart/external-events/router.js +1414 -0
  199. package/dist/heart/frontend-approval-runtime.js +506 -0
  200. package/dist/heart/frontend-journal.js +215 -0
  201. package/dist/heart/frontend-session-service.js +237 -0
  202. package/dist/heart/frontend-socket-client.js +154 -0
  203. package/dist/heart/frontend-socket.js +400 -0
  204. package/dist/heart/habits/habit-cancel.js +810 -0
  205. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  206. package/dist/heart/habits/habit-migration.js +194 -0
  207. package/dist/heart/habits/habit-parser.js +278 -0
  208. package/dist/heart/habits/habit-runtime-state.js +93 -0
  209. package/dist/heart/habits/habit-scheduler.js +653 -0
  210. package/dist/heart/habits/habit-session-summary.js +318 -0
  211. package/dist/heart/habits/habit-session.js +636 -0
  212. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
  213. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  214. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  215. package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
  216. package/dist/heart/identity.js +196 -59
  217. package/dist/heart/kept-notes.js +289 -0
  218. package/dist/heart/kicks.js +1 -1
  219. package/dist/heart/machine-identity.js +161 -0
  220. package/dist/heart/mail-import-discovery.js +356 -0
  221. package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
  222. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  223. package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
  224. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  225. package/dist/heart/mailbox/mailbox-http-transport.js +129 -0
  226. package/dist/heart/mailbox/mailbox-http.js +99 -0
  227. package/dist/heart/mailbox/mailbox-read.js +39 -0
  228. package/dist/heart/mailbox/mailbox-types.js +27 -0
  229. package/dist/heart/mailbox/mailbox-view.js +197 -0
  230. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  231. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  232. package/dist/heart/mailbox/readers/mail.js +375 -0
  233. package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
  234. package/dist/heart/mailbox/readers/sessions.js +231 -0
  235. package/dist/heart/mailbox/readers/shared.js +111 -0
  236. package/dist/heart/mcp/mcp-server.js +696 -0
  237. package/dist/heart/migrate-config.js +100 -0
  238. package/dist/heart/model-capabilities.js +11 -0
  239. package/dist/heart/orientation-frame.js +345 -0
  240. package/dist/heart/platform.js +81 -0
  241. package/dist/heart/primitives.js +1 -1
  242. package/dist/heart/private-runtime/decision-renderer.js +158 -0
  243. package/dist/heart/private-runtime/index.js +18 -0
  244. package/dist/heart/private-runtime/ledger.js +221 -0
  245. package/dist/heart/private-runtime/policy.js +252 -0
  246. package/dist/heart/private-runtime/types.js +2 -0
  247. package/dist/heart/progress-story.js +1 -1
  248. package/dist/heart/provider-attempt.js +137 -0
  249. package/dist/heart/provider-binding-resolver.js +273 -0
  250. package/dist/heart/provider-credentials.js +449 -0
  251. package/dist/heart/provider-failover.js +311 -0
  252. package/dist/heart/provider-models.js +96 -0
  253. package/dist/heart/provider-ping.js +265 -0
  254. package/dist/heart/provider-readiness-cache.js +119 -0
  255. package/dist/heart/provider-visibility.js +188 -0
  256. package/dist/heart/providers/anthropic-token.js +131 -0
  257. package/dist/heart/providers/anthropic.js +173 -60
  258. package/dist/heart/providers/azure.js +23 -11
  259. package/dist/heart/providers/error-classification.js +127 -0
  260. package/dist/heart/providers/github-copilot.js +34 -38
  261. package/dist/heart/providers/minimax-vlm.js +189 -0
  262. package/dist/heart/providers/minimax.js +26 -8
  263. package/dist/heart/providers/openai-codex-token.js +349 -0
  264. package/dist/heart/providers/openai-codex.js +55 -40
  265. package/dist/heart/providers/openai-compatible.js +177 -0
  266. package/dist/heart/run-ledger.js +247 -0
  267. package/dist/heart/runtime-capability-check.js +170 -0
  268. package/dist/heart/runtime-credentials.js +607 -0
  269. package/dist/heart/runtime-cwd.js +87 -0
  270. package/dist/heart/sense-truth.js +22 -4
  271. package/dist/heart/session-activity.js +92 -24
  272. package/dist/heart/session-events.js +1440 -0
  273. package/dist/heart/session-playback-cli-main.js +5 -0
  274. package/dist/heart/session-playback-cli.js +36 -0
  275. package/dist/heart/session-playback.js +231 -0
  276. package/dist/heart/session-redaction-repair-cli-main.js +31 -0
  277. package/dist/heart/session-redaction-repair.js +543 -0
  278. package/dist/heart/session-stats-cli-main.js +5 -0
  279. package/dist/heart/session-stats.js +182 -0
  280. package/dist/heart/session-transcript.js +133 -0
  281. package/dist/heart/start-of-turn-packet.js +372 -0
  282. package/dist/heart/steward-policy.js +302 -0
  283. package/dist/heart/streaming.js +604 -207
  284. package/dist/heart/structured-output.js +196 -0
  285. package/dist/heart/sync-classification.js +176 -0
  286. package/dist/heart/sync.js +449 -0
  287. package/dist/heart/target-resolution.js +11 -7
  288. package/dist/heart/tempo.js +93 -0
  289. package/dist/heart/temporal-view.js +41 -0
  290. package/dist/heart/timeouts.js +101 -0
  291. package/dist/heart/tool-activity-callbacks.js +59 -0
  292. package/dist/heart/tool-approval.js +375 -0
  293. package/dist/heart/tool-description.js +155 -0
  294. package/dist/heart/tool-friction.js +55 -0
  295. package/dist/heart/tool-loop.js +200 -0
  296. package/dist/heart/turn-context.js +482 -0
  297. package/dist/heart/turn-execution-lease.js +30 -0
  298. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  299. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  300. package/dist/heart/versioning/ouro-path-installer.js +432 -0
  301. package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
  302. package/dist/heart/versioning/ouro-version-manager.js +409 -0
  303. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  304. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  305. package/dist/heart/versioning/update-hooks.js +154 -0
  306. package/dist/heart/versioning/version-intent.js +114 -0
  307. package/dist/heart/work-card.js +380 -0
  308. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  309. package/dist/mailbox-ui/assets/index-J8zDwHmE.js +1 -0
  310. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  311. package/dist/mailbox-ui/index.html +16 -0
  312. package/dist/mailroom/attention.js +167 -0
  313. package/dist/mailroom/autonomy.js +209 -0
  314. package/dist/mailroom/blob-store.js +889 -0
  315. package/dist/mailroom/body-cache.js +61 -0
  316. package/dist/mailroom/cache-sync-cli.js +58 -0
  317. package/dist/mailroom/core.js +803 -0
  318. package/dist/mailroom/entry.js +160 -0
  319. package/dist/mailroom/file-store.js +568 -0
  320. package/dist/mailroom/hosted-cache-sync.js +384 -0
  321. package/dist/mailroom/mbox-import.js +393 -0
  322. package/dist/mailroom/migration.js +164 -0
  323. package/dist/mailroom/outbound.js +380 -0
  324. package/dist/mailroom/policy.js +263 -0
  325. package/dist/mailroom/reader.js +292 -0
  326. package/dist/mailroom/search-cache.js +513 -0
  327. package/dist/mailroom/search-relevance.js +319 -0
  328. package/dist/mailroom/smtp-ingress.js +176 -0
  329. package/dist/mailroom/source-state.js +176 -0
  330. package/dist/mailroom/thread.js +109 -0
  331. package/dist/mailroom/travel-extract.js +89 -0
  332. package/dist/mind/bundle-manifest.js +24 -2
  333. package/dist/mind/context.js +279 -111
  334. package/dist/mind/desk-section.js +362 -0
  335. package/dist/mind/diary-integrity.js +60 -0
  336. package/dist/mind/{memory.js → diary.js} +68 -77
  337. package/dist/mind/embedding-provider.js +60 -0
  338. package/dist/mind/file-state.js +179 -0
  339. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  340. package/dist/mind/obligation-steering.js +227 -0
  341. package/dist/mind/pending.js +36 -10
  342. package/dist/mind/prompt-budget.js +479 -0
  343. package/dist/mind/prompt-refresh.js +3 -2
  344. package/dist/mind/prompt.js +1059 -187
  345. package/dist/mind/provenance-trust.js +26 -0
  346. package/dist/mind/record-paths.js +312 -0
  347. package/dist/mind/scrutiny.js +173 -0
  348. package/dist/mind/session-transaction.js +564 -0
  349. package/dist/nerves/cli-logging.js +7 -1
  350. package/dist/nerves/coverage/audit-rules.js +15 -6
  351. package/dist/nerves/coverage/audit.js +28 -2
  352. package/dist/nerves/coverage/cli.js +1 -1
  353. package/dist/nerves/coverage/contract.js +5 -5
  354. package/dist/nerves/coverage/file-completeness.js +139 -5
  355. package/dist/nerves/coverage/run-artifacts.js +55 -35
  356. package/dist/nerves/coverage/source-scanner.js +4 -4
  357. package/dist/nerves/event-buffer.js +111 -0
  358. package/dist/nerves/index.js +293 -9
  359. package/dist/nerves/observation.js +20 -0
  360. package/dist/nerves/redact.js +79 -0
  361. package/dist/nerves/review/cli-main.js +5 -0
  362. package/dist/nerves/review/cli.js +156 -0
  363. package/dist/nerves/review/core.js +159 -0
  364. package/dist/nerves/runtime.js +17 -1
  365. package/dist/repertoire/ado-client.js +15 -56
  366. package/dist/repertoire/ado-semantic.js +16 -10
  367. package/dist/repertoire/api-client.js +97 -0
  368. package/dist/repertoire/bitwarden-store.js +1045 -0
  369. package/dist/repertoire/bundle-templates.js +71 -0
  370. package/dist/repertoire/bw-installer.js +180 -0
  371. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  372. package/dist/repertoire/coding/context-pack.js +331 -0
  373. package/dist/repertoire/coding/feedback.js +218 -30
  374. package/dist/repertoire/coding/index.js +15 -3
  375. package/dist/repertoire/coding/manager.js +166 -10
  376. package/dist/repertoire/coding/spawner.js +58 -11
  377. package/dist/repertoire/coding/tools.js +242 -14
  378. package/dist/repertoire/coding/workbench-client.js +272 -0
  379. package/dist/repertoire/coding/workbench-manager.js +346 -0
  380. package/dist/repertoire/commerce-errors.js +109 -0
  381. package/dist/repertoire/commerce-self-test.js +156 -0
  382. package/dist/repertoire/credential-access.js +178 -0
  383. package/dist/repertoire/desk/classifier.js +362 -0
  384. package/dist/repertoire/duffel-client.js +185 -0
  385. package/dist/repertoire/github-client.js +14 -55
  386. package/dist/repertoire/graph-client.js +11 -52
  387. package/dist/repertoire/guardrails.js +811 -18
  388. package/dist/repertoire/mcp-client.js +44 -3
  389. package/dist/repertoire/mcp-manager.js +427 -139
  390. package/dist/repertoire/mcp-tools.js +124 -0
  391. package/dist/repertoire/plugin-mcp.js +175 -0
  392. package/dist/repertoire/plugins.js +253 -0
  393. package/dist/repertoire/relationship-authorization.js +194 -0
  394. package/dist/repertoire/shell-sessions.js +134 -0
  395. package/dist/repertoire/skills.js +48 -4
  396. package/dist/repertoire/stripe-client.js +131 -0
  397. package/dist/repertoire/tool-arguments.js +170 -0
  398. package/dist/repertoire/tool-results.js +29 -0
  399. package/dist/repertoire/tools-a2a.js +699 -0
  400. package/dist/repertoire/tools-attachments.js +322 -0
  401. package/dist/repertoire/tools-awaiting.js +575 -0
  402. package/dist/repertoire/tools-base.js +82 -1139
  403. package/dist/repertoire/tools-bluebubbles.js +2 -0
  404. package/dist/repertoire/tools-bridge.js +144 -0
  405. package/dist/repertoire/tools-bundle.js +993 -0
  406. package/dist/repertoire/tools-commerce.js +253 -0
  407. package/dist/repertoire/tools-config.js +186 -0
  408. package/dist/repertoire/tools-continuity.js +575 -0
  409. package/dist/repertoire/tools-credential.js +383 -0
  410. package/dist/repertoire/tools-evolution.js +527 -0
  411. package/dist/repertoire/tools-files.js +344 -0
  412. package/dist/repertoire/tools-flight.js +290 -0
  413. package/dist/repertoire/tools-flow.js +119 -0
  414. package/dist/repertoire/tools-github.js +3 -8
  415. package/dist/repertoire/tools-habits.js +103 -0
  416. package/dist/repertoire/tools-mail.js +1828 -0
  417. package/dist/repertoire/tools-notes.js +485 -0
  418. package/dist/repertoire/tools-obligations.js +182 -0
  419. package/dist/repertoire/tools-orientation.js +31 -0
  420. package/dist/repertoire/tools-record.js +482 -0
  421. package/dist/repertoire/tools-rsvp.js +139 -0
  422. package/dist/repertoire/tools-runtime.js +150 -0
  423. package/dist/repertoire/tools-session.js +1133 -0
  424. package/dist/repertoire/tools-shell.js +149 -0
  425. package/dist/repertoire/tools-steward-policy.js +95 -0
  426. package/dist/repertoire/tools-stripe.js +224 -0
  427. package/dist/repertoire/tools-surface.js +369 -0
  428. package/dist/repertoire/tools-teams.js +12 -39
  429. package/dist/repertoire/tools-telegram-contacts.js +37 -0
  430. package/dist/repertoire/tools-travel.js +125 -0
  431. package/dist/repertoire/tools-trip.js +982 -0
  432. package/dist/repertoire/tools-unraid.js +484 -0
  433. package/dist/repertoire/tools-user-profile.js +146 -0
  434. package/dist/repertoire/tools-vault.js +40 -0
  435. package/dist/repertoire/tools-voice.js +145 -0
  436. package/dist/repertoire/tools.js +470 -147
  437. package/dist/repertoire/travel-api-client.js +360 -0
  438. package/dist/repertoire/unraid-client.js +155 -0
  439. package/dist/repertoire/unraid-restart.js +212 -0
  440. package/dist/repertoire/user-profile.js +131 -0
  441. package/dist/repertoire/vault-setup.js +246 -0
  442. package/dist/repertoire/vault-unlock.js +628 -0
  443. package/dist/rsvp/aisleplanner-client.js +354 -0
  444. package/dist/rsvp/cli.js +926 -0
  445. package/dist/rsvp/config.js +327 -0
  446. package/dist/rsvp/cutover.js +433 -0
  447. package/dist/rsvp/diagnostics.js +232 -0
  448. package/dist/rsvp/diff-renderer.js +176 -0
  449. package/dist/rsvp/habit-policy.js +110 -0
  450. package/dist/rsvp/habit-stage.js +123 -0
  451. package/dist/rsvp/incident-bundle.js +97 -0
  452. package/dist/rsvp/migration.js +204 -0
  453. package/dist/rsvp/native-habit-runner.js +630 -0
  454. package/dist/rsvp/outbound-state.js +628 -0
  455. package/dist/rsvp/query.js +118 -0
  456. package/dist/rsvp/replay.js +233 -0
  457. package/dist/rsvp/snapshot.js +232 -0
  458. package/dist/rsvp/spend-ledger.js +175 -0
  459. package/dist/scripts/claude-code-hook.js +41 -0
  460. package/dist/scripts/claude-code-stop-hook.js +47 -0
  461. package/dist/senses/a2a-entry.js +115 -0
  462. package/dist/senses/acp-server.js +386 -0
  463. package/dist/senses/attention-queue.js +186 -0
  464. package/dist/senses/await-turn-message.js +58 -0
  465. package/dist/senses/bluebubbles/active-turns.js +216 -0
  466. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  467. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  468. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +355 -40
  469. package/dist/senses/bluebubbles/context-packet.js +207 -0
  470. package/dist/senses/bluebubbles/context-smoke.js +144 -0
  471. package/dist/senses/bluebubbles/entry.js +90 -0
  472. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
  473. package/dist/senses/bluebubbles/index.js +3841 -0
  474. package/dist/senses/bluebubbles/latest-turn.js +311 -0
  475. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  476. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
  477. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
  478. package/dist/senses/bluebubbles/outbound-state.js +308 -0
  479. package/dist/senses/bluebubbles/processed-log.js +133 -0
  480. package/dist/senses/bluebubbles/reaction-policy.js +47 -0
  481. package/dist/senses/bluebubbles/replay.js +284 -0
  482. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  483. package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
  484. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  485. package/dist/senses/bluebubbles/webhook-registration.js +228 -0
  486. package/dist/senses/bluebubbles-meta-guard.js +39 -0
  487. package/dist/senses/cli/bracketed-paste.js +82 -0
  488. package/dist/senses/cli/image-paste.js +287 -0
  489. package/dist/senses/cli/image-ref-navigation.js +75 -0
  490. package/dist/senses/cli/ink-app.js +156 -0
  491. package/dist/senses/cli/inline-diff.js +64 -0
  492. package/dist/senses/cli/input-keys.js +174 -0
  493. package/dist/senses/cli/kill-ring.js +86 -0
  494. package/dist/senses/cli/message-list.js +51 -0
  495. package/dist/senses/cli/ouro-tui.js +607 -0
  496. package/dist/senses/cli/spinner-imperative.js +135 -0
  497. package/dist/senses/cli/spinner.js +101 -0
  498. package/dist/senses/cli/status-line.js +60 -0
  499. package/dist/senses/cli/streaming-markdown.js +526 -0
  500. package/dist/senses/cli/tool-display.js +85 -0
  501. package/dist/senses/cli/tool-render.js +85 -0
  502. package/dist/senses/cli/tui-store.js +241 -0
  503. package/dist/senses/cli/virtual-list.js +35 -0
  504. package/dist/senses/cli-entry.js +60 -8
  505. package/dist/senses/cli.js +604 -320
  506. package/dist/senses/commands.js +66 -3
  507. package/dist/senses/context-packet-ledger.js +371 -0
  508. package/dist/senses/context-packets.js +154 -0
  509. package/dist/senses/habit-lifecycle-guard.js +24 -0
  510. package/dist/senses/habit-turn-message.js +160 -0
  511. package/dist/senses/ingress-evidence.js +2 -0
  512. package/dist/senses/mail-entry.js +66 -0
  513. package/dist/senses/mail.js +524 -0
  514. package/dist/senses/pipeline.js +1115 -204
  515. package/dist/senses/private-runtime-worker.js +859 -0
  516. package/dist/senses/private-runtime.js +1502 -0
  517. package/dist/senses/proactive-content-guard.js +51 -0
  518. package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
  519. package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
  520. package/dist/senses/sanctuary-grounding.js +118 -0
  521. package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
  522. package/dist/senses/sanctuary-health-acceptance-probe.js +774 -0
  523. package/dist/senses/sanctuary-health-runner.js +101 -0
  524. package/dist/senses/sanctuary-health.js +408 -0
  525. package/dist/senses/sanctuary-install-state-contract.js +126 -0
  526. package/dist/senses/sanctuary-interactive-control.js +306 -0
  527. package/dist/senses/sanctuary-media-catalog-contract.js +235 -0
  528. package/dist/senses/sanctuary-media-optimization.js +514 -0
  529. package/dist/senses/sanctuary-runtime.js +338 -0
  530. package/dist/senses/sanctuary-sab.js +85 -0
  531. package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
  532. package/dist/senses/shared-turn.js +759 -0
  533. package/dist/senses/surface-tool.js +109 -0
  534. package/dist/senses/teams-entry.js +60 -8
  535. package/dist/senses/teams.js +519 -218
  536. package/dist/senses/telegram-admission.js +711 -0
  537. package/dist/senses/telegram-approval-runtime.js +675 -0
  538. package/dist/senses/telegram-attachments.js +182 -0
  539. package/dist/senses/telegram-audit-ledger.js +220 -0
  540. package/dist/senses/telegram-client.js +1694 -0
  541. package/dist/senses/telegram-effect-adapter.js +859 -0
  542. package/dist/senses/telegram-entry.js +83 -0
  543. package/dist/senses/telegram.js +2084 -0
  544. package/dist/senses/trust-gate.js +104 -9
  545. package/dist/senses/voice/audio-playback.js +237 -0
  546. package/dist/senses/voice/audio-routing.js +119 -0
  547. package/dist/senses/voice/elevenlabs.js +202 -0
  548. package/dist/senses/voice/floor-control.js +431 -0
  549. package/dist/senses/voice/floor-controller.js +115 -0
  550. package/dist/senses/voice/golden-path.js +116 -0
  551. package/dist/senses/voice/index.js +29 -0
  552. package/dist/senses/voice/meeting.js +113 -0
  553. package/dist/senses/voice/outbound.js +190 -0
  554. package/dist/senses/voice/phone.js +33 -0
  555. package/dist/senses/voice/playback.js +139 -0
  556. package/dist/senses/voice/realtime-eval.js +496 -0
  557. package/dist/senses/voice/realtime-trace.js +531 -0
  558. package/dist/senses/voice/transcript.js +70 -0
  559. package/dist/senses/voice/turn.js +191 -0
  560. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  561. package/dist/senses/voice/twilio-phone.js +5031 -0
  562. package/dist/senses/voice/types.js +2 -0
  563. package/dist/senses/voice/whisper.js +161 -0
  564. package/dist/senses/voice-entry.js +81 -0
  565. package/dist/senses/voice-realtime-eval-command.js +99 -0
  566. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  567. package/dist/senses/voice-twilio-entry.js +87 -0
  568. package/dist/trips/core.js +138 -0
  569. package/dist/trips/store.js +265 -0
  570. package/dist/util/frontmatter.js +69 -0
  571. package/npm-shrinkwrap.json +8138 -0
  572. package/package.json +72 -13
  573. package/skills/agent-commerce.md +113 -0
  574. package/skills/browser-navigation.md +117 -0
  575. package/skills/commerce-setup-guide.md +116 -0
  576. package/skills/commerce-setup.md +84 -0
  577. package/skills/configure-dev-tools.md +99 -0
  578. package/skills/travel-planning.md +138 -0
  579. package/dist/heart/daemon/auth-flow.js +0 -430
  580. package/dist/heart/daemon/ouro-path-installer.js +0 -260
  581. package/dist/heart/daemon/ouro-version-manager.js +0 -164
  582. package/dist/heart/daemon/update-hooks.js +0 -138
  583. package/dist/heart/obligations.js +0 -141
  584. package/dist/heart/safe-workspace.js +0 -228
  585. package/dist/heart/session-recall.js +0 -116
  586. package/dist/mind/friends/channel.js +0 -84
  587. package/dist/mind/friends/group-context.js +0 -144
  588. package/dist/mind/friends/resolver.js +0 -84
  589. package/dist/mind/friends/store-file.js +0 -190
  590. package/dist/mind/friends/store.js +0 -4
  591. package/dist/mind/friends/tokens.js +0 -26
  592. package/dist/mind/friends/trust-explanation.js +0 -74
  593. package/dist/mind/friends/types.js +0 -29
  594. package/dist/repertoire/tasks/board.js +0 -134
  595. package/dist/repertoire/tasks/index.js +0 -224
  596. package/dist/repertoire/tasks/lifecycle.js +0 -80
  597. package/dist/repertoire/tasks/middleware.js +0 -65
  598. package/dist/repertoire/tasks/parser.js +0 -173
  599. package/dist/repertoire/tasks/scanner.js +0 -132
  600. package/dist/repertoire/tasks/transitions.js +0 -144
  601. package/dist/senses/bluebubbles-entry.js +0 -13
  602. package/dist/senses/bluebubbles.js +0 -1181
  603. package/dist/senses/debug-activity.js +0 -154
  604. package/dist/senses/inner-dialog-worker.js +0 -90
  605. package/dist/senses/inner-dialog.js +0 -525
  606. package/subagents/README.md +0 -7
  607. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  608. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  609. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  610. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  611. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  612. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  613. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  614. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  615. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  616. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  617. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  618. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  619. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  620. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  621. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  622. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  623. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,1502 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.PRIVATE_TURN_DECISION_MAX_AGE_MS = void 0;
37
+ exports.loadPrivateRuntimeInstincts = loadPrivateRuntimeInstincts;
38
+ exports.buildPrivateRuntimeBootstrapMessage = buildPrivateRuntimeBootstrapMessage;
39
+ exports.buildNonCanonicalCleanupNudge = buildNonCanonicalCleanupNudge;
40
+ exports.buildInstinctUserMessage = buildInstinctUserMessage;
41
+ exports.readTaskFile = readTaskFile;
42
+ exports.buildTaskTriggeredMessage = buildTaskTriggeredMessage;
43
+ exports.deriveResumeCheckpoint = deriveResumeCheckpoint;
44
+ exports.privateRuntimeSessionPath = privateRuntimeSessionPath;
45
+ exports.enrichDelegatedFromWithBridge = enrichDelegatedFromWithBridge;
46
+ exports.routeDelegatedCompletion = routeDelegatedCompletion;
47
+ exports.buildParseErrorNudge = buildParseErrorNudge;
48
+ exports.buildHeldReturnWakeMessage = buildHeldReturnWakeMessage;
49
+ exports.runPrivateRuntimeTurn = runPrivateRuntimeTurn;
50
+ const fs = __importStar(require("fs"));
51
+ const path = __importStar(require("path"));
52
+ const config_1 = require("../heart/config");
53
+ const core_1 = require("../heart/core");
54
+ const identity_1 = require("../heart/identity");
55
+ const context_1 = require("../mind/context");
56
+ const prompt_1 = require("../mind/prompt");
57
+ const mcp_manager_1 = require("../repertoire/mcp-manager");
58
+ const tools_1 = require("../repertoire/tools");
59
+ const tools_awaiting_1 = require("../repertoire/tools-awaiting");
60
+ const relationship_authorization_1 = require("../repertoire/relationship-authorization");
61
+ const run_ledger_1 = require("../heart/run-ledger");
62
+ const bundle_manifest_1 = require("../mind/bundle-manifest");
63
+ const pending_1 = require("../mind/pending");
64
+ const obligations_1 = require("../arc/obligations");
65
+ const attention_queue_1 = require("./attention-queue");
66
+ const packets_1 = require("../arc/packets");
67
+ const friends_1 = require("@ouro.bot/friends");
68
+ const trust_gate_1 = require("./trust-gate");
69
+ const pipeline_1 = require("./pipeline");
70
+ const session_transaction_1 = require("../mind/session-transaction");
71
+ const nerves_1 = require("../nerves");
72
+ const runtime_1 = require("../nerves/runtime");
73
+ const provider_credentials_1 = require("../heart/provider-credentials");
74
+ const manager_1 = require("../heart/bridges/manager");
75
+ const session_activity_1 = require("../heart/session-activity");
76
+ const bluebubbles_1 = require("./bluebubbles");
77
+ const habit_turn_message_1 = require("./habit-turn-message");
78
+ const await_turn_message_1 = require("./await-turn-message");
79
+ const await_parser_1 = require("../heart/awaiting/await-parser");
80
+ const await_runtime_state_1 = require("../heart/awaiting/await-runtime-state");
81
+ const habit_parser_1 = require("../heart/habits/habit-parser");
82
+ const habit_runtime_state_1 = require("../heart/habits/habit-runtime-state");
83
+ const habit_lifecycle_guard_1 = require("./habit-lifecycle-guard");
84
+ const cadence_1 = require("../heart/daemon/cadence");
85
+ const habit_policy_1 = require("../rsvp/habit-policy");
86
+ const daemon_health_1 = require("../heart/daemon/daemon-health");
87
+ const flight_recorder_1 = require("../arc/flight-recorder");
88
+ const desk_section_1 = require("../mind/desk-section");
89
+ const sanctuary_runtime_1 = require("./sanctuary-runtime");
90
+ const shared_turn_1 = require("./shared-turn");
91
+ const relationship_authorization_2 = require("../repertoire/relationship-authorization");
92
+ const private_runtime_1 = require("../heart/private-runtime");
93
+ exports.PRIVATE_TURN_DECISION_MAX_AGE_MS = 15 * 60_000;
94
+ const DUPLICATE_PRIVATE_TURN_STATUS = "DUPLICATE_PRIVATE_TURN";
95
+ const DEFAULT_PRIVATE_RUNTIME_INSTINCTS = [
96
+ {
97
+ id: "heartbeat_checkin",
98
+ prompt: "...time passing. anything stirring?",
99
+ enabled: true,
100
+ },
101
+ ];
102
+ class StaleRelationshipAwaitError extends Error {
103
+ reason;
104
+ constructor(reason) {
105
+ super(`Relationship await authority ${reason}`);
106
+ this.reason = reason;
107
+ }
108
+ }
109
+ function exactFriendFileIsMissing(agentRoot, friendId) {
110
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/u.test(friendId))
111
+ throw new Error("Relationship await authority friend id is invalid");
112
+ try {
113
+ fs.lstatSync(path.join(agentRoot, "friends", `${friendId}.json`));
114
+ return false;
115
+ }
116
+ catch (error) {
117
+ if (error.code === "ENOENT")
118
+ return true;
119
+ throw error;
120
+ }
121
+ }
122
+ function relationshipAwaitCoordinates(awaitFile) {
123
+ const values = [awaitFile.filed_for_friend_id, awaitFile.filed_from, awaitFile.filed_from_key];
124
+ if (!awaitFile.request_id) {
125
+ if (awaitFile.filed_from === "external-event" && awaitFile.filed_for_friend_id && awaitFile.filed_from_key) {
126
+ if (Buffer.byteLength(awaitFile.filed_for_friend_id) > 256 || Buffer.byteLength(awaitFile.filed_from_key) > 1_024)
127
+ throw new Error("Relationship await provenance is invalid");
128
+ return { friendId: awaitFile.filed_for_friend_id, channel: awaitFile.filed_from, key: awaitFile.filed_from_key, requestId: null };
129
+ }
130
+ const isSystemAwait = awaitFile.filed_for_friend_id === null
131
+ && awaitFile.filed_from_key === null
132
+ && (awaitFile.filed_from === null || awaitFile.filed_from === "unknown" || awaitFile.filed_from === "cli");
133
+ if (isSystemAwait)
134
+ return null;
135
+ throw new Error("Relationship await provenance is incomplete or legacy");
136
+ }
137
+ if (values.some((value) => value === null))
138
+ throw new Error("Relationship await provenance is incomplete or legacy");
139
+ const [friendId, channel, key] = values;
140
+ if (channel !== "telegram" || Buffer.byteLength(friendId) > 256 || Buffer.byteLength(channel) > 64 || Buffer.byteLength(key) > 1_024 || Buffer.byteLength(awaitFile.request_id) > 256) {
141
+ throw new Error("Relationship await provenance is invalid");
142
+ }
143
+ return { friendId, channel, key, requestId: awaitFile.request_id };
144
+ }
145
+ async function resolveRelationshipAwaitAuthority(agentRoot, store, registry, coordinates) {
146
+ const friend = await store.get(coordinates.friendId);
147
+ if (!friend) {
148
+ if (exactFriendFileIsMissing(agentRoot, coordinates.friendId))
149
+ throw new StaleRelationshipAwaitError("friend is missing");
150
+ throw new Error("Relationship await authority friend exists but could not be read");
151
+ }
152
+ if (friend.id !== coordinates.friendId)
153
+ throw new Error("Relationship await authority friend record is ambiguous");
154
+ if (friend.admissionState !== "active" || !friend.capabilityProfileId)
155
+ throw new StaleRelationshipAwaitError("admission or profile is not active");
156
+ if (!registry.profiles[friend.capabilityProfileId])
157
+ throw new StaleRelationshipAwaitError("admission or profile is not active");
158
+ if (coordinates.channel === "external-event" && (friend.capabilityProfileId !== "sanctuary-owner" || !registry.profiles["sanctuary-event"])) {
159
+ throw new StaleRelationshipAwaitError("admission or profile is not active");
160
+ }
161
+ const authorization = coordinates.channel === "external-event"
162
+ ? (0, relationship_authorization_2.createRelationshipAuthorizationEvaluator)({ friend, registry, profileId: "sanctuary-event", requestPhase: "follow_up" })
163
+ : (0, relationship_authorization_2.createRelationshipAuthorizationEvaluator)({ friend, registry, requestId: coordinates.requestId, requestPhase: "follow_up" });
164
+ if (authorization.subject.friendId !== coordinates.friendId)
165
+ throw new Error("Relationship await authority friend is ambiguous");
166
+ if (!authorization.authorizeTool("resolve_await").allowed)
167
+ throw new StaleRelationshipAwaitError("admission or profile is not active");
168
+ return { authorization, friend };
169
+ }
170
+ function readAspirations(agentRoot) {
171
+ try {
172
+ return fs.readFileSync(path.join(agentRoot, "psyche", "ASPIRATIONS.md"), "utf8").trim();
173
+ }
174
+ catch {
175
+ return "";
176
+ }
177
+ }
178
+ function loadPrivateRuntimeInstincts() {
179
+ return [...DEFAULT_PRIVATE_RUNTIME_INSTINCTS];
180
+ }
181
+ function buildPrivateRuntimeBootstrapMessage(aspirations, stateSummary) {
182
+ const lines = ["waking up."];
183
+ if (aspirations) {
184
+ lines.push("", "## what matters to me", aspirations);
185
+ }
186
+ if (stateSummary) {
187
+ lines.push("", "## what i know so far", stateSummary);
188
+ }
189
+ lines.push("", "what needs my attention?");
190
+ return lines.join("\n");
191
+ }
192
+ function buildNonCanonicalCleanupNudge(nonCanonicalPaths) {
193
+ if (nonCanonicalPaths.length === 0)
194
+ return "";
195
+ const listed = nonCanonicalPaths.slice(0, 20).map((entry) => `- ${entry}`);
196
+ if (nonCanonicalPaths.length > 20) {
197
+ listed.push(`- ... (${nonCanonicalPaths.length - 20} more)`);
198
+ }
199
+ return [
200
+ "## canonical cleanup nudge",
201
+ "I found non-canonical files in my bundle. I should distill anything valuable into my diary and remove these files.",
202
+ ...listed,
203
+ ].join("\n");
204
+ }
205
+ function displayCheckpoint(checkpoint) {
206
+ const trimmed = checkpoint?.trim();
207
+ if (!trimmed || trimmed === "no prior checkpoint recorded") {
208
+ return undefined;
209
+ }
210
+ return trimmed;
211
+ }
212
+ function buildInstinctUserMessage(instincts, _reason, state) {
213
+ const active = instincts.find((instinct) => instinct.enabled !== false) ?? DEFAULT_PRIVATE_RUNTIME_INSTINCTS[0];
214
+ const checkpoint = displayCheckpoint(state.checkpoint);
215
+ const lines = [active.prompt];
216
+ if (checkpoint) {
217
+ lines.push(`\nlast checkpoint: ${checkpoint}`);
218
+ }
219
+ return lines.join("\n");
220
+ }
221
+ function readTaskFile(agentRoot, taskId) {
222
+ // Task files live in collection subdirectories (one-shots, ongoing).
223
+ // Try each collection, then fall back to root tasks/ for legacy layout.
224
+ // Habits are no longer in tasks/ — they live at bundle root habits/.
225
+ const collections = ["one-shots", "ongoing", ""];
226
+ for (const collection of collections) {
227
+ try {
228
+ return fs.readFileSync(path.join(agentRoot, "tasks", collection, `${taskId}.md`), "utf8").trim();
229
+ }
230
+ catch {
231
+ // not in this collection — try next
232
+ }
233
+ }
234
+ return "";
235
+ }
236
+ function buildTaskTriggeredMessage(taskId, taskContent, checkpoint) {
237
+ const lines = ["a task needs my attention."];
238
+ if (taskContent) {
239
+ lines.push("", `## task: ${taskId}`, taskContent);
240
+ }
241
+ else {
242
+ lines.push("", `## task: ${taskId}`, "(task file not found)");
243
+ }
244
+ const renderedCheckpoint = displayCheckpoint(checkpoint);
245
+ if (renderedCheckpoint) {
246
+ lines.push("", `last checkpoint: ${renderedCheckpoint}`);
247
+ }
248
+ return lines.join("\n");
249
+ }
250
+ function contentToText(content) {
251
+ if (typeof content === "string")
252
+ return content.trim();
253
+ if (!Array.isArray(content))
254
+ return "";
255
+ const text = content
256
+ .map((part) => {
257
+ if (typeof part === "string")
258
+ return part;
259
+ if (!part || typeof part !== "object")
260
+ return "";
261
+ if ("text" in part && typeof part.text === "string") {
262
+ return part.text;
263
+ }
264
+ return "";
265
+ })
266
+ .join("\n");
267
+ return text.trim();
268
+ }
269
+ function checkpointTextFromAssistantContent(content) {
270
+ const assistantText = contentToText(content);
271
+ if (!assistantText)
272
+ return null;
273
+ const cleanedLines = assistantText
274
+ .split("\n")
275
+ .map((line) => line.replace(/<\/?think>/gi, "").trim())
276
+ .filter((line) => line.length > 0);
277
+ const explicitCheckpoint = cleanedLines
278
+ .find((line) => /^checkpoint\s*:/i.test(line));
279
+ if (explicitCheckpoint) {
280
+ const parsed = explicitCheckpoint.replace(/^checkpoint\s*:\s*/i, "").trim();
281
+ return parsed || null;
282
+ }
283
+ const firstLine = cleanedLines[0];
284
+ return firstLine ?? null;
285
+ }
286
+ function truncateCheckpointText(text) {
287
+ if (text.length <= 220)
288
+ return text;
289
+ return `${text.slice(0, 217)}...`;
290
+ }
291
+ function parseToolArguments(argumentsValue) {
292
+ if (!argumentsValue)
293
+ return {};
294
+ try {
295
+ const parsed = JSON.parse(argumentsValue);
296
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
297
+ ? parsed
298
+ : {};
299
+ }
300
+ catch {
301
+ return {};
302
+ }
303
+ }
304
+ function toolArgumentText(args, keys) {
305
+ for (const key of keys) {
306
+ const value = args[key];
307
+ if (typeof value === "string" && value.trim()) {
308
+ return value.trim();
309
+ }
310
+ }
311
+ return "";
312
+ }
313
+ function summarizeToolAction(name, argumentsValue) {
314
+ if (!name)
315
+ return null;
316
+ const args = parseToolArguments(argumentsValue);
317
+ if (name === "surface") {
318
+ const message = toolArgumentText(args, ["message", "text", "content"]);
319
+ return message ? `surfaced: ${message}` : null;
320
+ }
321
+ if (name === "ponder") {
322
+ const thought = toolArgumentText(args, ["summary", "question", "topic", "prompt"]);
323
+ return thought ? `pondered: ${thought}` : null;
324
+ }
325
+ if (name === "diary_write") {
326
+ const note = toolArgumentText(args, ["text", "content", "note", "entry"]);
327
+ return note ? `diary: ${note}` : null;
328
+ }
329
+ if (name === "let_go") {
330
+ const reason = toolArgumentText(args, ["reason", "note", "status"]);
331
+ return reason ? `let go: ${reason}` : null;
332
+ }
333
+ if (name === "rest") {
334
+ const note = toolArgumentText(args, ["note", "status"]);
335
+ return note ? `rested: ${note}` : null;
336
+ }
337
+ return null;
338
+ }
339
+ function extractToolFunction(toolCall) {
340
+ if (!toolCall || typeof toolCall !== "object" || !("function" in toolCall))
341
+ return null;
342
+ const maybeFunction = toolCall.function;
343
+ if (!maybeFunction || typeof maybeFunction !== "object")
344
+ return null;
345
+ const name = "name" in maybeFunction && typeof maybeFunction.name === "string"
346
+ ? maybeFunction.name
347
+ : undefined;
348
+ const argumentsValue = "arguments" in maybeFunction && typeof maybeFunction.arguments === "string"
349
+ ? maybeFunction.arguments
350
+ : undefined;
351
+ return { name, arguments: argumentsValue };
352
+ }
353
+ function privateTurnRequestFromDecision(decision) {
354
+ return {
355
+ agent: decision.agent,
356
+ origin: decision.origin,
357
+ reason: decision.requestReason ?? decision.reason,
358
+ providerLane: decision.providerLane.lane,
359
+ triggerSource: decision.triggerSource,
360
+ idempotencyKey: decision.idempotencyKey,
361
+ budgetClass: decision.budgetClass,
362
+ originRefs: decision.originRefs,
363
+ };
364
+ }
365
+ function isRecord(value) {
366
+ return !!value && typeof value === "object" && !Array.isArray(value);
367
+ }
368
+ function configuredProviderLaneMetadata(agentName, lane) {
369
+ const configPath = path.join((0, identity_1.getAgentRoot)(agentName), "agent.json");
370
+ const parsed = JSON.parse(fs.readFileSync(configPath, "utf-8"));
371
+ if (!isRecord(parsed)) {
372
+ throw new Error("private-runtime provider lane mismatch: agent.json is not an object");
373
+ }
374
+ const facingKey = lane === "inner" ? "agentFacing" : "humanFacing";
375
+ const facing = parsed[facingKey];
376
+ if (!isRecord(facing)) {
377
+ throw new Error(`private-runtime provider lane mismatch: missing ${facingKey}`);
378
+ }
379
+ const provider = facing.provider;
380
+ const model = facing.model;
381
+ if (typeof provider !== "string" || provider.trim().length === 0 || typeof model !== "string" || model.trim().length === 0) {
382
+ throw new Error(`private-runtime provider lane mismatch: incomplete ${facingKey}`);
383
+ }
384
+ const credential = (0, provider_credentials_1.readCachedProviderCredentialRecord)(agentName, provider);
385
+ if (!credential.ok) {
386
+ throw new Error(`private-runtime provider lane mismatch: credential revision unavailable for ${provider}`);
387
+ }
388
+ return {
389
+ lane,
390
+ provider,
391
+ model,
392
+ source: "agent.json",
393
+ credentialRevision: credential.record.revision,
394
+ };
395
+ }
396
+ function assertProviderLaneStillMatches(decision, agentName) {
397
+ const current = configuredProviderLaneMetadata(agentName, decision.providerLane.lane);
398
+ if (typeof decision.providerLane.credentialRevision !== "string" || decision.providerLane.credentialRevision.trim().length === 0) {
399
+ throw new Error(`private-runtime provider lane mismatch: receipt for ${decision.providerLane.provider}/${decision.providerLane.model} is missing credential revision`);
400
+ }
401
+ if (current.lane !== decision.providerLane.lane
402
+ || current.provider !== decision.providerLane.provider
403
+ || current.model !== decision.providerLane.model
404
+ || current.source !== decision.providerLane.source
405
+ || current.credentialRevision !== decision.providerLane.credentialRevision) {
406
+ throw new Error(`private-runtime provider lane mismatch: receipt was for ${decision.providerLane.provider}/${decision.providerLane.model}, current ${decision.providerLane.lane} lane is ${current.provider}/${current.model}`);
407
+ }
408
+ }
409
+ function findOriginRef(refs, kind, id) {
410
+ return refs.find((ref) => ref.kind === kind && ref.id === id);
411
+ }
412
+ function assertPayloadBinding(decision, kind, id) {
413
+ const refs = decision.originRefs.filter((ref) => ref.kind === kind);
414
+ if (!id && refs.length === 0)
415
+ return;
416
+ if (!id) {
417
+ throw new Error(`private-runtime decision payload mismatch: missing ${kind} payload for ${refs.map((ref) => ref.id).join(", ")}`);
418
+ }
419
+ if (findOriginRef(refs, kind, id))
420
+ return;
421
+ throw new Error(`private-runtime decision payload mismatch: missing ${kind} origin ref ${id}`);
422
+ }
423
+ function assertNoSendBinding(decision, noSend) {
424
+ const refs = decision.originRefs.filter((ref) => ref.kind === "capability" && ref.id === "no-send");
425
+ if (noSend === true && refs.length === 1)
426
+ return;
427
+ if (noSend === undefined && refs.length === 0)
428
+ return;
429
+ throw new Error("private-runtime decision payload mismatch: no-send capability binding does not match the turn");
430
+ }
431
+ function ledgerDecisionFor(decision) {
432
+ const ledgerPath = decision.ledgerLocator?.path;
433
+ if (!ledgerPath) {
434
+ throw new Error("private-runtime decision has no ledger locator");
435
+ }
436
+ const rows = (0, private_runtime_1.readPrivateTurnLedger)(ledgerPath);
437
+ const lineIndex = typeof decision.ledgerLocator.line === "number"
438
+ ? decision.ledgerLocator.line - 1
439
+ : -1;
440
+ const row = lineIndex >= 0 && lineIndex < rows.length
441
+ ? rows[lineIndex]
442
+ : rows.find((candidate) => candidate.receiptId === decision.receiptId
443
+ && candidate.idempotencyKey === decision.idempotencyKey
444
+ && candidate.requestFingerprint === decision.requestFingerprint);
445
+ if (!row) {
446
+ throw new Error("private-runtime decision is not present in the ledger");
447
+ }
448
+ if (row.receiptId !== decision.receiptId
449
+ || row.idempotencyKey !== decision.idempotencyKey
450
+ || row.requestFingerprint !== decision.requestFingerprint
451
+ || row.result !== decision.result
452
+ || row.executable !== decision.executable) {
453
+ throw new Error("private-runtime decision does not match its ledger row");
454
+ }
455
+ return row;
456
+ }
457
+ function assertPrivateTurnDecisionAllowed(input) {
458
+ const { decision, agentName, options, now } = input;
459
+ if (!decision) {
460
+ throw new Error("private-runtime provider boundary requires an approved private-turn decision");
461
+ }
462
+ if (decision.agent !== agentName) {
463
+ throw new Error(`private-runtime decision agent mismatch: expected ${agentName}, got ${decision.agent}`);
464
+ }
465
+ if (decision.result !== "allow" || decision.executable !== true) {
466
+ throw new Error(`private-runtime decision denied: ${decision.deniedReason ?? decision.result}`);
467
+ }
468
+ assertProviderLaneStillMatches(decision, agentName);
469
+ const expectedFingerprint = (0, private_runtime_1.createPrivateTurnRequestFingerprint)(privateTurnRequestFromDecision(decision), decision.providerLane);
470
+ if (decision.requestFingerprint !== expectedFingerprint) {
471
+ throw new Error("private-runtime decision fingerprint mismatch");
472
+ }
473
+ assertPayloadBinding(decision, "task", options?.taskId);
474
+ assertPayloadBinding(decision, "habit", options?.habitName);
475
+ assertPayloadBinding(decision, "await", options?.awaitName);
476
+ assertNoSendBinding(decision, options?.noSend);
477
+ const ledgerRow = ledgerDecisionFor(decision);
478
+ const decidedAtMs = Date.parse(ledgerRow.decidedAt);
479
+ if (!Number.isFinite(decidedAtMs)) {
480
+ throw new Error("private-runtime decision has invalid decidedAt timestamp");
481
+ }
482
+ const ageMs = now().getTime() - decidedAtMs;
483
+ if (ageMs < 0 || ageMs > exports.PRIVATE_TURN_DECISION_MAX_AGE_MS) {
484
+ throw new Error("private-runtime decision is stale");
485
+ }
486
+ return ledgerRow;
487
+ }
488
+ function privateTurnExecutionPath(decision) {
489
+ const safeReceiptId = decision.receiptId.replace(/[^A-Za-z0-9_.-]/g, "_");
490
+ return path.join(path.dirname(decision.ledgerLocator.path), "executions", `${safeReceiptId}.json`);
491
+ }
492
+ function claimPrivateTurnExecution(decision, now) {
493
+ const executionPath = privateTurnExecutionPath(decision);
494
+ fs.mkdirSync(path.dirname(executionPath), { recursive: true });
495
+ try {
496
+ fs.writeFileSync(executionPath, JSON.stringify({
497
+ receiptId: decision.receiptId,
498
+ idempotencyKey: decision.idempotencyKey,
499
+ requestFingerprint: decision.requestFingerprint,
500
+ claimedAt: now().toISOString(),
501
+ }), { encoding: "utf-8", flag: "wx" });
502
+ return true;
503
+ }
504
+ catch (error) {
505
+ if (error.code === "EEXIST")
506
+ return false;
507
+ throw error;
508
+ }
509
+ }
510
+ function checkpointTextFromAssistantToolCalls(message) {
511
+ if (message.role !== "assistant" || !Array.isArray(message.tool_calls))
512
+ return null;
513
+ for (let i = message.tool_calls.length - 1; i >= 0; i--) {
514
+ const toolFunction = extractToolFunction(message.tool_calls[i]);
515
+ const summary = summarizeToolAction(toolFunction?.name, toolFunction?.arguments);
516
+ if (summary)
517
+ return summary;
518
+ }
519
+ return null;
520
+ }
521
+ function latestRestStatus(messages) {
522
+ for (let i = messages.length - 1; i >= 0; i--) {
523
+ const message = messages[i];
524
+ if (message.role !== "assistant" || !Array.isArray(message.tool_calls))
525
+ continue;
526
+ for (let j = message.tool_calls.length - 1; j >= 0; j--) {
527
+ const toolFunction = extractToolFunction(message.tool_calls[j]);
528
+ if (toolFunction?.name !== "rest")
529
+ continue;
530
+ const status = parseToolArguments(toolFunction.arguments).status;
531
+ return typeof status === "string" && status.trim() ? status.trim() : undefined;
532
+ }
533
+ }
534
+ return undefined;
535
+ }
536
+ function deriveResumeCheckpoint(messages) {
537
+ for (let i = messages.length - 1; i >= 0; i--) {
538
+ const message = messages[i];
539
+ if (message.role !== "assistant")
540
+ continue;
541
+ const textCheckpoint = checkpointTextFromAssistantContent(message.content);
542
+ if (textCheckpoint)
543
+ return truncateCheckpointText(textCheckpoint);
544
+ const toolCheckpoint = checkpointTextFromAssistantToolCalls(message);
545
+ if (toolCheckpoint)
546
+ return truncateCheckpointText(toolCheckpoint);
547
+ }
548
+ return "no prior checkpoint recorded";
549
+ }
550
+ function extractAssistantPreview(messages, maxLength = 120) {
551
+ const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant");
552
+ if (!lastAssistant)
553
+ return "";
554
+ const text = contentToText(lastAssistant.content);
555
+ if (!text)
556
+ return "";
557
+ /* v8 ignore next -- unreachable: contentToText().trim() guarantees a non-empty line @preserve */
558
+ const firstLine = text.split("\n").find((line) => line.trim().length > 0) ?? "";
559
+ if (firstLine.length <= maxLength)
560
+ return firstLine;
561
+ return `${firstLine.slice(0, maxLength - 3)}...`;
562
+ }
563
+ function extractToolCallNames(messages) {
564
+ const names = [];
565
+ for (const msg of messages) {
566
+ if (msg.role === "assistant" && "tool_calls" in msg && Array.isArray(msg.tool_calls)) {
567
+ for (const tc of msg.tool_calls) {
568
+ if ("function" in tc && tc.function?.name)
569
+ names.push(tc.function.name);
570
+ }
571
+ }
572
+ }
573
+ return [...new Set(names)];
574
+ }
575
+ function createPrivateRuntimeCallbacks() {
576
+ return {
577
+ settleOutputMode: "final_only",
578
+ onModelStart: () => { },
579
+ onModelStreamStart: () => { },
580
+ onTextChunk: () => { },
581
+ onReasoningChunk: () => { },
582
+ onToolStart: () => { },
583
+ onToolEnd: () => { },
584
+ onError: () => { },
585
+ };
586
+ }
587
+ function privateRuntimeSessionPath() {
588
+ return (0, config_1.sessionPath)(pending_1.PRIVATE_RUNTIME_PENDING.friendId, pending_1.PRIVATE_RUNTIME_PENDING.channel, pending_1.PRIVATE_RUNTIME_PENDING.key);
589
+ }
590
+ function privateRuntimeStatePath(sessionFilePath) {
591
+ return path.join(path.dirname(sessionFilePath), "runtime.json");
592
+ }
593
+ function writePrivateRuntimeState(sessionFilePath, state) {
594
+ const filePath = privateRuntimeStatePath(sessionFilePath);
595
+ try {
596
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
597
+ fs.writeFileSync(filePath, JSON.stringify(state, null, 2) + "\n", "utf8");
598
+ }
599
+ catch (error) {
600
+ (0, runtime_1.emitNervesEvent)({
601
+ level: "warn",
602
+ component: "senses",
603
+ event: "senses.private_runtime_state_error",
604
+ message: "failed to write private-runtime state",
605
+ meta: {
606
+ status: state.status,
607
+ reason: state.reason ?? null,
608
+ path: filePath,
609
+ /* v8 ignore next -- Node fs APIs throw Error objects for mkdirSync/writeFileSync failures @preserve */
610
+ error: error instanceof Error ? error.message : String(error),
611
+ },
612
+ });
613
+ }
614
+ }
615
+ /* v8 ignore start -- routing helpers: called from routing functions which are integration paths @preserve */
616
+ function writePendingEnvelope(pendingDir, message) {
617
+ fs.mkdirSync(pendingDir, { recursive: true });
618
+ const fileName = `${message.timestamp}-${Math.random().toString(36).slice(2, 10)}.json`;
619
+ const filePath = path.join(pendingDir, fileName);
620
+ fs.writeFileSync(filePath, JSON.stringify(message, null, 2), "utf8");
621
+ }
622
+ function sessionMatchesActivity(activity, session) {
623
+ return activity.friendId === session.friendId
624
+ && activity.channel === session.channel
625
+ && activity.key === session.key;
626
+ }
627
+ /* v8 ignore stop */
628
+ /* v8 ignore start -- routing: delivery now inline via surface tool; routing functions preserved for reuse @preserve */
629
+ function resolveBridgePreferredSession(delegatedFrom, sessionActivity) {
630
+ if (!delegatedFrom.bridgeId)
631
+ return null;
632
+ const bridge = (0, manager_1.createBridgeManager)().getBridge(delegatedFrom.bridgeId);
633
+ if (!bridge || bridge.lifecycle === "completed" || bridge.lifecycle === "cancelled") {
634
+ return null;
635
+ }
636
+ return sessionActivity.find((activity) => activity.friendId === delegatedFrom.friendId
637
+ && activity.channel !== "inner"
638
+ && bridge.attachedSessions.some((session) => sessionMatchesActivity(activity, session))) ?? null;
639
+ }
640
+ async function tryDeliverDelegatedCompletion(target, outboundEnvelope) {
641
+ if (target.channel !== "bluebubbles") {
642
+ return false;
643
+ }
644
+ const result = await (0, bluebubbles_1.sendProactiveBlueBubblesMessageToSession)({
645
+ friendId: target.friendId,
646
+ sessionKey: target.key,
647
+ text: outboundEnvelope.content,
648
+ intent: "explicit_cross_chat",
649
+ });
650
+ return result.delivered;
651
+ }
652
+ function enrichDelegatedFromWithBridge(delegatedFrom) {
653
+ if (delegatedFrom.bridgeId) {
654
+ return delegatedFrom;
655
+ }
656
+ const bridgeManager = (0, manager_1.createBridgeManager)();
657
+ const originBridges = bridgeManager.findBridgesForSession({
658
+ friendId: delegatedFrom.friendId,
659
+ channel: delegatedFrom.channel,
660
+ key: delegatedFrom.key,
661
+ });
662
+ const activeBridge = originBridges.find((b) => b.lifecycle === "active");
663
+ if (activeBridge) {
664
+ return { ...delegatedFrom, bridgeId: activeBridge.id };
665
+ }
666
+ return delegatedFrom;
667
+ }
668
+ function advanceObligationQuietly(agentName, obligationId, update) {
669
+ if (!obligationId)
670
+ return;
671
+ try {
672
+ (0, obligations_1.advanceReturnObligation)(agentName, obligationId, update);
673
+ /* v8 ignore start -- best-effort: obligation fs errors must never block return routing @preserve */
674
+ }
675
+ catch {
676
+ // swallowed
677
+ }
678
+ /* v8 ignore stop */
679
+ }
680
+ async function routeDelegatedCompletion(agentRoot, agentName, completion, drainedPending, timestamp) {
681
+ const delegated = (drainedPending ?? []).find((message) => message.delegatedFrom);
682
+ if (!delegated?.delegatedFrom || !completion?.answer?.trim()) {
683
+ return;
684
+ }
685
+ const delegatedFrom = enrichDelegatedFromWithBridge(delegated.delegatedFrom);
686
+ const obligationId = delegated.obligationId;
687
+ // Advance any private-runtime return obligations from queued -> running (they were drained this turn).
688
+ // drainedPending is guaranteed non-null here (we found delegated above).
689
+ for (const msg of drainedPending) {
690
+ if (msg.obligationId) {
691
+ advanceObligationQuietly(agentName, msg.obligationId, {
692
+ status: "running",
693
+ startedAt: timestamp,
694
+ });
695
+ }
696
+ }
697
+ if (delegated.obligationStatus === "pending") {
698
+ // Fulfill the persistent obligation in the store
699
+ try {
700
+ const pending = (0, obligations_1.findPendingObligationForOrigin)(agentRoot, {
701
+ friendId: delegatedFrom.friendId,
702
+ channel: delegatedFrom.channel,
703
+ key: delegatedFrom.key,
704
+ });
705
+ /* v8 ignore next 2 -- obligation fulfillment tested via obligations.test.ts; integration requires real disk state @preserve */
706
+ if (pending) {
707
+ (0, obligations_1.fulfillObligation)(agentRoot, pending.id);
708
+ }
709
+ }
710
+ catch {
711
+ /* v8 ignore next -- defensive: obligation store read failure should not break delivery @preserve */
712
+ }
713
+ (0, runtime_1.emitNervesEvent)({
714
+ event: "senses.obligation_fulfilled",
715
+ component: "senses",
716
+ message: "obligation fulfilled via delegated completion",
717
+ meta: {
718
+ friendId: delegatedFrom.friendId,
719
+ channel: delegatedFrom.channel,
720
+ key: delegatedFrom.key,
721
+ },
722
+ });
723
+ }
724
+ const outboundEnvelope = {
725
+ from: agentName,
726
+ friendId: delegatedFrom.friendId,
727
+ channel: delegatedFrom.channel,
728
+ key: delegatedFrom.key,
729
+ content: completion.answer.trim(),
730
+ timestamp,
731
+ delegatedFrom,
732
+ ...(obligationId ? { obligationId } : {}),
733
+ };
734
+ const sessionActivity = (0, session_activity_1.listSessionActivity)({
735
+ sessionsDir: path.join(agentRoot, "state", "sessions"),
736
+ friendsDir: path.join(agentRoot, "friends"),
737
+ agentName,
738
+ });
739
+ // Priority 1: Bridge-preferred session (if delegation was within a bridge).
740
+ const bridgeTarget = resolveBridgePreferredSession(delegatedFrom, sessionActivity);
741
+ if (bridgeTarget) {
742
+ if (await tryDeliverDelegatedCompletion(bridgeTarget, outboundEnvelope)) {
743
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "bridge-session" });
744
+ return;
745
+ }
746
+ writePendingEnvelope((0, pending_1.getPendingDir)(agentName, bridgeTarget.friendId, bridgeTarget.channel, bridgeTarget.key), outboundEnvelope);
747
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "bridge-session" });
748
+ return;
749
+ }
750
+ // Priority 1.5: Direct return to originating session (ponder without bridge).
751
+ // When delegatedFrom has specific channel+key, route directly there instead of searching for freshest.
752
+ if (delegatedFrom.channel && delegatedFrom.key && delegatedFrom.channel !== "inner") {
753
+ const directTarget = sessionActivity.find((a) => a.friendId === delegatedFrom.friendId && a.channel === delegatedFrom.channel && a.key === delegatedFrom.key);
754
+ if (directTarget) {
755
+ if (await tryDeliverDelegatedCompletion(directTarget, outboundEnvelope)) {
756
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "direct-originator" });
757
+ return;
758
+ }
759
+ }
760
+ // Even if session isn't in activity list (might have ended), queue to its pending dir
761
+ writePendingEnvelope((0, pending_1.getPendingDir)(agentName, delegatedFrom.friendId, delegatedFrom.channel, delegatedFrom.key), outboundEnvelope);
762
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "direct-originator" });
763
+ return;
764
+ }
765
+ // Priority 2: Freshest active friend session.
766
+ // For BB, prefer DM sessions (;-;) over group chats (;+;) — proactive outreach should never land in groups.
767
+ const allFriendSessions = (0, session_activity_1.listSessionActivity)({
768
+ sessionsDir: path.join(agentRoot, "state", "sessions"),
769
+ friendsDir: path.join(agentRoot, "friends"),
770
+ agentName,
771
+ }).filter((s) => s.friendId === delegatedFrom.friendId && s.channel !== "inner");
772
+ const bbDm = allFriendSessions.find((s) => s.channel === "bluebubbles" && s.key.includes(";-;"));
773
+ const freshest = bbDm ?? allFriendSessions.find((s) => s.channel !== "bluebubbles" || s.key.includes(";-;")) ?? allFriendSessions[0];
774
+ if (freshest) {
775
+ if (await tryDeliverDelegatedCompletion(freshest, outboundEnvelope)) {
776
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "freshest-session" });
777
+ return;
778
+ }
779
+ writePendingEnvelope((0, pending_1.getPendingDir)(agentName, freshest.friendId, freshest.channel, freshest.key), outboundEnvelope);
780
+ advanceObligationQuietly(agentName, obligationId, { status: "returned", returnedAt: timestamp, returnTarget: "freshest-session" });
781
+ return;
782
+ }
783
+ // Priority 3: Deferred return queue.
784
+ writePendingEnvelope((0, pending_1.getDeferredReturnDir)(agentName, delegatedFrom.friendId), outboundEnvelope);
785
+ advanceObligationQuietly(agentName, obligationId, { status: "deferred", returnedAt: timestamp, returnTarget: "deferred" });
786
+ }
787
+ /* v8 ignore stop */
788
+ // Self-referencing friend record for the private runtime (agent talking to itself).
789
+ // No real friend to resolve -- this satisfies the pipeline's friend resolver contract.
790
+ function createSelfFriend(agentName) {
791
+ return {
792
+ id: "self",
793
+ name: agentName,
794
+ trustLevel: "family",
795
+ externalIds: [],
796
+ tenantMemberships: [],
797
+ toolPreferences: {},
798
+ notes: {},
799
+ totalTokens: 0,
800
+ createdAt: new Date().toISOString(),
801
+ updatedAt: new Date().toISOString(),
802
+ schemaVersion: 1,
803
+ };
804
+ }
805
+ function buildOwnerPresentationPreferences(friend) {
806
+ const lines = [
807
+ `## ${friend.name}'s presentation preferences`,
808
+ "Use this relationship context to decide whether and how to contact the owner. It is presentation-only and grants no mutation authority.",
809
+ ];
810
+ lines.push(...(0, relationship_authorization_1.renderRelationshipPreferences)(friend));
811
+ if (lines.length === 2)
812
+ lines.push("- No presentation preferences have been learned yet; be calm, concise, and useful.");
813
+ return lines.join("\n");
814
+ }
815
+ // No-op friend store for the private runtime. It doesn't track token usage per-friend.
816
+ function createNoOpFriendStore() {
817
+ return {
818
+ get: async () => null,
819
+ put: async () => { },
820
+ delete: async () => { },
821
+ findByExternalId: async () => null,
822
+ };
823
+ }
824
+ function buildParseErrorNudge(parseErrors) {
825
+ if (parseErrors.length === 0)
826
+ return "";
827
+ const lines = parseErrors.map((e) => `I noticed my habit file \`${e.file}\` has invalid frontmatter — I should fix it. (${e.error})`);
828
+ return lines.join("\n");
829
+ }
830
+ function buildHeldReturnWakeMessage() {
831
+ return [
832
+ "held return work arrived; use the current held-work frame above as the authority for this turn.",
833
+ "Older checkpoints, rest summaries, transcript memories, completed returns, and repeated probes are historical context, not evidence about what is waiting now.",
834
+ "Return only the requested result; do not add commentary about prior attempts, old loops, or completed probes.",
835
+ "Return each listed item with surface(delegationId=...) before resting or settling.",
836
+ ].join("\n");
837
+ }
838
+ function buildExternalEventLeaseMessage(event) {
839
+ const members = [event, ...(event.relatedEvents ?? [])];
840
+ const dispositionInstruction = members.length === 1
841
+ ? "Investigate the current observation, then call external_event_disposition once for this lease before settling."
842
+ : "Investigate the current observations, then call external_event_disposition once with one bounded batch containing every listed lease before settling.";
843
+ return [
844
+ "[current external-event disposition contract]",
845
+ "This exact lease frame is authoritative for this turn. Ignore older receipts, failed tool arguments, held-work summaries, and checkpoints when choosing disposition arguments.",
846
+ dispositionInstruction,
847
+ ...members.flatMap((member, index) => [
848
+ "",
849
+ `lease ${index + 1}:`,
850
+ `recordPath: ${JSON.stringify(member.recordPath)}`,
851
+ `expectedGeneration: ${member.generation}`,
852
+ `classifiedRevision: ${JSON.stringify(member.observationRevision)}`,
853
+ ]),
854
+ ].join("\n");
855
+ }
856
+ function externalEventLeaseKey(event) {
857
+ return JSON.stringify([event.recordPath, event.generation, event.observationRevision, event.claimOwner]);
858
+ }
859
+ function buildAlsoDueLine(agentRoot, currentHabitName, now) {
860
+ const habitsDir = path.join(agentRoot, "habits");
861
+ let files;
862
+ try {
863
+ files = fs.readdirSync(habitsDir);
864
+ }
865
+ catch {
866
+ return "";
867
+ }
868
+ const nowMs = now().getTime();
869
+ const alsoDue = [];
870
+ for (const file of files) {
871
+ if (!file.endsWith(".md"))
872
+ continue;
873
+ const stem = file.replace(/\.md$/, "");
874
+ if (stem === currentHabitName)
875
+ continue;
876
+ try {
877
+ const content = fs.readFileSync(path.join(habitsDir, file), "utf-8");
878
+ const habit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(content, path.join(habitsDir, file)));
879
+ if (habit.status !== "active" || !habit.cadence)
880
+ continue;
881
+ const cadenceMs = (0, cadence_1.parseCadenceToMs)(habit.cadence);
882
+ if (cadenceMs === null)
883
+ continue;
884
+ if (habit.lastRun === null) {
885
+ alsoDue.push(stem);
886
+ continue;
887
+ }
888
+ const lastRunMs = new Date(habit.lastRun).getTime();
889
+ if (nowMs - lastRunMs >= cadenceMs) {
890
+ alsoDue.push(stem);
891
+ }
892
+ }
893
+ catch {
894
+ // skip unreadable habits
895
+ }
896
+ }
897
+ if (alsoDue.length === 0)
898
+ return "";
899
+ return `also due: ${alsoDue.join(", ")}`;
900
+ }
901
+ function buildHabitSurfacePolicy(origin, surface) {
902
+ const lines = ["## habit surface policy"];
903
+ lines.push("this habit runs privately, but it may message outward when it needs input, has a useful answer, is blocked, or should report status.");
904
+ if (surface.family)
905
+ lines.push("- family recipients are allowed by default.");
906
+ if (surface.originator && origin)
907
+ lines.push(`- the originator is allowed: ${origin.friendId} via ${origin.channel}/${origin.key}.`);
908
+ if (surface.originator && !origin)
909
+ lines.push("- originator messaging is enabled, but this habit has no origin metadata.");
910
+ if (surface.extra.length > 0)
911
+ lines.push(`- extra allowed recipients: ${surface.extra.join(", ")}.`);
912
+ lines.push("- use send_message for intentional contact; use surface only for a held return tied to an existing return obligation.");
913
+ return lines.join("\n");
914
+ }
915
+ function reduceHabitSessionToNoSend(habitSession) {
916
+ const deniedTools = new Set([
917
+ ...(habitSession?.permissionEnvelope.deniedTools ?? []),
918
+ ...(habitSession?.toolPolicy.grantedTools ?? []),
919
+ ...(habitSession?.toolPolicy.deniedTools ?? []),
920
+ "send_message",
921
+ "surface",
922
+ ]);
923
+ return {
924
+ ...habitSession,
925
+ noSend: true,
926
+ permissionEnvelope: {
927
+ schemaVersion: 1,
928
+ canMessageOutward: false,
929
+ returnRoutes: [],
930
+ deniedTools: [...deniedTools],
931
+ warnings: [...(habitSession?.permissionEnvelope.warnings ?? [])],
932
+ },
933
+ toolPolicy: {
934
+ requestedTools: habitSession?.toolPolicy.requestedTools ?? null,
935
+ grantedTools: [],
936
+ deniedTools: [...deniedTools],
937
+ outwardMessagingAllowed: false,
938
+ },
939
+ };
940
+ }
941
+ async function runPrivateRuntimeTurn(options) {
942
+ const now = options?.now ?? (() => new Date());
943
+ const reason = options?.reason ?? "instinct";
944
+ const sessionFilePath = options?.habitSession?.sessionPath ?? privateRuntimeSessionPath();
945
+ const agentName = (0, identity_1.getAgentName)();
946
+ const privateTurnDecision = assertPrivateTurnDecisionAllowed({
947
+ decision: options?.privateTurnDecision,
948
+ agentName,
949
+ options,
950
+ now,
951
+ });
952
+ if (!claimPrivateTurnExecution(privateTurnDecision, now)) {
953
+ return {
954
+ messages: [],
955
+ usage: undefined,
956
+ sessionPath: sessionFilePath,
957
+ turnOutcome: "rested",
958
+ restStatus: DUPLICATE_PRIVATE_TURN_STATUS,
959
+ };
960
+ }
961
+ writePrivateRuntimeState(sessionFilePath, {
962
+ status: "running",
963
+ reason,
964
+ startedAt: now().toISOString(),
965
+ });
966
+ const runWithLease = options?._withSessionTurnLease ?? session_transaction_1.withSessionTurnLease;
967
+ return await runWithLease(sessionFilePath, async (sessionTurnLease) => {
968
+ try {
969
+ const loaded = (0, context_1.loadSession)(sessionFilePath);
970
+ const existingMessages = loaded?.messages ? [...loaded.messages] : [];
971
+ const instincts = options?.instincts ?? loadPrivateRuntimeInstincts();
972
+ const state = {
973
+ cycleCount: 1,
974
+ resting: false,
975
+ lastHeartbeatAt: now().toISOString(),
976
+ };
977
+ const pendingDir = options?.habitSession?.pendingDir ?? (0, pending_1.getPrivateRuntimePendingDir)(agentName);
978
+ const shouldUseHeldReturnWake = !options?.taskId && reason !== "habit" && reason !== "await"
979
+ ? (0, obligations_1.listActiveReturnObligations)(agentName).length > 0
980
+ : false;
981
+ // ── Adapter concern: build user message ──────────────────────────
982
+ let userContent;
983
+ let habitTools;
984
+ let habitParsedSuccessfully = false;
985
+ let parsedAwait = null;
986
+ const isPayloadSpecificWake = !!options?.taskId
987
+ || (reason === "habit" && !!options?.habitName)
988
+ || (reason === "await" && !!options?.awaitName);
989
+ if (existingMessages.length === 0 && !isPayloadSpecificWake) {
990
+ // Fresh session: bootstrap message with non-canonical cleanup nudge
991
+ const aspirations = readAspirations((0, identity_1.getAgentRoot)());
992
+ const nonCanonical = (0, bundle_manifest_1.findNonCanonicalBundlePaths)((0, identity_1.getAgentRoot)());
993
+ const cleanupNudge = buildNonCanonicalCleanupNudge(nonCanonical);
994
+ userContent = [
995
+ buildPrivateRuntimeBootstrapMessage(aspirations, "No prior private-runtime session found."),
996
+ cleanupNudge,
997
+ ].filter(Boolean).join("\n\n");
998
+ }
999
+ else {
1000
+ // Resumed session: task-triggered or instinct message with checkpoint context
1001
+ const assistantTurns = existingMessages.filter((message) => message.role === "assistant").length;
1002
+ state.cycleCount = assistantTurns + 1;
1003
+ state.checkpoint = deriveResumeCheckpoint(existingMessages);
1004
+ if (options?.taskId) {
1005
+ const taskContent = readTaskFile((0, identity_1.getAgentRoot)(), options.taskId);
1006
+ userContent = buildTaskTriggeredMessage(options.taskId, taskContent, state.checkpoint);
1007
+ }
1008
+ else if (reason === "habit" && options?.habitName) {
1009
+ const agentRoot = (0, identity_1.getAgentRoot)();
1010
+ const habitName = options.habitName;
1011
+ const habitFilePath = path.join(agentRoot, "habits", `${habitName}.md`);
1012
+ const preparedHabit = options.preparedHabit?.habit.name === habitName ? options.preparedHabit.habit : null;
1013
+ const rsvpHabit = (0, habit_policy_1.isRsvpHabitName)(habitName);
1014
+ // Read and parse the habit file
1015
+ let habitBody;
1016
+ let habitTitle = habitName;
1017
+ let habitLastRun = null;
1018
+ let habitOrigin = null;
1019
+ let habitSurface = { family: true, originator: true, extra: [] };
1020
+ if (preparedHabit) {
1021
+ if (rsvpHabit && !preparedHabit.rsvp) {
1022
+ const detail = preparedHabit.status === "degraded"
1023
+ ? preparedHabit.degradedDetail
1024
+ : null;
1025
+ throw new Error(`RSVP habit metadata is required before private runtime execution: ${detail ?? habitName}`);
1026
+ }
1027
+ const blockedReason = (0, habit_lifecycle_guard_1.privateRuntimeHabitRejectionReason)(preparedHabit, "private-runtime");
1028
+ if (blockedReason)
1029
+ throw new Error(blockedReason);
1030
+ }
1031
+ let currentHabit;
1032
+ try {
1033
+ const habitContent = fs.readFileSync(habitFilePath, "utf-8");
1034
+ currentHabit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(habitContent, habitFilePath));
1035
+ }
1036
+ catch (error) {
1037
+ const readReason = error instanceof Error ? error.message : String(error);
1038
+ if (rsvpHabit) {
1039
+ throw new Error(`RSVP habit metadata is required before private runtime execution: ${readReason}`);
1040
+ }
1041
+ const degraded = (0, habit_parser_1.createDegradedHabitFile)(habitFilePath, "read_error", "", readReason);
1042
+ const blockedReason = (0, habit_lifecycle_guard_1.privateRuntimeHabitRejectionReason)(degraded, "private-runtime");
1043
+ throw new Error(blockedReason);
1044
+ }
1045
+ if (rsvpHabit && !currentHabit.rsvp) {
1046
+ const detail = currentHabit.status === "degraded" ? currentHabit.degradedDetail : null;
1047
+ throw new Error(`RSVP habit metadata is required before private runtime execution: ${detail ?? habitName}`);
1048
+ }
1049
+ const currentBlockedReason = (0, habit_lifecycle_guard_1.privateRuntimeHabitRejectionReason)(currentHabit, "private-runtime");
1050
+ if (currentBlockedReason)
1051
+ throw new Error(currentBlockedReason);
1052
+ const executableHabit = preparedHabit ?? currentHabit;
1053
+ habitBody = executableHabit.body || undefined;
1054
+ habitTitle = executableHabit.title || habitName;
1055
+ habitLastRun = executableHabit.lastRun;
1056
+ habitTools = executableHabit.tools;
1057
+ habitOrigin = executableHabit.origin;
1058
+ habitSurface = executableHabit.surface;
1059
+ // If the habit file couldn't be read at all (no body, no title parsed), error message
1060
+ if (habitBody === undefined && habitTitle === habitName) {
1061
+ userContent = `habit "${habitName}" could not be read (file not found or unreadable). check habits/${habitName}.md exists.`;
1062
+ }
1063
+ else {
1064
+ habitParsedSuccessfully = true;
1065
+ // Unified path: gather context for ALL habits (heartbeat included)
1066
+ const obligations = (0, obligations_1.listActiveReturnObligations)(agentName);
1067
+ const nowMs = now().getTime();
1068
+ const staleObligations = obligations.map((o) => ({
1069
+ friendName: o.origin.friendId,
1070
+ content: o.delegatedContent,
1071
+ stalenessMs: nowMs - o.createdAt,
1072
+ }));
1073
+ const alsoDue = buildAlsoDueLine(agentRoot, habitName, now);
1074
+ const arcResume = (0, flight_recorder_1.formatFlightRecorderResume)((0, flight_recorder_1.readFlightRecorderResume)(agentRoot));
1075
+ const deskOrientation = (0, desk_section_1.deskRecordOrientationSection)(agentRoot, now());
1076
+ const surfacePolicy = buildHabitSurfacePolicy(habitOrigin, habitSurface);
1077
+ // Degraded state (best-effort: never crash)
1078
+ let degradedComponents = [];
1079
+ try {
1080
+ const health = (0, daemon_health_1.readHealth)((0, daemon_health_1.getDefaultHealthPath)());
1081
+ if (health && health.degraded.length > 0) {
1082
+ degradedComponents = health.degraded.map((d) => ({ component: d.component, reason: d.reason }));
1083
+ }
1084
+ }
1085
+ catch {
1086
+ // Best-effort: missing file or parse error -> empty array, no crash
1087
+ }
1088
+ userContent = (0, habit_turn_message_1.buildHabitTurnMessage)({
1089
+ habitName,
1090
+ habitTitle,
1091
+ habitBody,
1092
+ lastRun: habitLastRun,
1093
+ checkpoint: displayCheckpoint(state.checkpoint),
1094
+ alsoDue: alsoDue || undefined,
1095
+ staleObligations,
1096
+ parseErrors: options?.parseErrors ?? [],
1097
+ degradedComponents,
1098
+ arcResume,
1099
+ deskOrientation,
1100
+ surfacePolicy,
1101
+ priorSessionSummary: options.preparedHabit?.habit.name === habitName ? options.preparedHabit.priorSessionSummary : undefined,
1102
+ now,
1103
+ });
1104
+ }
1105
+ }
1106
+ else if (reason === "await" && options?.awaitName) {
1107
+ const agentRoot = (0, identity_1.getAgentRoot)();
1108
+ const awaitName = options.awaitName;
1109
+ const awaitFilePath = path.join(agentRoot, "awaiting", `${awaitName}.md`);
1110
+ let awaitBody;
1111
+ let condition = null;
1112
+ let lastCheckedAt = null;
1113
+ let lastObservation = null;
1114
+ let checkedCount = 0;
1115
+ let awaitFound = false;
1116
+ try {
1117
+ const awaitContent = fs.readFileSync(awaitFilePath, "utf-8");
1118
+ const parsed = (0, await_runtime_state_1.applyAwaitRuntimeState)(agentRoot, (0, await_parser_1.parseAwaitFile)(awaitContent, awaitFilePath));
1119
+ parsedAwait = parsed;
1120
+ awaitFound = true;
1121
+ awaitBody = parsed.body || undefined;
1122
+ condition = parsed.condition;
1123
+ lastCheckedAt = parsed.last_checked ?? null;
1124
+ lastObservation = parsed.last_observation ?? null;
1125
+ checkedCount = parsed.checked_count ?? 0;
1126
+ }
1127
+ catch {
1128
+ // file missing — fall through to error message
1129
+ }
1130
+ if (!awaitFound || !condition) {
1131
+ userContent = `await "${awaitName}" could not be read (file not found or no condition). check awaiting/${awaitName}.md.`;
1132
+ }
1133
+ else {
1134
+ userContent = (0, await_turn_message_1.buildAwaitTurnMessage)({
1135
+ awaitName,
1136
+ condition,
1137
+ body: awaitBody,
1138
+ lastCheckedAt,
1139
+ lastObservation,
1140
+ checkedCount,
1141
+ checkpoint: displayCheckpoint(state.checkpoint),
1142
+ now,
1143
+ });
1144
+ }
1145
+ }
1146
+ else {
1147
+ userContent = buildInstinctUserMessage(instincts, reason, state);
1148
+ }
1149
+ }
1150
+ if (options?.externalEvent) {
1151
+ userContent = buildExternalEventLeaseMessage(options.externalEvent);
1152
+ }
1153
+ else if (shouldUseHeldReturnWake) {
1154
+ userContent = buildHeldReturnWakeMessage();
1155
+ }
1156
+ // ── Session loader: wraps existing session logic ──────────────────
1157
+ const innerCapabilities = (0, friends_1.getChannelCapabilities)("inner");
1158
+ const selfFriend = createSelfFriend(agentName);
1159
+ const selfContext = { friend: selfFriend, channel: innerCapabilities };
1160
+ const mcpOwner = { agentName, agentRoot: (0, identity_1.getAgentRoot)(agentName) };
1161
+ const mcpManager = await (0, mcp_manager_1.getSharedMcpManager)(mcpOwner) ?? undefined;
1162
+ const relationshipAwaitCoordinatesValue = parsedAwait ? relationshipAwaitCoordinates(parsedAwait) : null;
1163
+ const relationshipAwait = relationshipAwaitCoordinatesValue
1164
+ ? await (async () => {
1165
+ const agentRoot = (0, identity_1.getAgentRoot)(agentName);
1166
+ const assertLiveBinding = () => {
1167
+ const binding = relationshipAwaitCoordinatesValue.channel === "external-event"
1168
+ ? parsedAwait.wake_at && (0, tools_awaiting_1.hasActiveExternalEventAwait)(agentName, { recordPath: relationshipAwaitCoordinatesValue.key, awaitName: parsedAwait.name, wakeAt: parsedAwait.wake_at })
1169
+ ? { active: true }
1170
+ : { active: false, reason: "external event disposition is no longer active" }
1171
+ : (0, tools_awaiting_1.inspectRelationshipFollowUp)(agentRoot, {
1172
+ friendId: relationshipAwaitCoordinatesValue.friendId,
1173
+ channel: relationshipAwaitCoordinatesValue.channel,
1174
+ key: relationshipAwaitCoordinatesValue.key,
1175
+ requestId: relationshipAwaitCoordinatesValue.requestId,
1176
+ awaitName: parsedAwait.name,
1177
+ now: now().getTime(),
1178
+ });
1179
+ if (!binding.active) {
1180
+ (0, tools_awaiting_1.cancelStaleAwait)(agentRoot, agentName, parsedAwait.name, binding.reason);
1181
+ throw new Error(`Relationship await authority binding is missing, stale, or ambiguous: ${binding.reason}`);
1182
+ }
1183
+ };
1184
+ assertLiveBinding();
1185
+ const store = new friends_1.FileFriendStore(path.join(agentRoot, "friends"));
1186
+ const resolve = () => resolveRelationshipAwaitAuthority(agentRoot, store, (0, relationship_authorization_2.loadRelationshipCapabilityRegistry)(agentRoot), relationshipAwaitCoordinatesValue);
1187
+ const resolveOrCancel = async () => {
1188
+ try {
1189
+ return await resolve();
1190
+ }
1191
+ catch (error) {
1192
+ if (error instanceof StaleRelationshipAwaitError)
1193
+ (0, tools_awaiting_1.cancelStaleAwait)(agentRoot, agentName, parsedAwait.name, error.reason);
1194
+ throw error;
1195
+ }
1196
+ };
1197
+ const initial = await resolveOrCancel();
1198
+ return {
1199
+ store,
1200
+ context: { friend: initial.friend, channel: innerCapabilities },
1201
+ currentSession: {
1202
+ friendId: relationshipAwaitCoordinatesValue.friendId,
1203
+ channel: relationshipAwaitCoordinatesValue.channel,
1204
+ key: relationshipAwaitCoordinatesValue.key,
1205
+ sessionPath: relationshipAwaitCoordinatesValue.channel === "telegram"
1206
+ ? (0, shared_turn_1.getSenseSessionPath)(agentName, relationshipAwaitCoordinatesValue.friendId, "telegram", relationshipAwaitCoordinatesValue.key, agentRoot)
1207
+ : sessionFilePath,
1208
+ },
1209
+ relationshipAuthorization: {
1210
+ ...(relationshipAwaitCoordinatesValue.requestId ? { requestId: relationshipAwaitCoordinatesValue.requestId } : {}),
1211
+ profileId: initial.authorization.profileId,
1212
+ authorizedContextScopes: initial.authorization.authorizedContextScopes,
1213
+ advertisedToolNames: relationshipAwaitCoordinatesValue.channel === "external-event" ? ["resolve_await"] : initial.authorization.advertisedToolNames,
1214
+ authorizeTool: async (name, args) => {
1215
+ assertLiveBinding();
1216
+ const decision = (await resolveOrCancel()).authorization.authorizeTool(name, args);
1217
+ return relationshipAwaitCoordinatesValue.channel !== "external-event" || name === "resolve_await"
1218
+ ? decision
1219
+ : { ...decision, allowed: false, reason: "external event await wake is resolve-only" };
1220
+ },
1221
+ },
1222
+ };
1223
+ })()
1224
+ : undefined;
1225
+ const committedExternalEventLeases = new Set();
1226
+ const externalEventRelationship = options?.externalEvent
1227
+ ? await (async () => {
1228
+ const agentRoot = (0, identity_1.getAgentRoot)(agentName);
1229
+ const store = new friends_1.FileFriendStore(path.join(agentRoot, "friends"));
1230
+ const registry = (0, relationship_authorization_2.loadRelationshipCapabilityRegistry)(agentRoot);
1231
+ const resolve = () => (0, relationship_authorization_2.resolveProfileScopedRelationshipAuthorization)({
1232
+ store,
1233
+ registry,
1234
+ relationshipProfileId: "sanctuary-owner",
1235
+ profileId: "sanctuary-event",
1236
+ });
1237
+ const initial = await resolve();
1238
+ const initialDisposition = initial.authorizeTool("external_event_disposition");
1239
+ if (!initialDisposition.allowed)
1240
+ throw new Error(`external event relationship authority denied: ${initialDisposition.reason}`);
1241
+ const owners = (await store.listAll()).filter((friend) => friend.capabilityProfileId === "sanctuary-owner");
1242
+ const [owner] = owners;
1243
+ if (owners.length !== 1 || !owner)
1244
+ throw new Error("external event owner presentation context must resolve to exactly one Friend");
1245
+ return {
1246
+ store,
1247
+ context: { friend: owner, channel: innerCapabilities },
1248
+ ownerPresentationPreferences: buildOwnerPresentationPreferences(owner),
1249
+ relationshipAuthorization: {
1250
+ profileId: initial.profileId,
1251
+ authorizedContextScopes: initial.authorizedContextScopes,
1252
+ advertisedToolNames: initial.advertisedToolNames,
1253
+ authorizeTool: async (name) => (await resolve()).authorizeTool(name),
1254
+ },
1255
+ externalEventAuthority: {
1256
+ authorizeDisposition: () => {
1257
+ const decision = initial.authorizeTool("external_event_disposition");
1258
+ return decision.allowed ? { allowed: true, reason: "relationship-authorized" } : { allowed: false, reason: decision.reason };
1259
+ },
1260
+ recordCommittedDisposition: (event) => {
1261
+ committedExternalEventLeases.add(externalEventLeaseKey(event));
1262
+ },
1263
+ },
1264
+ externalEventEffects: {
1265
+ deliverOwnerDecision: async (input) => {
1266
+ const { sendTelegramExternalEventDecision } = await Promise.resolve().then(() => __importStar(require("./telegram")));
1267
+ await sendTelegramExternalEventDecision(agentName, input);
1268
+ },
1269
+ },
1270
+ };
1271
+ })()
1272
+ : undefined;
1273
+ if (externalEventRelationship)
1274
+ userContent = `${userContent}\n\n${externalEventRelationship.ownerPresentationPreferences}`;
1275
+ const userMessage = { role: "user", content: userContent };
1276
+ // ── Habit tool enforcement ───────────────────────────────────────
1277
+ let habitToolsResolved;
1278
+ if (habitTools !== undefined) {
1279
+ const fullTools = (0, tools_1.getToolsForChannel)(innerCapabilities);
1280
+ habitToolsResolved = fullTools.filter((t) => habitTools.includes(t.function.name));
1281
+ (0, runtime_1.emitNervesEvent)({
1282
+ event: "habit.tools_restricted",
1283
+ component: "senses",
1284
+ message: "habit running with restricted tools",
1285
+ meta: {
1286
+ habitName: options?.habitName,
1287
+ declared: habitTools,
1288
+ resolved: habitToolsResolved.map((t) => t.function.name),
1289
+ },
1290
+ });
1291
+ }
1292
+ else if (reason === "habit" && options?.habitName && habitParsedSuccessfully) {
1293
+ (0, runtime_1.emitNervesEvent)({
1294
+ event: "habit.tools_unrestricted",
1295
+ component: "senses",
1296
+ message: "habit running with full tool repertoire",
1297
+ meta: { habitName: options.habitName },
1298
+ });
1299
+ }
1300
+ if (options?.noSend === true) {
1301
+ habitToolsResolved = [];
1302
+ }
1303
+ const externalEventExcludedTools = new Set(["rest", "settle", "speak"]);
1304
+ const externalEventToolsResolved = options?.externalEvent
1305
+ ? (0, tools_1.getToolsForChannel)(innerCapabilities, undefined, undefined, undefined, undefined, undefined, {
1306
+ agentName, relationshipAuthorization: externalEventRelationship.relationshipAuthorization,
1307
+ })
1308
+ .filter((tool) => !externalEventExcludedTools.has(tool.function.name))
1309
+ : undefined;
1310
+ const relationshipAwaitToolsResolved = relationshipAwait
1311
+ ? (0, tools_1.getToolsForChannel)(innerCapabilities, undefined, undefined, undefined, undefined, undefined, {
1312
+ agentName, relationshipAuthorization: relationshipAwait.relationshipAuthorization,
1313
+ })
1314
+ : undefined;
1315
+ const effectiveHabitSession = options?.noSend === true
1316
+ ? reduceHabitSessionToNoSend(options.habitSession)
1317
+ : options?.habitSession;
1318
+ const sessionLoader = {
1319
+ loadOrCreate: async () => {
1320
+ if (existingMessages.length > 0) {
1321
+ return {
1322
+ messages: existingMessages,
1323
+ sessionPath: sessionFilePath,
1324
+ structuredOutputs: loaded?.structuredOutputs,
1325
+ };
1326
+ }
1327
+ // Fresh session: build system prompt
1328
+ const systemPrompt = await (0, prompt_1.buildSystem)("inner", {
1329
+ toolChoiceRequired: true,
1330
+ flightRecorderResume: (0, flight_recorder_1.readFlightRecorderResume)((0, identity_1.getAgentRoot)()),
1331
+ });
1332
+ return {
1333
+ messages: [{ role: "system", content: (0, prompt_1.flattenSystemPrompt)(systemPrompt) }],
1334
+ sessionPath: sessionFilePath,
1335
+ structuredOutputs: [],
1336
+ };
1337
+ },
1338
+ };
1339
+ // ── Call shared pipeline ──────────────────────────────────────────
1340
+ const callbacks = createPrivateRuntimeCallbacks();
1341
+ const traceId = (0, nerves_1.createTraceId)();
1342
+ // Attention queue: built when pending messages are drained, shared with tool context
1343
+ let attentionQueue = [];
1344
+ const externalRunStartedAt = now().toISOString();
1345
+ const externalRunBase = options?.externalEvent ? {
1346
+ agent: agentName,
1347
+ triggerType: "inbound",
1348
+ sourceKind: "private-runtime",
1349
+ senseOrHabit: "external-event",
1350
+ target: { source: options.externalEvent.source, eventId: options.externalEvent.eventId, generation: options.externalEvent.generation, observationRevision: options.externalEvent.observationRevision },
1351
+ idempotencyScope: { recordPath: options.externalEvent.recordPath, generation: options.externalEvent.generation, observationRevision: options.externalEvent.observationRevision },
1352
+ startedAt: externalRunStartedAt,
1353
+ } : null;
1354
+ if (externalRunBase)
1355
+ (0, run_ledger_1.appendRunLedgerRecordNonFatal)((0, identity_1.getAgentRoot)(agentName), (0, run_ledger_1.createRunLedgerRecord)({ ...externalRunBase, lifecycle: "started" }));
1356
+ let result;
1357
+ try {
1358
+ result = await (0, pipeline_1.handleInboundTurn)({
1359
+ channel: "inner",
1360
+ sessionKey: "dialog",
1361
+ capabilities: innerCapabilities,
1362
+ messages: [userMessage],
1363
+ continuityIngressTexts: [],
1364
+ callbacks,
1365
+ sessionTurnLease,
1366
+ friendResolver: { resolve: () => Promise.resolve(selfContext) },
1367
+ sessionLoader,
1368
+ pendingDir,
1369
+ friendStore: createNoOpFriendStore(),
1370
+ enforceTrustGate: trust_gate_1.enforceTrustGate,
1371
+ drainPending: pending_1.drainPending,
1372
+ runAgent: core_1.runAgent,
1373
+ postTurn: (turnMessages, sessionPathArg, usage, hooks, state) => {
1374
+ const prepared = (0, context_1.postTurnTrim)(turnMessages, usage, hooks);
1375
+ return (0, context_1.deferPostTurnPersist)(sessionPathArg, prepared, usage, state);
1376
+ },
1377
+ accumulateFriendTokens: friends_1.accumulateFriendTokens,
1378
+ signal: options?.signal,
1379
+ /* v8 ignore start -- attention queue: callback invoked by pipeline during pending drain; tested via attention-queue unit tests @preserve */
1380
+ onPendingDrained: (drained) => {
1381
+ const outstandingObligations = (0, obligations_1.listActiveReturnObligations)(agentName);
1382
+ const builtAttentionQueue = (0, attention_queue_1.buildAttentionQueue)({
1383
+ drainedPending: drained,
1384
+ outstandingObligations,
1385
+ friendNameResolver: (friendId) => {
1386
+ try {
1387
+ const raw = fs.readFileSync(path.join((0, identity_1.getAgentRoot)(agentName), "friends", friendId + ".json"), "utf-8");
1388
+ const parsed = JSON.parse(raw);
1389
+ return typeof parsed.name === "string" ? parsed.name : null;
1390
+ }
1391
+ catch {
1392
+ return null;
1393
+ }
1394
+ },
1395
+ packetResolver: (packetId) => {
1396
+ try {
1397
+ return (0, packets_1.readPonderPacket)((0, identity_1.getAgentRoot)(agentName), packetId);
1398
+ }
1399
+ catch {
1400
+ return null;
1401
+ }
1402
+ },
1403
+ });
1404
+ attentionQueue.splice(0, attentionQueue.length, ...builtAttentionQueue);
1405
+ const attentionFrame = (0, attention_queue_1.buildAttentionQueueStatusFrame)(attentionQueue);
1406
+ return attentionFrame ? [attentionFrame] : [];
1407
+ },
1408
+ /* v8 ignore stop */
1409
+ runAgentOptions: {
1410
+ traceId,
1411
+ toolChoiceRequired: true,
1412
+ mcpManager,
1413
+ ...(options?.externalEvent
1414
+ ? { tools: externalEventToolsResolved }
1415
+ : relationshipAwaitToolsResolved !== undefined ? { tools: relationshipAwaitToolsResolved }
1416
+ : habitToolsResolved !== undefined ? { tools: habitToolsResolved } : {}),
1417
+ toolContext: {
1418
+ signin: async () => undefined,
1419
+ delegatedOrigins: attentionQueue,
1420
+ ...(relationshipAwait ? {
1421
+ friendStore: relationshipAwait.store,
1422
+ context: relationshipAwait.context,
1423
+ currentSession: relationshipAwait.currentSession,
1424
+ relationshipAuthorization: relationshipAwait.relationshipAuthorization,
1425
+ } : {}),
1426
+ ...(options?.externalEvent ? {
1427
+ currentExternalEvent: Object.freeze({ ...options.externalEvent }),
1428
+ friendStore: externalEventRelationship.store,
1429
+ context: externalEventRelationship.context,
1430
+ relationshipAuthorization: externalEventRelationship.relationshipAuthorization,
1431
+ externalEventAuthority: externalEventRelationship.externalEventAuthority,
1432
+ externalEventEffects: externalEventRelationship.externalEventEffects,
1433
+ ...(["sanctuary-health", "sanctuary-usenet"].includes(options.externalEvent.source) ? (0, sanctuary_runtime_1.createSanctuaryToolContext)(agentName) : {}),
1434
+ } : {}),
1435
+ ...(options?.noSend ? { noSend: true } : {}),
1436
+ ...(effectiveHabitSession ? { habitSession: effectiveHabitSession } : {}),
1437
+ ...mcpOwner,
1438
+ },
1439
+ ...(effectiveHabitSession ? { habitSession: effectiveHabitSession } : {}),
1440
+ },
1441
+ });
1442
+ if (options?.externalEvent && ["settled", "observed", "rested"].includes(String(result.turnOutcome))) {
1443
+ const incomplete = [options.externalEvent, ...(options.externalEvent.relatedEvents ?? [])]
1444
+ .filter((event) => !committedExternalEventLeases.has(externalEventLeaseKey(event)));
1445
+ if (incomplete.length > 0) {
1446
+ throw new Error(`External-event turn did not commit dispositions for every exact lease (${incomplete.length} incomplete)`);
1447
+ }
1448
+ }
1449
+ if (externalRunBase) {
1450
+ const lifecycle = result.turnOutcome === "settled" || result.turnOutcome === "observed" || result.turnOutcome === "rested"
1451
+ ? "completed"
1452
+ : result.turnOutcome === "errored" ? "error"
1453
+ : result.turnOutcome === "blocked" || result.turnOutcome === "suspended" ? "blocked"
1454
+ : "skipped";
1455
+ (0, run_ledger_1.appendRunLedgerRecordNonFatal)((0, identity_1.getAgentRoot)(agentName), (0, run_ledger_1.createRunLedgerRecord)({ ...externalRunBase, lifecycle, endedAt: now().toISOString(), usage: (0, run_ledger_1.usageMetadataFromUsageData)(result.usage, result.usage ? "provider" : "reported-unavailable"), ...(result.turnOutcome === "errored" ? { errorName: "AgentTurnError" } : {}) }));
1456
+ }
1457
+ }
1458
+ catch (error) {
1459
+ if (externalRunBase)
1460
+ (0, run_ledger_1.appendRunLedgerRecordNonFatal)((0, identity_1.getAgentRoot)(agentName), (0, run_ledger_1.createRunLedgerRecord)({ ...externalRunBase, lifecycle: "error", endedAt: now().toISOString(), errorName: error instanceof Error ? error.name : "UnknownError" }));
1461
+ throw error;
1462
+ }
1463
+ // Post-turn routeDelegatedCompletion removed: delivery is now inline via surface tool.
1464
+ // settle in the private runtime produces no CompletionMetadata, so routeDelegatedCompletion
1465
+ // would be a no-op. The routing infrastructure is reused by the surface handler.
1466
+ const resultMessages = result.messages ?? [];
1467
+ const assistantPreview = extractAssistantPreview(resultMessages);
1468
+ const toolCalls = extractToolCallNames(resultMessages);
1469
+ (0, runtime_1.emitNervesEvent)({
1470
+ component: "senses",
1471
+ event: "senses.private_runtime_turn",
1472
+ message: "private-runtime turn completed",
1473
+ meta: {
1474
+ reason,
1475
+ session: sessionFilePath,
1476
+ ...(options?.taskId && { taskId: options.taskId }),
1477
+ ...(assistantPreview && { assistantPreview }),
1478
+ ...(toolCalls.length > 0 && { toolCalls }),
1479
+ ...(result.usage && {
1480
+ promptTokens: result.usage.input_tokens,
1481
+ completionTokens: result.usage.output_tokens,
1482
+ totalTokens: result.usage.total_tokens,
1483
+ }),
1484
+ },
1485
+ });
1486
+ return {
1487
+ messages: resultMessages,
1488
+ usage: result.usage,
1489
+ sessionPath: result.sessionPath ?? sessionFilePath,
1490
+ completion: result.completion,
1491
+ turnOutcome: result.turnOutcome,
1492
+ restStatus: latestRestStatus(resultMessages),
1493
+ };
1494
+ }
1495
+ finally {
1496
+ writePrivateRuntimeState(sessionFilePath, {
1497
+ status: "idle",
1498
+ lastCompletedAt: now().toISOString(),
1499
+ });
1500
+ }
1501
+ });
1502
+ }