@ouro.bot/cli 0.1.0-alpha.99 → 0.1.0-alpha.991

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 (777) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +171 -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 +6257 -16
  16. package/deploy/unraid/Dockerfile +71 -0
  17. package/deploy/unraid/INSTALL.md +64 -0
  18. package/deploy/unraid/README.txt +3032 -0
  19. package/deploy/unraid/audit-container-spec.sh +4 -0
  20. package/deploy/unraid/container-runtime.json +1 -0
  21. package/deploy/unraid/credit-gateway.md +95 -0
  22. package/deploy/unraid/docker-man-template-transaction.mjs +727 -0
  23. package/deploy/unraid/docker-man-template-xml.cjs +105 -0
  24. package/deploy/unraid/github_known_hosts +3 -0
  25. package/deploy/unraid/install.sh +274 -0
  26. package/deploy/unraid/migrate-sanctuary-bundle.mjs +63 -0
  27. package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
  28. package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
  29. package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
  30. package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
  31. package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
  32. package/deploy/unraid/ouro-sync-ssh +98 -0
  33. package/deploy/unraid/ouro-sync.sudoers +3 -0
  34. package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
  35. package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
  36. package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
  37. package/deploy/unraid/sanctuary-authority-installation.json +36 -0
  38. package/deploy/unraid/sanctuary-authority-service.sh +30 -0
  39. package/deploy/unraid/sanctuary-butler-upgrade.mjs +1523 -0
  40. package/deploy/unraid/sanctuary-deployment-target.mjs +710 -0
  41. package/deploy/unraid/sanctuary-replay-gate.mjs +2467 -0
  42. package/deploy/unraid/sanctuary-safe-rename.py +24 -0
  43. package/deploy/unraid/sanctuary-sync-cutover.sh +1039 -0
  44. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2088 -0
  45. package/deploy/unraid/sanctuary-unit16-run.sh +570 -0
  46. package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
  47. package/deploy/unraid/sanctuary.ouro/agent.json +67 -0
  48. package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
  49. package/deploy/unraid/sanctuary.ouro/awaiting/house-care-sweep.md +17 -0
  50. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
  51. package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
  52. package/deploy/unraid/sanctuary.ouro/mcp/media-mcp.mjs +2255 -0
  53. package/deploy/unraid/sanctuary.ouro/product/PRODUCT.md +13 -0
  54. package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
  55. package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
  56. package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +7 -0
  57. package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +7 -0
  58. package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +15 -0
  59. package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +3 -0
  60. package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
  61. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +234 -0
  62. package/deploy/unraid/sanctuary.xml +30 -0
  63. package/dist/a2a/card.js +57 -0
  64. package/dist/a2a/client.js +290 -0
  65. package/dist/a2a/config.js +50 -0
  66. package/dist/a2a/delegated-command-grants.js +93 -0
  67. package/dist/a2a/delegated-command.js +197 -0
  68. package/dist/a2a/delegation-stores.js +56 -0
  69. package/dist/a2a/did-resolution.js +205 -0
  70. package/dist/a2a/escalation-grants.js +84 -0
  71. package/dist/a2a/escalation-wiring.js +60 -0
  72. package/dist/a2a/identity.js +258 -0
  73. package/dist/a2a/inbound-share.js +131 -0
  74. package/dist/a2a/mission-result-wire.js +265 -0
  75. package/dist/a2a/onboarding.js +133 -0
  76. package/dist/a2a/operator-trust.js +399 -0
  77. package/dist/a2a/outbox-client.js +59 -0
  78. package/dist/a2a/outbox-store.js +188 -0
  79. package/dist/a2a/outbox-wire.js +106 -0
  80. package/dist/a2a/pin-store.js +167 -0
  81. package/dist/a2a/refusals.js +53 -0
  82. package/dist/a2a/relay-client.js +106 -0
  83. package/dist/a2a/relay-config-vault.js +64 -0
  84. package/dist/a2a/relay-contacts.js +120 -0
  85. package/dist/a2a/relay-inbox.js +360 -0
  86. package/dist/a2a/relay-retirements.js +89 -0
  87. package/dist/a2a/replay-grant-holders.js +33 -0
  88. package/dist/a2a/replay-harness.js +188 -0
  89. package/dist/a2a/resolution-proof.js +53 -0
  90. package/dist/a2a/sealed-chat.js +114 -0
  91. package/dist/a2a/seen-ledger.js +214 -0
  92. package/dist/a2a/server.js +808 -0
  93. package/dist/a2a/task-store.js +69 -0
  94. package/dist/a2a/transport.js +100 -0
  95. package/dist/a2a/trust-commands.js +203 -0
  96. package/dist/a2a/trusted-files.js +185 -0
  97. package/dist/a2a/types.js +3 -0
  98. package/dist/arc/attention-types.js +8 -0
  99. package/dist/arc/cares.js +360 -0
  100. package/dist/arc/episodes.js +118 -0
  101. package/dist/arc/evolution.js +490 -0
  102. package/dist/arc/flight-recorder.js +1034 -0
  103. package/dist/arc/intentions.js +134 -0
  104. package/dist/arc/json-store.js +117 -0
  105. package/dist/arc/obligations.js +386 -0
  106. package/dist/arc/packets.js +336 -0
  107. package/dist/arc/presence.js +185 -0
  108. package/dist/arc/task-lifecycle.js +57 -0
  109. package/dist/commerce/store.js +755 -0
  110. package/dist/commerce/types.js +3 -0
  111. package/dist/gateway/keys.js +117 -0
  112. package/dist/gateway/server.js +429 -0
  113. package/dist/heart/active-work.js +798 -40
  114. package/dist/heart/agent-entry.js +252 -3
  115. package/dist/heart/approval-files.js +113 -0
  116. package/dist/heart/approval-store.js +960 -0
  117. package/dist/heart/attachments/image-normalize.js +201 -0
  118. package/dist/heart/attachments/materialize.js +97 -0
  119. package/dist/heart/attachments/originals.js +88 -0
  120. package/dist/heart/attachments/render.js +29 -0
  121. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  122. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  123. package/dist/heart/attachments/sources/index.js +18 -0
  124. package/dist/heart/attachments/sources/telegram.js +71 -0
  125. package/dist/heart/attachments/store.js +132 -0
  126. package/dist/heart/attachments/types.js +93 -0
  127. package/dist/heart/auth/auth-flow.js +511 -0
  128. package/dist/heart/autonomy-budget.js +478 -0
  129. package/dist/heart/awaiting/a2a-await-delivery.js +109 -0
  130. package/dist/heart/awaiting/await-alert.js +152 -0
  131. package/dist/heart/awaiting/await-expiry.js +143 -0
  132. package/dist/heart/awaiting/await-loader.js +91 -0
  133. package/dist/heart/awaiting/await-parser.js +152 -0
  134. package/dist/heart/awaiting/await-runtime-state.js +130 -0
  135. package/dist/heart/awaiting/await-scheduler.js +391 -0
  136. package/dist/heart/background-operations.js +281 -0
  137. package/dist/heart/bluebubbles-host-account.js +78 -0
  138. package/dist/heart/bridges/manager.js +137 -17
  139. package/dist/heart/bridges/store.js +14 -2
  140. package/dist/heart/bundle-state.js +168 -0
  141. package/dist/heart/commitments.js +44 -18
  142. package/dist/heart/config-registry.js +331 -0
  143. package/dist/heart/config.js +179 -131
  144. package/dist/heart/context-loss-gauntlet.js +387 -0
  145. package/dist/heart/context-loss-sentinel.js +1204 -0
  146. package/dist/heart/core.js +2378 -586
  147. package/dist/heart/cross-chat-delivery.js +9 -22
  148. package/dist/heart/daemon/agent-config-check.js +474 -0
  149. package/dist/heart/daemon/agent-discovery.js +287 -3
  150. package/dist/heart/daemon/agent-home.js +355 -0
  151. package/dist/heart/daemon/agent-service.js +542 -0
  152. package/dist/heart/daemon/agentic-repair.js +547 -0
  153. package/dist/heart/daemon/await-private-wake.js +59 -0
  154. package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
  155. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  156. package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
  157. package/dist/heart/daemon/bluebubbles-host.js +273 -0
  158. package/dist/heart/daemon/boot-sync-probe.js +223 -0
  159. package/dist/heart/daemon/cadence.js +180 -0
  160. package/dist/heart/daemon/cli-arg-redaction.js +26 -0
  161. package/dist/heart/daemon/cli-defaults.js +881 -0
  162. package/dist/heart/daemon/cli-desk.js +331 -0
  163. package/dist/heart/daemon/cli-exec.js +9339 -0
  164. package/dist/heart/daemon/cli-help.js +766 -0
  165. package/dist/heart/daemon/cli-parse.js +3343 -0
  166. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  167. package/dist/heart/daemon/cli-render.js +819 -0
  168. package/dist/heart/daemon/cli-types.js +8 -0
  169. package/dist/heart/daemon/connect-bay.js +323 -0
  170. package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
  171. package/dist/heart/daemon/container-healthcheck.js +112 -0
  172. package/dist/heart/daemon/container-runtime.js +97 -0
  173. package/dist/heart/daemon/container-spec-auditor-main.js +187 -0
  174. package/dist/heart/daemon/container-spec-auditor.js +257 -0
  175. package/dist/heart/daemon/daemon-bootstrap-startup.js +115 -0
  176. package/dist/heart/daemon/daemon-cli.js +29 -2373
  177. package/dist/heart/daemon/daemon-entry.js +975 -11
  178. package/dist/heart/daemon/daemon-health.js +186 -0
  179. package/dist/heart/daemon/daemon-rollup.js +57 -0
  180. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  181. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  182. package/dist/heart/daemon/daemon.js +2110 -104
  183. package/dist/heart/daemon/desk-admin.js +420 -0
  184. package/dist/heart/daemon/dns-workflow.js +394 -0
  185. package/dist/heart/daemon/doctor-types.js +8 -0
  186. package/dist/heart/daemon/doctor.js +1766 -0
  187. package/dist/heart/daemon/freshness.js +345 -0
  188. package/dist/heart/daemon/habit-private-wake.js +61 -0
  189. package/dist/heart/daemon/health-monitor.js +154 -11
  190. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  191. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  192. package/dist/heart/daemon/http-health-probe.js +80 -0
  193. package/dist/heart/daemon/human-command-screens.js +234 -0
  194. package/dist/heart/daemon/human-readiness.js +114 -0
  195. package/dist/heart/daemon/inner-status.js +78 -0
  196. package/dist/heart/daemon/interactive-repair.js +394 -0
  197. package/dist/heart/daemon/launchd.js +37 -8
  198. package/dist/heart/daemon/log-tailer.js +79 -10
  199. package/dist/heart/daemon/logs-prune.js +132 -0
  200. package/dist/heart/daemon/mcp-canary.js +524 -0
  201. package/dist/heart/daemon/message-router.js +65 -5
  202. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  203. package/dist/heart/daemon/os-cron-deps.js +135 -0
  204. package/dist/heart/daemon/os-cron.js +22 -14
  205. package/dist/heart/daemon/ouro-bot-entry.js +6 -3
  206. package/dist/heart/daemon/ouro-entry.js +9 -3
  207. package/dist/heart/daemon/plugin-cli.js +432 -0
  208. package/dist/heart/daemon/process-manager.js +760 -61
  209. package/dist/heart/daemon/provider-discovery.js +137 -0
  210. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  211. package/dist/heart/daemon/prunable-bundle.js +144 -0
  212. package/dist/heart/daemon/pulse.js +511 -0
  213. package/dist/heart/daemon/readiness-repair.js +365 -0
  214. package/dist/heart/daemon/run-hooks.js +2 -0
  215. package/dist/heart/daemon/runtime-logging.js +47 -14
  216. package/dist/heart/daemon/runtime-metadata.js +2 -30
  217. package/dist/heart/daemon/runtime-mode.js +13 -2
  218. package/dist/heart/daemon/safe-mode.js +161 -0
  219. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2662 -0
  220. package/dist/heart/daemon/sanctuary-acceptance-harness.js +1832 -0
  221. package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
  222. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +956 -0
  223. package/dist/heart/daemon/sanctuary-authority-codec.js +86 -0
  224. package/dist/heart/daemon/sanctuary-authority-epoch.js +291 -0
  225. package/dist/heart/daemon/sanctuary-authority-installation.js +161 -0
  226. package/dist/heart/daemon/sanctuary-authority-ledger.js +241 -0
  227. package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +1332 -0
  228. package/dist/heart/daemon/sanctuary-authority-vault-migration.js +79 -0
  229. package/dist/heart/daemon/sanctuary-bundle-migration.js +974 -0
  230. package/dist/heart/daemon/sanctuary-host-authority.js +1008 -0
  231. package/dist/heart/daemon/sanctuary-host-detached-supervisor.js +493 -0
  232. package/dist/heart/daemon/sanctuary-host-executor.js +670 -0
  233. package/dist/heart/daemon/sanctuary-host-linux-kernel.js +334 -0
  234. package/dist/heart/daemon/sanctuary-host-supervisor-entry.js +207 -0
  235. package/dist/heart/daemon/sanctuary-host-supervisor.js +95 -0
  236. package/dist/heart/daemon/sanctuary-package-management.js +113 -0
  237. package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
  238. package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
  239. package/dist/heart/daemon/sanctuary-telegram-authority-entry.js +475 -0
  240. package/dist/heart/daemon/sanctuary-telegram-authority-gateway.js +585 -0
  241. package/dist/heart/daemon/sanctuary-telegram-authority-service.js +676 -0
  242. package/dist/heart/daemon/sense-manager.js +786 -48
  243. package/dist/heart/daemon/session-id-resolver.js +131 -0
  244. package/dist/heart/daemon/skill-management-installer.js +1 -1
  245. package/dist/heart/daemon/socket-client.js +180 -12
  246. package/dist/heart/daemon/stale-bundle-prune.js +113 -0
  247. package/dist/heart/daemon/startup-tui.js +339 -0
  248. package/dist/heart/daemon/supercronic-supervisor.js +282 -0
  249. package/dist/heart/daemon/task-scheduler.js +117 -39
  250. package/dist/heart/daemon/terminal-ui.js +503 -0
  251. package/dist/heart/daemon/thoughts.js +138 -54
  252. package/dist/heart/daemon/up-progress.js +366 -0
  253. package/dist/heart/daemon/vault-items.js +56 -0
  254. package/dist/heart/delegation.js +1 -4
  255. package/dist/heart/external-events/router.js +1531 -0
  256. package/dist/heart/failure-reports.js +336 -0
  257. package/dist/heart/file-lock.js +109 -0
  258. package/dist/heart/frontend-approval-runtime.js +506 -0
  259. package/dist/heart/frontend-journal.js +215 -0
  260. package/dist/heart/frontend-session-service.js +271 -0
  261. package/dist/heart/frontend-socket-client.js +173 -0
  262. package/dist/heart/frontend-socket.js +434 -0
  263. package/dist/heart/frontend-turn-errors.js +20 -0
  264. package/dist/heart/habits/habit-cancel.js +810 -0
  265. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  266. package/dist/heart/habits/habit-migration.js +194 -0
  267. package/dist/heart/habits/habit-parser.js +278 -0
  268. package/dist/heart/habits/habit-runtime-state.js +93 -0
  269. package/dist/heart/habits/habit-scheduler.js +653 -0
  270. package/dist/heart/habits/habit-session-summary.js +318 -0
  271. package/dist/heart/habits/habit-session.js +636 -0
  272. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
  273. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  274. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  275. package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
  276. package/dist/heart/identity.js +239 -59
  277. package/dist/heart/kept-notes.js +289 -0
  278. package/dist/heart/kicks.js +1 -1
  279. package/dist/heart/machine-identity.js +175 -0
  280. package/dist/heart/mail-import-discovery.js +356 -0
  281. package/dist/heart/mailbox/mailbox-http-hooks.js +99 -0
  282. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  283. package/dist/heart/mailbox/mailbox-http-routes.js +406 -0
  284. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  285. package/dist/heart/mailbox/mailbox-http-transport.js +272 -0
  286. package/dist/heart/mailbox/mailbox-http.js +99 -0
  287. package/dist/heart/mailbox/mailbox-read.js +41 -0
  288. package/dist/heart/mailbox/mailbox-supervision.js +131 -0
  289. package/dist/heart/mailbox/mailbox-types.js +27 -0
  290. package/dist/heart/mailbox/mailbox-view.js +197 -0
  291. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  292. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  293. package/dist/heart/mailbox/readers/mail.js +375 -0
  294. package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
  295. package/dist/heart/mailbox/readers/sessions.js +231 -0
  296. package/dist/heart/mailbox/readers/shared.js +111 -0
  297. package/dist/heart/mcp/mcp-server.js +760 -0
  298. package/dist/heart/migrate-config.js +100 -0
  299. package/dist/heart/model-capabilities.js +83 -16
  300. package/dist/heart/orientation-frame.js +376 -0
  301. package/dist/heart/platform.js +81 -0
  302. package/dist/heart/primitives.js +1 -1
  303. package/dist/heart/private-runtime/decision-renderer.js +158 -0
  304. package/dist/heart/private-runtime/index.js +18 -0
  305. package/dist/heart/private-runtime/ledger.js +221 -0
  306. package/dist/heart/private-runtime/policy.js +260 -0
  307. package/dist/heart/private-runtime/types.js +2 -0
  308. package/dist/heart/progress-story.js +1 -1
  309. package/dist/heart/provider-attempt.js +137 -0
  310. package/dist/heart/provider-binding-resolver.js +273 -0
  311. package/dist/heart/provider-credentials.js +449 -0
  312. package/dist/heart/provider-failover.js +311 -0
  313. package/dist/heart/provider-models.js +96 -0
  314. package/dist/heart/provider-ping.js +266 -0
  315. package/dist/heart/provider-readiness-cache.js +119 -0
  316. package/dist/heart/provider-visibility.js +188 -0
  317. package/dist/heart/providers/anthropic-token.js +131 -0
  318. package/dist/heart/providers/anthropic.js +248 -67
  319. package/dist/heart/providers/azure.js +23 -11
  320. package/dist/heart/providers/error-classification.js +129 -0
  321. package/dist/heart/providers/github-copilot.js +38 -39
  322. package/dist/heart/providers/minimax-vlm.js +189 -0
  323. package/dist/heart/providers/minimax.js +26 -8
  324. package/dist/heart/providers/openai-codex-token.js +349 -0
  325. package/dist/heart/providers/openai-codex.js +55 -40
  326. package/dist/heart/providers/openai-compatible.js +177 -0
  327. package/dist/heart/reach-channel.js +85 -0
  328. package/dist/heart/reply-style.js +52 -0
  329. package/dist/heart/run-ledger.js +247 -0
  330. package/dist/heart/runtime-capability-check.js +170 -0
  331. package/dist/heart/runtime-credentials.js +608 -0
  332. package/dist/heart/runtime-cwd.js +87 -0
  333. package/dist/heart/sense-truth.js +24 -4
  334. package/dist/heart/session-activity.js +94 -24
  335. package/dist/heart/session-events.js +1521 -0
  336. package/dist/heart/session-playback-cli-main.js +5 -0
  337. package/dist/heart/session-playback-cli.js +36 -0
  338. package/dist/heart/session-playback.js +231 -0
  339. package/dist/heart/session-redaction-repair-cli-main.js +31 -0
  340. package/dist/heart/session-redaction-repair.js +552 -0
  341. package/dist/heart/session-stats-cli-main.js +5 -0
  342. package/dist/heart/session-stats.js +183 -0
  343. package/dist/heart/session-transcript.js +133 -0
  344. package/dist/heart/shelf-claims.js +78 -0
  345. package/dist/heart/shepherd/custody-types.js +2 -0
  346. package/dist/heart/shepherd/mandates.js +352 -0
  347. package/dist/heart/shepherd/operation-commands.js +19 -0
  348. package/dist/heart/shepherd/operations.js +135 -0
  349. package/dist/heart/shepherd/supervision.js +114 -0
  350. package/dist/heart/shepherd/types.js +2 -0
  351. package/dist/heart/shepherd-config.js +123 -0
  352. package/dist/heart/source-grounding.js +313 -0
  353. package/dist/heart/start-of-turn-packet.js +372 -0
  354. package/dist/heart/steward-policy.js +656 -0
  355. package/dist/heart/streaming.js +631 -207
  356. package/dist/heart/structured-output.js +196 -0
  357. package/dist/heart/sync-classification.js +176 -0
  358. package/dist/heart/sync-health.js +152 -0
  359. package/dist/heart/sync-lock.js +431 -0
  360. package/dist/heart/sync.js +1579 -0
  361. package/dist/heart/target-resolution.js +11 -7
  362. package/dist/heart/tempo.js +93 -0
  363. package/dist/heart/temporal-view.js +41 -0
  364. package/dist/heart/timeouts.js +101 -0
  365. package/dist/heart/tool-activity-callbacks.js +59 -0
  366. package/dist/heart/tool-approval.js +382 -0
  367. package/dist/heart/tool-description.js +155 -0
  368. package/dist/heart/tool-friction.js +55 -0
  369. package/dist/heart/tool-loop.js +206 -0
  370. package/dist/heart/tool-output-budget.js +41 -0
  371. package/dist/heart/turn-context.js +496 -0
  372. package/dist/heart/turn-execution-lease.js +30 -0
  373. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  374. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +3 -2
  375. package/dist/heart/versioning/ouro-path-installer.js +432 -0
  376. package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
  377. package/dist/heart/versioning/ouro-version-manager.js +432 -0
  378. package/dist/heart/versioning/release-sources.js +173 -0
  379. package/dist/heart/versioning/self-update-defaults.js +294 -0
  380. package/dist/heart/versioning/self-update.js +196 -0
  381. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  382. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  383. package/dist/heart/versioning/update-hooks.js +154 -0
  384. package/dist/heart/versioning/update-state.js +126 -0
  385. package/dist/heart/versioning/updater-launchd.js +150 -0
  386. package/dist/heart/versioning/version-intent.js +114 -0
  387. package/dist/heart/work-card.js +380 -0
  388. package/dist/mailbox-ui/assets/index-Dbska1tZ.js +1 -0
  389. package/dist/mailbox-ui/assets/index-DsiKaPyH.css +1 -0
  390. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  391. package/dist/mailbox-ui/index.html +16 -0
  392. package/dist/mailroom/attention.js +167 -0
  393. package/dist/mailroom/autonomy.js +209 -0
  394. package/dist/mailroom/blob-store.js +889 -0
  395. package/dist/mailroom/body-cache.js +61 -0
  396. package/dist/mailroom/cache-sync-cli.js +58 -0
  397. package/dist/mailroom/core.js +803 -0
  398. package/dist/mailroom/entry.js +160 -0
  399. package/dist/mailroom/file-store.js +568 -0
  400. package/dist/mailroom/hosted-cache-sync.js +384 -0
  401. package/dist/mailroom/mbox-import.js +393 -0
  402. package/dist/mailroom/migration.js +164 -0
  403. package/dist/mailroom/outbound.js +380 -0
  404. package/dist/mailroom/policy.js +263 -0
  405. package/dist/mailroom/reader.js +292 -0
  406. package/dist/mailroom/search-cache.js +513 -0
  407. package/dist/mailroom/search-relevance.js +319 -0
  408. package/dist/mailroom/smtp-ingress.js +176 -0
  409. package/dist/mailroom/source-state.js +176 -0
  410. package/dist/mailroom/thread.js +109 -0
  411. package/dist/mailroom/travel-extract.js +89 -0
  412. package/dist/mind/bundle-manifest.js +25 -2
  413. package/dist/mind/context.js +328 -139
  414. package/dist/mind/desk-section.js +362 -0
  415. package/dist/mind/diary-integrity.js +60 -0
  416. package/dist/mind/{memory.js → diary.js} +68 -77
  417. package/dist/mind/embedding-provider.js +60 -0
  418. package/dist/mind/file-state.js +179 -0
  419. package/dist/mind/friend-link-codes.js +209 -0
  420. package/dist/mind/friend-merge.js +336 -0
  421. package/dist/mind/house-names.js +43 -0
  422. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  423. package/dist/mind/obligation-steering.js +199 -3
  424. package/dist/mind/outbound-record.js +168 -0
  425. package/dist/mind/pending.js +36 -10
  426. package/dist/mind/prompt-budget.js +479 -0
  427. package/dist/mind/prompt-refresh.js +3 -2
  428. package/dist/mind/prompt.js +1222 -203
  429. package/dist/mind/provenance-trust.js +26 -0
  430. package/dist/mind/record-paths.js +312 -0
  431. package/dist/mind/scrutiny.js +173 -0
  432. package/dist/mind/session-transaction.js +622 -0
  433. package/dist/nerves/cli-logging.js +7 -1
  434. package/dist/nerves/coverage/audit-rules.js +15 -6
  435. package/dist/nerves/coverage/audit.js +28 -2
  436. package/dist/nerves/coverage/cli.js +1 -1
  437. package/dist/nerves/coverage/contract.js +5 -5
  438. package/dist/nerves/coverage/file-completeness.js +143 -5
  439. package/dist/nerves/coverage/run-artifacts.js +55 -35
  440. package/dist/nerves/coverage/source-scanner.js +4 -4
  441. package/dist/nerves/event-buffer.js +111 -0
  442. package/dist/nerves/index.js +293 -9
  443. package/dist/nerves/observation.js +20 -0
  444. package/dist/nerves/redact.js +79 -0
  445. package/dist/nerves/review/cli-main.js +5 -0
  446. package/dist/nerves/review/cli.js +156 -0
  447. package/dist/nerves/review/core.js +159 -0
  448. package/dist/nerves/runtime.js +17 -1
  449. package/dist/repertoire/ado-client.js +15 -56
  450. package/dist/repertoire/ado-semantic.js +16 -10
  451. package/dist/repertoire/api-client.js +97 -0
  452. package/dist/repertoire/bitwarden-store.js +1199 -0
  453. package/dist/repertoire/bundle-templates.js +71 -0
  454. package/dist/repertoire/bw-installer.js +231 -0
  455. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  456. package/dist/repertoire/coding/context-pack.js +331 -0
  457. package/dist/repertoire/coding/feedback.js +146 -34
  458. package/dist/repertoire/coding/index.js +15 -3
  459. package/dist/repertoire/coding/manager.js +159 -10
  460. package/dist/repertoire/coding/spawner.js +40 -11
  461. package/dist/repertoire/coding/tools.js +182 -18
  462. package/dist/repertoire/coding/workbench-client.js +272 -0
  463. package/dist/repertoire/coding/workbench-manager.js +346 -0
  464. package/dist/repertoire/commerce-errors.js +109 -0
  465. package/dist/repertoire/commerce-self-test.js +156 -0
  466. package/dist/repertoire/credential-access.js +183 -0
  467. package/dist/repertoire/desk/classifier.js +362 -0
  468. package/dist/repertoire/duffel-client.js +185 -0
  469. package/dist/repertoire/github-client.js +14 -55
  470. package/dist/repertoire/graph-client.js +11 -52
  471. package/dist/repertoire/guardrails.js +1480 -22
  472. package/dist/repertoire/house-sweep.js +471 -0
  473. package/dist/repertoire/mcp-client.js +58 -5
  474. package/dist/repertoire/mcp-manager.js +427 -139
  475. package/dist/repertoire/mcp-tools.js +132 -0
  476. package/dist/repertoire/mcp-write-guard.js +46 -0
  477. package/dist/repertoire/plugin-mcp.js +175 -0
  478. package/dist/repertoire/plugins.js +253 -0
  479. package/dist/repertoire/relationship-authorization.js +322 -0
  480. package/dist/repertoire/sanctuary-container-policy.js +50 -0
  481. package/dist/repertoire/shell-sessions.js +134 -0
  482. package/dist/repertoire/skills.js +48 -4
  483. package/dist/repertoire/stripe-client.js +131 -0
  484. package/dist/repertoire/tool-arguments.js +182 -0
  485. package/dist/repertoire/tool-results.js +29 -0
  486. package/dist/repertoire/tools-a2a.js +742 -0
  487. package/dist/repertoire/tools-attachments.js +322 -0
  488. package/dist/repertoire/tools-awaiting.js +897 -0
  489. package/dist/repertoire/tools-base.js +83 -1168
  490. package/dist/repertoire/tools-bluebubbles.js +2 -0
  491. package/dist/repertoire/tools-bridge.js +144 -0
  492. package/dist/repertoire/tools-bundle.js +917 -0
  493. package/dist/repertoire/tools-commerce.js +253 -0
  494. package/dist/repertoire/tools-config.js +186 -0
  495. package/dist/repertoire/tools-continuity.js +588 -0
  496. package/dist/repertoire/tools-credential.js +383 -0
  497. package/dist/repertoire/tools-escalation.js +84 -0
  498. package/dist/repertoire/tools-evolution.js +527 -0
  499. package/dist/repertoire/tools-files.js +362 -0
  500. package/dist/repertoire/tools-flight.js +290 -0
  501. package/dist/repertoire/tools-flow.js +119 -0
  502. package/dist/repertoire/tools-friend-link.js +57 -0
  503. package/dist/repertoire/tools-github.js +3 -8
  504. package/dist/repertoire/tools-habits.js +103 -0
  505. package/dist/repertoire/tools-house-care.js +174 -0
  506. package/dist/repertoire/tools-mail.js +1828 -0
  507. package/dist/repertoire/tools-notes.js +501 -0
  508. package/dist/repertoire/tools-obligations.js +182 -0
  509. package/dist/repertoire/tools-orientation.js +31 -0
  510. package/dist/repertoire/tools-record.js +482 -0
  511. package/dist/repertoire/tools-rsvp.js +139 -0
  512. package/dist/repertoire/tools-runtime.js +238 -0
  513. package/dist/repertoire/tools-sanctuary-host.js +202 -0
  514. package/dist/repertoire/tools-session.js +1141 -0
  515. package/dist/repertoire/tools-shell.js +154 -0
  516. package/dist/repertoire/tools-shepherd-guidance.js +171 -0
  517. package/dist/repertoire/tools-shepherd.js +325 -0
  518. package/dist/repertoire/tools-steward-policy.js +147 -0
  519. package/dist/repertoire/tools-stripe.js +224 -0
  520. package/dist/repertoire/tools-surface.js +369 -0
  521. package/dist/repertoire/tools-teams.js +50 -39
  522. package/dist/repertoire/tools-telegram-contacts.js +37 -0
  523. package/dist/repertoire/tools-travel.js +125 -0
  524. package/dist/repertoire/tools-trip.js +982 -0
  525. package/dist/repertoire/tools-unraid.js +556 -0
  526. package/dist/repertoire/tools-user-profile.js +146 -0
  527. package/dist/repertoire/tools-vault.js +40 -0
  528. package/dist/repertoire/tools-voice-local.js +198 -0
  529. package/dist/repertoire/tools-voice.js +145 -0
  530. package/dist/repertoire/tools.js +523 -156
  531. package/dist/repertoire/travel-api-client.js +360 -0
  532. package/dist/repertoire/unraid-client.js +155 -0
  533. package/dist/repertoire/unraid-restart.js +339 -0
  534. package/dist/repertoire/user-profile.js +131 -0
  535. package/dist/repertoire/vault-setup.js +246 -0
  536. package/dist/repertoire/vault-unlock.js +686 -0
  537. package/dist/rsvp/aisleplanner-client.js +354 -0
  538. package/dist/rsvp/cli.js +936 -0
  539. package/dist/rsvp/config.js +327 -0
  540. package/dist/rsvp/cutover.js +453 -0
  541. package/dist/rsvp/diagnostics.js +232 -0
  542. package/dist/rsvp/diff-renderer.js +176 -0
  543. package/dist/rsvp/habit-policy.js +110 -0
  544. package/dist/rsvp/habit-stage.js +123 -0
  545. package/dist/rsvp/incident-bundle.js +97 -0
  546. package/dist/rsvp/migration.js +204 -0
  547. package/dist/rsvp/native-habit-runner.js +630 -0
  548. package/dist/rsvp/outbound-state.js +628 -0
  549. package/dist/rsvp/query.js +118 -0
  550. package/dist/rsvp/replay.js +233 -0
  551. package/dist/rsvp/snapshot.js +232 -0
  552. package/dist/rsvp/spend-ledger.js +175 -0
  553. package/dist/scripts/claude-code-hook.js +41 -0
  554. package/dist/scripts/claude-code-stop-hook.js +47 -0
  555. package/dist/senses/a2a-entry.js +140 -0
  556. package/dist/senses/acp-server.js +386 -0
  557. package/dist/senses/attention-queue.js +186 -0
  558. package/dist/senses/await-turn-message.js +65 -0
  559. package/dist/senses/bluebubbles/active-turns.js +216 -0
  560. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  561. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  562. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +393 -43
  563. package/dist/senses/bluebubbles/context-packet.js +207 -0
  564. package/dist/senses/bluebubbles/context-smoke.js +144 -0
  565. package/dist/senses/bluebubbles/entry.js +90 -0
  566. package/dist/senses/bluebubbles/host-account-verifier.js +88 -0
  567. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
  568. package/dist/senses/bluebubbles/index.js +4054 -0
  569. package/dist/senses/bluebubbles/latest-turn.js +311 -0
  570. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  571. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
  572. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
  573. package/dist/senses/bluebubbles/outbound-state.js +335 -0
  574. package/dist/senses/bluebubbles/processed-log.js +133 -0
  575. package/dist/senses/bluebubbles/reaction-policy.js +47 -0
  576. package/dist/senses/bluebubbles/replay.js +284 -0
  577. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  578. package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
  579. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  580. package/dist/senses/bluebubbles/webhook-registration.js +257 -0
  581. package/dist/senses/bluebubbles-meta-guard.js +39 -0
  582. package/dist/senses/cli/bracketed-paste.js +82 -0
  583. package/dist/senses/cli/image-paste.js +287 -0
  584. package/dist/senses/cli/image-ref-navigation.js +75 -0
  585. package/dist/senses/cli/ink-app.js +156 -0
  586. package/dist/senses/cli/inline-diff.js +64 -0
  587. package/dist/senses/cli/input-keys.js +174 -0
  588. package/dist/senses/cli/kill-ring.js +86 -0
  589. package/dist/senses/cli/message-list.js +51 -0
  590. package/dist/senses/cli/ouro-tui.js +607 -0
  591. package/dist/senses/cli/spinner-imperative.js +135 -0
  592. package/dist/senses/cli/spinner.js +101 -0
  593. package/dist/senses/cli/status-line.js +60 -0
  594. package/dist/senses/cli/streaming-markdown.js +526 -0
  595. package/dist/senses/cli/tool-display.js +85 -0
  596. package/dist/senses/cli/tool-render.js +85 -0
  597. package/dist/senses/cli/tui-store.js +241 -0
  598. package/dist/senses/cli/virtual-list.js +35 -0
  599. package/dist/senses/cli-entry.js +60 -8
  600. package/dist/senses/cli.js +570 -309
  601. package/dist/senses/commands.js +66 -3
  602. package/dist/senses/context-packet-ledger.js +371 -0
  603. package/dist/senses/context-packets.js +154 -0
  604. package/dist/senses/habit-lifecycle-guard.js +24 -0
  605. package/dist/senses/habit-turn-message.js +160 -0
  606. package/dist/senses/ingress-evidence.js +2 -0
  607. package/dist/senses/mail-entry.js +66 -0
  608. package/dist/senses/mail.js +524 -0
  609. package/dist/senses/pipeline.js +1192 -204
  610. package/dist/senses/private-runtime-worker.js +857 -0
  611. package/dist/senses/private-runtime.js +1622 -0
  612. package/dist/senses/proactive-content-guard.js +51 -0
  613. package/dist/senses/root-host-approval-port.js +345 -0
  614. package/dist/senses/root-host-approval-runtime.js +393 -0
  615. package/dist/senses/sanctuary-authority-resident.js +102 -0
  616. package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
  617. package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
  618. package/dist/senses/sanctuary-grounding.js +118 -0
  619. package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
  620. package/dist/senses/sanctuary-health-acceptance-probe.js +786 -0
  621. package/dist/senses/sanctuary-health-runner.js +106 -0
  622. package/dist/senses/sanctuary-health.js +442 -0
  623. package/dist/senses/sanctuary-house.js +97 -0
  624. package/dist/senses/sanctuary-install-state-contract.js +169 -0
  625. package/dist/senses/sanctuary-interactive-control.js +410 -0
  626. package/dist/senses/sanctuary-media-catalog-contract.js +268 -0
  627. package/dist/senses/sanctuary-media-optimization.js +517 -0
  628. package/dist/senses/sanctuary-runtime.js +390 -0
  629. package/dist/senses/sanctuary-sab.js +85 -0
  630. package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
  631. package/dist/senses/shared-turn.js +832 -0
  632. package/dist/senses/shepherd/agent-presentation.js +88 -0
  633. package/dist/senses/shepherd/attention-page.js +166 -0
  634. package/dist/senses/shepherd/attention-sidebar.js +76 -0
  635. package/dist/senses/shepherd/attention.js +295 -0
  636. package/dist/senses/shepherd/checkin-config.js +76 -0
  637. package/dist/senses/shepherd/checkin-store.js +386 -0
  638. package/dist/senses/shepherd/client.js +196 -0
  639. package/dist/senses/shepherd/cmux.js +483 -0
  640. package/dist/senses/shepherd/composer.js +336 -0
  641. package/dist/senses/shepherd/copilot-app.js +648 -0
  642. package/dist/senses/shepherd/feedback-reply.js +108 -0
  643. package/dist/senses/shepherd/feedback-source.js +20 -0
  644. package/dist/senses/shepherd/feedback-store.js +331 -0
  645. package/dist/senses/shepherd/feedback-submit.js +182 -0
  646. package/dist/senses/shepherd/feedback-worker.js +208 -0
  647. package/dist/senses/shepherd/guidance.js +273 -0
  648. package/dist/senses/shepherd/herdr.js +427 -0
  649. package/dist/senses/shepherd/host.js +17 -0
  650. package/dist/senses/shepherd/human-decision-guard.js +29 -0
  651. package/dist/senses/shepherd/judge-evaluation-command.js +183 -0
  652. package/dist/senses/shepherd/judge-evaluation-entry.js +13 -0
  653. package/dist/senses/shepherd/judge-evaluation.js +155 -0
  654. package/dist/senses/shepherd/judge.js +210 -0
  655. package/dist/senses/shepherd/notice-outbox.js +262 -0
  656. package/dist/senses/shepherd/observation-publisher.js +320 -0
  657. package/dist/senses/shepherd/operations-defaults.js +86 -0
  658. package/dist/senses/shepherd/operations.js +159 -0
  659. package/dist/senses/shepherd/owner-notice.js +489 -0
  660. package/dist/senses/shepherd/prompt-state.js +60 -0
  661. package/dist/senses/shepherd/recovery.js +543 -0
  662. package/dist/senses/shepherd/redact.js +66 -0
  663. package/dist/senses/shepherd/returns.js +79 -0
  664. package/dist/senses/shepherd/sense.js +849 -0
  665. package/dist/senses/shepherd/shepherd-judge-corpus-v1.json +170 -0
  666. package/dist/senses/shepherd/surface.js +123 -0
  667. package/dist/senses/shepherd/target-binding.js +13 -0
  668. package/dist/senses/shepherd/terminal-process.js +147 -0
  669. package/dist/senses/shepherd-entry.js +98 -0
  670. package/dist/senses/surface-tool.js +109 -0
  671. package/dist/senses/teams-entry.js +68 -8
  672. package/dist/senses/teams-image.js +119 -0
  673. package/dist/senses/teams.js +998 -337
  674. package/dist/senses/telegram-admission.js +718 -0
  675. package/dist/senses/telegram-approval-runtime.js +793 -0
  676. package/dist/senses/telegram-attachments.js +186 -0
  677. package/dist/senses/telegram-audit-ledger.js +220 -0
  678. package/dist/senses/telegram-authority-transport.js +231 -0
  679. package/dist/senses/telegram-client.js +1755 -0
  680. package/dist/senses/telegram-effect-adapter.js +904 -0
  681. package/dist/senses/telegram-entry.js +83 -0
  682. package/dist/senses/telegram-handoff.js +154 -0
  683. package/dist/senses/telegram.js +2474 -0
  684. package/dist/senses/trust-gate.js +104 -9
  685. package/dist/senses/voice/audio-playback.js +237 -0
  686. package/dist/senses/voice/audio-routing.js +119 -0
  687. package/dist/senses/voice/call-auth.js +250 -0
  688. package/dist/senses/voice/elevenlabs.js +202 -0
  689. package/dist/senses/voice/floor-control.js +431 -0
  690. package/dist/senses/voice/floor-controller.js +115 -0
  691. package/dist/senses/voice/golden-path.js +116 -0
  692. package/dist/senses/voice/index.js +29 -0
  693. package/dist/senses/voice/local-audio-control.js +344 -0
  694. package/dist/senses/voice/local-audio-devices.js +516 -0
  695. package/dist/senses/voice/local-audio-disclosure.js +174 -0
  696. package/dist/senses/voice/local-audio-identity.js +103 -0
  697. package/dist/senses/voice/local-audio-join.js +325 -0
  698. package/dist/senses/voice/local-audio-mute.js +199 -0
  699. package/dist/senses/voice/local-audio-notify.js +124 -0
  700. package/dist/senses/voice/local-audio-prompts.js +116 -0
  701. package/dist/senses/voice/local-audio-transport.js +427 -0
  702. package/dist/senses/voice/local-audio.js +281 -0
  703. package/dist/senses/voice/local-media-stream.js +145 -0
  704. package/dist/senses/voice/meeting.js +113 -0
  705. package/dist/senses/voice/outbound.js +190 -0
  706. package/dist/senses/voice/phone.js +33 -0
  707. package/dist/senses/voice/playback.js +139 -0
  708. package/dist/senses/voice/process-guards.js +51 -0
  709. package/dist/senses/voice/realtime-eval.js +496 -0
  710. package/dist/senses/voice/realtime-tool-schema.js +195 -0
  711. package/dist/senses/voice/realtime-trace.js +531 -0
  712. package/dist/senses/voice/transcript.js +70 -0
  713. package/dist/senses/voice/turn.js +191 -0
  714. package/dist/senses/voice/twilio-phone-runtime.js +836 -0
  715. package/dist/senses/voice/twilio-phone.js +5454 -0
  716. package/dist/senses/voice/types.js +2 -0
  717. package/dist/senses/voice/whisper.js +161 -0
  718. package/dist/senses/voice-entry.js +83 -0
  719. package/dist/senses/voice-realtime-eval-command.js +99 -0
  720. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  721. package/dist/senses/voice-twilio-entry.js +87 -0
  722. package/dist/trips/core.js +138 -0
  723. package/dist/trips/store.js +265 -0
  724. package/dist/util/frontmatter.js +69 -0
  725. package/npm-shrinkwrap.json +8342 -0
  726. package/package.json +76 -13
  727. package/skills/agent-commerce.md +113 -0
  728. package/skills/browser-navigation.md +117 -0
  729. package/skills/commerce-setup-guide.md +116 -0
  730. package/skills/commerce-setup.md +84 -0
  731. package/skills/configure-dev-tools.md +99 -0
  732. package/skills/travel-planning.md +138 -0
  733. package/dist/heart/daemon/auth-flow.js +0 -430
  734. package/dist/heart/daemon/ouro-path-installer.js +0 -260
  735. package/dist/heart/daemon/ouro-version-manager.js +0 -171
  736. package/dist/heart/daemon/update-hooks.js +0 -138
  737. package/dist/heart/obligations.js +0 -191
  738. package/dist/heart/safe-workspace.js +0 -381
  739. package/dist/heart/session-recall.js +0 -116
  740. package/dist/mind/friends/channel.js +0 -84
  741. package/dist/mind/friends/group-context.js +0 -144
  742. package/dist/mind/friends/resolver.js +0 -84
  743. package/dist/mind/friends/store-file.js +0 -190
  744. package/dist/mind/friends/store.js +0 -4
  745. package/dist/mind/friends/tokens.js +0 -26
  746. package/dist/mind/friends/trust-explanation.js +0 -74
  747. package/dist/mind/friends/types.js +0 -29
  748. package/dist/repertoire/tasks/board.js +0 -134
  749. package/dist/repertoire/tasks/index.js +0 -224
  750. package/dist/repertoire/tasks/lifecycle.js +0 -80
  751. package/dist/repertoire/tasks/middleware.js +0 -65
  752. package/dist/repertoire/tasks/parser.js +0 -173
  753. package/dist/repertoire/tasks/scanner.js +0 -132
  754. package/dist/repertoire/tasks/transitions.js +0 -144
  755. package/dist/senses/bluebubbles-entry.js +0 -13
  756. package/dist/senses/bluebubbles.js +0 -1181
  757. package/dist/senses/debug-activity.js +0 -154
  758. package/dist/senses/inner-dialog-worker.js +0 -90
  759. package/dist/senses/inner-dialog.js +0 -525
  760. package/subagents/README.md +0 -7
  761. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  762. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  763. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  764. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  765. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  766. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  767. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  768. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  769. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  770. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  771. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  772. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  773. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  774. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  775. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  776. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  777. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,974 @@
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.SANCTUARY_GIT_EXCLUDES = exports.SANCTUARY_BUNDLE_ROLLBACK_FILE = exports.SANCTUARY_STARTER_PSYCHE_FILES = exports.SANCTUARY_PACKAGE_MANAGED_FILES = void 0;
37
+ exports.sanctuaryGitExcludeText = sanctuaryGitExcludeText;
38
+ exports.bundleSyncEnabled = bundleSyncEnabled;
39
+ exports.writeSanctuaryGitExclude = writeSanctuaryGitExclude;
40
+ exports.inspectSanctuaryDirectoryFromBase = inspectSanctuaryDirectoryFromBase;
41
+ exports.sanctuaryDirectoriesShareIdentity = sanctuaryDirectoriesShareIdentity;
42
+ exports.inspectSanctuaryPackageManagedBundle = inspectSanctuaryPackageManagedBundle;
43
+ exports.ensureSanctuaryPackageManagedBundle = ensureSanctuaryPackageManagedBundle;
44
+ exports.seedSanctuaryPsycheIfAbsent = seedSanctuaryPsycheIfAbsent;
45
+ exports.inspectSanctuaryPackageManagedBundleRollback = inspectSanctuaryPackageManagedBundleRollback;
46
+ exports.rollbackSanctuaryPackageManagedBundle = rollbackSanctuaryPackageManagedBundle;
47
+ exports.commitSanctuaryPackageManagedBundle = commitSanctuaryPackageManagedBundle;
48
+ exports.migrateSanctuaryPackageManagedBundle = migrateSanctuaryPackageManagedBundle;
49
+ const fs = __importStar(require("node:fs"));
50
+ const path = __importStar(require("node:path"));
51
+ const node_child_process_1 = require("node:child_process");
52
+ const node_crypto_1 = require("node:crypto");
53
+ const runtime_1 = require("../../nerves/runtime");
54
+ const house_names_1 = require("../../mind/house-names");
55
+ exports.SANCTUARY_PACKAGE_MANAGED_FILES = [
56
+ "provider-readiness.json",
57
+ "tool-profiles.json",
58
+ "mcp/media-mcp.mjs",
59
+ "habits/sanctuary-health.md",
60
+ "awaiting/house-care-sweep.md",
61
+ "product/PRODUCT.md",
62
+ ];
63
+ // The psyche belongs to the install: it is seeded from these files only when `psyche/` is absent, and no release touches it again.
64
+ exports.SANCTUARY_STARTER_PSYCHE_FILES = ["psyche/ASPIRATIONS.md", "psyche/IDENTITY.md", "psyche/LORE.md", "psyche/SOUL.md", "psyche/TACIT.md"];
65
+ const PSYCHE_SEED_STAGE_PREFIX = ".psyche-seed.";
66
+ // mkdtemp appends six characters from [A-Za-z0-9]; any other name under the prefix belongs to the owner.
67
+ const PSYCHE_SEED_STAGE_NAME = /^\.psyche-seed\.[A-Za-z0-9]{6}$/u;
68
+ const STARTER_PSYCHE_NAMES = new Set(exports.SANCTUARY_STARTER_PSYCHE_FILES.map((relative) => path.basename(relative)));
69
+ exports.SANCTUARY_BUNDLE_ROLLBACK_FILE = ".sanctuary-package-managed-rollback.json";
70
+ const SANCTUARY_BUNDLE_COMMITTING_FILE = `${exports.SANCTUARY_BUNDLE_ROLLBACK_FILE}.committing`;
71
+ /**
72
+ * What sync never commits from the Butler's bundle. The first block is the hourly host backup's own list, copied from
73
+ * bundle-backup/repo.git/info/exclude on 2026-11-06. Then any MCP credential file, the files each release installs, and
74
+ * the release's own bookkeeping, then the transient temp and lock files written inside the bundle. The cutover writes this list with `ouro sanctuary git-exclude --print`, and every boot
75
+ * writes it again.
76
+ */
77
+ exports.SANCTUARY_GIT_EXCLUDES = [
78
+ "**/credentials.json",
79
+ "mcp/media-credentials.json",
80
+ "books/hey/.config/",
81
+ "**/*.key",
82
+ "**/*.pem",
83
+ "**/deploy_key*",
84
+ "**/id_rsa*",
85
+ "**/id_ed25519*",
86
+ "**/id_ecdsa*",
87
+ "**/.env",
88
+ "state/",
89
+ "inbox/",
90
+ "arc/flight-recorder/",
91
+ "arc/obligations/",
92
+ "arc/packets/",
93
+ "books/bin/",
94
+ "books/vendor/",
95
+ "books/work/",
96
+ "books/fonts/",
97
+ "mcp/*.pre-*",
98
+ "books/hey/",
99
+ "**/__pycache__/",
100
+ "mcp/*credentials*",
101
+ ...exports.SANCTUARY_PACKAGE_MANAGED_FILES,
102
+ "bundle-meta.json",
103
+ `${exports.SANCTUARY_BUNDLE_ROLLBACK_FILE}*`,
104
+ `${PSYCHE_SEED_STAGE_PREFIX}*`,
105
+ // The upgrade's release marker and its staged copy, planted in psyche/ for the length of a gated ship.
106
+ "psyche/.release-marker*",
107
+ // Transient files the runtime and the replay gate write inside the bundle: atomic-write temps and lock files.
108
+ "*.tmp",
109
+ "*.tmp-*",
110
+ "*.tmp.*",
111
+ "*.lock",
112
+ "*.lock.reclaim",
113
+ "*.turn.lock-*",
114
+ ".locks/",
115
+ ];
116
+ /** The exclude file's content: one entry per line. */
117
+ function sanctuaryGitExcludeText() {
118
+ return `${exports.SANCTUARY_GIT_EXCLUDES.join("\n")}\n`;
119
+ }
120
+ /** Whether the bundle's agent.json turns sync on. An unreadable agent.json reads as off. */
121
+ function bundleSyncEnabled(agentRoot) {
122
+ try {
123
+ const sync = readObject(path.join(agentRoot, "agent.json")).sync;
124
+ return sync?.enabled === true;
125
+ }
126
+ catch {
127
+ return false;
128
+ }
129
+ }
130
+ /**
131
+ * Write the bundle's `.git/info/exclude`. A bundle with sync on and no repository yet (a fresh install) gets
132
+ * `git init -b main` first; sync makes the first commit on the first turn. A bundle with sync off and no
133
+ * repository is left alone. A tracked .gitignore is the owner's and is never touched.
134
+ */
135
+ function writeSanctuaryGitExclude(agentRoot) {
136
+ const gitDir = path.join(agentRoot, ".git");
137
+ let initialized = false;
138
+ if (!fs.existsSync(gitDir)) {
139
+ if (!bundleSyncEnabled(agentRoot))
140
+ return { initialized: false, written: false };
141
+ const run = (0, node_child_process_1.spawnSync)("git", ["init", "-q", "-b", "main"], { cwd: agentRoot, env: { ...process.env, LC_ALL: "C", LANG: "C" }, encoding: "utf8" });
142
+ if (run.status !== 0)
143
+ throw new Error(`git init failed: ${run.error ? run.error.message : run.stderr.trim()}`);
144
+ initialized = true;
145
+ }
146
+ const excludePath = path.join(gitDir, "info", "exclude");
147
+ const text = sanctuaryGitExcludeText();
148
+ let current = null;
149
+ try {
150
+ current = fs.readFileSync(excludePath, "utf8");
151
+ }
152
+ catch (error) {
153
+ if (!isMissing(error))
154
+ throw error;
155
+ }
156
+ if (current === text)
157
+ return { initialized, written: false };
158
+ fs.mkdirSync(path.dirname(excludePath), { recursive: true });
159
+ writeAtomic(excludePath, text, 0o644);
160
+ (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.sanctuary_git_exclude_written", message: "wrote the Sanctuary bundle's git exclude", meta: { initialized, entries: exports.SANCTUARY_GIT_EXCLUDES.length } });
161
+ return { initialized, written: true };
162
+ }
163
+ const BUNDLE_META_VERSION_FIELDS = ["runtimeVersion", "bundleSchemaVersion", "lastUpdated"];
164
+ class SanctuaryInspectionFault extends Error {
165
+ code;
166
+ constructor(code, message = code) {
167
+ super(message);
168
+ this.code = code;
169
+ }
170
+ }
171
+ const CANONICAL_EMPTY_PACKAGED_POLICY = { schemaVersion: 1, version: 0, desiredStates: {}, routineActionGrants: {}, updatedAt: null };
172
+ function readObject(filePath) {
173
+ const value = JSON.parse(fs.readFileSync(filePath, "utf8"));
174
+ if (!value || typeof value !== "object" || Array.isArray(value))
175
+ throw new Error(`${path.basename(filePath)} must contain an object`);
176
+ return value;
177
+ }
178
+ function isMissing(error) {
179
+ return !!error && typeof error === "object" && "code" in error && error.code === "ENOENT";
180
+ }
181
+ function isFilesystemFailure(error) {
182
+ return !!error && typeof error === "object" && "code" in error && typeof error.code === "string";
183
+ }
184
+ function inspectSanctuaryDirectoryFromBase(baseRoot, segments) {
185
+ if (!path.isAbsolute(baseRoot))
186
+ return null;
187
+ let current = path.resolve(baseRoot);
188
+ let stat = null;
189
+ for (const candidate of [current, ...segments.map((segment) => { current = path.join(current, segment); return current; })]) {
190
+ try {
191
+ stat = fs.lstatSync(candidate);
192
+ }
193
+ catch (error) {
194
+ if (isMissing(error))
195
+ return null;
196
+ throw error;
197
+ }
198
+ if (stat.isSymbolicLink() || !stat.isDirectory())
199
+ return null;
200
+ }
201
+ const realPath = fs.realpathSync(current);
202
+ if (realPath !== path.resolve(current))
203
+ return null;
204
+ return { realPath, device: stat.dev, inode: stat.ino };
205
+ }
206
+ function sanctuaryDirectoriesShareIdentity(left, right) {
207
+ return left.realPath === right.realPath || (left.device === right.device && left.inode === right.inode);
208
+ }
209
+ function inspectStandaloneSanctuaryDirectory(root) {
210
+ if (!path.isAbsolute(root))
211
+ return null;
212
+ const resolved = path.resolve(root);
213
+ return inspectSanctuaryDirectoryFromBase(path.dirname(resolved), [path.basename(resolved)]);
214
+ }
215
+ function isCanonicalEmptyPackagedPolicy(value) {
216
+ return JSON.stringify(Object.keys(value).sort()) === JSON.stringify(Object.keys(CANONICAL_EMPTY_PACKAGED_POLICY).sort())
217
+ && value.schemaVersion === 1
218
+ && value.version === 0
219
+ && value.updatedAt === null
220
+ && !!value.desiredStates
221
+ && typeof value.desiredStates === "object"
222
+ && !Array.isArray(value.desiredStates)
223
+ && Object.keys(value.desiredStates).length === 0
224
+ && !!value.routineActionGrants
225
+ && typeof value.routineActionGrants === "object"
226
+ && !Array.isArray(value.routineActionGrants)
227
+ && Object.keys(value.routineActionGrants).length === 0;
228
+ }
229
+ function validatePackagedPolicy(packageRoot) {
230
+ const relative = "state/policy/steward.json";
231
+ validateDestination(packageRoot, relative);
232
+ requirePlainFile(path.join(packageRoot, relative), "packaged steward policy");
233
+ const value = readObject(path.join(packageRoot, relative));
234
+ if (value.routineActionGrants && typeof value.routineActionGrants === "object" && !Array.isArray(value.routineActionGrants) && Object.keys(value.routineActionGrants).length > 0)
235
+ throw new Error("packaged steward policy must not carry routine action grants; authorize them through an authenticated owner session");
236
+ if (value.desiredStates && typeof value.desiredStates === "object" && !Array.isArray(value.desiredStates) && Object.keys(value.desiredStates).length > 0)
237
+ throw new Error("packaged steward policy must not carry desired state");
238
+ if (!isCanonicalEmptyPackagedPolicy(value))
239
+ throw new Error("packaged steward policy must be the canonical empty policy");
240
+ }
241
+ function requirePlainFile(filePath, label) {
242
+ let stat;
243
+ try {
244
+ stat = fs.lstatSync(filePath);
245
+ }
246
+ catch {
247
+ throw new Error(`${label} is missing`);
248
+ }
249
+ if (stat.isSymbolicLink())
250
+ throw new Error(`${label} must not be a symlink`);
251
+ if (!stat.isFile())
252
+ throw new Error(`${label} must be a regular file`);
253
+ }
254
+ function ensureSafeParent(agentRoot, relative) {
255
+ let current = agentRoot;
256
+ for (const segment of path.dirname(relative).split(path.sep).filter((value) => value !== ".")) {
257
+ current = path.join(current, segment);
258
+ if (!fs.existsSync(current))
259
+ fs.mkdirSync(current, { mode: 0o700 });
260
+ }
261
+ }
262
+ function validateDestination(agentRoot, relative) {
263
+ let current = agentRoot;
264
+ for (const segment of relative.split(path.sep)) {
265
+ current = path.join(current, segment);
266
+ let stat;
267
+ try {
268
+ stat = fs.lstatSync(current);
269
+ }
270
+ catch {
271
+ return;
272
+ }
273
+ if (stat.isSymbolicLink())
274
+ throw new Error(`package-managed destination must not be a symlink: ${relative}`);
275
+ if (current !== path.join(agentRoot, relative) && !stat.isDirectory())
276
+ throw new Error(`package-managed destination parent must be a directory: ${relative}`);
277
+ if (current === path.join(agentRoot, relative) && !stat.isFile())
278
+ throw new Error(`package-managed destination must be a regular file: ${relative}`);
279
+ }
280
+ }
281
+ function syncDirectory(directoryPath) {
282
+ const directory = fs.openSync(directoryPath, fs.constants.O_RDONLY | fs.constants.O_DIRECTORY | fs.constants.O_NOFOLLOW);
283
+ try {
284
+ fs.fsyncSync(directory);
285
+ }
286
+ finally {
287
+ fs.closeSync(directory);
288
+ }
289
+ }
290
+ function syncNearestExistingDirectory(directoryPath, agentRoot) {
291
+ let current = directoryPath;
292
+ while (current !== agentRoot && !fs.existsSync(current))
293
+ current = path.dirname(current);
294
+ syncDirectory(current);
295
+ }
296
+ function writeAtomic(filePath, content, mode = 0o600) {
297
+ const stagingDirectory = fs.mkdtempSync(`${filePath}.package-migration.`);
298
+ const temporary = path.join(stagingDirectory, "value");
299
+ try {
300
+ const fd = fs.openSync(temporary, "wx", 0o600);
301
+ try {
302
+ fs.writeFileSync(fd, content);
303
+ fs.fchmodSync(fd, mode);
304
+ fs.fsyncSync(fd);
305
+ }
306
+ finally {
307
+ fs.closeSync(fd);
308
+ }
309
+ fs.renameSync(temporary, filePath);
310
+ }
311
+ finally {
312
+ fs.rmSync(temporary, { force: true });
313
+ fs.rmdirSync(stagingDirectory);
314
+ }
315
+ syncDirectory(path.dirname(filePath));
316
+ }
317
+ const SNAPSHOT_RELATIVES = [...exports.SANCTUARY_PACKAGE_MANAGED_FILES, "bundle-meta.json"];
318
+ function packageManagedArtifactPaths(agentRoot) {
319
+ return SNAPSHOT_RELATIVES.map((relative) => path.join(agentRoot, relative));
320
+ }
321
+ function inspectInterruptedWrites(filePaths, restoredModes) {
322
+ const stages = [];
323
+ for (const filePath of [...filePaths].sort()) {
324
+ const parent = path.dirname(filePath);
325
+ const prefix = `${path.basename(filePath)}.package-migration.`;
326
+ let names;
327
+ try {
328
+ names = fs.readdirSync(parent).sort();
329
+ }
330
+ catch (error) {
331
+ if (isMissing(error))
332
+ continue;
333
+ throw error;
334
+ }
335
+ for (const name of names) {
336
+ if (!name.startsWith(prefix))
337
+ continue;
338
+ const stagingDirectory = path.join(parent, name);
339
+ const parentStat = fs.lstatSync(parent);
340
+ const stagingStat = fs.lstatSync(stagingDirectory);
341
+ if (parentStat.isSymbolicLink() || !parentStat.isDirectory() || stagingStat.isSymbolicLink() || !stagingStat.isDirectory() || (stagingStat.mode & 0o777) !== 0o700 || stagingStat.uid !== parentStat.uid || stagingStat.gid !== parentStat.gid)
342
+ throw new Error(`interrupted package migration stage is invalid: ${name}`);
343
+ const entries = fs.readdirSync(stagingDirectory);
344
+ if (entries.some((entry) => entry !== "value"))
345
+ throw new Error(`interrupted package migration stage contains unexpected entries: ${name}`);
346
+ const temporary = entries.includes("value") ? path.join(stagingDirectory, "value") : null;
347
+ if (temporary) {
348
+ const temporaryStat = fs.lstatSync(temporary);
349
+ const temporaryMode = temporaryStat.mode & 0o777;
350
+ if (temporaryStat.isSymbolicLink() || !temporaryStat.isFile() || (temporaryMode !== 0o600 && temporaryMode !== restoredModes?.get(filePath)) || temporaryStat.uid !== stagingStat.uid || temporaryStat.gid !== stagingStat.gid)
351
+ throw new Error(`interrupted package migration value is invalid: ${name}`);
352
+ }
353
+ stages.push({ stagingDirectory, temporary });
354
+ }
355
+ }
356
+ return stages;
357
+ }
358
+ function cleanupInterruptedWrites(filePaths, restoredModes) {
359
+ const stages = inspectInterruptedWrites(filePaths, restoredModes);
360
+ for (const stage of stages) {
361
+ if (stage.temporary)
362
+ fs.unlinkSync(stage.temporary);
363
+ fs.rmdirSync(stage.stagingDirectory);
364
+ }
365
+ for (const parent of [...new Set(stages.map((stage) => path.dirname(stage.stagingDirectory)))].sort()) {
366
+ syncDirectory(parent);
367
+ }
368
+ }
369
+ function snapshotDirectoryRelatives() {
370
+ const directories = new Set();
371
+ for (const relative of SNAPSHOT_RELATIVES) {
372
+ let directory = path.dirname(relative);
373
+ while (directory !== ".") {
374
+ directories.add(directory);
375
+ directory = path.dirname(directory);
376
+ }
377
+ }
378
+ return [...directories].sort((left, right) => left.length - right.length);
379
+ }
380
+ function captureMigrationSnapshot(agentRoot) {
381
+ const files = SNAPSHOT_RELATIVES.map((relative) => {
382
+ const filePath = path.join(agentRoot, relative);
383
+ if (!fs.existsSync(filePath))
384
+ return { path: filePath, content: null, mode: null };
385
+ const stat = fs.lstatSync(filePath);
386
+ return { path: filePath, content: fs.readFileSync(filePath), mode: stat.mode & 0o777 };
387
+ });
388
+ const directories = snapshotDirectoryRelatives().map((relative) => {
389
+ const directory = path.join(agentRoot, relative);
390
+ if (!fs.existsSync(directory))
391
+ return { path: directory, mode: null };
392
+ const stat = fs.lstatSync(directory);
393
+ return { path: directory, mode: stat.mode & 0o777 };
394
+ });
395
+ return { files, directories };
396
+ }
397
+ function rollbackPath(agentRoot) {
398
+ return path.join(agentRoot, exports.SANCTUARY_BUNDLE_ROLLBACK_FILE);
399
+ }
400
+ function durableSnapshot(agentRoot, snapshot, rollbackImageId, targetImageId) {
401
+ const payload = {
402
+ schemaVersion: 1,
403
+ rollbackImageId,
404
+ targetImageId,
405
+ files: snapshot.files.map((file) => ({ relative: path.relative(agentRoot, file.path), contentBase64: file.content?.toString("base64") ?? null, mode: file.mode })),
406
+ directories: snapshot.directories.map((directory) => ({ relative: path.relative(agentRoot, directory.path), mode: directory.mode })),
407
+ };
408
+ return { ...payload, snapshotDigest: (0, node_crypto_1.createHash)("sha256").update(JSON.stringify(payload)).digest("hex") };
409
+ }
410
+ function readDurableRecord(agentRoot) {
411
+ const names = fs.readdirSync(agentRoot);
412
+ const stagePrefixes = [`${exports.SANCTUARY_BUNDLE_ROLLBACK_FILE}.package-migration.`, `${SANCTUARY_BUNDLE_COMMITTING_FILE}.package-migration.`];
413
+ if (names.some((name) => stagePrefixes.some((prefix) => name.startsWith(prefix))))
414
+ throw new Error("Sanctuary bundle journal staging residue requires verified recovery");
415
+ const candidates = [rollbackPath(agentRoot), path.join(agentRoot, SANCTUARY_BUNDLE_COMMITTING_FILE)].flatMap((filePath) => {
416
+ try {
417
+ return [{ filePath, stat: fs.lstatSync(filePath) }];
418
+ }
419
+ catch (error) {
420
+ if (isMissing(error))
421
+ return [];
422
+ throw error;
423
+ }
424
+ });
425
+ if (candidates.length === 0)
426
+ return null;
427
+ if (candidates.length !== 1)
428
+ throw new Error("Sanctuary bundle rollback record state is ambiguous");
429
+ const [{ filePath, stat }] = candidates;
430
+ if (stat.isSymbolicLink())
431
+ throw new Error("Sanctuary bundle rollback record must not be a symlink");
432
+ if (!stat.isFile() || (stat.mode & 0o777) !== 0o600)
433
+ throw new Error("Sanctuary bundle rollback record must be a mode-0600 regular file");
434
+ const serialized = fs.readFileSync(filePath, "utf8");
435
+ let value;
436
+ try {
437
+ value = JSON.parse(serialized);
438
+ }
439
+ catch {
440
+ throw new Error("Sanctuary bundle rollback record is invalid JSON");
441
+ }
442
+ if (!value || typeof value !== "object" || Array.isArray(value))
443
+ throw new Error("Sanctuary bundle rollback record is invalid");
444
+ const record = value;
445
+ if (record.schemaVersion !== 1 || typeof record.rollbackImageId !== "string" || !/^sha256:[0-9a-f]{64}$/u.test(record.rollbackImageId) || typeof record.targetImageId !== "string" || !/^sha256:[0-9a-f]{64}$/u.test(record.targetImageId) || record.targetImageId === record.rollbackImageId || typeof record.snapshotDigest !== "string" || !/^[0-9a-f]{64}$/u.test(record.snapshotDigest) || !Array.isArray(record.files) || !Array.isArray(record.directories))
446
+ throw new Error("Sanctuary bundle rollback record is invalid");
447
+ const fileRelatives = record.files.map((file) => file?.relative);
448
+ const directoryRelatives = record.directories.map((directory) => directory?.relative);
449
+ const expectedDirectories = snapshotDirectoryRelatives();
450
+ if (JSON.stringify(fileRelatives) !== JSON.stringify(SNAPSHOT_RELATIVES) || JSON.stringify(directoryRelatives) !== JSON.stringify(expectedDirectories))
451
+ throw new Error("Sanctuary bundle rollback record paths are invalid");
452
+ for (const relative of SNAPSHOT_RELATIVES)
453
+ validateDestination(agentRoot, relative);
454
+ const validMode = (mode) => mode === null || (Number.isInteger(mode) && mode >= 0 && mode <= 0o777);
455
+ const files = record.files.map((file) => {
456
+ if (!file || typeof file.relative !== "string" || !validMode(file.mode) || (file.contentBase64 !== null && typeof file.contentBase64 !== "string") || (file.contentBase64 === null) !== (file.mode === null))
457
+ throw new Error("Sanctuary bundle rollback record file is invalid");
458
+ const content = file.contentBase64 === null ? null : Buffer.from(file.contentBase64, "base64");
459
+ if (file.contentBase64 !== null && (!content || content.toString("base64") !== file.contentBase64))
460
+ throw new Error("Sanctuary bundle rollback record content is invalid");
461
+ return { path: path.join(agentRoot, file.relative), content, mode: file.mode };
462
+ });
463
+ const directories = record.directories.map((directory) => {
464
+ if (!directory || typeof directory.relative !== "string" || !validMode(directory.mode))
465
+ throw new Error("Sanctuary bundle rollback record directory is invalid");
466
+ return { path: path.join(agentRoot, directory.relative), mode: directory.mode };
467
+ });
468
+ const payload = { schemaVersion: record.schemaVersion, rollbackImageId: record.rollbackImageId, targetImageId: record.targetImageId, files: record.files, directories: record.directories };
469
+ if ((0, node_crypto_1.createHash)("sha256").update(JSON.stringify(payload)).digest("hex") !== record.snapshotDigest)
470
+ throw new Error("Sanctuary bundle rollback record digest is invalid");
471
+ return { snapshot: { files, directories }, rollbackImageId: record.rollbackImageId, targetImageId: record.targetImageId, filePath, state: filePath === rollbackPath(agentRoot) ? "rollback" : "committing" };
472
+ }
473
+ function removeRollbackRecord(agentRoot, filePath) {
474
+ fs.unlinkSync(filePath);
475
+ syncDirectory(agentRoot);
476
+ }
477
+ function validateAgentRoot(agentRoot) {
478
+ if (!path.isAbsolute(agentRoot))
479
+ throw new Error("agent root must be an absolute path");
480
+ if (!inspectStandaloneSanctuaryDirectory(agentRoot))
481
+ throw new Error("agent root must be a canonical real directory");
482
+ }
483
+ function inspectionError(code) {
484
+ if (code === "invalid_package_root" || code === "invalid_package_source" || code === "packaged_policy_not_empty" || code === "package_version_mismatch") {
485
+ return { ok: false, error: { code, message: "verified release contents are invalid", degraded: true, repair: { actor: "human-required", action: "roll_back_or_install_verified_release" } } };
486
+ }
487
+ if (code === "invalid_live_root" || code === "invalid_live_bundle") {
488
+ return { ok: false, error: { code, message: "installed Sanctuary bundle is invalid", degraded: true, repair: { actor: "human-required", action: "roll_back_or_install_verified_release" } } };
489
+ }
490
+ if (code === "invalid_journal") {
491
+ return { ok: false, error: { code, message: "Sanctuary update recovery is required", degraded: true, repair: { actor: "human-required", action: "run_verified_update_recovery" } } };
492
+ }
493
+ return { ok: false, error: { code, message: "Sanctuary install state is unavailable", degraded: true, repair: { actor: "human-required", action: "run_verified_update_recovery" } } };
494
+ }
495
+ function validateInspectionRoot(root, code) {
496
+ const identity = inspectStandaloneSanctuaryDirectory(root);
497
+ if (!identity)
498
+ throw new SanctuaryInspectionFault(code);
499
+ return identity;
500
+ }
501
+ function inspectRelativeFile(root, relative, code) {
502
+ let current = root;
503
+ let result = null;
504
+ const segments = relative.split(path.sep);
505
+ for (let index = 0; index < segments.length; index += 1) {
506
+ current = path.join(current, segments[index]);
507
+ let stat;
508
+ try {
509
+ stat = fs.lstatSync(current);
510
+ }
511
+ catch (error) {
512
+ if (isMissing(error))
513
+ return null;
514
+ throw error;
515
+ }
516
+ if (stat.isSymbolicLink())
517
+ throw new SanctuaryInspectionFault(code);
518
+ if (index < segments.length - 1 && !stat.isDirectory())
519
+ throw new SanctuaryInspectionFault(code);
520
+ if (index === segments.length - 1 && !stat.isFile())
521
+ throw new SanctuaryInspectionFault(code);
522
+ if (index === segments.length - 1)
523
+ result = stat;
524
+ }
525
+ return result;
526
+ }
527
+ function readInspectionObject(filePath, code) {
528
+ let value;
529
+ try {
530
+ value = JSON.parse(fs.readFileSync(filePath, "utf8"));
531
+ }
532
+ catch (error) {
533
+ if (error instanceof SyntaxError)
534
+ throw new SanctuaryInspectionFault(code);
535
+ throw error;
536
+ }
537
+ if (!value || typeof value !== "object" || Array.isArray(value))
538
+ throw new SanctuaryInspectionFault(code);
539
+ return value;
540
+ }
541
+ function inspectPackageSources(packageRoot, runtimePackageVersion) {
542
+ const managed = new Map();
543
+ for (const relative of exports.SANCTUARY_PACKAGE_MANAGED_FILES) {
544
+ if (!inspectRelativeFile(packageRoot, relative, "invalid_package_source"))
545
+ throw new SanctuaryInspectionFault("invalid_package_source");
546
+ managed.set(relative, fs.readFileSync(path.join(packageRoot, relative)));
547
+ }
548
+ if (!inspectRelativeFile(packageRoot, "bundle-meta.json", "invalid_package_source"))
549
+ throw new SanctuaryInspectionFault("invalid_package_source");
550
+ const metadata = readInspectionObject(path.join(packageRoot, "bundle-meta.json"), "invalid_package_source");
551
+ if (typeof metadata.runtimeVersion !== "string" || metadata.runtimeVersion.length === 0 || !Number.isInteger(metadata.bundleSchemaVersion) || typeof metadata.lastUpdated !== "string" || metadata.lastUpdated.length === 0)
552
+ throw new SanctuaryInspectionFault("invalid_package_source");
553
+ if (!inspectRelativeFile(packageRoot, "state/policy/steward.json", "invalid_package_source"))
554
+ throw new SanctuaryInspectionFault("invalid_package_source");
555
+ const policy = readInspectionObject(path.join(packageRoot, "state/policy/steward.json"), "invalid_package_source");
556
+ if (!isCanonicalEmptyPackagedPolicy(policy))
557
+ throw new SanctuaryInspectionFault("packaged_policy_not_empty");
558
+ if (runtimePackageVersion.length === 0 || metadata.runtimeVersion !== runtimePackageVersion)
559
+ throw new SanctuaryInspectionFault("package_version_mismatch");
560
+ return { managed, metadata, packagedBundleVersion: metadata.runtimeVersion };
561
+ }
562
+ function journalRepair(journalState, parity) {
563
+ if (parity === "exact" && journalState !== "committing")
564
+ return { actor: "none", action: "none" };
565
+ if (parity === "mismatch" && journalState === "absent")
566
+ return { actor: "human-required", action: "restart_from_verified_release" };
567
+ return { actor: "human-required", action: "run_verified_update_recovery" };
568
+ }
569
+ function inspectSanctuaryPackageManagedBundle(input) {
570
+ try {
571
+ const packageIdentity = validateInspectionRoot(input.packageRoot, "invalid_package_root");
572
+ const packaged = inspectPackageSources(input.packageRoot, input.runtimePackageVersion);
573
+ const agentIdentity = validateInspectionRoot(input.agentRoot, "invalid_live_root");
574
+ if (sanctuaryDirectoriesShareIdentity(packageIdentity, agentIdentity))
575
+ throw new SanctuaryInspectionFault("invalid_live_root");
576
+ let managedMissing = false;
577
+ let managedContent = false;
578
+ let managedMode = false;
579
+ for (const relative of exports.SANCTUARY_PACKAGE_MANAGED_FILES) {
580
+ const stat = inspectRelativeFile(input.agentRoot, relative, "invalid_live_bundle");
581
+ if (!stat) {
582
+ managedMissing = true;
583
+ continue;
584
+ }
585
+ if (!fs.readFileSync(path.join(input.agentRoot, relative)).equals(packaged.managed.get(relative)))
586
+ managedContent = true;
587
+ if ((stat.mode & 0o777) !== 0o600)
588
+ managedMode = true;
589
+ }
590
+ let liveBundleVersion = null;
591
+ let bundleMetaMissing = false;
592
+ let bundleMetaField = false;
593
+ let bundleMetaMode = false;
594
+ const liveMetaStat = inspectRelativeFile(input.agentRoot, "bundle-meta.json", "invalid_live_bundle");
595
+ if (!liveMetaStat) {
596
+ bundleMetaMissing = true;
597
+ }
598
+ else {
599
+ const liveMeta = readInspectionObject(path.join(input.agentRoot, "bundle-meta.json"), "invalid_live_bundle");
600
+ liveBundleVersion = typeof liveMeta.runtimeVersion === "string" ? liveMeta.runtimeVersion : null;
601
+ bundleMetaField = BUNDLE_META_VERSION_FIELDS.some((field) => liveMeta[field] !== packaged.metadata[field]);
602
+ bundleMetaMode = (liveMetaStat.mode & 0o777) !== 0o600;
603
+ }
604
+ let journalState = "absent";
605
+ try {
606
+ if (inspectInterruptedWrites(packageManagedArtifactPaths(input.agentRoot)).length > 0)
607
+ throw new Error("Sanctuary bundle staging residue requires verified recovery");
608
+ journalState = readDurableRecord(input.agentRoot)?.state ?? "absent";
609
+ }
610
+ catch (error) {
611
+ if (isFilesystemFailure(error))
612
+ throw error;
613
+ throw new SanctuaryInspectionFault("invalid_journal");
614
+ }
615
+ const mismatchCodes = [];
616
+ if (managedMissing)
617
+ mismatchCodes.push("managed_file_missing");
618
+ if (managedContent)
619
+ mismatchCodes.push("managed_file_content");
620
+ if (managedMode)
621
+ mismatchCodes.push("managed_file_mode");
622
+ if (bundleMetaMissing)
623
+ mismatchCodes.push("bundle_meta_missing");
624
+ if (bundleMetaField)
625
+ mismatchCodes.push("bundle_meta_field");
626
+ if (bundleMetaMode)
627
+ mismatchCodes.push("bundle_meta_mode");
628
+ const parity = mismatchCodes.length === 0 ? "exact" : "mismatch";
629
+ const ready = parity === "exact" && journalState !== "committing";
630
+ return {
631
+ ok: true,
632
+ data: {
633
+ runtimePackageVersion: input.runtimePackageVersion,
634
+ packagedBundleVersion: packaged.packagedBundleVersion,
635
+ liveBundleVersion,
636
+ parity,
637
+ mismatchCodes,
638
+ journalState,
639
+ ready,
640
+ repair: journalRepair(journalState, parity),
641
+ },
642
+ };
643
+ }
644
+ catch (error) {
645
+ return inspectionError(error instanceof SanctuaryInspectionFault ? error.code : "inspection_unavailable");
646
+ }
647
+ }
648
+ function ensureSanctuaryPackageManagedBundle(input, deps = {}) {
649
+ const seedFailure = seedLivePsyche(input, deps.seed ?? seedSanctuaryPsycheIfAbsent);
650
+ if (seedFailure)
651
+ return seedFailure;
652
+ const inspect = deps.inspect ?? inspectSanctuaryPackageManagedBundle;
653
+ const before = inspect(input);
654
+ if (!before.ok) {
655
+ if (before.error.code !== "invalid_journal")
656
+ return before;
657
+ try {
658
+ (deps.migrate ?? migrateSanctuaryPackageManagedBundle)({ packageRoot: input.packageRoot, agentRoot: input.agentRoot });
659
+ }
660
+ catch {
661
+ return before;
662
+ }
663
+ }
664
+ else if (before.data.ready) {
665
+ return before;
666
+ }
667
+ else if (before.data.parity === "mismatch" && before.data.journalState !== "absent") {
668
+ return before;
669
+ }
670
+ else if (before.data.parity === "exact" && before.data.journalState === "committing") {
671
+ (deps.commit ?? commitSanctuaryPackageManagedBundle)(input.agentRoot);
672
+ }
673
+ else {
674
+ (deps.migrate ?? migrateSanctuaryPackageManagedBundle)({ packageRoot: input.packageRoot, agentRoot: input.agentRoot });
675
+ }
676
+ const after = inspect(input);
677
+ if (!after.ok || !after.data.ready)
678
+ return after;
679
+ if (after.data.parity !== "exact" || after.data.journalState !== "absent")
680
+ throw new Error("Sanctuary package-managed bundle did not converge");
681
+ return after;
682
+ }
683
+ // A live root that is not a canonical directory is left for inspection to report as invalid_live_root.
684
+ function seedLivePsyche(input, seed) {
685
+ try {
686
+ if (!inspectStandaloneSanctuaryDirectory(input.agentRoot))
687
+ return null;
688
+ const seeded = seed({ packageRoot: input.packageRoot, agentRoot: input.agentRoot });
689
+ return seeded.ok ? null : inspectionError(seeded.code);
690
+ }
691
+ catch (error) {
692
+ return inspectionError(error instanceof SanctuaryInspectionFault ? error.code : "inspection_unavailable");
693
+ }
694
+ }
695
+ function psycheState(agentRoot) {
696
+ let stat;
697
+ try {
698
+ stat = fs.lstatSync(path.join(agentRoot, "psyche"));
699
+ }
700
+ catch (error) {
701
+ if (isMissing(error))
702
+ return "absent";
703
+ throw error;
704
+ }
705
+ return stat.isDirectory() ? "directory" : "invalid";
706
+ }
707
+ function sameInode(left, right) {
708
+ return left.dev === right.dev && left.ino === right.ino;
709
+ }
710
+ // Returns the entries of a stage this seeder could have left, or null when anything about it says otherwise.
711
+ function interruptedPsycheSeedEntries(stage, root) {
712
+ const before = fs.lstatSync(stage);
713
+ const mode = before.mode & 0o777;
714
+ if (!before.isDirectory() || (mode !== 0o700 && mode !== 0o755) || before.uid !== root.uid || before.gid !== root.gid)
715
+ return null;
716
+ const handle = fs.openSync(stage, fs.constants.O_RDONLY | fs.constants.O_DIRECTORY | fs.constants.O_NOFOLLOW);
717
+ let entries = [];
718
+ try {
719
+ if (!sameInode(before, fs.fstatSync(handle)))
720
+ return null;
721
+ entries = fs.readdirSync(stage);
722
+ if (!sameInode(before, fs.lstatSync(stage)))
723
+ return null;
724
+ }
725
+ finally {
726
+ fs.closeSync(handle);
727
+ }
728
+ for (const entry of entries) {
729
+ if (!STARTER_PSYCHE_NAMES.has(entry))
730
+ return null;
731
+ const stat = fs.lstatSync(path.join(stage, entry));
732
+ if (!stat.isFile() || (stat.mode & 0o777) !== 0o600 || stat.uid !== root.uid)
733
+ return null;
734
+ }
735
+ return entries;
736
+ }
737
+ // A seed interrupted before its rename leaves a mkdtemp-named stage holding only starter files that never became the psyche.
738
+ // Anything that does not match that exact shape may be the owner's, so it is left alone.
739
+ function cleanupInterruptedPsycheSeeds(agentRoot) {
740
+ const root = fs.lstatSync(agentRoot);
741
+ let removed = false;
742
+ for (const name of fs.readdirSync(agentRoot).filter((entry) => PSYCHE_SEED_STAGE_NAME.test(entry)).sort()) {
743
+ const stage = path.join(agentRoot, name);
744
+ const entries = interruptedPsycheSeedEntries(stage, root);
745
+ if (!entries)
746
+ continue;
747
+ for (const entry of entries)
748
+ fs.unlinkSync(path.join(stage, entry));
749
+ fs.rmdirSync(stage);
750
+ removed = true;
751
+ }
752
+ if (removed)
753
+ syncDirectory(agentRoot);
754
+ }
755
+ /** The names in the install's own house/house.json, read only as a plain, non-symlinked file; anything else gives none. */
756
+ function seedHouseNames(agentRoot) {
757
+ const relative = path.join("house", "house.json");
758
+ let fd;
759
+ try {
760
+ if (!inspectRelativeFile(agentRoot, relative, "invalid_live_bundle"))
761
+ return {};
762
+ // Opened without following a link and re-checked on the descriptor, so a swap after the check reads nothing.
763
+ fd = fs.openSync(path.join(agentRoot, relative), fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
764
+ if (!fs.fstatSync(fd).isFile())
765
+ return {};
766
+ return (0, house_names_1.houseNameFields)(fs.readFileSync(fd, "utf8"));
767
+ }
768
+ catch {
769
+ return {};
770
+ }
771
+ finally {
772
+ if (fd !== undefined)
773
+ fs.closeSync(fd);
774
+ }
775
+ }
776
+ function seedSanctuaryPsycheIfAbsent(input, deps = {}) {
777
+ validateAgentRoot(input.agentRoot);
778
+ cleanupInterruptedPsycheSeeds(input.agentRoot);
779
+ const state = psycheState(input.agentRoot);
780
+ if (state === "directory")
781
+ return { ok: true, seeded: false };
782
+ if (state === "invalid")
783
+ return { ok: false, code: "invalid_live_bundle" };
784
+ const names = seedHouseNames(input.agentRoot);
785
+ const named = Object.keys(names).length > 0;
786
+ const sources = exports.SANCTUARY_STARTER_PSYCHE_FILES.map((relative) => {
787
+ if (!inspectRelativeFile(input.packageRoot, relative, "invalid_package_source"))
788
+ throw new SanctuaryInspectionFault("invalid_package_source", `starter psyche source is missing: ${relative}`);
789
+ const raw = fs.readFileSync(path.join(input.packageRoot, relative));
790
+ // With no names to give, the seed is the packaged bytes exactly.
791
+ return { name: path.basename(relative), content: named ? Buffer.from((0, house_names_1.fillHouseNames)(raw.toString("utf8"), names), "utf8") : raw };
792
+ });
793
+ const writeFile = deps.writeFile ?? ((fd, content) => fs.writeFileSync(fd, content));
794
+ const stage = fs.mkdtempSync(path.join(input.agentRoot, PSYCHE_SEED_STAGE_PREFIX));
795
+ for (const source of sources) {
796
+ const fd = fs.openSync(path.join(stage, source.name), "wx", 0o600);
797
+ try {
798
+ writeFile(fd, source.content);
799
+ fs.fchmodSync(fd, 0o600);
800
+ fs.fsyncSync(fd);
801
+ }
802
+ finally {
803
+ fs.closeSync(fd);
804
+ }
805
+ }
806
+ const directory = fs.openSync(stage, fs.constants.O_RDONLY | fs.constants.O_DIRECTORY | fs.constants.O_NOFOLLOW);
807
+ try {
808
+ fs.fchmodSync(directory, 0o755);
809
+ fs.fsyncSync(directory);
810
+ }
811
+ finally {
812
+ fs.closeSync(directory);
813
+ }
814
+ if (psycheState(input.agentRoot) !== "absent")
815
+ throw new SanctuaryInspectionFault("invalid_live_bundle", "psyche appeared while the starter psyche was staged");
816
+ // POSIX rename can still replace an empty psyche directory created in this window, which loses no content; Node has no RENAME_NOREPLACE.
817
+ fs.renameSync(stage, path.join(input.agentRoot, "psyche"));
818
+ syncDirectory(input.agentRoot);
819
+ (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.sanctuary_psyche_seeded", message: "seeded the starter psyche into a bundle that had none", meta: { agentRoot: input.agentRoot, files: sources.length } });
820
+ return { ok: true, seeded: true };
821
+ }
822
+ function inspectSanctuaryPackageManagedBundleRollback(agentRoot) {
823
+ validateAgentRoot(agentRoot);
824
+ const record = readDurableRecord(agentRoot);
825
+ return record ? { rollbackImageId: record.rollbackImageId, targetImageId: record.targetImageId, state: record.state } : null;
826
+ }
827
+ function rollbackSanctuaryPackageManagedBundle(agentRoot, options = {}) {
828
+ validateAgentRoot(agentRoot);
829
+ const record = readDurableRecord(agentRoot);
830
+ if (!record)
831
+ return false;
832
+ if (record.state === "committing")
833
+ throw new Error("Sanctuary bundle commit is pending and cannot be rolled back");
834
+ restoreMigrationSnapshot(record.snapshot, agentRoot);
835
+ if (!options.retainRecord)
836
+ removeRollbackRecord(agentRoot, record.filePath);
837
+ return true;
838
+ }
839
+ function commitSanctuaryPackageManagedBundle(agentRoot) {
840
+ validateAgentRoot(agentRoot);
841
+ const record = readDurableRecord(agentRoot);
842
+ if (!record)
843
+ return false;
844
+ const committingPath = path.join(agentRoot, SANCTUARY_BUNDLE_COMMITTING_FILE);
845
+ if (record.filePath !== committingPath) {
846
+ fs.renameSync(record.filePath, committingPath);
847
+ syncDirectory(agentRoot);
848
+ }
849
+ removeRollbackRecord(agentRoot, committingPath);
850
+ return true;
851
+ }
852
+ function restoreMigrationSnapshot(snapshot, agentRoot) {
853
+ const restoredModes = new Map();
854
+ for (const file of snapshot.files)
855
+ if (file.mode !== null)
856
+ restoredModes.set(file.path, file.mode);
857
+ cleanupInterruptedWrites(snapshot.files.map((file) => file.path), restoredModes);
858
+ for (const file of snapshot.files) {
859
+ if (file.content === null) {
860
+ fs.rmSync(file.path, { force: true });
861
+ syncNearestExistingDirectory(path.dirname(file.path), agentRoot);
862
+ }
863
+ else {
864
+ writeAtomic(file.path, file.content, file.mode);
865
+ }
866
+ }
867
+ for (const directory of [...snapshot.directories].reverse()) {
868
+ if (directory.mode === null) {
869
+ if (!fs.existsSync(directory.path)) {
870
+ syncNearestExistingDirectory(path.dirname(directory.path), agentRoot);
871
+ }
872
+ else if (fs.readdirSync(directory.path).length === 0) {
873
+ fs.rmdirSync(directory.path);
874
+ syncNearestExistingDirectory(path.dirname(directory.path), agentRoot);
875
+ }
876
+ }
877
+ else {
878
+ const handle = fs.openSync(directory.path, fs.constants.O_RDONLY | fs.constants.O_DIRECTORY | fs.constants.O_NOFOLLOW);
879
+ try {
880
+ fs.fchmodSync(handle, directory.mode);
881
+ fs.fsyncSync(handle);
882
+ }
883
+ finally {
884
+ fs.closeSync(handle);
885
+ }
886
+ }
887
+ }
888
+ }
889
+ function migrateSanctuaryPackageManagedBundle(input) {
890
+ (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.sanctuary_bundle_migration_start", message: "starting Sanctuary package-managed bundle migration", meta: { agentRoot: input.agentRoot } });
891
+ let snapshot = null;
892
+ try {
893
+ if (!path.isAbsolute(input.packageRoot) || !path.isAbsolute(input.agentRoot))
894
+ throw new Error("package and agent roots must be absolute paths");
895
+ const packageIdentity = inspectStandaloneSanctuaryDirectory(input.packageRoot);
896
+ const agentIdentity = inspectStandaloneSanctuaryDirectory(input.agentRoot);
897
+ if (!packageIdentity)
898
+ throw new Error("package root must be a canonical real directory");
899
+ if (!agentIdentity)
900
+ throw new Error("agent root must be a canonical real directory");
901
+ if (sanctuaryDirectoriesShareIdentity(packageIdentity, agentIdentity))
902
+ throw new Error("package and agent roots must be distinct real directories");
903
+ if (input.retainRollback && (!input.rollbackImageId || !/^sha256:[0-9a-f]{64}$/u.test(input.rollbackImageId) || !input.targetImageId || !/^sha256:[0-9a-f]{64}$/u.test(input.targetImageId) || input.targetImageId === input.rollbackImageId))
904
+ throw new Error("retained rollback requires distinct exact rollback and target image IDs");
905
+ const existingRollback = rollbackPath(input.agentRoot);
906
+ if (readDurableRecord(input.agentRoot))
907
+ throw new Error("Sanctuary bundle rollback is pending; rollback or commit it before another migration");
908
+ for (const relative of exports.SANCTUARY_PACKAGE_MANAGED_FILES) {
909
+ requirePlainFile(path.join(input.packageRoot, relative), `package-managed source ${relative}`);
910
+ validateDestination(input.agentRoot, relative);
911
+ }
912
+ requirePlainFile(path.join(input.packageRoot, "bundle-meta.json"), "packaged bundle-meta.json");
913
+ validateDestination(input.agentRoot, "bundle-meta.json");
914
+ const packagedMeta = readObject(path.join(input.packageRoot, "bundle-meta.json"));
915
+ for (const field of BUNDLE_META_VERSION_FIELDS)
916
+ if (!(field in packagedMeta))
917
+ throw new Error(`packaged bundle-meta.json is missing ${field}`);
918
+ validatePackagedPolicy(input.packageRoot);
919
+ cleanupInterruptedWrites(packageManagedArtifactPaths(input.agentRoot));
920
+ snapshot = captureMigrationSnapshot(input.agentRoot);
921
+ if (input.retainRollback) {
922
+ writeAtomic(existingRollback, `${JSON.stringify(durableSnapshot(input.agentRoot, snapshot, input.rollbackImageId, input.targetImageId))}\n`);
923
+ }
924
+ let managedFilesUpdated = 0;
925
+ for (const relative of exports.SANCTUARY_PACKAGE_MANAGED_FILES) {
926
+ const source = fs.readFileSync(path.join(input.packageRoot, relative), "utf8");
927
+ const destination = path.join(input.agentRoot, relative);
928
+ ensureSafeParent(input.agentRoot, relative);
929
+ if (fs.existsSync(destination) && fs.readFileSync(destination, "utf8") === source && (fs.statSync(destination).mode & 0o777) === 0o600)
930
+ continue;
931
+ writeAtomic(destination, source);
932
+ managedFilesUpdated += 1;
933
+ }
934
+ const metaPath = path.join(input.agentRoot, "bundle-meta.json");
935
+ const metaExists = fs.existsSync(metaPath);
936
+ const currentMeta = metaExists ? readObject(metaPath) : {};
937
+ const nextMeta = { ...currentMeta };
938
+ for (const field of BUNDLE_META_VERSION_FIELDS)
939
+ nextMeta[field] = packagedMeta[field];
940
+ if (!metaExists || BUNDLE_META_VERSION_FIELDS.some((field) => currentMeta[field] !== packagedMeta[field])) {
941
+ writeAtomic(metaPath, `${JSON.stringify(nextMeta, null, 2)}\n`);
942
+ }
943
+ else if ((fs.statSync(metaPath).mode & 0o777) !== 0o600) {
944
+ fs.chmodSync(metaPath, 0o600);
945
+ const meta = fs.openSync(metaPath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
946
+ try {
947
+ fs.fsyncSync(meta);
948
+ }
949
+ finally {
950
+ fs.closeSync(meta);
951
+ }
952
+ }
953
+ if (!seedSanctuaryPsycheIfAbsent({ packageRoot: input.packageRoot, agentRoot: input.agentRoot }).ok)
954
+ throw new Error("psyche must be a real directory, not a symlink or file");
955
+ const result = { managedFilesUpdated };
956
+ (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.sanctuary_bundle_migration_end", message: "completed Sanctuary package-managed bundle migration", meta: result });
957
+ return result;
958
+ }
959
+ catch (error) {
960
+ let failure = error;
961
+ if (snapshot) {
962
+ try {
963
+ restoreMigrationSnapshot(snapshot, input.agentRoot);
964
+ if (fs.existsSync(rollbackPath(input.agentRoot)))
965
+ removeRollbackRecord(input.agentRoot, rollbackPath(input.agentRoot));
966
+ }
967
+ catch (restoreError) {
968
+ failure = new AggregateError([error, restoreError], "Sanctuary bundle migration and rollback both failed");
969
+ }
970
+ }
971
+ (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.sanctuary_bundle_migration_error", level: "error", message: "Sanctuary package-managed bundle migration failed", meta: { error: String(failure), agentRoot: input.agentRoot } });
972
+ throw failure;
973
+ }
974
+ }