@ouro.bot/cli 0.1.0-alpha.83 → 0.1.0-alpha.831

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 (647) 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/assets/sanctuary-host-launcher.sh +16 -0
  15. package/changelog.json +5308 -16
  16. package/deploy/unraid/Dockerfile +54 -0
  17. package/deploy/unraid/README.txt +2983 -0
  18. package/deploy/unraid/audit-container-spec.sh +4 -0
  19. package/deploy/unraid/container-runtime.json +1 -0
  20. package/deploy/unraid/docker-man-template-transaction.mjs +711 -0
  21. package/deploy/unraid/docker-man-template-xml.cjs +105 -0
  22. package/deploy/unraid/migrate-sanctuary-bundle.mjs +60 -0
  23. package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
  24. package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
  25. package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
  26. package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
  27. package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
  28. package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
  29. package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
  30. package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
  31. package/deploy/unraid/sanctuary-authority-installation.json +36 -0
  32. package/deploy/unraid/sanctuary-authority-service.sh +30 -0
  33. package/deploy/unraid/sanctuary-deployment-target.mjs +710 -0
  34. package/deploy/unraid/sanctuary-safe-rename.py +24 -0
  35. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2084 -0
  36. package/deploy/unraid/sanctuary-unit16-run.sh +560 -0
  37. package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
  38. package/deploy/unraid/sanctuary.ouro/agent.json +66 -0
  39. package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
  40. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
  41. package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
  42. package/deploy/unraid/sanctuary.ouro/mcp/media-mcp.mjs +795 -0
  43. package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
  44. package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
  45. package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +5 -0
  46. package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +15 -0
  47. package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +25 -0
  48. package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +15 -0
  49. package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
  50. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +135 -0
  51. package/deploy/unraid/sanctuary.xml +28 -0
  52. package/dist/a2a/card.js +57 -0
  53. package/dist/a2a/client.js +180 -0
  54. package/dist/a2a/config.js +50 -0
  55. package/dist/a2a/delegation-stores.js +56 -0
  56. package/dist/a2a/did-resolution.js +93 -0
  57. package/dist/a2a/identity.js +170 -0
  58. package/dist/a2a/inbound-share.js +107 -0
  59. package/dist/a2a/mission-result-wire.js +196 -0
  60. package/dist/a2a/onboarding.js +115 -0
  61. package/dist/a2a/pin-store.js +132 -0
  62. package/dist/a2a/seen-ledger.js +120 -0
  63. package/dist/a2a/server.js +604 -0
  64. package/dist/a2a/task-store.js +69 -0
  65. package/dist/a2a/transport.js +45 -0
  66. package/dist/a2a/types.js +3 -0
  67. package/dist/arc/attention-types.js +8 -0
  68. package/dist/arc/cares.js +360 -0
  69. package/dist/arc/episodes.js +118 -0
  70. package/dist/arc/evolution.js +490 -0
  71. package/dist/arc/flight-recorder.js +1034 -0
  72. package/dist/arc/intentions.js +134 -0
  73. package/dist/arc/json-store.js +117 -0
  74. package/dist/arc/obligations.js +386 -0
  75. package/dist/arc/packets.js +336 -0
  76. package/dist/arc/presence.js +185 -0
  77. package/dist/arc/task-lifecycle.js +57 -0
  78. package/dist/commerce/store.js +755 -0
  79. package/dist/commerce/types.js +3 -0
  80. package/dist/heart/active-work.js +798 -40
  81. package/dist/heart/agent-entry.js +252 -3
  82. package/dist/heart/approval-files.js +113 -0
  83. package/dist/heart/approval-store.js +960 -0
  84. package/dist/heart/attachments/image-normalize.js +194 -0
  85. package/dist/heart/attachments/materialize.js +97 -0
  86. package/dist/heart/attachments/originals.js +88 -0
  87. package/dist/heart/attachments/render.js +29 -0
  88. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  89. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  90. package/dist/heart/attachments/sources/index.js +18 -0
  91. package/dist/heart/attachments/sources/telegram.js +71 -0
  92. package/dist/heart/attachments/store.js +132 -0
  93. package/dist/heart/attachments/types.js +93 -0
  94. package/dist/heart/auth/auth-flow.js +495 -0
  95. package/dist/heart/autonomy-budget.js +478 -0
  96. package/dist/heart/awaiting/await-alert.js +148 -0
  97. package/dist/heart/awaiting/await-expiry.js +143 -0
  98. package/dist/heart/awaiting/await-loader.js +91 -0
  99. package/dist/heart/awaiting/await-parser.js +149 -0
  100. package/dist/heart/awaiting/await-runtime-state.js +111 -0
  101. package/dist/heart/awaiting/await-scheduler.js +382 -0
  102. package/dist/heart/background-operations.js +281 -0
  103. package/dist/heart/bridges/manager.js +137 -17
  104. package/dist/heart/bridges/store.js +14 -2
  105. package/dist/heart/bundle-state.js +168 -0
  106. package/dist/heart/commitments.js +44 -18
  107. package/dist/heart/config-registry.js +331 -0
  108. package/dist/heart/config.js +174 -131
  109. package/dist/heart/context-loss-gauntlet.js +387 -0
  110. package/dist/heart/context-loss-sentinel.js +1157 -0
  111. package/dist/heart/core.js +2169 -581
  112. package/dist/heart/cross-chat-delivery.js +9 -22
  113. package/dist/heart/daemon/agent-config-check.js +451 -0
  114. package/dist/heart/daemon/agent-discovery.js +185 -3
  115. package/dist/heart/daemon/agent-service.js +542 -0
  116. package/dist/heart/daemon/agentic-repair.js +547 -0
  117. package/dist/heart/daemon/await-private-wake.js +59 -0
  118. package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
  119. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  120. package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
  121. package/dist/heart/daemon/bluebubbles-host.js +273 -0
  122. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  123. package/dist/heart/daemon/cadence.js +180 -0
  124. package/dist/heart/daemon/cli-defaults.js +854 -0
  125. package/dist/heart/daemon/cli-desk.js +322 -0
  126. package/dist/heart/daemon/cli-exec.js +8822 -0
  127. package/dist/heart/daemon/cli-help.js +716 -0
  128. package/dist/heart/daemon/cli-parse.js +2771 -0
  129. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  130. package/dist/heart/daemon/cli-render.js +777 -0
  131. package/dist/heart/daemon/cli-types.js +8 -0
  132. package/dist/heart/daemon/connect-bay.js +323 -0
  133. package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
  134. package/dist/heart/daemon/container-healthcheck.js +112 -0
  135. package/dist/heart/daemon/container-runtime.js +97 -0
  136. package/dist/heart/daemon/container-spec-auditor-main.js +171 -0
  137. package/dist/heart/daemon/container-spec-auditor.js +229 -0
  138. package/dist/heart/daemon/daemon-bootstrap-startup.js +115 -0
  139. package/dist/heart/daemon/daemon-cli.js +29 -2349
  140. package/dist/heart/daemon/daemon-entry.js +930 -11
  141. package/dist/heart/daemon/daemon-health.js +186 -0
  142. package/dist/heart/daemon/daemon-rollup.js +57 -0
  143. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  144. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  145. package/dist/heart/daemon/daemon.js +2084 -105
  146. package/dist/heart/daemon/dns-workflow.js +394 -0
  147. package/dist/heart/daemon/doctor-types.js +8 -0
  148. package/dist/heart/daemon/doctor.js +1755 -0
  149. package/dist/heart/daemon/freshness.js +345 -0
  150. package/dist/heart/daemon/habit-private-wake.js +61 -0
  151. package/dist/heart/daemon/health-monitor.js +142 -11
  152. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  153. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  154. package/dist/heart/daemon/http-health-probe.js +80 -0
  155. package/dist/heart/daemon/human-command-screens.js +234 -0
  156. package/dist/heart/daemon/human-readiness.js +114 -0
  157. package/dist/heart/daemon/inner-status.js +78 -0
  158. package/dist/heart/daemon/interactive-repair.js +394 -0
  159. package/dist/heart/daemon/launchd.js +37 -8
  160. package/dist/heart/daemon/log-tailer.js +79 -10
  161. package/dist/heart/daemon/logs-prune.js +132 -0
  162. package/dist/heart/daemon/mcp-canary.js +524 -0
  163. package/dist/heart/daemon/message-router.js +65 -5
  164. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  165. package/dist/heart/daemon/os-cron-deps.js +135 -0
  166. package/dist/heart/daemon/os-cron.js +22 -14
  167. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  168. package/dist/heart/daemon/ouro-entry.js +3 -1
  169. package/dist/heart/daemon/plugin-cli.js +432 -0
  170. package/dist/heart/daemon/process-manager.js +733 -61
  171. package/dist/heart/daemon/provider-discovery.js +137 -0
  172. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  173. package/dist/heart/daemon/prunable-bundle.js +144 -0
  174. package/dist/heart/daemon/pulse.js +511 -0
  175. package/dist/heart/daemon/readiness-repair.js +365 -0
  176. package/dist/heart/daemon/run-hooks.js +2 -0
  177. package/dist/heart/daemon/runtime-logging.js +47 -14
  178. package/dist/heart/daemon/runtime-metadata.js +2 -30
  179. package/dist/heart/daemon/runtime-mode.js +13 -2
  180. package/dist/heart/daemon/safe-mode.js +161 -0
  181. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2654 -0
  182. package/dist/heart/daemon/sanctuary-acceptance-harness.js +1830 -0
  183. package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
  184. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +955 -0
  185. package/dist/heart/daemon/sanctuary-authority-codec.js +86 -0
  186. package/dist/heart/daemon/sanctuary-authority-epoch.js +256 -0
  187. package/dist/heart/daemon/sanctuary-authority-installation.js +140 -0
  188. package/dist/heart/daemon/sanctuary-authority-ledger.js +241 -0
  189. package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +819 -0
  190. package/dist/heart/daemon/sanctuary-authority-vault-migration.js +79 -0
  191. package/dist/heart/daemon/sanctuary-bundle-migration.js +729 -0
  192. package/dist/heart/daemon/sanctuary-host-authority.js +1008 -0
  193. package/dist/heart/daemon/sanctuary-host-detached-supervisor.js +494 -0
  194. package/dist/heart/daemon/sanctuary-host-executor.js +670 -0
  195. package/dist/heart/daemon/sanctuary-host-linux-kernel.js +334 -0
  196. package/dist/heart/daemon/sanctuary-host-supervisor-entry.js +207 -0
  197. package/dist/heart/daemon/sanctuary-host-supervisor.js +95 -0
  198. package/dist/heart/daemon/sanctuary-package-management.js +103 -0
  199. package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
  200. package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
  201. package/dist/heart/daemon/sanctuary-telegram-authority-entry.js +445 -0
  202. package/dist/heart/daemon/sanctuary-telegram-authority-gateway.js +585 -0
  203. package/dist/heart/daemon/sanctuary-telegram-authority-service.js +630 -0
  204. package/dist/heart/daemon/sense-manager.js +699 -48
  205. package/dist/heart/daemon/session-id-resolver.js +131 -0
  206. package/dist/heart/daemon/skill-management-installer.js +1 -1
  207. package/dist/heart/daemon/socket-client.js +180 -12
  208. package/dist/heart/daemon/stale-bundle-prune.js +113 -0
  209. package/dist/heart/daemon/startup-tui.js +339 -0
  210. package/dist/heart/daemon/supercronic-supervisor.js +282 -0
  211. package/dist/heart/daemon/task-scheduler.js +117 -39
  212. package/dist/heart/daemon/terminal-ui.js +499 -0
  213. package/dist/heart/daemon/thoughts.js +138 -54
  214. package/dist/heart/daemon/up-progress.js +366 -0
  215. package/dist/heart/daemon/vault-items.js +56 -0
  216. package/dist/heart/delegation.js +1 -4
  217. package/dist/heart/external-events/router.js +1430 -0
  218. package/dist/heart/frontend-approval-runtime.js +506 -0
  219. package/dist/heart/frontend-journal.js +215 -0
  220. package/dist/heart/frontend-session-service.js +237 -0
  221. package/dist/heart/frontend-socket-client.js +164 -0
  222. package/dist/heart/frontend-socket.js +400 -0
  223. package/dist/heart/habits/habit-cancel.js +810 -0
  224. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  225. package/dist/heart/habits/habit-migration.js +194 -0
  226. package/dist/heart/habits/habit-parser.js +278 -0
  227. package/dist/heart/habits/habit-runtime-state.js +93 -0
  228. package/dist/heart/habits/habit-scheduler.js +653 -0
  229. package/dist/heart/habits/habit-session-summary.js +318 -0
  230. package/dist/heart/habits/habit-session.js +636 -0
  231. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
  232. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  233. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  234. package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
  235. package/dist/heart/identity.js +196 -59
  236. package/dist/heart/kept-notes.js +289 -0
  237. package/dist/heart/kicks.js +1 -1
  238. package/dist/heart/machine-identity.js +161 -0
  239. package/dist/heart/mail-import-discovery.js +356 -0
  240. package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
  241. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  242. package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
  243. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  244. package/dist/heart/mailbox/mailbox-http-transport.js +129 -0
  245. package/dist/heart/mailbox/mailbox-http.js +99 -0
  246. package/dist/heart/mailbox/mailbox-read.js +39 -0
  247. package/dist/heart/mailbox/mailbox-types.js +27 -0
  248. package/dist/heart/mailbox/mailbox-view.js +197 -0
  249. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  250. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  251. package/dist/heart/mailbox/readers/mail.js +375 -0
  252. package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
  253. package/dist/heart/mailbox/readers/sessions.js +231 -0
  254. package/dist/heart/mailbox/readers/shared.js +111 -0
  255. package/dist/heart/mcp/mcp-server.js +696 -0
  256. package/dist/heart/migrate-config.js +100 -0
  257. package/dist/heart/model-capabilities.js +11 -0
  258. package/dist/heart/orientation-frame.js +345 -0
  259. package/dist/heart/platform.js +81 -0
  260. package/dist/heart/primitives.js +1 -1
  261. package/dist/heart/private-runtime/decision-renderer.js +158 -0
  262. package/dist/heart/private-runtime/index.js +18 -0
  263. package/dist/heart/private-runtime/ledger.js +221 -0
  264. package/dist/heart/private-runtime/policy.js +252 -0
  265. package/dist/heart/private-runtime/types.js +2 -0
  266. package/dist/heart/progress-story.js +1 -1
  267. package/dist/heart/provider-attempt.js +137 -0
  268. package/dist/heart/provider-binding-resolver.js +273 -0
  269. package/dist/heart/provider-credentials.js +449 -0
  270. package/dist/heart/provider-failover.js +311 -0
  271. package/dist/heart/provider-models.js +96 -0
  272. package/dist/heart/provider-ping.js +265 -0
  273. package/dist/heart/provider-readiness-cache.js +119 -0
  274. package/dist/heart/provider-visibility.js +188 -0
  275. package/dist/heart/providers/anthropic-token.js +131 -0
  276. package/dist/heart/providers/anthropic.js +173 -60
  277. package/dist/heart/providers/azure.js +23 -11
  278. package/dist/heart/providers/error-classification.js +127 -0
  279. package/dist/heart/providers/github-copilot.js +34 -38
  280. package/dist/heart/providers/minimax-vlm.js +189 -0
  281. package/dist/heart/providers/minimax.js +26 -8
  282. package/dist/heart/providers/openai-codex-token.js +349 -0
  283. package/dist/heart/providers/openai-codex.js +55 -40
  284. package/dist/heart/providers/openai-compatible.js +177 -0
  285. package/dist/heart/run-ledger.js +247 -0
  286. package/dist/heart/runtime-capability-check.js +170 -0
  287. package/dist/heart/runtime-credentials.js +607 -0
  288. package/dist/heart/runtime-cwd.js +87 -0
  289. package/dist/heart/sense-truth.js +22 -4
  290. package/dist/heart/session-activity.js +92 -24
  291. package/dist/heart/session-events.js +1504 -0
  292. package/dist/heart/session-playback-cli-main.js +5 -0
  293. package/dist/heart/session-playback-cli.js +36 -0
  294. package/dist/heart/session-playback.js +231 -0
  295. package/dist/heart/session-redaction-repair-cli-main.js +31 -0
  296. package/dist/heart/session-redaction-repair.js +552 -0
  297. package/dist/heart/session-stats-cli-main.js +5 -0
  298. package/dist/heart/session-stats.js +183 -0
  299. package/dist/heart/session-transcript.js +133 -0
  300. package/dist/heart/start-of-turn-packet.js +372 -0
  301. package/dist/heart/steward-policy.js +618 -0
  302. package/dist/heart/streaming.js +604 -207
  303. package/dist/heart/structured-output.js +196 -0
  304. package/dist/heart/sync-classification.js +176 -0
  305. package/dist/heart/sync.js +449 -0
  306. package/dist/heart/target-resolution.js +11 -7
  307. package/dist/heart/tempo.js +93 -0
  308. package/dist/heart/temporal-view.js +41 -0
  309. package/dist/heart/timeouts.js +101 -0
  310. package/dist/heart/tool-activity-callbacks.js +59 -0
  311. package/dist/heart/tool-approval.js +382 -0
  312. package/dist/heart/tool-description.js +155 -0
  313. package/dist/heart/tool-friction.js +55 -0
  314. package/dist/heart/tool-loop.js +200 -0
  315. package/dist/heart/turn-context.js +482 -0
  316. package/dist/heart/turn-execution-lease.js +30 -0
  317. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  318. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  319. package/dist/heart/versioning/ouro-path-installer.js +432 -0
  320. package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
  321. package/dist/heart/versioning/ouro-version-manager.js +409 -0
  322. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  323. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  324. package/dist/heart/versioning/update-hooks.js +154 -0
  325. package/dist/heart/versioning/version-intent.js +114 -0
  326. package/dist/heart/work-card.js +380 -0
  327. package/dist/mailbox-ui/assets/index-Cyv4mw3Y.js +1 -0
  328. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  329. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  330. package/dist/mailbox-ui/index.html +16 -0
  331. package/dist/mailroom/attention.js +167 -0
  332. package/dist/mailroom/autonomy.js +209 -0
  333. package/dist/mailroom/blob-store.js +889 -0
  334. package/dist/mailroom/body-cache.js +61 -0
  335. package/dist/mailroom/cache-sync-cli.js +58 -0
  336. package/dist/mailroom/core.js +803 -0
  337. package/dist/mailroom/entry.js +160 -0
  338. package/dist/mailroom/file-store.js +568 -0
  339. package/dist/mailroom/hosted-cache-sync.js +384 -0
  340. package/dist/mailroom/mbox-import.js +393 -0
  341. package/dist/mailroom/migration.js +164 -0
  342. package/dist/mailroom/outbound.js +380 -0
  343. package/dist/mailroom/policy.js +263 -0
  344. package/dist/mailroom/reader.js +292 -0
  345. package/dist/mailroom/search-cache.js +513 -0
  346. package/dist/mailroom/search-relevance.js +319 -0
  347. package/dist/mailroom/smtp-ingress.js +176 -0
  348. package/dist/mailroom/source-state.js +176 -0
  349. package/dist/mailroom/thread.js +109 -0
  350. package/dist/mailroom/travel-extract.js +89 -0
  351. package/dist/mind/bundle-manifest.js +24 -2
  352. package/dist/mind/context.js +309 -111
  353. package/dist/mind/desk-section.js +362 -0
  354. package/dist/mind/diary-integrity.js +60 -0
  355. package/dist/mind/{memory.js → diary.js} +68 -77
  356. package/dist/mind/embedding-provider.js +60 -0
  357. package/dist/mind/file-state.js +179 -0
  358. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  359. package/dist/mind/obligation-steering.js +199 -3
  360. package/dist/mind/pending.js +36 -10
  361. package/dist/mind/prompt-budget.js +479 -0
  362. package/dist/mind/prompt-refresh.js +3 -2
  363. package/dist/mind/prompt.js +1050 -189
  364. package/dist/mind/provenance-trust.js +26 -0
  365. package/dist/mind/record-paths.js +312 -0
  366. package/dist/mind/scrutiny.js +173 -0
  367. package/dist/mind/session-transaction.js +564 -0
  368. package/dist/nerves/cli-logging.js +7 -1
  369. package/dist/nerves/coverage/audit-rules.js +15 -6
  370. package/dist/nerves/coverage/audit.js +28 -2
  371. package/dist/nerves/coverage/cli.js +1 -1
  372. package/dist/nerves/coverage/contract.js +5 -5
  373. package/dist/nerves/coverage/file-completeness.js +139 -5
  374. package/dist/nerves/coverage/run-artifacts.js +55 -35
  375. package/dist/nerves/coverage/source-scanner.js +4 -4
  376. package/dist/nerves/event-buffer.js +111 -0
  377. package/dist/nerves/index.js +293 -9
  378. package/dist/nerves/observation.js +20 -0
  379. package/dist/nerves/redact.js +79 -0
  380. package/dist/nerves/review/cli-main.js +5 -0
  381. package/dist/nerves/review/cli.js +156 -0
  382. package/dist/nerves/review/core.js +159 -0
  383. package/dist/nerves/runtime.js +17 -1
  384. package/dist/repertoire/ado-client.js +15 -56
  385. package/dist/repertoire/ado-semantic.js +16 -10
  386. package/dist/repertoire/api-client.js +97 -0
  387. package/dist/repertoire/bitwarden-store.js +1045 -0
  388. package/dist/repertoire/bundle-templates.js +71 -0
  389. package/dist/repertoire/bw-installer.js +180 -0
  390. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  391. package/dist/repertoire/coding/context-pack.js +331 -0
  392. package/dist/repertoire/coding/feedback.js +174 -32
  393. package/dist/repertoire/coding/index.js +15 -3
  394. package/dist/repertoire/coding/manager.js +159 -10
  395. package/dist/repertoire/coding/spawner.js +58 -11
  396. package/dist/repertoire/coding/tools.js +221 -15
  397. package/dist/repertoire/coding/workbench-client.js +272 -0
  398. package/dist/repertoire/coding/workbench-manager.js +346 -0
  399. package/dist/repertoire/commerce-errors.js +109 -0
  400. package/dist/repertoire/commerce-self-test.js +156 -0
  401. package/dist/repertoire/credential-access.js +178 -0
  402. package/dist/repertoire/desk/classifier.js +362 -0
  403. package/dist/repertoire/duffel-client.js +185 -0
  404. package/dist/repertoire/github-client.js +14 -55
  405. package/dist/repertoire/graph-client.js +11 -52
  406. package/dist/repertoire/guardrails.js +811 -18
  407. package/dist/repertoire/mcp-client.js +44 -3
  408. package/dist/repertoire/mcp-manager.js +427 -139
  409. package/dist/repertoire/mcp-tools.js +124 -0
  410. package/dist/repertoire/plugin-mcp.js +175 -0
  411. package/dist/repertoire/plugins.js +253 -0
  412. package/dist/repertoire/relationship-authorization.js +322 -0
  413. package/dist/repertoire/shell-sessions.js +134 -0
  414. package/dist/repertoire/skills.js +48 -4
  415. package/dist/repertoire/stripe-client.js +131 -0
  416. package/dist/repertoire/tool-arguments.js +170 -0
  417. package/dist/repertoire/tool-results.js +29 -0
  418. package/dist/repertoire/tools-a2a.js +699 -0
  419. package/dist/repertoire/tools-attachments.js +322 -0
  420. package/dist/repertoire/tools-awaiting.js +575 -0
  421. package/dist/repertoire/tools-base.js +77 -1138
  422. package/dist/repertoire/tools-bluebubbles.js +2 -0
  423. package/dist/repertoire/tools-bridge.js +144 -0
  424. package/dist/repertoire/tools-bundle.js +993 -0
  425. package/dist/repertoire/tools-commerce.js +253 -0
  426. package/dist/repertoire/tools-config.js +186 -0
  427. package/dist/repertoire/tools-continuity.js +575 -0
  428. package/dist/repertoire/tools-credential.js +383 -0
  429. package/dist/repertoire/tools-evolution.js +527 -0
  430. package/dist/repertoire/tools-files.js +344 -0
  431. package/dist/repertoire/tools-flight.js +290 -0
  432. package/dist/repertoire/tools-flow.js +119 -0
  433. package/dist/repertoire/tools-github.js +3 -8
  434. package/dist/repertoire/tools-habits.js +103 -0
  435. package/dist/repertoire/tools-mail.js +1828 -0
  436. package/dist/repertoire/tools-notes.js +485 -0
  437. package/dist/repertoire/tools-obligations.js +182 -0
  438. package/dist/repertoire/tools-orientation.js +31 -0
  439. package/dist/repertoire/tools-record.js +482 -0
  440. package/dist/repertoire/tools-rsvp.js +139 -0
  441. package/dist/repertoire/tools-runtime.js +150 -0
  442. package/dist/repertoire/tools-sanctuary-host.js +202 -0
  443. package/dist/repertoire/tools-session.js +1133 -0
  444. package/dist/repertoire/tools-shell.js +149 -0
  445. package/dist/repertoire/tools-steward-policy.js +119 -0
  446. package/dist/repertoire/tools-stripe.js +224 -0
  447. package/dist/repertoire/tools-surface.js +369 -0
  448. package/dist/repertoire/tools-teams.js +12 -39
  449. package/dist/repertoire/tools-telegram-contacts.js +37 -0
  450. package/dist/repertoire/tools-travel.js +125 -0
  451. package/dist/repertoire/tools-trip.js +982 -0
  452. package/dist/repertoire/tools-unraid.js +531 -0
  453. package/dist/repertoire/tools-user-profile.js +146 -0
  454. package/dist/repertoire/tools-vault.js +40 -0
  455. package/dist/repertoire/tools-voice.js +145 -0
  456. package/dist/repertoire/tools.js +494 -148
  457. package/dist/repertoire/travel-api-client.js +360 -0
  458. package/dist/repertoire/unraid-client.js +155 -0
  459. package/dist/repertoire/unraid-restart.js +339 -0
  460. package/dist/repertoire/user-profile.js +131 -0
  461. package/dist/repertoire/vault-setup.js +246 -0
  462. package/dist/repertoire/vault-unlock.js +628 -0
  463. package/dist/rsvp/aisleplanner-client.js +354 -0
  464. package/dist/rsvp/cli.js +926 -0
  465. package/dist/rsvp/config.js +327 -0
  466. package/dist/rsvp/cutover.js +433 -0
  467. package/dist/rsvp/diagnostics.js +232 -0
  468. package/dist/rsvp/diff-renderer.js +176 -0
  469. package/dist/rsvp/habit-policy.js +110 -0
  470. package/dist/rsvp/habit-stage.js +123 -0
  471. package/dist/rsvp/incident-bundle.js +97 -0
  472. package/dist/rsvp/migration.js +204 -0
  473. package/dist/rsvp/native-habit-runner.js +630 -0
  474. package/dist/rsvp/outbound-state.js +628 -0
  475. package/dist/rsvp/query.js +118 -0
  476. package/dist/rsvp/replay.js +233 -0
  477. package/dist/rsvp/snapshot.js +232 -0
  478. package/dist/rsvp/spend-ledger.js +175 -0
  479. package/dist/scripts/claude-code-hook.js +41 -0
  480. package/dist/scripts/claude-code-stop-hook.js +47 -0
  481. package/dist/senses/a2a-entry.js +115 -0
  482. package/dist/senses/acp-server.js +386 -0
  483. package/dist/senses/attention-queue.js +186 -0
  484. package/dist/senses/await-turn-message.js +58 -0
  485. package/dist/senses/bluebubbles/active-turns.js +216 -0
  486. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  487. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  488. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +355 -40
  489. package/dist/senses/bluebubbles/context-packet.js +207 -0
  490. package/dist/senses/bluebubbles/context-smoke.js +144 -0
  491. package/dist/senses/bluebubbles/entry.js +90 -0
  492. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
  493. package/dist/senses/bluebubbles/index.js +3841 -0
  494. package/dist/senses/bluebubbles/latest-turn.js +311 -0
  495. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  496. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
  497. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
  498. package/dist/senses/bluebubbles/outbound-state.js +308 -0
  499. package/dist/senses/bluebubbles/processed-log.js +133 -0
  500. package/dist/senses/bluebubbles/reaction-policy.js +47 -0
  501. package/dist/senses/bluebubbles/replay.js +284 -0
  502. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  503. package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
  504. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  505. package/dist/senses/bluebubbles/webhook-registration.js +228 -0
  506. package/dist/senses/bluebubbles-meta-guard.js +39 -0
  507. package/dist/senses/cli/bracketed-paste.js +82 -0
  508. package/dist/senses/cli/image-paste.js +287 -0
  509. package/dist/senses/cli/image-ref-navigation.js +75 -0
  510. package/dist/senses/cli/ink-app.js +156 -0
  511. package/dist/senses/cli/inline-diff.js +64 -0
  512. package/dist/senses/cli/input-keys.js +174 -0
  513. package/dist/senses/cli/kill-ring.js +86 -0
  514. package/dist/senses/cli/message-list.js +51 -0
  515. package/dist/senses/cli/ouro-tui.js +607 -0
  516. package/dist/senses/cli/spinner-imperative.js +135 -0
  517. package/dist/senses/cli/spinner.js +101 -0
  518. package/dist/senses/cli/status-line.js +60 -0
  519. package/dist/senses/cli/streaming-markdown.js +526 -0
  520. package/dist/senses/cli/tool-display.js +85 -0
  521. package/dist/senses/cli/tool-render.js +85 -0
  522. package/dist/senses/cli/tui-store.js +241 -0
  523. package/dist/senses/cli/virtual-list.js +35 -0
  524. package/dist/senses/cli-entry.js +60 -8
  525. package/dist/senses/cli.js +604 -320
  526. package/dist/senses/commands.js +66 -3
  527. package/dist/senses/context-packet-ledger.js +371 -0
  528. package/dist/senses/context-packets.js +154 -0
  529. package/dist/senses/habit-lifecycle-guard.js +24 -0
  530. package/dist/senses/habit-turn-message.js +160 -0
  531. package/dist/senses/ingress-evidence.js +2 -0
  532. package/dist/senses/mail-entry.js +66 -0
  533. package/dist/senses/mail.js +524 -0
  534. package/dist/senses/pipeline.js +1115 -204
  535. package/dist/senses/private-runtime-worker.js +859 -0
  536. package/dist/senses/private-runtime.js +1517 -0
  537. package/dist/senses/proactive-content-guard.js +51 -0
  538. package/dist/senses/root-host-approval-port.js +345 -0
  539. package/dist/senses/root-host-approval-runtime.js +393 -0
  540. package/dist/senses/sanctuary-authority-resident.js +102 -0
  541. package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
  542. package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
  543. package/dist/senses/sanctuary-grounding.js +118 -0
  544. package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
  545. package/dist/senses/sanctuary-health-acceptance-probe.js +774 -0
  546. package/dist/senses/sanctuary-health-runner.js +100 -0
  547. package/dist/senses/sanctuary-health.js +408 -0
  548. package/dist/senses/sanctuary-install-state-contract.js +126 -0
  549. package/dist/senses/sanctuary-interactive-control.js +410 -0
  550. package/dist/senses/sanctuary-media-catalog-contract.js +297 -0
  551. package/dist/senses/sanctuary-media-optimization.js +514 -0
  552. package/dist/senses/sanctuary-runtime.js +340 -0
  553. package/dist/senses/sanctuary-sab.js +85 -0
  554. package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
  555. package/dist/senses/shared-turn.js +772 -0
  556. package/dist/senses/surface-tool.js +109 -0
  557. package/dist/senses/teams-entry.js +60 -8
  558. package/dist/senses/teams.js +519 -218
  559. package/dist/senses/telegram-admission.js +718 -0
  560. package/dist/senses/telegram-approval-runtime.js +793 -0
  561. package/dist/senses/telegram-attachments.js +186 -0
  562. package/dist/senses/telegram-audit-ledger.js +220 -0
  563. package/dist/senses/telegram-authority-transport.js +231 -0
  564. package/dist/senses/telegram-client.js +1749 -0
  565. package/dist/senses/telegram-effect-adapter.js +896 -0
  566. package/dist/senses/telegram-entry.js +83 -0
  567. package/dist/senses/telegram.js +2324 -0
  568. package/dist/senses/trust-gate.js +104 -9
  569. package/dist/senses/voice/audio-playback.js +237 -0
  570. package/dist/senses/voice/audio-routing.js +119 -0
  571. package/dist/senses/voice/elevenlabs.js +202 -0
  572. package/dist/senses/voice/floor-control.js +431 -0
  573. package/dist/senses/voice/floor-controller.js +115 -0
  574. package/dist/senses/voice/golden-path.js +116 -0
  575. package/dist/senses/voice/index.js +29 -0
  576. package/dist/senses/voice/meeting.js +113 -0
  577. package/dist/senses/voice/outbound.js +190 -0
  578. package/dist/senses/voice/phone.js +33 -0
  579. package/dist/senses/voice/playback.js +139 -0
  580. package/dist/senses/voice/realtime-eval.js +496 -0
  581. package/dist/senses/voice/realtime-trace.js +531 -0
  582. package/dist/senses/voice/transcript.js +70 -0
  583. package/dist/senses/voice/turn.js +191 -0
  584. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  585. package/dist/senses/voice/twilio-phone.js +5031 -0
  586. package/dist/senses/voice/types.js +2 -0
  587. package/dist/senses/voice/whisper.js +161 -0
  588. package/dist/senses/voice-entry.js +81 -0
  589. package/dist/senses/voice-realtime-eval-command.js +99 -0
  590. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  591. package/dist/senses/voice-twilio-entry.js +87 -0
  592. package/dist/trips/core.js +138 -0
  593. package/dist/trips/store.js +265 -0
  594. package/dist/util/frontmatter.js +69 -0
  595. package/npm-shrinkwrap.json +8138 -0
  596. package/package.json +72 -13
  597. package/skills/agent-commerce.md +113 -0
  598. package/skills/browser-navigation.md +117 -0
  599. package/skills/commerce-setup-guide.md +116 -0
  600. package/skills/commerce-setup.md +84 -0
  601. package/skills/configure-dev-tools.md +99 -0
  602. package/skills/travel-planning.md +138 -0
  603. package/dist/heart/daemon/auth-flow.js +0 -430
  604. package/dist/heart/daemon/ouro-path-installer.js +0 -260
  605. package/dist/heart/daemon/ouro-version-manager.js +0 -171
  606. package/dist/heart/daemon/update-hooks.js +0 -138
  607. package/dist/heart/obligations.js +0 -191
  608. package/dist/heart/safe-workspace.js +0 -228
  609. package/dist/heart/session-recall.js +0 -116
  610. package/dist/mind/friends/channel.js +0 -84
  611. package/dist/mind/friends/group-context.js +0 -144
  612. package/dist/mind/friends/resolver.js +0 -84
  613. package/dist/mind/friends/store-file.js +0 -190
  614. package/dist/mind/friends/store.js +0 -4
  615. package/dist/mind/friends/tokens.js +0 -26
  616. package/dist/mind/friends/trust-explanation.js +0 -74
  617. package/dist/mind/friends/types.js +0 -29
  618. package/dist/repertoire/tasks/board.js +0 -134
  619. package/dist/repertoire/tasks/index.js +0 -224
  620. package/dist/repertoire/tasks/lifecycle.js +0 -80
  621. package/dist/repertoire/tasks/middleware.js +0 -65
  622. package/dist/repertoire/tasks/parser.js +0 -173
  623. package/dist/repertoire/tasks/scanner.js +0 -132
  624. package/dist/repertoire/tasks/transitions.js +0 -144
  625. package/dist/senses/bluebubbles-entry.js +0 -13
  626. package/dist/senses/bluebubbles.js +0 -1181
  627. package/dist/senses/debug-activity.js +0 -154
  628. package/dist/senses/inner-dialog-worker.js +0 -90
  629. package/dist/senses/inner-dialog.js +0 -525
  630. package/subagents/README.md +0 -7
  631. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  632. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  633. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  634. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  635. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  636. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  637. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  638. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  639. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  640. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  641. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  642. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  643. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  644. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  645. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  646. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  647. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,1133 @@
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.sessionToolDefinitions = void 0;
37
+ exports.readButlerOperationalVisibility = readButlerOperationalVisibility;
38
+ exports.formatButlerOperationalVisibility = formatButlerOperationalVisibility;
39
+ exports.renderInnerProgressStatus = renderInnerProgressStatus;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const crypto_1 = require("crypto");
43
+ const config_1 = require("../heart/config");
44
+ const identity_1 = require("../heart/identity");
45
+ const session_events_1 = require("../heart/session-events");
46
+ const runtime_1 = require("../nerves/runtime");
47
+ const socket_client_1 = require("../heart/daemon/socket-client");
48
+ const thoughts_1 = require("../heart/daemon/thoughts");
49
+ const manager_1 = require("../heart/bridges/manager");
50
+ const session_transcript_1 = require("../heart/session-transcript");
51
+ const session_activity_1 = require("../heart/session-activity");
52
+ const active_work_1 = require("../heart/active-work");
53
+ const coding_1 = require("./coding");
54
+ const pending_1 = require("../mind/pending");
55
+ const obligations_1 = require("../arc/obligations");
56
+ const progress_story_1 = require("../heart/progress-story");
57
+ const habit_session_summary_1 = require("../heart/habits/habit-session-summary");
58
+ const cross_chat_delivery_1 = require("../heart/cross-chat-delivery");
59
+ const tool_arguments_1 = require("./tool-arguments");
60
+ const mail_import_discovery_1 = require("../heart/mail-import-discovery");
61
+ const outbound_1 = require("../senses/voice/outbound");
62
+ const router_1 = require("../heart/external-events/router");
63
+ const steward_policy_1 = require("../heart/steward-policy");
64
+ const await_parser_1 = require("../heart/awaiting/await-parser");
65
+ const daemon_health_1 = require("../heart/daemon/daemon-health");
66
+ const turn_context_1 = require("../heart/turn-context");
67
+ const telegram_effect_adapter_1 = require("../senses/telegram-effect-adapter");
68
+ const telegram_admission_1 = require("../senses/telegram-admission");
69
+ const sanctuary_health_1 = require("../senses/sanctuary-health");
70
+ const run_ledger_1 = require("../heart/run-ledger");
71
+ const NO_SESSION_FOUND_MESSAGE = "no session found for that friend/channel/key combination.";
72
+ const EMPTY_SESSION_MESSAGE = "session exists but has no non-system messages.";
73
+ const VALID_HABIT_SUMMARY_WHICH = new Set(["latest", "previous", "latest-success", "latest-failure"]);
74
+ async function summarizeSessionTailSafely(options) {
75
+ try {
76
+ return await (0, session_transcript_1.summarizeSessionTail)(options);
77
+ }
78
+ catch (error) {
79
+ if (options.summarize) {
80
+ (0, runtime_1.emitNervesEvent)({
81
+ component: "daemon",
82
+ event: "daemon.session_tail_summary_summary_fallback",
83
+ message: "session tail summarization failed; using raw transcript",
84
+ meta: {
85
+ friendId: options.friendId,
86
+ channel: options.channel,
87
+ key: options.key,
88
+ error: error instanceof Error ? error.message : String(error),
89
+ },
90
+ });
91
+ try {
92
+ return await (0, session_transcript_1.summarizeSessionTail)({
93
+ ...options,
94
+ summarize: undefined,
95
+ });
96
+ /* v8 ignore start -- defensive: session tail fallback @preserve */
97
+ }
98
+ catch {
99
+ return { kind: "missing" };
100
+ }
101
+ /* v8 ignore stop */
102
+ }
103
+ return { kind: "missing" };
104
+ }
105
+ }
106
+ function optionalArg(args, key) {
107
+ const value = args[key];
108
+ if (value === undefined || value === null)
109
+ return undefined;
110
+ if (typeof value !== "string")
111
+ return null;
112
+ const trimmed = value.trim();
113
+ return trimmed ? trimmed : undefined;
114
+ }
115
+ function validateSessionSummarySelector(args) {
116
+ const runId = optionalArg(args, "runId");
117
+ const habitName = optionalArg(args, "habitName");
118
+ const operationId = optionalArg(args, "operationId");
119
+ const which = optionalArg(args, "which");
120
+ if (runId === null || habitName === null || operationId === null || which === null) {
121
+ return {
122
+ ok: false,
123
+ code: which === null ? "invalid_which" : "selector_required",
124
+ message: which === null
125
+ ? "which must be latest, previous, latest-success, or latest-failure"
126
+ : "selector fields must be strings",
127
+ };
128
+ }
129
+ if (runId !== undefined) {
130
+ if (habitName !== undefined || operationId !== undefined || which !== undefined) {
131
+ return {
132
+ ok: false,
133
+ code: "run_id_exclusive",
134
+ message: "runId cannot be combined with habitName, operationId, or which",
135
+ };
136
+ }
137
+ return { ok: true, selector: { runId } };
138
+ }
139
+ if (habitName === undefined && operationId === undefined) {
140
+ return {
141
+ ok: false,
142
+ code: "selector_required",
143
+ message: "provide runId, habitName, or operationId",
144
+ };
145
+ }
146
+ if (which !== undefined && !VALID_HABIT_SUMMARY_WHICH.has(which)) {
147
+ return {
148
+ ok: false,
149
+ code: "invalid_which",
150
+ message: "which must be latest, previous, latest-success, or latest-failure",
151
+ };
152
+ }
153
+ return {
154
+ ok: true,
155
+ selector: {
156
+ ...(habitName !== undefined ? { habitName } : {}),
157
+ ...(operationId !== undefined ? { operationId } : {}),
158
+ ...(which !== undefined ? { which } : {}),
159
+ },
160
+ };
161
+ }
162
+ function renderSessionSummaryText(summary) {
163
+ const lines = [
164
+ `habit ${summary.habitName} run ${summary.runId} finished with ${summary.status}.`,
165
+ summary.operationId ? `operation: ${summary.operationId}` : null,
166
+ summary.summary,
167
+ summary.nextLikelyStep ? `next: ${summary.nextLikelyStep}` : null,
168
+ summary.decisions.length > 0 ? `decisions: ${summary.decisions.join("; ")}` : null,
169
+ summary.pending.count > 0 ? `pending: ${summary.pending.count} file(s) (${summary.pending.files.join(", ")})` : "pending: none",
170
+ summary.messagesSent.length > 0 ? `messages: ${summary.messagesSent.length}` : "messages: none",
171
+ summary.toolsUsed.length > 0 ? `tools: ${summary.toolsUsed.join(", ")}` : "tools: none",
172
+ summary.errors.length > 0 ? `errors: ${summary.errors.join("; ")}` : null,
173
+ summary.warnings.length > 0 ? `warnings: ${summary.warnings.join("; ")}` : null,
174
+ `receipt: ${summary.sources.receipt}`,
175
+ `session: ${summary.sources.session}`,
176
+ ];
177
+ return lines.filter((line) => Boolean(line)).join("\n");
178
+ }
179
+ function writePendingEnvelope(queueDir, message) {
180
+ fs.mkdirSync(queueDir, { recursive: true });
181
+ const fileName = `${message.timestamp}-${Math.random().toString(36).slice(2, 10)}.json`;
182
+ const filePath = path.join(queueDir, fileName);
183
+ fs.writeFileSync(filePath, JSON.stringify({ ...message, content: (0, session_events_1.capStructuredRecordString)(message.content) }, null, 2));
184
+ return fileName.replace(/\.json$/, "");
185
+ }
186
+ function renderCrossChatDeliveryStatus(target, result) {
187
+ const phase = result.status === "delivered_now"
188
+ ? "completed"
189
+ : result.status === "queued_for_later"
190
+ ? "queued"
191
+ : result.status === "blocked"
192
+ ? "blocked"
193
+ : "errored";
194
+ const lead = result.status === "delivered_now"
195
+ ? "delivered now"
196
+ : result.status === "queued_for_later"
197
+ ? "queued for later"
198
+ : result.status === "blocked"
199
+ ? "blocked"
200
+ : "failed";
201
+ return (0, progress_story_1.renderProgressStory)((0, progress_story_1.buildProgressStory)({
202
+ scope: "shared-work",
203
+ phase,
204
+ objective: `message to ${target}`,
205
+ outcomeText: `${lead}\n${result.detail}`,
206
+ }));
207
+ }
208
+ function normalizeHabitSendStatus(status) {
209
+ return status === "queued_for_later" ? "queued" : status;
210
+ }
211
+ function recordHabitSendAttempt(ctx, args, result) {
212
+ ctx?.habitSession?.recordSurfaceAttempt?.({
213
+ recipient: args.friendId,
214
+ channel: args.channel,
215
+ reason: result.status === "blocked" ? "blocked" : result.status === "failed" ? "other" : "status",
216
+ result: normalizeHabitSendStatus(result.status),
217
+ rawStatus: result.rawStatus ?? result.status,
218
+ ...(result.status === "blocked" || result.status === "failed" ? { error: result.detail } : {}),
219
+ });
220
+ }
221
+ async function deliverVoiceChannelMessage(request, agentName, initialAudio) {
222
+ const result = await (0, outbound_1.placeTrustedFriendVoiceOutboundCall)({
223
+ agentName,
224
+ agentRoot: (0, identity_1.getAgentRoot)(),
225
+ friendId: request.friendId,
226
+ reason: request.content,
227
+ ...(initialAudio ? { initialAudio } : {}),
228
+ });
229
+ if (result.status === "placed") {
230
+ return {
231
+ status: "delivered_now",
232
+ detail: result.detail,
233
+ };
234
+ }
235
+ return {
236
+ status: result.status,
237
+ detail: result.detail,
238
+ };
239
+ }
240
+ /* v8 ignore start -- voice initial-audio parsing is exercised by voice transport tests; session tool keeps a thin argument adapter @preserve */
241
+ function parseVoiceInitialAudio(args) {
242
+ const source = args.voiceAudioSource === "url" || args.voiceAudioSource === "file" || args.voiceAudioSource === "tone"
243
+ ? args.voiceAudioSource
244
+ : undefined;
245
+ const hasAudioHint = Boolean(source
246
+ || args.voiceAudioUrl?.trim()
247
+ || args.voiceAudioPath?.trim()
248
+ || args.voiceAudioLabel?.trim()
249
+ || args.voiceAudioToneHz?.trim()
250
+ || args.voiceAudioDurationMs?.trim());
251
+ if (!hasAudioHint)
252
+ return undefined;
253
+ const toneHz = args.voiceAudioToneHz?.trim() ? Number(args.voiceAudioToneHz) : undefined;
254
+ const durationMs = args.voiceAudioDurationMs?.trim() ? Number(args.voiceAudioDurationMs) : undefined;
255
+ return {
256
+ source: source ?? "tone",
257
+ ...(args.voiceAudioUrl?.trim() ? { url: args.voiceAudioUrl.trim() } : {}),
258
+ ...(args.voiceAudioPath?.trim() ? { path: args.voiceAudioPath.trim() } : {}),
259
+ ...(args.voiceAudioLabel?.trim() ? { label: args.voiceAudioLabel.trim() } : {}),
260
+ ...(Number.isFinite(toneHz) ? { toneHz } : {}),
261
+ ...(Number.isFinite(durationMs) ? { durationMs } : {}),
262
+ };
263
+ }
264
+ /* v8 ignore stop */
265
+ function isLiveCodingSessionStatus(status) {
266
+ return status === "spawning"
267
+ || status === "running"
268
+ || status === "waiting_input"
269
+ || status === "stalled";
270
+ }
271
+ function readActiveWorkInnerState() {
272
+ const defaultJob = {
273
+ status: "idle",
274
+ content: null,
275
+ origin: null,
276
+ mode: "reflect",
277
+ obligationStatus: null,
278
+ surfacedResult: null,
279
+ queuedAt: null,
280
+ startedAt: null,
281
+ surfacedAt: null,
282
+ };
283
+ try {
284
+ const agentRoot = (0, identity_1.getAgentRoot)();
285
+ const pendingDir = (0, pending_1.getPrivateRuntimePendingDir)((0, identity_1.getAgentName)());
286
+ const sessionPath = (0, thoughts_1.getPrivateRuntimeSessionPath)(agentRoot);
287
+ const { pendingMessages, turns, runtimeState } = (0, thoughts_1.readPrivateRuntimeRawData)(sessionPath, pendingDir);
288
+ const dialogStatus = (0, thoughts_1.derivePrivateRuntimeStatus)(pendingMessages, turns, runtimeState);
289
+ const job = (0, thoughts_1.deriveInnerJob)(pendingMessages, turns, runtimeState);
290
+ const storeObligationPending = (0, obligations_1.readPendingObligations)(agentRoot).length > 0;
291
+ return {
292
+ status: dialogStatus.processing === "started" ? "running" : "idle",
293
+ hasPending: dialogStatus.queue !== "clear",
294
+ origin: dialogStatus.origin,
295
+ contentSnippet: dialogStatus.contentSnippet,
296
+ obligationPending: dialogStatus.obligationPending || storeObligationPending,
297
+ job,
298
+ };
299
+ }
300
+ catch {
301
+ return {
302
+ status: "idle",
303
+ hasPending: false,
304
+ job: defaultJob,
305
+ };
306
+ }
307
+ }
308
+ async function buildToolActiveWorkFrame(ctx) {
309
+ const currentSession = ctx?.currentSession
310
+ ? {
311
+ friendId: ctx.currentSession.friendId,
312
+ channel: ctx.currentSession.channel,
313
+ key: ctx.currentSession.key,
314
+ sessionPath: (0, config_1.resolveSessionPath)(ctx.currentSession.friendId, ctx.currentSession.channel, ctx.currentSession.key),
315
+ }
316
+ : null;
317
+ const agentRoot = (0, identity_1.getAgentRoot)();
318
+ const bridges = currentSession
319
+ ? (0, manager_1.createBridgeManager)().findBridgesForSession({
320
+ friendId: currentSession.friendId,
321
+ channel: currentSession.channel,
322
+ key: currentSession.key,
323
+ })
324
+ : [];
325
+ let friendActivity = [];
326
+ try {
327
+ friendActivity = (0, session_activity_1.listSessionActivity)({
328
+ sessionsDir: `${agentRoot}/state/sessions`,
329
+ friendsDir: `${agentRoot}/friends`,
330
+ agentName: (0, identity_1.getAgentName)(),
331
+ currentSession,
332
+ });
333
+ }
334
+ catch {
335
+ friendActivity = [];
336
+ }
337
+ const pendingObligations = (() => {
338
+ try {
339
+ return (0, obligations_1.readPendingObligations)(agentRoot);
340
+ }
341
+ catch {
342
+ return [];
343
+ }
344
+ })();
345
+ let codingSessions = [];
346
+ let otherCodingSessions = [];
347
+ try {
348
+ const liveCodingSessions = (0, coding_1.getCodingSessionManager)()
349
+ .listSessions()
350
+ .filter((session) => isLiveCodingSessionStatus(session.status) && Boolean(session.originSession));
351
+ if (currentSession) {
352
+ codingSessions = liveCodingSessions.filter((session) => session.originSession?.friendId === currentSession.friendId
353
+ && session.originSession.channel === currentSession.channel
354
+ && session.originSession.key === currentSession.key);
355
+ otherCodingSessions = liveCodingSessions.filter((session) => !(session.originSession?.friendId === currentSession.friendId
356
+ && session.originSession.channel === currentSession.channel
357
+ && session.originSession.key === currentSession.key));
358
+ }
359
+ else {
360
+ codingSessions = [];
361
+ otherCodingSessions = liveCodingSessions;
362
+ }
363
+ }
364
+ catch {
365
+ codingSessions = [];
366
+ otherCodingSessions = [];
367
+ }
368
+ const currentObligation = currentSession
369
+ ? pendingObligations.find((obligation) => obligation.status !== "fulfilled"
370
+ && obligation.origin.friendId === currentSession.friendId
371
+ && obligation.origin.channel === currentSession.channel
372
+ && obligation.origin.key === currentSession.key)?.content ?? null
373
+ : null;
374
+ const backgroundOperations = (0, mail_import_discovery_1.listVisibleBackgroundOperations)({
375
+ agentName: (0, identity_1.getAgentName)(),
376
+ agentRoot,
377
+ repoRoot: process.cwd(),
378
+ homeDir: process.env.HOME,
379
+ nowMs: Date.now(),
380
+ limit: 5,
381
+ });
382
+ return (0, active_work_1.buildActiveWorkFrame)({
383
+ currentSession,
384
+ currentObligation,
385
+ mustResolveBeforeHandoff: false,
386
+ inner: readActiveWorkInnerState(),
387
+ bridges,
388
+ codingSessions,
389
+ backgroundOperations,
390
+ otherCodingSessions,
391
+ pendingObligations,
392
+ friendActivity,
393
+ targetCandidates: [],
394
+ });
395
+ }
396
+ function boundedStatusText(value, max = 180) {
397
+ const normalized = value.replace(/\s+/g, " ").trim();
398
+ return normalized.length <= max ? normalized : `${normalized.slice(0, max - 3)}...`;
399
+ }
400
+ function readButlerOperationalVisibility(agentRoot = (0, identity_1.getAgentRoot)(), agentName = (0, identity_1.getAgentName)()) {
401
+ const sourceErrors = {};
402
+ const read = (source, operation, fallback) => {
403
+ try {
404
+ return operation();
405
+ }
406
+ catch (error) {
407
+ sourceErrors[source] = boundedStatusText(error instanceof Error ? error.message : String(error)) || "unknown read failure";
408
+ return fallback;
409
+ }
410
+ };
411
+ const awaitsDir = path.join(agentRoot, "awaiting");
412
+ const awaits = read("awaits", () => fs.existsSync(awaitsDir) ? fs.readdirSync(awaitsDir, { withFileTypes: true })
413
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".md"))
414
+ .map((entry) => {
415
+ const filePath = path.join(awaitsDir, entry.name);
416
+ return (0, await_parser_1.parseAwaitFile)(fs.readFileSync(filePath, "utf8"), filePath);
417
+ })
418
+ .filter((entry) => entry.status === "pending") : [], []);
419
+ const effectsRoot = path.join(agentRoot, "state", "telegram", "effects");
420
+ const telegramEffects = read("telegram_effects", () => {
421
+ if (!fs.existsSync(effectsRoot))
422
+ throw new Error("Telegram effect journal has not been created yet");
423
+ const journal = new telegram_effect_adapter_1.FileTelegramEffectJournal(effectsRoot);
424
+ try {
425
+ return journal.list().map((artifact) => ({
426
+ id: artifact.id,
427
+ authorClass: artifact.authorClass,
428
+ targetKind: artifact.target.kind,
429
+ state: artifact.parts.some((part) => part.state === "indeterminate") ? "indeterminate"
430
+ : artifact.parts.some((part) => part.state === "attempting") ? "attempting"
431
+ : artifact.parts.every((part) => part.state === "session_recorded") ? "session_recorded"
432
+ : artifact.parts.some((part) => part.state === "accepted") ? "accepted"
433
+ : "prepared",
434
+ acceptedAt: artifact.parts.flatMap((part) => part.acceptedAt ? [part.acceptedAt] : []).sort().at(-1) ?? null,
435
+ sessionRecordedAt: artifact.parts.flatMap((part) => part.sessionRecordedAt ? [part.sessionRecordedAt] : []).sort().at(-1) ?? null,
436
+ messageIds: artifact.parts.flatMap((part) => part.messageId ? [part.messageId] : []),
437
+ sessionEventIds: artifact.parts.flatMap((part) => part.sessionEventId ? [part.sessionEventId] : []),
438
+ updatedAt: artifact.updatedAt,
439
+ }));
440
+ }
441
+ finally {
442
+ journal.close();
443
+ }
444
+ }, []);
445
+ const admissionsRoot = path.join(agentRoot, "state", "senses", "telegram", "admissions");
446
+ const telegramAdmissions = read("telegram_admissions", () => {
447
+ if (!fs.existsSync(admissionsRoot))
448
+ throw new Error("Telegram admission store has not been created yet");
449
+ const store = new telegram_admission_1.FileTelegramAdmissionStore(admissionsRoot);
450
+ try {
451
+ return store.list().map((record) => ({ id: record.id, status: record.status, displayCode: record.displayCode, createdAt: record.createdAt, expiresAt: record.expiresAt }));
452
+ }
453
+ finally {
454
+ store.close();
455
+ }
456
+ }, []);
457
+ return {
458
+ agentName,
459
+ externalEvents: read("external_events", () => (0, router_1.listExternalEventStatus)((0, router_1.getExternalEventRoot)()).filter((event) => event.agent === agentName), []),
460
+ stewardPolicy: read("steward_policy", () => (0, steward_policy_1.readStewardPolicy)(agentRoot), { schemaVersion: 1, version: 0, desiredStates: {}, routineActionGrants: {}, updatedAt: null }),
461
+ awaits,
462
+ telegramEffects,
463
+ telegramAdmissions,
464
+ daemonHealth: read("daemon_health", () => {
465
+ const health = (0, daemon_health_1.readHealth)((0, daemon_health_1.getDefaultHealthPath)());
466
+ if (!health)
467
+ throw new Error("daemon health is missing or invalid");
468
+ return health;
469
+ }, null),
470
+ healthState: read("health_state", () => (0, sanctuary_health_1.readSanctuaryHealthState)(path.join(agentRoot, "state", "health", "sanctuary-health.json")), undefined),
471
+ routineActions: read("routine_actions", () => (0, steward_policy_1.readRoutineActionReceipts)(agentRoot), []),
472
+ providerLanes: read("provider", () => {
473
+ const config = (0, identity_1.loadAgentConfig)();
474
+ if (!config.humanFacing || !config.agentFacing)
475
+ throw new Error("provider lanes are unavailable");
476
+ return { outward: config.humanFacing, inner: config.agentFacing };
477
+ }, null),
478
+ lastAutomatedEventRun: read("run_ledger", () => (0, run_ledger_1.readRunLedger)(agentRoot)
479
+ .filter((row) => row.sourceKind === "private-runtime" && row.senseOrHabit === "external-event" && row.lifecycle === "completed")
480
+ .sort((left, right) => (right.endedAt ?? right.recordedAt).localeCompare(left.endedAt ?? left.recordedAt))[0] ?? null, null),
481
+ senseStatusLines: read("senses", () => (0, turn_context_1.readSenseStatusLines)(), []),
482
+ sourceErrors,
483
+ };
484
+ }
485
+ function formatButlerOperationalVisibility(status, options = {}) {
486
+ const section = options.section ?? "all";
487
+ const offset = Math.max(0, options.offset ?? 0);
488
+ const limit = Math.min(20, Math.max(1, options.limit ?? 10));
489
+ const show = (wanted) => section === "all" || section === wanted;
490
+ const page = (rows) => rows.slice(offset, offset + limit);
491
+ const more = (label, total) => total > offset + limit ? ` - ${total - offset - limit} more ${label}; call query_active_work with section=${label}, offset=${offset + limit}, limit=${limit}` : null;
492
+ const daemon = status.daemonHealth;
493
+ const agentHealth = daemon?.agents[status.agentName];
494
+ const lines = ["## butler operational visibility"];
495
+ const error = (source) => status.sourceErrors[source] ? `unavailable (${status.sourceErrors[source]})` : null;
496
+ if (show("health")) {
497
+ lines.push(`- daemon: ${error("daemon_health") ?? daemon?.status ?? "unavailable"}${daemon ? `; mode ${daemon.mode}; pid ${daemon.pid}` : ""}`);
498
+ lines.push(`- butler: ${agentHealth ? `${agentHealth.status}; pid ${agentHealth.pid ?? "none"}; crashes ${agentHealth.crashes}` : "unavailable"}`);
499
+ lines.push("- senses:");
500
+ lines.push(...(error("senses") ? [` - ${error("senses")}`] : status.senseStatusLines.length > 0 ? status.senseStatusLines.map((line) => ` ${line}`) : [" - unavailable"]));
501
+ const health = status.healthState;
502
+ lines.push(`- health sweeps: ${error("health_state") ?? health?.sweepReceipts.length ?? 0}; delivered ${health?.deliveredReceipts.length ?? 0}; indeterminate ${health?.indeterminateDeliveries.length ?? 0}; outbox ${health?.outbox ? `${health.outbox.status}:${health.outbox.id}` : "clear"}; open incidents ${health ? Object.keys(health.incidents).length : 0}; updated ${health?.updatedAt ?? "unavailable"}`);
503
+ const healthRows = [
504
+ ...(health?.sweepReceipts ?? []).map((sweep) => ({ at: sweep.completedAt, text: `sweep ${sweep.sweepId}: opened ${sweep.opened}; recovered ${sweep.recovered}; completed ${sweep.completedAt}${sweep.deliveryId ? `; delivery ${sweep.deliveryId}` : ""}` })),
505
+ ...(health?.deliveredReceipts ?? []).map((delivery) => ({ at: delivery.deliveredAt, text: `delivered ${delivery.deliveryId}: ${delivery.kind}; messages ${delivery.messageIds.join(",")}; at ${delivery.deliveredAt}` })),
506
+ ...(health?.indeterminateDeliveries ?? []).map((delivery) => ({ at: delivery.createdAt, text: `indeterminate ${delivery.id}: ${delivery.kind}; ${delivery.status}; created ${delivery.createdAt}` })),
507
+ ].sort((a, b) => b.at.localeCompare(a.at));
508
+ for (const row of page(healthRows))
509
+ lines.push(` - ${row.text}`);
510
+ const overflow = more("health", healthRows.length);
511
+ if (overflow)
512
+ lines.push(overflow);
513
+ }
514
+ if (show("provider"))
515
+ lines.push(`- provider lanes: ${error("provider") ?? (status.providerLanes ? `outward ${status.providerLanes.outward.provider}/${status.providerLanes.outward.model}; inner ${status.providerLanes.inner.provider}/${status.providerLanes.inner.model}` : "unavailable")}`);
516
+ if (show("policy")) {
517
+ lines.push(`- steward policy: ${error("steward_policy") ?? `version ${status.stewardPolicy.version}; ${Object.keys(status.stewardPolicy.desiredStates).length} desired states; ${Object.keys(status.stewardPolicy.routineActionGrants).length} routine grants`}`);
518
+ const entries = [...Object.entries(status.stewardPolicy.desiredStates).map(([key, value]) => ({ key, kind: "desired", value })), ...Object.entries(status.stewardPolicy.routineActionGrants).map(([key, value]) => ({ key, kind: "grant", value }))];
519
+ for (const entry of page(entries)) {
520
+ const expiry = entry.value.expiresAt;
521
+ const active = !expiry || Date.parse(expiry) > Date.now();
522
+ lines.push(entry.kind === "desired" ? ` - ${entry.key} = ${boundedStatusText(entry.value.value)}; ${active ? "active" : "expired"}; ${entry.value.provenance}; source ${boundedStatusText(entry.value.source)}; v${entry.value.version}${expiry ? `; expires ${expiry}` : ""}` : ` - ${entry.key}: ${entry.value.action} on ${entry.value.targets.join(", ")}; ${active ? "active" : "expired"}; max ${entry.value.maxCount}/${entry.value.windowMs}ms; ${entry.value.verificationRequired ? "verification required" : "no verification"}; v${entry.value.version}${expiry ? `; expires ${expiry}` : ""}`);
523
+ }
524
+ const overflow = more("policy", entries.length);
525
+ if (overflow)
526
+ lines.push(overflow);
527
+ }
528
+ if (show("actions")) {
529
+ const actions = [...(status.routineActions ?? [])].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
530
+ lines.push(`- routine action receipts: ${error("routine_actions") ?? actions.length}`);
531
+ for (const action of page(actions)) {
532
+ const verification = action.state === "verified" ? `verified ${action.verifiedAfterState ?? "state unavailable"}` : action.state === "failed" ? "failed" : action.state === "indeterminate" ? "indeterminate; manual inspection required" : action.state === "recovered_no_effect" ? "no effect occurred" : "pending";
533
+ lines.push(` - ${action.id}: ${action.action} ${action.target}; ${action.state}; updated ${action.updatedAt}; verification ${verification}`);
534
+ }
535
+ const overflow = more("actions", actions.length);
536
+ if (overflow)
537
+ lines.push(overflow);
538
+ }
539
+ if (show("awaits")) {
540
+ lines.push(`- pending awaits: ${status.awaits.length}`);
541
+ if (error("awaits"))
542
+ lines.push(` - ${error("awaits")}`);
543
+ for (const pending of page(status.awaits))
544
+ lines.push(` - ${pending.name}: ${boundedStatusText(pending.condition ?? (pending.body || "condition unavailable"))}${pending.wake_at ? `; wake ${pending.wake_at}` : ""}`);
545
+ const overflow = more("awaits", status.awaits.length);
546
+ if (overflow)
547
+ lines.push(overflow);
548
+ }
549
+ if (show("telegram")) {
550
+ const acceptedTimes = status.telegramEffects.flatMap((effect) => effect.acceptedAt ? [effect.acceptedAt] : []).sort().reverse();
551
+ const recordedTimes = status.telegramEffects.flatMap((effect) => effect.sessionRecordedAt ? [effect.sessionRecordedAt] : []).sort().reverse();
552
+ const legacyAccepted = status.telegramEffects.some((effect) => !effect.acceptedAt && (effect.state === "accepted" || effect.state === "session_recorded"));
553
+ const legacyRecorded = status.telegramEffects.some((effect) => !effect.sessionRecordedAt && effect.state === "session_recorded");
554
+ lines.push(`- latest Telegram accepted: ${acceptedTimes[0] ?? (legacyAccepted ? "timestamp unavailable (legacy artifacts present)" : "none")}; latest session recorded: ${recordedTimes[0] ?? (legacyRecorded ? "timestamp unavailable (legacy artifacts present)" : "none")}`);
555
+ lines.push(`- Telegram effects: ${error("telegram_effects") ?? status.telegramEffects.length}`);
556
+ lines.push(`- Telegram admissions: ${error("telegram_admissions") ?? status.telegramAdmissions.length}`);
557
+ const telegramRows = [
558
+ ...status.telegramEffects.map((effect) => ({ at: effect.updatedAt, effect })),
559
+ ...status.telegramAdmissions.map((admission) => ({ at: new Date(admission.createdAt).toISOString(), admission })),
560
+ ].sort((a, b) => b.at.localeCompare(a.at));
561
+ for (const row of page(telegramRows)) {
562
+ if ("admission" in row) {
563
+ const admission = row.admission;
564
+ lines.push(` - admission ${admission.id}: ${admission.status}; code ${admission.displayCode}; expires ${new Date(admission.expiresAt).toISOString()}`);
565
+ continue;
566
+ }
567
+ const effect = row.effect;
568
+ const accepted = effect.acceptedAt ?? ((effect.state === "accepted" || effect.state === "session_recorded") ? "timestamp unavailable (legacy)" : "not accepted");
569
+ const recorded = effect.sessionRecordedAt ?? (effect.state === "session_recorded" ? "timestamp unavailable (legacy)" : "not recorded");
570
+ lines.push(` - ${effect.id}: ${effect.state}; ${effect.authorClass}; ${effect.targetKind}; accepted ${accepted}; session recorded ${recorded}; message ids ${effect.messageIds?.join(",") || "none"}; session events ${effect.sessionEventIds?.join(",") || "none"}; updated ${effect.updatedAt}`);
571
+ }
572
+ const overflow = more("telegram", telegramRows.length);
573
+ if (overflow)
574
+ lines.push(overflow);
575
+ }
576
+ if (show("events")) {
577
+ const events = [...status.externalEvents].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
578
+ const completedRun = status.lastAutomatedEventRun;
579
+ lines.push(`- external issues: ${events.length}; last successful automated event turn ${error("run_ledger") ?? (completedRun ? `${completedRun.endedAt ?? completedRun.recordedAt}; run ${completedRun.runId}; target ${completedRun.targetHash}` : "none")}`);
580
+ if (error("external_events"))
581
+ lines.push(` - ${error("external_events")}`);
582
+ for (const event of page(events)) {
583
+ const policy = event.stewardPolicy?.kind === "current" ? `${event.stewardPolicy.key}@${event.stewardPolicy.version}` : "none";
584
+ lines.push(` - ${event.source}/${event.eventType}/${event.eventId}: ${event.executionState}; disposition ${event.classification ?? "pending"}/${event.decision ?? "pending"}; reason ${boundedStatusText(event.reason ?? event.lastError ?? "not yet recorded")}; silence/wake ${event.nextWake ? JSON.stringify(event.nextWake) : "pending"}; steward ${policy}${event.awaitId ? `; await ${event.awaitId}` : ""}${event.careId ? `; care ${event.careId}` : ""}`);
585
+ }
586
+ const overflow = more("events", events.length);
587
+ if (overflow)
588
+ lines.push(overflow);
589
+ }
590
+ return lines.join("\n");
591
+ }
592
+ function findDelegatingBridgeId(ctx) {
593
+ const currentSession = ctx?.currentSession;
594
+ if (!currentSession)
595
+ return undefined;
596
+ return ctx?.activeBridges?.find((bridge) => bridge.lifecycle === "active"
597
+ && bridge.attachedSessions.some((session) => session.friendId === currentSession.friendId
598
+ && session.channel === currentSession.channel
599
+ && session.key === currentSession.key))?.id;
600
+ }
601
+ function sendMessageRiskProfile(args) {
602
+ if (args.friendId?.trim() === "self") {
603
+ return {
604
+ mutates: "private_attention_write",
605
+ risk: "high",
606
+ reason: "queues private-runtime attention without contacting an external session",
607
+ };
608
+ }
609
+ return {
610
+ mutates: ["durable_state_write", "external_side_effect"],
611
+ risk: "high",
612
+ reason: "queues or delivers messages across sessions/channels",
613
+ };
614
+ }
615
+ function renderInnerProgressStatus(status) {
616
+ if (status.processing === "pending") {
617
+ return "i've queued this thought for private attention. it'll come up when my private runtime is free.";
618
+ }
619
+ if (status.processing === "started") {
620
+ return "i'm working through this privately right now.";
621
+ }
622
+ // processed / completed
623
+ if (status.surfaced && status.surfaced !== "nothing recent" && status.surfaced !== "no outward result") {
624
+ return `i thought about this privately and came to something: ${status.surfaced}`;
625
+ }
626
+ return "i thought about this privately. i'll bring it back when the time is right.";
627
+ }
628
+ exports.sessionToolDefinitions = [
629
+ {
630
+ tool: {
631
+ type: "function",
632
+ function: {
633
+ name: "query_active_work",
634
+ description: "read the current live world-state across visible sessions, coding lanes, private-runtime work, and return obligations. Sanctuary operational details support bounded section/offset/limit paging.",
635
+ parameters: {
636
+ type: "object",
637
+ properties: {
638
+ section: { type: "string", enum: ["all", "health", "policy", "awaits", "telegram", "events", "actions", "provider"], description: "Sanctuary detail section; defaults to all" },
639
+ offset: { type: "string", description: "zero-based detail offset; defaults to 0" },
640
+ limit: { type: "string", description: "detail rows per section, 1-20; defaults to 10" },
641
+ },
642
+ },
643
+ },
644
+ },
645
+ handler: async (args, ctx) => {
646
+ const frame = await buildToolActiveWorkFrame(ctx);
647
+ const activeWork = `this is my current top-level live world-state.\nanswer whole-self status questions from this before drilling into individual sessions.\n\n${(0, active_work_1.formatActiveWorkFrame)(frame)}`;
648
+ const numeric = (value, fallback, min, max) => value === undefined ? fallback : /^\d+$/u.test(value) ? Math.min(max, Math.max(min, Number(value))) : fallback;
649
+ return (0, identity_1.getAgentName)() === "sanctuary"
650
+ ? `${activeWork}\n\n${formatButlerOperationalVisibility(readButlerOperationalVisibility(), { section: args.section, offset: numeric(args.offset, 0, 0, 10_000), limit: numeric(args.limit, 10, 1, 20) })}`
651
+ : activeWork;
652
+ },
653
+ },
654
+ {
655
+ tool: {
656
+ type: "function",
657
+ function: {
658
+ name: "session_summary",
659
+ description: "read-only orientation for habit runs. returns a structured live summary from habit receipts, session files, pending dirs, and runtime cursors without writing state.",
660
+ parameters: {
661
+ type: "object",
662
+ properties: {
663
+ runId: { type: "string", description: "exact habit run id; cannot be combined with habitName, operationId, or which" },
664
+ habitName: { type: "string", description: "habit name to select from" },
665
+ operationId: { type: "string", description: "operation id for stateful habit run groups, such as habit:heartbeat" },
666
+ which: {
667
+ type: "string",
668
+ enum: ["latest", "previous", "latest-success", "latest-failure"],
669
+ description: "which matching run to read; defaults to latest",
670
+ },
671
+ },
672
+ },
673
+ },
674
+ },
675
+ handler: (args, ctx) => {
676
+ const validation = validateSessionSummarySelector(args);
677
+ if (!validation.ok) {
678
+ return JSON.stringify({
679
+ kind: "invalid_selector",
680
+ code: validation.code,
681
+ message: validation.message,
682
+ }, null, 2);
683
+ }
684
+ (0, tool_arguments_1.assertRelationshipToolOwner)(ctx);
685
+ const summary = (0, habit_session_summary_1.readHabitSessionSummary)(ctx?.agentRoot ?? (0, identity_1.getAgentRoot)(ctx?.agentName), validation.selector);
686
+ if (!summary) {
687
+ return JSON.stringify({
688
+ kind: "not_found",
689
+ message: "no habit run matched selector",
690
+ selector: validation.selector,
691
+ }, null, 2);
692
+ }
693
+ return JSON.stringify({
694
+ kind: "habit_session_summary",
695
+ text: renderSessionSummaryText(summary),
696
+ summary,
697
+ }, null, 2);
698
+ },
699
+ riskProfile: {
700
+ mutates: "none",
701
+ risk: "low",
702
+ reason: "reads habit run summaries from local receipts and session artifacts",
703
+ },
704
+ summaryKeys: ["runId", "habitName", "operationId", "which"],
705
+ },
706
+ {
707
+ tool: {
708
+ type: "function",
709
+ function: {
710
+ name: "query_session",
711
+ description: "inspect another session. use transcript for recent context or status for self/private-runtime progress. deprecated search invocations should use search_facts, consult_diary, or consult_notes instead.",
712
+ parameters: {
713
+ type: "object",
714
+ properties: {
715
+ friendId: { type: "string", description: "the friend UUID (or 'self')" },
716
+ channel: { type: "string", description: "the channel: cli, teams, bluebubbles, voice, mcp, or legacy inner for private-runtime compatibility" },
717
+ key: { type: "string", description: "session key (defaults to 'session')" },
718
+ messageCount: { type: "string", description: "how many recent messages to return (default 20)" },
719
+ mode: {
720
+ type: "string",
721
+ enum: ["transcript", "status", "search"],
722
+ description: "transcript (default), lightweight status for self/private-runtime checks, or deprecated search; use search_facts, consult_diary, or consult_notes instead",
723
+ },
724
+ query: { type: "string", description: "deprecated when mode=search; use search_facts, consult_diary, or consult_notes instead" },
725
+ },
726
+ required: ["friendId", "channel"],
727
+ },
728
+ },
729
+ },
730
+ handler: async (args, ctx) => {
731
+ let friendId = args.friendId;
732
+ const channel = args.channel;
733
+ const key = args.key || "session";
734
+ const count = parseInt(args.messageCount || "20", 10);
735
+ const mode = args.mode || "transcript";
736
+ if (!(0, config_1.isValidSessionCoordinate)(friendId) || !(0, config_1.isValidSessionCoordinate)(channel)) {
737
+ (0, runtime_1.emitNervesEvent)({
738
+ level: "warn", component: "tools", event: "tool.session_path_rejected",
739
+ message: "session query rejected invalid coordinates", meta: { reason: "invalid friend or channel" },
740
+ });
741
+ return NO_SESSION_FOUND_MESSAGE;
742
+ }
743
+ (0, tool_arguments_1.assertRelationshipToolOwner)(ctx);
744
+ // Resolve friend name -> UUID if not already a UUID or "self"
745
+ if (friendId && friendId !== "self" && !/^[0-9a-f]{8}-[0-9a-f]{4}-/.test(friendId) && ctx?.friendStore?.listAll) {
746
+ const allFriends = await ctx.friendStore.listAll();
747
+ const match = allFriends.find(f => f.name.toLowerCase() === friendId.toLowerCase());
748
+ if (match) {
749
+ friendId = match.id;
750
+ }
751
+ }
752
+ if (mode === "status") {
753
+ if (friendId !== "self" || channel !== "inner") {
754
+ return "status mode is only available for self/private runtime.";
755
+ }
756
+ const agentRoot = ctx?.agentRoot ?? (0, identity_1.getAgentRoot)(ctx?.agentName);
757
+ const sessionPath = (0, thoughts_1.getPrivateRuntimeSessionPath)(agentRoot);
758
+ const pendingDir = (0, pending_1.getPrivateRuntimePendingDir)(ctx?.agentName ?? (0, identity_1.getAgentName)(), agentRoot);
759
+ return renderInnerProgressStatus((0, thoughts_1.readPrivateRuntimeStatus)(sessionPath, pendingDir));
760
+ }
761
+ if (mode === "search") {
762
+ return JSON.stringify({
763
+ kind: "deprecated",
764
+ message: "query_session mode=search is no longer available; use search_facts, consult_diary, or consult_notes instead.",
765
+ removalCycle: "alpha.616",
766
+ });
767
+ }
768
+ let sessFile;
769
+ try {
770
+ sessFile = (0, config_1.resolveSessionPath)(friendId, channel, key, {
771
+ agentRoot: ctx?.agentRoot ?? (0, identity_1.getAgentRoot)(ctx?.agentName), confined: true,
772
+ });
773
+ }
774
+ catch (error) {
775
+ if (!(error instanceof config_1.InvalidSessionPathError))
776
+ throw error;
777
+ (0, runtime_1.emitNervesEvent)({
778
+ level: "warn", component: "tools", event: "tool.session_path_rejected",
779
+ message: "session query rejected an unconfined path", meta: { reason: error.message },
780
+ });
781
+ return NO_SESSION_FOUND_MESSAGE;
782
+ }
783
+ const sessionTail = await summarizeSessionTailSafely({
784
+ sessionPath: sessFile,
785
+ friendId,
786
+ channel,
787
+ key,
788
+ messageCount: count,
789
+ trustLevel: ctx?.context?.friend?.trustLevel,
790
+ summarize: ctx?.summarize,
791
+ });
792
+ if (sessionTail.kind === "missing") {
793
+ return NO_SESSION_FOUND_MESSAGE;
794
+ }
795
+ if (sessionTail.kind === "empty") {
796
+ return EMPTY_SESSION_MESSAGE;
797
+ }
798
+ return sessionTail.summary;
799
+ },
800
+ },
801
+ {
802
+ tool: {
803
+ type: "function",
804
+ function: {
805
+ name: "send_message",
806
+ description: "send a message to a friend's session. when the request is explicitly authorized from a trusted live chat, the harness will try to deliver immediately; otherwise it reports truthful queued/block/failure state. do not use friendId=self for user-requested private-return work; use ponder so the typed return contract can be tracked and surfaced once.",
807
+ parameters: {
808
+ type: "object",
809
+ properties: {
810
+ friendId: { type: "string", description: "the friend UUID (or 'self')" },
811
+ channel: { type: "string", description: "the channel: cli, teams, bluebubbles, voice, mcp, or legacy inner for private-runtime compatibility. channel=voice intentionally starts a live phone call to a trusted friend through the Voice sense." },
812
+ key: { type: "string", description: "session key (defaults to 'session')" },
813
+ content: { type: "string", description: "the message content to send" },
814
+ voiceAudioSource: { type: "string", enum: ["tone", "url", "file"], description: "optional initial non-speech audio to play after the opening greeting when channel=voice" },
815
+ voiceAudioUrl: { type: "string", description: "short audio URL for voiceAudioSource=url" },
816
+ voiceAudioPath: { type: "string", description: "local audio file path for voiceAudioSource=file" },
817
+ voiceAudioLabel: { type: "string", description: "short label for the initial voice audio" },
818
+ voiceAudioToneHz: { type: "number", description: "tone frequency for voiceAudioSource=tone" },
819
+ voiceAudioDurationMs: { type: "number", description: "initial audio duration in milliseconds" },
820
+ },
821
+ required: ["friendId", "channel", "content"],
822
+ },
823
+ },
824
+ },
825
+ handler: async (args, ctx) => {
826
+ let friendId = args.friendId;
827
+ const channel = args.channel;
828
+ const key = args.key || "session";
829
+ const content = args.content;
830
+ const voiceInitialAudio = channel === "voice" ? parseVoiceInitialAudio(args) : undefined;
831
+ const now = Date.now();
832
+ const agentName = (0, identity_1.getAgentName)();
833
+ // Resolve friend name → UUID if needed
834
+ /* v8 ignore start -- name resolution: reads real filesystem, tested via live integration @preserve */
835
+ if (friendId !== "self") {
836
+ const originalFriendId = friendId;
837
+ try {
838
+ const agentRoot = (0, identity_1.getAgentRoot)();
839
+ const sessionsDir = path.join(agentRoot, "state", "sessions");
840
+ const friendsDir = path.join(agentRoot, "friends");
841
+ const sessionDirExists = fs.existsSync(path.join(sessionsDir, friendId));
842
+ if (!sessionDirExists) {
843
+ const friendFiles = fs.readdirSync(friendsDir).filter((f) => f.endsWith(".json"));
844
+ for (const file of friendFiles) {
845
+ const raw = fs.readFileSync(path.join(friendsDir, file), "utf-8");
846
+ const record = JSON.parse(raw);
847
+ if (record.name?.toLowerCase() === friendId.toLowerCase() && record.id) {
848
+ friendId = record.id;
849
+ break;
850
+ }
851
+ }
852
+ (0, runtime_1.emitNervesEvent)({
853
+ component: "repertoire",
854
+ event: "repertoire.send_message_name_resolve",
855
+ message: friendId !== originalFriendId ? "resolved friend name to UUID" : "friend name resolution failed",
856
+ meta: { original: originalFriendId, resolved: friendId, friendsDir, fileCount: friendFiles.length },
857
+ });
858
+ }
859
+ }
860
+ catch (err) {
861
+ (0, runtime_1.emitNervesEvent)({
862
+ level: "warn",
863
+ component: "repertoire",
864
+ event: "repertoire.send_message_name_resolve_error",
865
+ message: "friend name resolution threw",
866
+ meta: { friendId: originalFriendId, error: err instanceof Error ? err.message : String(err) },
867
+ });
868
+ }
869
+ }
870
+ /* v8 ignore stop */
871
+ // Self-routing: messages to "self" always go to the private-runtime pending dir,
872
+ // regardless of the channel or key the agent specified.
873
+ const isSelf = friendId === "self";
874
+ const pendingDir = isSelf
875
+ ? (0, pending_1.getPrivateRuntimePendingDir)(agentName)
876
+ : (0, pending_1.getPendingDir)(agentName, friendId, channel, key);
877
+ const delegatingBridgeId = findDelegatingBridgeId(ctx);
878
+ const delegatedFrom = isSelf
879
+ && ctx?.currentSession
880
+ && !(ctx.currentSession.friendId === "self" && ctx.currentSession.channel === "inner")
881
+ ? {
882
+ friendId: ctx.currentSession.friendId,
883
+ channel: ctx.currentSession.channel,
884
+ key: ctx.currentSession.key,
885
+ ...(delegatingBridgeId ? { bridgeId: delegatingBridgeId } : {}),
886
+ }
887
+ : undefined;
888
+ const obligationId = delegatedFrom ? (0, obligations_1.generateObligationId)(now) : undefined;
889
+ const envelope = {
890
+ from: agentName,
891
+ friendId,
892
+ channel,
893
+ key,
894
+ content,
895
+ timestamp: now,
896
+ ...(delegatedFrom ? { delegatedFrom, obligationStatus: "pending" } : {}),
897
+ ...(obligationId ? { obligationId } : {}),
898
+ };
899
+ if (isSelf) {
900
+ const pendingMessageId = writePendingEnvelope(pendingDir, envelope);
901
+ if (delegatedFrom) {
902
+ try {
903
+ (0, obligations_1.createObligation)((0, identity_1.getAgentRoot)(), {
904
+ origin: {
905
+ friendId: delegatedFrom.friendId,
906
+ channel: delegatedFrom.channel,
907
+ key: delegatedFrom.key,
908
+ },
909
+ ...(delegatedFrom.bridgeId ? { bridgeId: delegatedFrom.bridgeId } : {}),
910
+ content,
911
+ });
912
+ }
913
+ catch {
914
+ /* v8 ignore next -- defensive: obligation store write failure should not break send_message @preserve */
915
+ }
916
+ /* v8 ignore next -- obligationId always set when delegatedFrom is set (see generateObligationId above) @preserve */
917
+ if (obligationId) {
918
+ (0, obligations_1.createReturnObligation)(agentName, {
919
+ id: obligationId,
920
+ origin: delegatedFrom,
921
+ status: "queued",
922
+ delegatedContent: content.length > 120 ? `${content.slice(0, 117)}...` : content,
923
+ createdAt: now,
924
+ });
925
+ }
926
+ (0, runtime_1.emitNervesEvent)({
927
+ event: "repertoire.obligation_created",
928
+ component: "repertoire",
929
+ message: "obligation created for private-runtime delegation",
930
+ meta: {
931
+ friendId: delegatedFrom.friendId,
932
+ channel: delegatedFrom.channel,
933
+ key: delegatedFrom.key,
934
+ },
935
+ });
936
+ }
937
+ try {
938
+ await (0, socket_client_1.requestPrivateWake)(agentName, ctx?.daemonSocketPath, {
939
+ reason: "send_message self-route private attention",
940
+ triggerSource: "send-message-self-route",
941
+ budgetClass: "interactive",
942
+ idempotencyKey: `send-message-self-route:${agentName}:${pendingMessageId}`,
943
+ originRefs: [
944
+ { kind: "tool", id: "send_message" },
945
+ { kind: "pending-queue", id: "self/inner/dialog" },
946
+ { kind: "pending-message", id: pendingMessageId },
947
+ ],
948
+ });
949
+ }
950
+ catch {
951
+ // Queue-first self routing must not inline-run private work when the daemon is unavailable.
952
+ }
953
+ return renderInnerProgressStatus({
954
+ queue: "queued to private runtime",
955
+ wake: "daemon requested",
956
+ processing: "pending",
957
+ surfaced: "nothing yet",
958
+ });
959
+ }
960
+ // Resolve BB session key if using default — agents don't know the real session key
961
+ /* v8 ignore start -- BB session key resolution: reads real filesystem @preserve */
962
+ let resolvedKey = key;
963
+ if (channel === "bluebubbles" && key === "session") {
964
+ try {
965
+ const agentRoot = (0, identity_1.getAgentRoot)();
966
+ const bbDir = path.join(agentRoot, "state", "sessions", friendId, "bluebubbles");
967
+ if (fs.existsSync(bbDir)) {
968
+ const files = fs.readdirSync(bbDir).filter((f) => f.endsWith(".json"));
969
+ // Only use DM sessions (;-;) for proactive delivery — never group chats (;+;)
970
+ const dmFile = files.find((f) => f.includes(";-;"));
971
+ if (dmFile) {
972
+ resolvedKey = dmFile.replace(/\.json$/, "");
973
+ }
974
+ }
975
+ }
976
+ catch { /* continue with default key */ }
977
+ }
978
+ /* v8 ignore stop */
979
+ const deliveryResult = await (0, cross_chat_delivery_1.deliverCrossChatMessage)({
980
+ friendId,
981
+ channel,
982
+ key: resolvedKey,
983
+ content,
984
+ intent: ctx?.currentSession && ctx.currentSession.friendId !== "self"
985
+ ? "explicit_cross_chat"
986
+ : "generic_outreach",
987
+ ...(ctx?.currentSession && ctx.currentSession.friendId !== "self"
988
+ ? {
989
+ authorizingSession: {
990
+ friendId: ctx.currentSession.friendId,
991
+ channel: ctx.currentSession.channel,
992
+ key: ctx.currentSession.key,
993
+ trustLevel: ctx?.context?.friend?.trustLevel,
994
+ },
995
+ }
996
+ : {}),
997
+ }, {
998
+ agentName,
999
+ queuePending: (message) => writePendingEnvelope(pendingDir, message),
1000
+ deliverers: {
1001
+ bluebubbles: async (request) => {
1002
+ const { sendProactiveBlueBubblesMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/bluebubbles")));
1003
+ const result = await sendProactiveBlueBubblesMessageToSession({
1004
+ friendId: request.friendId,
1005
+ sessionKey: request.key,
1006
+ text: request.content,
1007
+ intent: request.intent,
1008
+ authorizingSession: request.authorizingSession,
1009
+ });
1010
+ if (result.delivered) {
1011
+ return {
1012
+ status: "delivered_now",
1013
+ detail: "sent to the active bluebubbles chat now",
1014
+ };
1015
+ }
1016
+ if (result.reason === "missing_target") {
1017
+ return {
1018
+ status: "blocked",
1019
+ detail: "bluebubbles could not resolve a routable target for that session",
1020
+ };
1021
+ }
1022
+ if (result.reason === "blocked_meta_content") {
1023
+ return {
1024
+ status: "blocked",
1025
+ detail: "blocked: contains internal meta markers",
1026
+ };
1027
+ }
1028
+ if (result.reason === "send_error") {
1029
+ return {
1030
+ status: "failed",
1031
+ detail: "bluebubbles send failed",
1032
+ };
1033
+ }
1034
+ return {
1035
+ status: "unavailable",
1036
+ detail: "live delivery unavailable right now; queued for the next active turn",
1037
+ };
1038
+ },
1039
+ teams: async (request) => {
1040
+ if (!ctx?.botApi) {
1041
+ return {
1042
+ status: "unavailable",
1043
+ detail: "live delivery unavailable right now; queued for the next active turn",
1044
+ };
1045
+ }
1046
+ const { sendProactiveTeamsMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/teams")));
1047
+ const result = await sendProactiveTeamsMessageToSession({
1048
+ friendId: request.friendId,
1049
+ sessionKey: request.key,
1050
+ text: request.content,
1051
+ intent: request.intent,
1052
+ authorizingSession: request.authorizingSession,
1053
+ }, {
1054
+ botApi: ctx.botApi,
1055
+ });
1056
+ if (result.delivered) {
1057
+ return {
1058
+ status: "delivered_now",
1059
+ detail: "sent to the active teams chat now",
1060
+ };
1061
+ }
1062
+ if (result.reason === "missing_target") {
1063
+ return {
1064
+ status: "blocked",
1065
+ detail: "teams could not resolve a routable target for that session",
1066
+ };
1067
+ }
1068
+ if (result.reason === "send_error") {
1069
+ return {
1070
+ status: "failed",
1071
+ detail: "teams send failed",
1072
+ };
1073
+ }
1074
+ return {
1075
+ status: "unavailable",
1076
+ detail: "live delivery unavailable right now; queued for the next active turn",
1077
+ };
1078
+ },
1079
+ telegram: async (request) => {
1080
+ const key = (0, config_1.canonicalizeTelegramSessionKey)(request.key);
1081
+ const hash = (0, crypto_1.createHash)("sha256").update(`${request.friendId}\0${key}\0${request.content}`).digest("hex");
1082
+ const { sendTelegramAwaitFollowUp } = await Promise.resolve().then(() => __importStar(require("../senses/telegram")));
1083
+ return sendTelegramAwaitFollowUp(agentName, {
1084
+ ...request,
1085
+ key,
1086
+ requestId: request.requestId ?? `send-message:${hash}`,
1087
+ deliveryId: request.deliveryId ?? `send-message:${hash}`,
1088
+ });
1089
+ },
1090
+ voice: async (request) => deliverVoiceChannelMessage(request, agentName, voiceInitialAudio),
1091
+ },
1092
+ });
1093
+ recordHabitSendAttempt(ctx, { friendId, channel, key }, deliveryResult);
1094
+ return renderCrossChatDeliveryStatus(`${friendId} on ${channel}/${key}`, deliveryResult);
1095
+ },
1096
+ riskProfile: sendMessageRiskProfile,
1097
+ },
1098
+ {
1099
+ tool: {
1100
+ type: "function",
1101
+ function: {
1102
+ name: "set_reasoning_effort",
1103
+ description: "adjust your own reasoning depth for subsequent turns. use higher effort for complex analysis, lower for simple tasks.",
1104
+ parameters: {
1105
+ type: "object",
1106
+ properties: {
1107
+ level: { type: "string", description: "the reasoning effort level to set" },
1108
+ },
1109
+ required: ["level"],
1110
+ },
1111
+ },
1112
+ },
1113
+ handler: (args, ctx) => {
1114
+ if (!ctx?.supportedReasoningEfforts || !ctx.setReasoningEffort) {
1115
+ return "reasoning effort adjustment is not available in this context.";
1116
+ }
1117
+ const level = (args.level || "").trim();
1118
+ if (!ctx.supportedReasoningEfforts.includes(level)) {
1119
+ return `invalid reasoning effort level "${level}". accepted levels: ${ctx.supportedReasoningEfforts.join(", ")}`;
1120
+ }
1121
+ ctx.setReasoningEffort(level);
1122
+ (0, runtime_1.emitNervesEvent)({
1123
+ component: "repertoire",
1124
+ event: "repertoire.reasoning_effort_changed",
1125
+ message: `reasoning effort set to ${level}`,
1126
+ meta: { level },
1127
+ });
1128
+ return `reasoning effort set to "${level}".`;
1129
+ },
1130
+ requiredCapability: "reasoning-effort",
1131
+ summaryKeys: ["level"],
1132
+ },
1133
+ ];