@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,896 @@
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.FileTelegramEffectJournal = exports.FIXED_USENET_SYSTEM_FAILSAFE = exports.FIXED_ADMISSION_ACKNOWLEDGEMENT = void 0;
37
+ exports.prepareTelegramEffect = prepareTelegramEffect;
38
+ exports.executeTelegramEffect = executeTelegramEffect;
39
+ exports.createTelegramAuthorizedEffectExecutor = createTelegramAuthorizedEffectExecutor;
40
+ exports.reconcileTelegramSystemFailsafe = reconcileTelegramSystemFailsafe;
41
+ exports.sweepTelegramSystemFailsafes = sweepTelegramSystemFailsafes;
42
+ exports.recoverTelegramEffectOutbox = recoverTelegramEffectOutbox;
43
+ exports.createTelegramApprovalEffectPort = createTelegramApprovalEffectPort;
44
+ exports.recordTelegramEffectInSession = recordTelegramEffectInSession;
45
+ exports.appendTelegramArtifactEvents = appendTelegramArtifactEvents;
46
+ exports.appendTelegramInboundEvent = appendTelegramInboundEvent;
47
+ exports.recordTelegramEffectsInSession = recordTelegramEffectsInSession;
48
+ exports.resolveTelegramReply = resolveTelegramReply;
49
+ exports.resolveTelegramControlArtifact = resolveTelegramControlArtifact;
50
+ const crypto = __importStar(require("node:crypto"));
51
+ const fs = __importStar(require("node:fs"));
52
+ const path = __importStar(require("node:path"));
53
+ const runtime_1 = require("../nerves/runtime");
54
+ const router_1 = require("../heart/external-events/router");
55
+ const session_events_1 = require("../heart/session-events");
56
+ const session_transaction_1 = require("../mind/session-transaction");
57
+ const telegram_client_1 = require("./telegram-client");
58
+ exports.FIXED_ADMISSION_ACKNOWLEDGEMENT = "Thanks — I’ve asked Ari. Your message is still unread and unprocessed; I’ll only read it if Ari welcomes you in.";
59
+ exports.FIXED_USENET_SYSTEM_FAILSAFE = "Quick heads-up: I paused downloads because the server was discarding most of what it fetched. Nothing needs doing this second — I’ll investigate and follow up when I’m back online.";
60
+ const SYSTEM_FAILSAFE_UNAVAILABLE_MS = 2 * 60_000;
61
+ function isTransportOnlyControl(artifact) {
62
+ return artifact.authorClass === "control" && artifact.effect.kind !== "text";
63
+ }
64
+ function artifactId(idempotencyKey) {
65
+ return crypto.createHash("sha256").update(idempotencyKey).digest("hex");
66
+ }
67
+ function requireText(value, label) {
68
+ if (!value.trim())
69
+ throw new Error(`${label} must be nonempty`);
70
+ return value;
71
+ }
72
+ function preparedTexts(effect) {
73
+ if (effect.kind === "text" || effect.kind === "admission_ack")
74
+ return (0, telegram_client_1.splitTelegramText)(requireText(effect.text, "Telegram text"));
75
+ if (effect.kind === "card" || effect.kind === "edit")
76
+ return [requireText(effect.text, "Telegram text")];
77
+ return [effect.text?.trim() || null];
78
+ }
79
+ // Bold spans may carry one level of emphasis inside them, because `**bold with
80
+ // *italic* inside**` is ordinary model prose. The inner span is rendered by the
81
+ // same conservative scan, so a bold run that does not resolve cleanly still
82
+ // degrades the whole message to literal text rather than emitting partial
83
+ // markup. Everything else stays as strict as before: a span must open on a
84
+ // letter or digit and close on a non-space, which is what keeps `**/src/**`,
85
+ // `2 ** 3` and `a_b_c` literal.
86
+ const TELEGRAM_BOLD_WITH_NESTING = /`([^`\n]+)`|\*\*([\p{L}\p{N}](?:[^*_`\n]|\*(?!\*)|_)*\S|[\p{L}\p{N}])\*\*|\*([\p{L}\p{N}](?:[^*_`\n]*\S)?)\*|_([\p{L}\p{N}](?:[^*_`\n]*\S)?)_/gu;
87
+ const TELEGRAM_EMPHASIS_ONLY = /`([^`\n]+)`|\*([\p{L}\p{N}](?:[^*_`\n]*\S)?)\*|_([\p{L}\p{N}](?:[^*_`\n]*\S)?)_/gu;
88
+ function renderTelegramButlerHtml(text) {
89
+ return renderTelegramStyledSpan(text, true) ?? (0, telegram_client_1.escapeTelegramHtml)(text);
90
+ }
91
+ // Returns null when the span cannot be rendered cleanly, so every caller falls
92
+ // back to escaping rather than emitting half-applied markup.
93
+ function renderTelegramStyledSpan(text, allowBold) {
94
+ let html = "";
95
+ let cursor = 0;
96
+ const pattern = allowBold ? TELEGRAM_BOLD_WITH_NESTING : TELEGRAM_EMPHASIS_ONLY;
97
+ pattern.lastIndex = 0;
98
+ for (const match of text.matchAll(pattern)) {
99
+ const gap = text.slice(cursor, match.index);
100
+ if (/[*_`]/u.test(gap))
101
+ return null;
102
+ html += (0, telegram_client_1.escapeTelegramHtml)(gap);
103
+ const code = match[1];
104
+ const bold = allowBold ? match[2] : undefined;
105
+ const italic = allowBold ? match[3] : match[2];
106
+ const underscored = allowBold ? match[4] : match[3];
107
+ if (code !== undefined)
108
+ html += `<code>${(0, telegram_client_1.escapeTelegramHtml)(code)}</code>`;
109
+ else if (bold !== undefined) {
110
+ const inner = renderTelegramStyledSpan(bold, false);
111
+ if (inner === null)
112
+ return null;
113
+ html += `<b>${inner}</b>`;
114
+ // A single-marker span is bold at the top level, which is the long-standing
115
+ // convention here, but inside a bold run it is the nested emphasis the
116
+ // author meant - and nesting <b> in <b> would be markup Telegram has no
117
+ // reason to accept.
118
+ }
119
+ else if (italic !== undefined)
120
+ html += allowBold ? `<b>${(0, telegram_client_1.escapeTelegramHtml)(italic)}</b>` : `<i>${(0, telegram_client_1.escapeTelegramHtml)(italic)}</i>`;
121
+ else
122
+ html += `<i>${(0, telegram_client_1.escapeTelegramHtml)(underscored)}</i>`;
123
+ cursor = match.index + match[0].length;
124
+ }
125
+ const tail = text.slice(cursor);
126
+ return /[*_`]/u.test(tail) ? null : html + (0, telegram_client_1.escapeTelegramHtml)(tail);
127
+ }
128
+ function assertEffectTarget(target, effect, idempotencyKey) {
129
+ if (target.kind === "admission_gate") {
130
+ if (effect.kind !== "admission_ack" || effect.text !== exports.FIXED_ADMISSION_ACKNOWLEDGEMENT || idempotencyKey !== `ack:${target.admissionId}`) {
131
+ throw new Error("admission targets allow only the fixed admission acknowledgement");
132
+ }
133
+ }
134
+ else if (effect.kind === "admission_ack") {
135
+ throw new Error("fixed admission acknowledgement requires an admission target");
136
+ }
137
+ }
138
+ function canonicalTarget(target) {
139
+ if (!target || typeof target !== "object")
140
+ throw new Error("Telegram effect artifact is invalid");
141
+ if (target.kind === "admission_gate")
142
+ return target;
143
+ return {
144
+ kind: "approved_relationship",
145
+ friendId: target.friendId,
146
+ sessionKey: target.sessionKey,
147
+ ...(target.requestId ? { requestId: target.requestId } : {}),
148
+ };
149
+ }
150
+ function boundedText(value, max = 50_000) {
151
+ return typeof value === "string" && value.length > 0 && Buffer.byteLength(value, "utf8") <= max;
152
+ }
153
+ function canonicalTime(value) {
154
+ return typeof value === "string" && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
155
+ }
156
+ function validateArtifact(artifact, expectedId) {
157
+ const target = artifact?.target;
158
+ const effect = artifact?.effect;
159
+ const targetValid = target?.kind === "approved_relationship"
160
+ ? boundedText(target.friendId, 512) && boundedText(target.sessionKey, 512)
161
+ && (target.requestId === undefined || boundedText(target.requestId, 512))
162
+ : target?.kind === "admission_gate" && boundedText(target.admissionId, 512) && /^[1-9][0-9]*$/u.test(target.botId)
163
+ && /^[1-9][0-9]*$/u.test(target.userId) && /^[1-9][0-9]*$/u.test(target.chatId);
164
+ const effectValid = effect?.kind === "text" || effect?.kind === "admission_ack"
165
+ ? boundedText(effect.text, 150_000)
166
+ : effect?.kind === "card"
167
+ ? boundedText(effect.text) && Array.isArray(effect.buttons) && effect.buttons.length > 0 && effect.buttons.length <= 20
168
+ && effect.buttons.every((row) => Array.isArray(row) && row.length > 0 && row.length <= 8
169
+ && row.every((button) => boundedText(button?.text, 256) && boundedText(button?.callbackData, 64) && Buffer.byteLength(button.callbackData, "utf8") <= 64))
170
+ : effect?.kind === "edit"
171
+ ? Number.isSafeInteger(effect.messageId) && effect.messageId > 0 && boundedText(effect.text)
172
+ : effect?.kind === "callback_ack"
173
+ ? boundedText(effect.callbackQueryId, 512) && (effect.text === undefined || boundedText(effect.text, 512)) && (effect.showAlert === undefined || typeof effect.showAlert === "boolean")
174
+ : false;
175
+ let expectedTexts = [];
176
+ try {
177
+ if (targetValid && effectValid) {
178
+ assertEffectTarget(target, effect, artifact.idempotencyKey);
179
+ expectedTexts = preparedTexts(effect);
180
+ }
181
+ }
182
+ catch {
183
+ expectedTexts = [];
184
+ }
185
+ const partsValid = Array.isArray(artifact.parts) && artifact.parts.length === expectedTexts.length && artifact.parts.length > 0 && artifact.parts.length <= 100
186
+ && artifact.parts.every((part, index) => part.index === index && part.text === expectedTexts[index]
187
+ && ["prepared", "attempting", "accepted", "session_recorded", "indeterminate"].includes(part.state)
188
+ && canonicalTime(part.updatedAt)
189
+ && (part.acceptedAt === undefined || canonicalTime(part.acceptedAt))
190
+ && (part.sessionRecordedAt === undefined || canonicalTime(part.sessionRecordedAt))
191
+ && (part.messageId === undefined || (Number.isSafeInteger(part.messageId) && part.messageId > 0))
192
+ && (part.sessionEventId === undefined || boundedText(part.sessionEventId, 512))
193
+ && (part.attempts === undefined || (Number.isSafeInteger(part.attempts) && part.attempts >= 0 && part.attempts <= 100))
194
+ && (part.state === "session_recorded"
195
+ ? (boundedText(part.sessionEventId, 512) || (isTransportOnlyControl(artifact) && part.sessionEventId === undefined))
196
+ : part.sessionEventId === undefined)
197
+ && ((effect.kind === "callback_ack" || part.state === "prepared" || part.state === "attempting" || part.state === "indeterminate")
198
+ || (Number.isSafeInteger(part.messageId) && part.messageId > 0)));
199
+ if (artifact.schemaVersion !== 1 || artifact.id !== expectedId || artifact.id !== artifactId(artifact.idempotencyKey)
200
+ || !boundedText(artifact.idempotencyKey, 1024) || !targetValid || !effectValid || expectedTexts.length === 0
201
+ || !["butler", "control", "system_failsafe"].includes(artifact.authorClass)
202
+ || !boundedText(artifact.authorizationReceiptId, 1024) || !canonicalTime(artifact.authorizationExpiresAt)
203
+ || (artifact.obligationReturnId !== undefined && !boundedText(artifact.obligationReturnId, 512))
204
+ || !canonicalTime(artifact.createdAt) || !canonicalTime(artifact.updatedAt) || !partsValid) {
205
+ throw new Error("Telegram effect artifact is invalid");
206
+ }
207
+ }
208
+ class FileTelegramEffectJournal {
209
+ root;
210
+ directoryFd;
211
+ descriptorRoot;
212
+ rootDevice;
213
+ rootInode;
214
+ closed = false;
215
+ constructor(root) {
216
+ this.root = root;
217
+ if (fs.existsSync(root)) {
218
+ const stat = fs.lstatSync(root);
219
+ if (stat.isSymbolicLink())
220
+ throw new Error("Telegram effect journal root must not be a symbolic link");
221
+ if (!stat.isDirectory())
222
+ throw new Error("Telegram effect journal root must be a directory");
223
+ }
224
+ else {
225
+ fs.mkdirSync(root, { recursive: true, mode: 0o700 });
226
+ }
227
+ this.directoryFd = fs.openSync(root, fs.constants.O_RDONLY | fs.constants.O_DIRECTORY | fs.constants.O_NOFOLLOW);
228
+ this.descriptorRoot = root;
229
+ fs.fchmodSync(this.directoryFd, 0o700);
230
+ const identity = fs.fstatSync(this.directoryFd);
231
+ this.rootDevice = identity.dev;
232
+ this.rootInode = identity.ino;
233
+ const verified = fs.lstatSync(root);
234
+ if (!verified.isDirectory() || verified.isSymbolicLink() || (verified.mode & 0o777) !== 0o700)
235
+ throw new Error("Telegram effect journal root is unsafe");
236
+ }
237
+ artifactPath(id) {
238
+ if (this.closed)
239
+ throw new Error("Telegram effect journal is closed");
240
+ if (!/^[a-f0-9]{64}$/u.test(id))
241
+ throw new Error("Telegram effect artifact id is invalid");
242
+ return path.join(this.descriptorRoot, `${id}.json`);
243
+ }
244
+ assertRootIdentity() {
245
+ const current = fs.lstatSync(this.root);
246
+ if (current.isSymbolicLink() || !current.isDirectory() || current.dev !== this.rootDevice || current.ino !== this.rootInode) {
247
+ throw new Error("Telegram effect journal root identity changed");
248
+ }
249
+ }
250
+ coordinationPath(id) {
251
+ if (!/^[a-f0-9]{64}$/u.test(id))
252
+ throw new Error("Telegram effect artifact id is invalid");
253
+ this.assertRootIdentity();
254
+ return path.join(path.dirname(this.root), `${path.basename(this.root)}.coordination`, id);
255
+ }
256
+ close() {
257
+ if (this.closed)
258
+ return;
259
+ this.closed = true;
260
+ fs.closeSync(this.directoryFd);
261
+ }
262
+ read(id) {
263
+ this.assertRootIdentity();
264
+ const filePath = this.artifactPath(id);
265
+ const fd = fs.openSync(filePath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
266
+ try {
267
+ this.assertRootIdentity();
268
+ const stat = fs.fstatSync(fd);
269
+ if (!stat.isFile() || stat.size < 2 || stat.size > 512 * 1024)
270
+ throw new Error("Telegram effect artifact is not a bounded regular file");
271
+ const raw = fs.readFileSync(fd, "utf8");
272
+ const artifact = JSON.parse(raw);
273
+ artifact.target = canonicalTarget(artifact.target);
274
+ validateArtifact(artifact, id);
275
+ if (raw.includes('"chatId"') && artifact.target.kind === "approved_relationship")
276
+ this.write(artifact);
277
+ return artifact;
278
+ }
279
+ finally {
280
+ fs.closeSync(fd);
281
+ }
282
+ }
283
+ readIfExists(id) {
284
+ const filePath = this.artifactPath(id);
285
+ return fs.existsSync(filePath) ? this.read(id) : null;
286
+ }
287
+ quarantineInvalid(id, reason) {
288
+ this.assertRootIdentity();
289
+ const filePath = this.artifactPath(id);
290
+ if (!fs.existsSync(filePath))
291
+ return;
292
+ const quarantineRoot = path.join(path.dirname(this.root), `${path.basename(this.root)}.quarantine`);
293
+ fs.mkdirSync(quarantineRoot, { recursive: true, mode: 0o700 });
294
+ fs.chmodSync(quarantineRoot, 0o700);
295
+ const quarantinePath = path.join(quarantineRoot, `${id}.${Date.now()}.${process.pid}.invalid.json`);
296
+ fs.renameSync(filePath, quarantinePath);
297
+ fs.chmodSync(quarantinePath, 0o600);
298
+ (0, runtime_1.emitNervesEvent)({
299
+ level: "error",
300
+ component: "senses",
301
+ event: "senses.telegram_effect_artifact_quarantined",
302
+ message: "quarantined invalid Telegram effect artifact",
303
+ meta: { artifactId: id, reason },
304
+ });
305
+ }
306
+ write(artifact) {
307
+ this.assertRootIdentity();
308
+ const filePath = this.artifactPath(artifact.id);
309
+ const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
310
+ const fd = fs.openSync(tempPath, "wx", 0o600);
311
+ try {
312
+ this.assertRootIdentity();
313
+ fs.writeFileSync(fd, `${JSON.stringify(artifact, null, 2)}\n`, "utf8");
314
+ fs.fsyncSync(fd);
315
+ }
316
+ finally {
317
+ fs.closeSync(fd);
318
+ }
319
+ this.assertRootIdentity();
320
+ fs.renameSync(tempPath, filePath);
321
+ fs.chmodSync(filePath, 0o600);
322
+ fs.fsyncSync(this.directoryFd);
323
+ this.assertRootIdentity();
324
+ }
325
+ list() {
326
+ this.assertRootIdentity();
327
+ const entries = fs.readdirSync(this.descriptorRoot, { withFileTypes: true });
328
+ this.assertRootIdentity();
329
+ return entries
330
+ .filter((entry) => entry.isFile() && /^[a-f0-9]{64}\.json$/u.test(entry.name))
331
+ .map((entry) => this.read(entry.name.slice(0, -5)));
332
+ }
333
+ listRecoverable() {
334
+ this.assertRootIdentity();
335
+ const entries = fs.readdirSync(this.descriptorRoot, { withFileTypes: true });
336
+ this.assertRootIdentity();
337
+ const artifacts = [];
338
+ for (const entry of entries.filter((candidate) => candidate.isFile() && /^[a-f0-9]{64}\.json$/u.test(candidate.name))) {
339
+ const id = entry.name.slice(0, -5);
340
+ try {
341
+ artifacts.push(this.read(id));
342
+ }
343
+ catch (error) {
344
+ (0, runtime_1.emitNervesEvent)({
345
+ level: "error",
346
+ component: "senses",
347
+ event: "senses.telegram_effect_recovery_artifact_skipped",
348
+ message: "skipped invalid Telegram effect artifact during recovery",
349
+ meta: { artifactId: id, error: error instanceof Error ? error.message : String(error) },
350
+ });
351
+ }
352
+ }
353
+ return artifacts;
354
+ }
355
+ }
356
+ exports.FileTelegramEffectJournal = FileTelegramEffectJournal;
357
+ function prepareTelegramEffect(store, input) {
358
+ if (!input.authorization.allowed)
359
+ throw new Error(`Telegram effect authorization denied: ${input.authorization.reason}`);
360
+ if (!/^[1-9][0-9]*$/u.test(input.authorization.transport.chatId))
361
+ throw new Error("Telegram effect authorization returned an invalid transport route");
362
+ const idempotencyKey = requireText(input.idempotencyKey, "Telegram effect idempotency key");
363
+ const target = canonicalTarget(input.target);
364
+ assertEffectTarget(target, input.effect, idempotencyKey);
365
+ if (target.kind === "admission_gate" && input.authorization.transport.chatId !== target.chatId)
366
+ throw new Error("Telegram admission transport route changed");
367
+ const id = artifactId(idempotencyKey);
368
+ let existing = null;
369
+ try {
370
+ existing = store.readIfExists(id);
371
+ }
372
+ catch (error) {
373
+ if (!isTransportOnlyControl({ authorClass: input.authorClass, effect: input.effect, target }))
374
+ throw error;
375
+ store.quarantineInvalid(id, error instanceof Error ? error.message : String(error));
376
+ }
377
+ if (existing) {
378
+ if (JSON.stringify(existing.target) !== JSON.stringify(target)
379
+ || existing.authorClass !== input.authorClass
380
+ || JSON.stringify(existing.effect) !== JSON.stringify(input.effect)
381
+ || existing.obligationReturnId !== input.obligationReturnId) {
382
+ throw new Error("Telegram effect idempotency key was reused for a different effect");
383
+ }
384
+ return existing;
385
+ }
386
+ const now = input.now ?? new Date().toISOString();
387
+ const artifact = {
388
+ schemaVersion: 1,
389
+ id,
390
+ idempotencyKey,
391
+ target,
392
+ authorClass: input.authorClass,
393
+ effect: input.effect,
394
+ authorizationReceiptId: input.authorization.receiptId,
395
+ authorizationExpiresAt: input.authorization.expiresAt,
396
+ ...(input.obligationReturnId ? { obligationReturnId: input.obligationReturnId } : {}),
397
+ parts: preparedTexts(input.effect).map((text, index) => ({ index, text, state: "prepared", updatedAt: now })),
398
+ createdAt: now,
399
+ updatedAt: now,
400
+ };
401
+ store.write(artifact);
402
+ (0, runtime_1.emitNervesEvent)({ component: "senses", event: "senses.telegram_effect_prepared", message: "prepared Telegram effect", meta: { artifactId: id, effectKind: input.effect.kind, targetKind: input.target.kind, partCount: artifact.parts.length } });
403
+ return artifact;
404
+ }
405
+ function canonicalMessageId(result) {
406
+ const messageId = result && typeof result === "object" && !Array.isArray(result) ? result.message_id : undefined;
407
+ if (!Number.isSafeInteger(messageId) || messageId < 1)
408
+ throw new Error("Telegram effect response omitted message_id");
409
+ return messageId;
410
+ }
411
+ async function executePart(api, artifact, part, chatId, signal) {
412
+ const effect = artifact.effect;
413
+ if (effect.kind === "text" || effect.kind === "admission_ack") {
414
+ const renderHtml = effect.kind === "text" && artifact.authorClass === "butler" ? renderTelegramButlerHtml : undefined;
415
+ const ids = await (0, telegram_client_1.sendTelegramText)(api, chatId, part.text, { ...(signal ? { signal } : {}), ...(renderHtml ? { renderHtml } : {}) });
416
+ if (ids.length !== 1)
417
+ throw new Error("Telegram effect chunk renderer returned an unexpected message count");
418
+ return ids[0];
419
+ }
420
+ if (effect.kind === "card") {
421
+ const reply_markup = { inline_keyboard: effect.buttons.map((row) => row.map((button) => ({ text: button.text, callback_data: button.callbackData }))) };
422
+ let result;
423
+ try {
424
+ result = await api.request("sendMessage", { chat_id: chatId, text: (0, telegram_client_1.escapeTelegramHtml)(effect.text), parse_mode: "HTML", reply_markup }, signal);
425
+ }
426
+ catch (error) {
427
+ if (!(error instanceof telegram_client_1.TelegramApiError) || error.status !== 400)
428
+ throw error;
429
+ result = await api.request("sendMessage", { chat_id: chatId, text: effect.text, reply_markup }, signal);
430
+ }
431
+ return canonicalMessageId(result);
432
+ }
433
+ if (effect.kind === "edit") {
434
+ const base = { chat_id: chatId, message_id: effect.messageId, reply_markup: { inline_keyboard: [] } };
435
+ try {
436
+ await api.request("editMessageText", { ...base, text: (0, telegram_client_1.escapeTelegramHtml)(effect.text), parse_mode: "HTML" }, signal ? AbortSignal.any([signal, AbortSignal.timeout(30_000)]) : AbortSignal.timeout(30_000));
437
+ }
438
+ catch (error) {
439
+ if (error instanceof telegram_client_1.TelegramApiError && error.status === 400 && /message is not modified/iu.test(error.message))
440
+ return effect.messageId;
441
+ if (!(error instanceof telegram_client_1.TelegramApiError) || error.status !== 400)
442
+ throw error;
443
+ try {
444
+ await api.request("editMessageText", { ...base, text: effect.text }, signal ? AbortSignal.any([signal, AbortSignal.timeout(30_000)]) : AbortSignal.timeout(30_000));
445
+ }
446
+ catch (fallbackError) {
447
+ if (!(fallbackError instanceof telegram_client_1.TelegramApiError) || fallbackError.status !== 400 || !/message is not modified/iu.test(fallbackError.message))
448
+ throw fallbackError;
449
+ }
450
+ }
451
+ return effect.messageId;
452
+ }
453
+ await api.request("answerCallbackQuery", { callback_query_id: effect.callbackQueryId, ...(effect.text ? { text: effect.text } : {}), ...(effect.showAlert ? { show_alert: true } : {}) }, signal);
454
+ return undefined;
455
+ }
456
+ async function executeTelegramEffect(store, artifactIdValue, api, reauthorize, signal) {
457
+ return (0, session_transaction_1.withSessionTurnLease)(store.coordinationPath(artifactIdValue), async () => {
458
+ const artifact = store.read(artifactIdValue);
459
+ if (artifact.parts.some((part) => part.state === "indeterminate"))
460
+ throw new Error("Telegram effect has an indeterminate part and cannot be retried blindly");
461
+ const interrupted = artifact.parts.filter((part) => part.state === "attempting");
462
+ if (interrupted.length > 0) {
463
+ const now = new Date().toISOString();
464
+ for (const part of interrupted) {
465
+ part.state = "indeterminate";
466
+ part.updatedAt = now;
467
+ }
468
+ artifact.updatedAt = now;
469
+ store.write(artifact);
470
+ throw new Error("Telegram effect has an indeterminate part after an interrupted send and cannot be retried blindly");
471
+ }
472
+ const authorization = await reauthorize(artifact);
473
+ if (!authorization.allowed)
474
+ throw new Error(`Telegram effect authorization denied: ${authorization.reason}`);
475
+ if (Date.parse(authorization.expiresAt) <= Date.now())
476
+ throw new Error("Telegram effect authorization expired");
477
+ if (!/^[1-9][0-9]*$/u.test(authorization.transport.chatId))
478
+ throw new Error("Telegram effect authorization returned an invalid transport route");
479
+ if (artifact.target.kind === "admission_gate" && authorization.transport.chatId !== artifact.target.chatId)
480
+ throw new Error("Telegram admission transport route changed");
481
+ artifact.authorizationReceiptId = authorization.receiptId;
482
+ artifact.authorizationExpiresAt = authorization.expiresAt;
483
+ for (const part of artifact.parts) {
484
+ if (part.state === "accepted" || part.state === "session_recorded")
485
+ continue;
486
+ if (signal?.aborted)
487
+ throw signal.reason;
488
+ const attemptingAt = new Date().toISOString();
489
+ part.state = "attempting";
490
+ part.attempts = (part.attempts ?? 0) + 1;
491
+ part.updatedAt = attemptingAt;
492
+ artifact.updatedAt = attemptingAt;
493
+ store.write(artifact);
494
+ try {
495
+ const messageId = await executePart(api, artifact, part, authorization.transport.chatId, signal);
496
+ part.state = "accepted";
497
+ if (messageId !== undefined)
498
+ part.messageId = messageId;
499
+ part.acceptedAt = new Date().toISOString();
500
+ part.updatedAt = part.acceptedAt;
501
+ artifact.updatedAt = part.updatedAt;
502
+ store.write(artifact);
503
+ }
504
+ catch (error) {
505
+ const safelyRetryable = artifact.effect.kind === "edit" || artifact.effect.kind === "callback_ack"
506
+ || (error instanceof telegram_client_1.TelegramApiError && error.errorCode !== null);
507
+ part.state = safelyRetryable ? "prepared" : "indeterminate";
508
+ part.updatedAt = new Date().toISOString();
509
+ artifact.updatedAt = part.updatedAt;
510
+ store.write(artifact);
511
+ if (!safelyRetryable)
512
+ (0, runtime_1.emitNervesEvent)({ level: "error", component: "senses", event: "senses.telegram_effect_indeterminate", message: "Telegram effect became indeterminate", meta: { artifactId: artifact.id, partIndex: part.index, effectKind: artifact.effect.kind, error: error instanceof Error ? error.message : String(error) } });
513
+ throw error;
514
+ }
515
+ }
516
+ (0, runtime_1.emitNervesEvent)({ component: "senses", event: "senses.telegram_effect_accepted", message: "Telegram effect accepted", meta: { artifactId: artifact.id, effectKind: artifact.effect.kind, partCount: artifact.parts.length } });
517
+ return artifact;
518
+ });
519
+ }
520
+ function createTelegramAuthorizedEffectExecutor(options) {
521
+ const barrier = options.barrier ?? (() => undefined);
522
+ const getStore = () => typeof options.store === "function" ? options.store() : options.store;
523
+ return async (input) => {
524
+ if (input.signal?.aborted)
525
+ throw input.signal.reason;
526
+ barrier();
527
+ const authorization = await options.authorize({ phase: "prepare", ...input });
528
+ if (!authorization.allowed)
529
+ throw new Error(`Telegram effect authorization denied: ${authorization.reason}`);
530
+ const store = getStore();
531
+ const prepared = prepareTelegramEffect(store, { ...input, authorization });
532
+ try {
533
+ const executed = await executeTelegramEffect(store, prepared.id, options.api, async (artifact) => {
534
+ if (input.signal?.aborted)
535
+ throw input.signal.reason;
536
+ barrier();
537
+ return options.authorize({
538
+ phase: "send",
539
+ idempotencyKey: artifact.idempotencyKey,
540
+ target: artifact.target,
541
+ authorClass: artifact.authorClass,
542
+ effect: artifact.effect,
543
+ artifact,
544
+ });
545
+ }, input.signal);
546
+ barrier();
547
+ for (const part of executed.parts) {
548
+ if (part.messageId !== undefined && part.text !== null)
549
+ input.onMessageDelivered?.(part.messageId, part.text);
550
+ }
551
+ return executed;
552
+ }
553
+ catch (error) {
554
+ const attempted = store.read(prepared.id);
555
+ for (const part of attempted.parts) {
556
+ if ((part.state === "accepted" || part.state === "session_recorded") && part.messageId !== undefined && part.text !== null) {
557
+ input.onMessageDelivered?.(part.messageId, part.text);
558
+ }
559
+ }
560
+ throw error;
561
+ }
562
+ };
563
+ }
564
+ async function reconcileTelegramSystemFailsafe(input) {
565
+ const { record } = input;
566
+ const action = record.privilegedProtectiveAction;
567
+ if (record.privilegedFailsafe)
568
+ return { sent: false, reason: "already_recorded", artifactId: record.privilegedFailsafe.artifactId };
569
+ if (record.agent !== "sanctuary" || record.source !== "sanctuary-usenet" || record.eventType !== "usenet.protective_action"
570
+ || record.priority !== "critical" || !action?.critical)
571
+ return { sent: false, reason: "noncritical" };
572
+ if (!action.verification.verified)
573
+ return { sent: false, reason: "unverified" };
574
+ if (action.action !== "sabnzbd.pause")
575
+ return { sent: false, reason: "policy_blocked" };
576
+ if (record.dispatchEnabled === false)
577
+ return { sent: false, reason: "policy_blocked" };
578
+ if ((record.executionState !== "retry_wait" && record.executionState !== "dead_letter") || !record.lastError || record.attemptCount < 1) {
579
+ return { sent: false, reason: "butler_available" };
580
+ }
581
+ const now = input.now?.() ?? new Date().toISOString();
582
+ const nowMs = Date.parse(now);
583
+ if (!Number.isFinite(nowMs) || nowMs - Date.parse(record.updatedAt) < SYSTEM_FAILSAFE_UNAVAILABLE_MS)
584
+ return { sent: false, reason: "unavailability_window" };
585
+ if (nowMs > Date.parse(action.expiresAt))
586
+ return { sent: false, reason: "expired" };
587
+ const verification = await input.verifyProtectiveState(action);
588
+ if (!verification.verified || !verification.reference.trim() || Buffer.byteLength(verification.reference) > 512)
589
+ return { sent: false, reason: "unverified" };
590
+ const artifact = await input.execute({
591
+ idempotencyKey: `system-failsafe:${action.transitionId}`,
592
+ target: input.target,
593
+ authorClass: "system_failsafe",
594
+ effect: { kind: "text", text: exports.FIXED_USENET_SYSTEM_FAILSAFE },
595
+ });
596
+ await input.recordArtifact(artifact);
597
+ input.bindArtifact(record.recordPath, { artifactId: artifact.id, verificationRef: verification.reference, recordedAt: now });
598
+ (0, runtime_1.emitNervesEvent)({ component: "senses", event: "senses.telegram_system_failsafe_sent", message: "sent verified Sanctuary system failsafe", meta: { artifactId: artifact.id, eventId: record.eventId, transitionId: action.transitionId } });
599
+ return { sent: true, reason: "sent", artifactId: artifact.id };
600
+ }
601
+ async function sweepTelegramSystemFailsafes(input) {
602
+ const records = (0, router_1.listExternalEventStatus)(input.eventRoot).filter((status) => !status.corrupt && status.agent === "sanctuary" && status.source === "sanctuary-usenet").slice(0, 32);
603
+ let sent = 0;
604
+ for (const status of records) {
605
+ const result = await reconcileTelegramSystemFailsafe({
606
+ record: (0, router_1.readExternalEventRecord)(status.recordPath),
607
+ ...(input.now ? { now: input.now } : {}),
608
+ target: input.target,
609
+ verifyProtectiveState: input.verifyProtectiveState,
610
+ execute: input.execute,
611
+ recordArtifact: input.recordArtifact,
612
+ bindArtifact: router_1.bindPrivilegedFailsafeArtifact,
613
+ });
614
+ if (result.sent)
615
+ sent += 1;
616
+ }
617
+ return { inspected: records.length, sent };
618
+ }
619
+ async function recoverTelegramEffectOutbox(input) {
620
+ const limit = Math.min(Math.max(input.maxArtifacts ?? 20, 1), 100);
621
+ const candidates = input.store.listRecoverable()
622
+ .filter((artifact) => (!input.matches || input.matches(artifact))
623
+ && !artifact.parts.some((part) => part.state === "attempting" || part.state === "indeterminate")
624
+ && artifact.parts.some((part) => part.state === "prepared" && (part.attempts ?? 0) < 3))
625
+ .sort((left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id))
626
+ .slice(0, limit);
627
+ let accepted = 0;
628
+ let failed = 0;
629
+ for (const artifact of candidates) {
630
+ try {
631
+ await input.execute({ idempotencyKey: artifact.idempotencyKey, target: artifact.target, authorClass: artifact.authorClass, effect: artifact.effect, ...(artifact.obligationReturnId ? { obligationReturnId: artifact.obligationReturnId } : {}) });
632
+ accepted += 1;
633
+ }
634
+ catch {
635
+ failed += 1;
636
+ }
637
+ }
638
+ return { attempted: candidates.length, accepted, failed };
639
+ }
640
+ function createTelegramApprovalEffectPort(options) {
641
+ const executeAndRecord = async (input, causalEventId) => {
642
+ const artifact = await options.execute({ ...input, target: options.target });
643
+ await options.record(artifact, causalEventId);
644
+ return artifact;
645
+ };
646
+ return {
647
+ async sendText(input) {
648
+ if (input.chatId !== options.chatId)
649
+ throw new Error("Telegram approval text target changed");
650
+ const artifact = await executeAndRecord({ idempotencyKey: input.idempotencyKey, authorClass: input.authorClass, effect: { kind: "text", text: input.text }, ...(input.signal ? { signal: input.signal } : {}) }, input.causalEventId);
651
+ return artifact.parts.flatMap((part) => part.messageId === undefined ? [] : [part.messageId]);
652
+ },
653
+ async sendCard(input) {
654
+ if (input.chatId !== options.chatId)
655
+ throw new Error("Telegram approval card target changed");
656
+ const artifact = await executeAndRecord({ idempotencyKey: input.idempotencyKey, authorClass: "control", effect: { kind: "card", text: input.text, buttons: input.buttons }, ...(input.signal ? { signal: input.signal } : {}) });
657
+ const messageId = artifact.parts[0]?.messageId;
658
+ if (!messageId)
659
+ throw new Error("Telegram approval card omitted its message id");
660
+ return messageId;
661
+ },
662
+ async edit(input) {
663
+ if (input.chatId !== options.chatId)
664
+ throw new Error("Telegram approval edit target changed");
665
+ await executeAndRecord({ idempotencyKey: input.idempotencyKey, authorClass: "control", effect: { kind: "edit", messageId: input.messageId, text: input.text }, ...(input.signal ? { signal: input.signal } : {}) });
666
+ },
667
+ async acknowledge(input) {
668
+ await executeAndRecord({
669
+ idempotencyKey: input.idempotencyKey,
670
+ authorClass: "control",
671
+ effect: { kind: "callback_ack", callbackQueryId: input.callbackQueryId, ...(input.text ? { text: input.text } : {}), ...(input.showAlert ? { showAlert: true } : {}) },
672
+ ...(input.signal ? { signal: input.signal } : {}),
673
+ });
674
+ },
675
+ };
676
+ }
677
+ function recordTelegramEffectInSession(store, artifactIdValue, sessionEventIds) {
678
+ const artifact = store.read(artifactIdValue);
679
+ const accepted = artifact.parts.filter((part) => part.state === "accepted");
680
+ const transportOnlyControl = isTransportOnlyControl(artifact);
681
+ if ((!transportOnlyControl && accepted.length !== sessionEventIds.length) || (transportOnlyControl && sessionEventIds.length !== 0) || sessionEventIds.some((value) => !value.trim())) {
682
+ throw new Error("Telegram session event ids do not match accepted effect parts");
683
+ }
684
+ accepted.forEach((part, index) => {
685
+ part.state = "session_recorded";
686
+ if (!transportOnlyControl)
687
+ part.sessionEventId = sessionEventIds[index];
688
+ part.sessionRecordedAt = new Date().toISOString();
689
+ part.updatedAt = part.sessionRecordedAt;
690
+ });
691
+ artifact.updatedAt = new Date().toISOString();
692
+ store.write(artifact);
693
+ (0, runtime_1.emitNervesEvent)({ component: "senses", event: "senses.telegram_effect_session_recorded", message: "recorded Telegram effect in session continuity", meta: { artifactId: artifact.id, authorClass: artifact.authorClass, partCount: accepted.length } });
694
+ return artifact;
695
+ }
696
+ function bindButlerArtifactToCanonicalEvent(envelope, artifact, causalEventId) {
697
+ if (artifact.authorClass !== "butler" || artifact.effect.kind !== "text" || !causalEventId)
698
+ return null;
699
+ const reference = `telegram-artifact:${artifact.id}`;
700
+ const candidate = envelope.events.find((event) => event.id === causalEventId && event.role === "assistant");
701
+ if (!candidate)
702
+ throw new Error("Telegram effect canonical causal event is unavailable");
703
+ const messageReferences = artifact.parts.flatMap((part) => part.messageId ? [`telegram-message:${part.messageId}`] : []);
704
+ const requestReferences = artifact.target.kind === "approved_relationship" && artifact.target.requestId ? [`request:${artifact.target.requestId}`] : [];
705
+ const events = envelope.events.map((event) => event.id === candidate.id
706
+ ? { ...event, relations: { ...event.relations, references: [...new Set([...event.relations.references, reference, ...messageReferences, ...requestReferences])] } }
707
+ : event);
708
+ return { envelope: { ...envelope, events }, eventIds: artifact.parts.filter((part) => part.state === "accepted").map(() => candidate.id) };
709
+ }
710
+ function artifactEventContent(artifact, part) {
711
+ const text = part.text ?? "";
712
+ if (artifact.authorClass === "butler")
713
+ return text;
714
+ if (artifact.authorClass === "control")
715
+ return `[Telegram control artifact]\n${text}`;
716
+ return `[System failsafe already sent]\n${text}`;
717
+ }
718
+ function appendTelegramArtifactEvents(envelope, artifact, recordedAt) {
719
+ const accepted = artifact.parts.filter((part) => part.state === "accepted");
720
+ if (accepted.length === 0)
721
+ throw new Error("Telegram artifact has no accepted parts to record");
722
+ let sequence = envelope.events.reduce((maximum, event) => Math.max(maximum, event.sequence), 0);
723
+ const events = accepted.map((part) => {
724
+ sequence += 1;
725
+ const id = `evt-${String(sequence).padStart(6, "0")}`;
726
+ const role = artifact.authorClass === "butler" ? "assistant" : "system";
727
+ const name = artifact.authorClass === "butler"
728
+ ? "telegram-butler"
729
+ : artifact.authorClass === "control" ? "telegram-control" : "telegram-system-failsafe";
730
+ return {
731
+ id,
732
+ sequence,
733
+ role,
734
+ content: artifactEventContent(artifact, part),
735
+ name,
736
+ toolCallId: null,
737
+ toolCalls: [],
738
+ attachments: [],
739
+ time: { authoredAt: recordedAt, authoredAtSource: "local", observedAt: recordedAt, observedAtSource: "local", recordedAt, recordedAtSource: "save" },
740
+ relations: {
741
+ replyToEventId: null,
742
+ threadRootEventId: null,
743
+ references: [
744
+ `telegram-artifact:${artifact.id}`,
745
+ ...(part.messageId ? [`telegram-message:${part.messageId}`] : []),
746
+ ...(artifact.target.kind === "approved_relationship" && artifact.target.requestId ? [`request:${artifact.target.requestId}`] : []),
747
+ ],
748
+ toolCallId: null,
749
+ supersedesEventId: null,
750
+ redactsEventId: null,
751
+ },
752
+ provenance: { captureKind: "synthetic", legacyVersion: null, sourceMessageIndex: null },
753
+ };
754
+ });
755
+ const eventIds = events.map((event) => event.id);
756
+ const priorIds = (0, session_events_1.projectedSessionEventIds)(envelope);
757
+ return {
758
+ envelope: {
759
+ ...envelope,
760
+ events: [...envelope.events, ...events],
761
+ projection: {
762
+ ...envelope.projection, eventIds: [...priorIds, ...eventIds], projectedAt: recordedAt,
763
+ trimmed: new Set(priorIds).size < (0, session_events_1.selectEffectiveSessionEvents)(envelope.events).length,
764
+ },
765
+ },
766
+ eventIds,
767
+ };
768
+ }
769
+ function appendTelegramInboundEvent(envelope, input) {
770
+ if (envelope.events.some((event) => event.relations.references.includes(input.reference)))
771
+ return envelope;
772
+ const sequence = envelope.events.reduce((maximum, event) => Math.max(maximum, event.sequence), 0) + 1;
773
+ const id = `evt-${String(sequence).padStart(6, "0")}`;
774
+ const event = {
775
+ id,
776
+ sequence,
777
+ role: "user",
778
+ content: input.text,
779
+ name: "telegram-user",
780
+ toolCallId: null,
781
+ toolCalls: [],
782
+ attachments: [...new Set(input.attachmentIds ?? [])],
783
+ time: { authoredAt: null, authoredAtSource: "unknown", observedAt: input.recordedAt, observedAtSource: "ingest", recordedAt: input.recordedAt, recordedAtSource: "save" },
784
+ relations: {
785
+ replyToEventId: input.relations?.replyToEventId ?? null,
786
+ threadRootEventId: input.relations?.threadRootEventId ?? null,
787
+ references: [...new Set([input.reference, ...(input.relations?.references ?? [])])],
788
+ toolCallId: null,
789
+ supersedesEventId: null,
790
+ redactsEventId: null,
791
+ },
792
+ provenance: { captureKind: "live", legacyVersion: null, sourceMessageIndex: null },
793
+ };
794
+ const priorIds = (0, session_events_1.projectedSessionEventIds)(envelope);
795
+ return {
796
+ ...envelope,
797
+ events: [...envelope.events, event],
798
+ projection: {
799
+ ...envelope.projection, eventIds: [...priorIds, id], projectedAt: input.recordedAt,
800
+ trimmed: new Set(priorIds).size < (0, session_events_1.selectEffectiveSessionEvents)(envelope.events).length,
801
+ },
802
+ };
803
+ }
804
+ async function recordTelegramEffectsInSession(input) {
805
+ if (input.artifacts.length === 0 && !input.inbound)
806
+ return null;
807
+ const record = async (lease) => {
808
+ const transaction = (0, session_transaction_1.readSessionTransaction)(input.sessionPath, lease);
809
+ let envelope = (0, session_events_1.loadSessionEnvelopeFile)(input.sessionPath) ?? {
810
+ version: 2,
811
+ events: [],
812
+ projection: { eventIds: [], trimmed: false, maxTokens: null, contextMargin: null, inputTokens: null, projectedAt: null },
813
+ lastUsage: null,
814
+ state: { mustResolveBeforeHandoff: false, lastFriendActivityAt: null },
815
+ };
816
+ let inboundReceipt = null;
817
+ let changed = false;
818
+ if (input.inbound) {
819
+ const existing = envelope.events.filter((event) => event.relations.references.includes(input.inbound.reference));
820
+ const expectedAttachmentIds = [...new Set(input.inbound.attachmentIds ?? [])];
821
+ if (existing.length > 1 || (existing.length === 1 && (existing[0].role !== "user" || existing[0].content !== input.inbound.text
822
+ || JSON.stringify(existing[0].attachments) !== JSON.stringify(expectedAttachmentIds)))) {
823
+ throw new Error("Telegram session has conflicting inbound ingress");
824
+ }
825
+ if (existing.length === 1) {
826
+ inboundReceipt = { eventId: existing[0].id, reference: input.inbound.reference };
827
+ }
828
+ else {
829
+ envelope = appendTelegramInboundEvent(envelope, { ...input.inbound, attachmentIds: expectedAttachmentIds, recordedAt: new Date().toISOString() });
830
+ inboundReceipt = { eventId: envelope.events.at(-1).id, reference: input.inbound.reference };
831
+ changed = true;
832
+ }
833
+ }
834
+ const recordings = [];
835
+ for (const artifact of input.artifacts) {
836
+ const unrecorded = artifact.parts.filter((part) => part.state === "accepted");
837
+ if (unrecorded.length === 0)
838
+ continue;
839
+ if (isTransportOnlyControl(artifact)) {
840
+ recordings.push({ artifact, eventIds: [] });
841
+ continue;
842
+ }
843
+ const reference = `telegram-artifact:${artifact.id}`;
844
+ const existingEvents = envelope.events.filter((event) => event.relations.references.includes(reference));
845
+ if (existingEvents.length > 0) {
846
+ const eventIds = unrecorded.map((part) => existingEvents.find((event) => !part.messageId || event.relations.references.includes(`telegram-message:${part.messageId}`))?.id);
847
+ if (eventIds.every((id) => typeof id === "string")) {
848
+ recordings.push({ artifact, eventIds });
849
+ continue;
850
+ }
851
+ }
852
+ if (existingEvents.length !== 0)
853
+ throw new Error("Telegram effect session reconciliation is partial");
854
+ const appended = bindButlerArtifactToCanonicalEvent(envelope, artifact, input.causalEventIds?.[artifact.id])
855
+ ?? appendTelegramArtifactEvents(envelope, artifact, new Date().toISOString());
856
+ envelope = appended.envelope;
857
+ recordings.push({ artifact, eventIds: appended.eventIds });
858
+ changed = true;
859
+ }
860
+ if (changed)
861
+ (0, session_transaction_1.writeSessionTransaction)(input.sessionPath, envelope, { lease, expectedRevision: transaction.revision });
862
+ for (const recording of recordings)
863
+ recordTelegramEffectInSession(input.store, recording.artifact.id, recording.eventIds);
864
+ return inboundReceipt;
865
+ };
866
+ const lease = (0, session_transaction_1.currentSessionTurnLease)(input.sessionPath);
867
+ return lease ? record(lease) : (0, session_transaction_1.withSessionTurnLease)(input.sessionPath, record);
868
+ }
869
+ function resolveTelegramReply(store, input) {
870
+ for (const artifact of store.list()) {
871
+ if (artifact.target.kind !== "approved_relationship" || artifact.target.friendId !== input.friendId || artifact.target.sessionKey !== input.sessionKey)
872
+ continue;
873
+ const part = artifact.parts.find((candidate) => candidate.messageId === input.messageId && candidate.state === "session_recorded" && candidate.sessionEventId);
874
+ if (!part?.sessionEventId)
875
+ continue;
876
+ return {
877
+ artifactId: artifact.id,
878
+ authorClass: artifact.authorClass,
879
+ sessionEventId: part.sessionEventId,
880
+ requestId: artifact.target.requestId ?? null,
881
+ };
882
+ }
883
+ return null;
884
+ }
885
+ function resolveTelegramControlArtifact(store, input) {
886
+ for (const artifact of store.list()) {
887
+ if (artifact.authorClass !== "control" || artifact.target.kind !== "approved_relationship"
888
+ || artifact.effect.kind !== "card"
889
+ || artifact.target.friendId !== input.friendId || artifact.target.sessionKey !== input.sessionKey)
890
+ continue;
891
+ if (!artifact.parts.some((part) => part.messageId === input.messageId && part.state === "session_recorded"))
892
+ continue;
893
+ return { artifactId: artifact.id, requestId: artifact.target.requestId ?? null };
894
+ }
895
+ return null;
896
+ }