@ouro.bot/cli 0.1.0-alpha.92 → 0.1.0-alpha.920

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 (716) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -23
  3. package/RepairGuide.ouro/agent.json +5 -0
  4. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  5. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  6. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  7. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  8. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  9. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  12. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  13. package/assets/bluebubbles-host +264 -0
  14. package/assets/sanctuary-host-launcher.sh +16 -0
  15. package/changelog.json +5819 -16
  16. package/deploy/unraid/Dockerfile +58 -0
  17. package/deploy/unraid/README.txt +2997 -0
  18. package/deploy/unraid/audit-container-spec.sh +4 -0
  19. package/deploy/unraid/container-runtime.json +1 -0
  20. package/deploy/unraid/docker-man-template-transaction.mjs +711 -0
  21. package/deploy/unraid/docker-man-template-xml.cjs +105 -0
  22. package/deploy/unraid/migrate-sanctuary-bundle.mjs +60 -0
  23. package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
  24. package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
  25. package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
  26. package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
  27. package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
  28. package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
  29. package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
  30. package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
  31. package/deploy/unraid/sanctuary-authority-installation.json +36 -0
  32. package/deploy/unraid/sanctuary-authority-service.sh +30 -0
  33. package/deploy/unraid/sanctuary-butler-upgrade.mjs +1254 -0
  34. package/deploy/unraid/sanctuary-deployment-target.mjs +710 -0
  35. package/deploy/unraid/sanctuary-replay-gate.mjs +1564 -0
  36. package/deploy/unraid/sanctuary-safe-rename.py +24 -0
  37. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2086 -0
  38. package/deploy/unraid/sanctuary-unit16-run.sh +560 -0
  39. package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
  40. package/deploy/unraid/sanctuary.ouro/agent.json +66 -0
  41. package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
  42. package/deploy/unraid/sanctuary.ouro/awaiting/house-care-sweep.md +17 -0
  43. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
  44. package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
  45. package/deploy/unraid/sanctuary.ouro/mcp/media-mcp.mjs +2231 -0
  46. package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
  47. package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
  48. package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +5 -0
  49. package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +33 -0
  50. package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +27 -0
  51. package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +22 -0
  52. package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
  53. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +232 -0
  54. package/deploy/unraid/sanctuary.xml +30 -0
  55. package/dist/a2a/card.js +57 -0
  56. package/dist/a2a/client.js +250 -0
  57. package/dist/a2a/config.js +50 -0
  58. package/dist/a2a/delegated-command-grants.js +93 -0
  59. package/dist/a2a/delegated-command.js +197 -0
  60. package/dist/a2a/delegation-stores.js +56 -0
  61. package/dist/a2a/did-resolution.js +93 -0
  62. package/dist/a2a/escalation-grants.js +84 -0
  63. package/dist/a2a/escalation-wiring.js +60 -0
  64. package/dist/a2a/identity.js +258 -0
  65. package/dist/a2a/inbound-share.js +110 -0
  66. package/dist/a2a/mission-result-wire.js +196 -0
  67. package/dist/a2a/onboarding.js +133 -0
  68. package/dist/a2a/operator-trust.js +382 -0
  69. package/dist/a2a/outbox-client.js +57 -0
  70. package/dist/a2a/outbox-store.js +188 -0
  71. package/dist/a2a/outbox-wire.js +95 -0
  72. package/dist/a2a/pin-store.js +132 -0
  73. package/dist/a2a/replay-grant-holders.js +33 -0
  74. package/dist/a2a/replay-harness.js +188 -0
  75. package/dist/a2a/resolution-proof.js +53 -0
  76. package/dist/a2a/sealed-chat.js +113 -0
  77. package/dist/a2a/seen-ledger.js +120 -0
  78. package/dist/a2a/server.js +771 -0
  79. package/dist/a2a/task-store.js +69 -0
  80. package/dist/a2a/transport.js +45 -0
  81. package/dist/a2a/trust-commands.js +203 -0
  82. package/dist/a2a/trusted-files.js +185 -0
  83. package/dist/a2a/types.js +3 -0
  84. package/dist/arc/attention-types.js +8 -0
  85. package/dist/arc/cares.js +360 -0
  86. package/dist/arc/episodes.js +118 -0
  87. package/dist/arc/evolution.js +490 -0
  88. package/dist/arc/flight-recorder.js +1034 -0
  89. package/dist/arc/intentions.js +134 -0
  90. package/dist/arc/json-store.js +117 -0
  91. package/dist/arc/obligations.js +386 -0
  92. package/dist/arc/packets.js +336 -0
  93. package/dist/arc/presence.js +185 -0
  94. package/dist/arc/task-lifecycle.js +57 -0
  95. package/dist/commerce/store.js +755 -0
  96. package/dist/commerce/types.js +3 -0
  97. package/dist/heart/active-work.js +798 -40
  98. package/dist/heart/agent-entry.js +252 -3
  99. package/dist/heart/approval-files.js +113 -0
  100. package/dist/heart/approval-store.js +960 -0
  101. package/dist/heart/attachments/image-normalize.js +194 -0
  102. package/dist/heart/attachments/materialize.js +97 -0
  103. package/dist/heart/attachments/originals.js +88 -0
  104. package/dist/heart/attachments/render.js +29 -0
  105. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  106. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  107. package/dist/heart/attachments/sources/index.js +18 -0
  108. package/dist/heart/attachments/sources/telegram.js +71 -0
  109. package/dist/heart/attachments/store.js +132 -0
  110. package/dist/heart/attachments/types.js +93 -0
  111. package/dist/heart/auth/auth-flow.js +495 -0
  112. package/dist/heart/autonomy-budget.js +478 -0
  113. package/dist/heart/awaiting/a2a-await-delivery.js +109 -0
  114. package/dist/heart/awaiting/await-alert.js +152 -0
  115. package/dist/heart/awaiting/await-expiry.js +143 -0
  116. package/dist/heart/awaiting/await-loader.js +91 -0
  117. package/dist/heart/awaiting/await-parser.js +152 -0
  118. package/dist/heart/awaiting/await-runtime-state.js +111 -0
  119. package/dist/heart/awaiting/await-scheduler.js +391 -0
  120. package/dist/heart/background-operations.js +281 -0
  121. package/dist/heart/bluebubbles-host-account.js +78 -0
  122. package/dist/heart/bridges/manager.js +137 -17
  123. package/dist/heart/bridges/store.js +14 -2
  124. package/dist/heart/bundle-state.js +168 -0
  125. package/dist/heart/commitments.js +44 -18
  126. package/dist/heart/config-registry.js +331 -0
  127. package/dist/heart/config.js +174 -131
  128. package/dist/heart/context-loss-gauntlet.js +387 -0
  129. package/dist/heart/context-loss-sentinel.js +1159 -0
  130. package/dist/heart/core.js +2364 -578
  131. package/dist/heart/cross-chat-delivery.js +9 -22
  132. package/dist/heart/daemon/agent-config-check.js +451 -0
  133. package/dist/heart/daemon/agent-discovery.js +283 -3
  134. package/dist/heart/daemon/agent-home.js +319 -0
  135. package/dist/heart/daemon/agent-service.js +542 -0
  136. package/dist/heart/daemon/agentic-repair.js +547 -0
  137. package/dist/heart/daemon/await-private-wake.js +59 -0
  138. package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
  139. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  140. package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
  141. package/dist/heart/daemon/bluebubbles-host.js +273 -0
  142. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  143. package/dist/heart/daemon/cadence.js +180 -0
  144. package/dist/heart/daemon/cli-arg-redaction.js +26 -0
  145. package/dist/heart/daemon/cli-defaults.js +876 -0
  146. package/dist/heart/daemon/cli-desk.js +322 -0
  147. package/dist/heart/daemon/cli-exec.js +9199 -0
  148. package/dist/heart/daemon/cli-help.js +735 -0
  149. package/dist/heart/daemon/cli-parse.js +3211 -0
  150. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  151. package/dist/heart/daemon/cli-render.js +819 -0
  152. package/dist/heart/daemon/cli-types.js +8 -0
  153. package/dist/heart/daemon/connect-bay.js +323 -0
  154. package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
  155. package/dist/heart/daemon/container-healthcheck.js +112 -0
  156. package/dist/heart/daemon/container-runtime.js +97 -0
  157. package/dist/heart/daemon/container-spec-auditor-main.js +171 -0
  158. package/dist/heart/daemon/container-spec-auditor.js +235 -0
  159. package/dist/heart/daemon/daemon-bootstrap-startup.js +115 -0
  160. package/dist/heart/daemon/daemon-cli.js +29 -2350
  161. package/dist/heart/daemon/daemon-entry.js +953 -11
  162. package/dist/heart/daemon/daemon-health.js +186 -0
  163. package/dist/heart/daemon/daemon-rollup.js +57 -0
  164. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  165. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  166. package/dist/heart/daemon/daemon.js +2084 -105
  167. package/dist/heart/daemon/dns-workflow.js +394 -0
  168. package/dist/heart/daemon/doctor-types.js +8 -0
  169. package/dist/heart/daemon/doctor.js +1766 -0
  170. package/dist/heart/daemon/freshness.js +345 -0
  171. package/dist/heart/daemon/habit-private-wake.js +61 -0
  172. package/dist/heart/daemon/health-monitor.js +154 -11
  173. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  174. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  175. package/dist/heart/daemon/http-health-probe.js +80 -0
  176. package/dist/heart/daemon/human-command-screens.js +234 -0
  177. package/dist/heart/daemon/human-readiness.js +114 -0
  178. package/dist/heart/daemon/inner-status.js +78 -0
  179. package/dist/heart/daemon/interactive-repair.js +394 -0
  180. package/dist/heart/daemon/launchd.js +37 -8
  181. package/dist/heart/daemon/log-tailer.js +79 -10
  182. package/dist/heart/daemon/logs-prune.js +132 -0
  183. package/dist/heart/daemon/mcp-canary.js +524 -0
  184. package/dist/heart/daemon/message-router.js +65 -5
  185. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  186. package/dist/heart/daemon/os-cron-deps.js +135 -0
  187. package/dist/heart/daemon/os-cron.js +22 -14
  188. package/dist/heart/daemon/ouro-bot-entry.js +6 -3
  189. package/dist/heart/daemon/ouro-entry.js +5 -2
  190. package/dist/heart/daemon/plugin-cli.js +432 -0
  191. package/dist/heart/daemon/process-manager.js +760 -61
  192. package/dist/heart/daemon/provider-discovery.js +137 -0
  193. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  194. package/dist/heart/daemon/prunable-bundle.js +144 -0
  195. package/dist/heart/daemon/pulse.js +511 -0
  196. package/dist/heart/daemon/readiness-repair.js +365 -0
  197. package/dist/heart/daemon/run-hooks.js +2 -0
  198. package/dist/heart/daemon/runtime-logging.js +47 -14
  199. package/dist/heart/daemon/runtime-metadata.js +2 -30
  200. package/dist/heart/daemon/runtime-mode.js +13 -2
  201. package/dist/heart/daemon/safe-mode.js +161 -0
  202. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2654 -0
  203. package/dist/heart/daemon/sanctuary-acceptance-harness.js +1830 -0
  204. package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
  205. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +955 -0
  206. package/dist/heart/daemon/sanctuary-authority-codec.js +86 -0
  207. package/dist/heart/daemon/sanctuary-authority-epoch.js +281 -0
  208. package/dist/heart/daemon/sanctuary-authority-installation.js +161 -0
  209. package/dist/heart/daemon/sanctuary-authority-ledger.js +241 -0
  210. package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +1267 -0
  211. package/dist/heart/daemon/sanctuary-authority-vault-migration.js +79 -0
  212. package/dist/heart/daemon/sanctuary-bundle-migration.js +730 -0
  213. package/dist/heart/daemon/sanctuary-host-authority.js +1008 -0
  214. package/dist/heart/daemon/sanctuary-host-detached-supervisor.js +493 -0
  215. package/dist/heart/daemon/sanctuary-host-executor.js +670 -0
  216. package/dist/heart/daemon/sanctuary-host-linux-kernel.js +334 -0
  217. package/dist/heart/daemon/sanctuary-host-supervisor-entry.js +207 -0
  218. package/dist/heart/daemon/sanctuary-host-supervisor.js +95 -0
  219. package/dist/heart/daemon/sanctuary-package-management.js +103 -0
  220. package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
  221. package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
  222. package/dist/heart/daemon/sanctuary-telegram-authority-entry.js +475 -0
  223. package/dist/heart/daemon/sanctuary-telegram-authority-gateway.js +585 -0
  224. package/dist/heart/daemon/sanctuary-telegram-authority-service.js +676 -0
  225. package/dist/heart/daemon/sense-manager.js +733 -48
  226. package/dist/heart/daemon/session-id-resolver.js +131 -0
  227. package/dist/heart/daemon/skill-management-installer.js +1 -1
  228. package/dist/heart/daemon/socket-client.js +180 -12
  229. package/dist/heart/daemon/stale-bundle-prune.js +113 -0
  230. package/dist/heart/daemon/startup-tui.js +339 -0
  231. package/dist/heart/daemon/supercronic-supervisor.js +282 -0
  232. package/dist/heart/daemon/task-scheduler.js +117 -39
  233. package/dist/heart/daemon/terminal-ui.js +503 -0
  234. package/dist/heart/daemon/thoughts.js +138 -54
  235. package/dist/heart/daemon/up-progress.js +366 -0
  236. package/dist/heart/daemon/vault-items.js +56 -0
  237. package/dist/heart/delegation.js +1 -4
  238. package/dist/heart/external-events/router.js +1516 -0
  239. package/dist/heart/failure-reports.js +336 -0
  240. package/dist/heart/file-lock.js +109 -0
  241. package/dist/heart/frontend-approval-runtime.js +506 -0
  242. package/dist/heart/frontend-journal.js +215 -0
  243. package/dist/heart/frontend-session-service.js +237 -0
  244. package/dist/heart/frontend-socket-client.js +164 -0
  245. package/dist/heart/frontend-socket.js +400 -0
  246. package/dist/heart/habits/habit-cancel.js +810 -0
  247. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  248. package/dist/heart/habits/habit-migration.js +194 -0
  249. package/dist/heart/habits/habit-parser.js +278 -0
  250. package/dist/heart/habits/habit-runtime-state.js +93 -0
  251. package/dist/heart/habits/habit-scheduler.js +653 -0
  252. package/dist/heart/habits/habit-session-summary.js +318 -0
  253. package/dist/heart/habits/habit-session.js +636 -0
  254. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
  255. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  256. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  257. package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
  258. package/dist/heart/identity.js +230 -59
  259. package/dist/heart/kept-notes.js +289 -0
  260. package/dist/heart/kicks.js +1 -1
  261. package/dist/heart/machine-identity.js +175 -0
  262. package/dist/heart/mail-import-discovery.js +356 -0
  263. package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
  264. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  265. package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
  266. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  267. package/dist/heart/mailbox/mailbox-http-transport.js +272 -0
  268. package/dist/heart/mailbox/mailbox-http.js +99 -0
  269. package/dist/heart/mailbox/mailbox-read.js +39 -0
  270. package/dist/heart/mailbox/mailbox-types.js +27 -0
  271. package/dist/heart/mailbox/mailbox-view.js +197 -0
  272. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  273. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  274. package/dist/heart/mailbox/readers/mail.js +375 -0
  275. package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
  276. package/dist/heart/mailbox/readers/sessions.js +231 -0
  277. package/dist/heart/mailbox/readers/shared.js +111 -0
  278. package/dist/heart/mcp/mcp-server.js +696 -0
  279. package/dist/heart/migrate-config.js +100 -0
  280. package/dist/heart/model-capabilities.js +83 -16
  281. package/dist/heart/orientation-frame.js +345 -0
  282. package/dist/heart/platform.js +81 -0
  283. package/dist/heart/primitives.js +1 -1
  284. package/dist/heart/private-runtime/decision-renderer.js +158 -0
  285. package/dist/heart/private-runtime/index.js +18 -0
  286. package/dist/heart/private-runtime/ledger.js +221 -0
  287. package/dist/heart/private-runtime/policy.js +260 -0
  288. package/dist/heart/private-runtime/types.js +2 -0
  289. package/dist/heart/progress-story.js +1 -1
  290. package/dist/heart/provider-attempt.js +137 -0
  291. package/dist/heart/provider-binding-resolver.js +273 -0
  292. package/dist/heart/provider-credentials.js +449 -0
  293. package/dist/heart/provider-failover.js +311 -0
  294. package/dist/heart/provider-models.js +96 -0
  295. package/dist/heart/provider-ping.js +265 -0
  296. package/dist/heart/provider-readiness-cache.js +119 -0
  297. package/dist/heart/provider-visibility.js +188 -0
  298. package/dist/heart/providers/anthropic-token.js +131 -0
  299. package/dist/heart/providers/anthropic.js +173 -60
  300. package/dist/heart/providers/azure.js +23 -11
  301. package/dist/heart/providers/error-classification.js +127 -0
  302. package/dist/heart/providers/github-copilot.js +38 -39
  303. package/dist/heart/providers/minimax-vlm.js +189 -0
  304. package/dist/heart/providers/minimax.js +26 -8
  305. package/dist/heart/providers/openai-codex-token.js +349 -0
  306. package/dist/heart/providers/openai-codex.js +55 -40
  307. package/dist/heart/providers/openai-compatible.js +177 -0
  308. package/dist/heart/reply-style.js +52 -0
  309. package/dist/heart/run-ledger.js +247 -0
  310. package/dist/heart/runtime-capability-check.js +170 -0
  311. package/dist/heart/runtime-credentials.js +607 -0
  312. package/dist/heart/runtime-cwd.js +87 -0
  313. package/dist/heart/sense-truth.js +24 -4
  314. package/dist/heart/session-activity.js +92 -24
  315. package/dist/heart/session-events.js +1504 -0
  316. package/dist/heart/session-playback-cli-main.js +5 -0
  317. package/dist/heart/session-playback-cli.js +36 -0
  318. package/dist/heart/session-playback.js +231 -0
  319. package/dist/heart/session-redaction-repair-cli-main.js +31 -0
  320. package/dist/heart/session-redaction-repair.js +552 -0
  321. package/dist/heart/session-stats-cli-main.js +5 -0
  322. package/dist/heart/session-stats.js +183 -0
  323. package/dist/heart/session-transcript.js +133 -0
  324. package/dist/heart/shelf-claims.js +78 -0
  325. package/dist/heart/shepherd-config.js +113 -0
  326. package/dist/heart/source-grounding.js +297 -0
  327. package/dist/heart/start-of-turn-packet.js +372 -0
  328. package/dist/heart/steward-policy.js +656 -0
  329. package/dist/heart/streaming.js +609 -207
  330. package/dist/heart/structured-output.js +196 -0
  331. package/dist/heart/sync-classification.js +176 -0
  332. package/dist/heart/sync-health.js +152 -0
  333. package/dist/heart/sync.js +726 -0
  334. package/dist/heart/target-resolution.js +11 -7
  335. package/dist/heart/tempo.js +93 -0
  336. package/dist/heart/temporal-view.js +41 -0
  337. package/dist/heart/timeouts.js +101 -0
  338. package/dist/heart/tool-activity-callbacks.js +59 -0
  339. package/dist/heart/tool-approval.js +382 -0
  340. package/dist/heart/tool-description.js +155 -0
  341. package/dist/heart/tool-friction.js +55 -0
  342. package/dist/heart/tool-loop.js +206 -0
  343. package/dist/heart/turn-context.js +496 -0
  344. package/dist/heart/turn-execution-lease.js +30 -0
  345. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  346. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +3 -2
  347. package/dist/heart/versioning/ouro-path-installer.js +432 -0
  348. package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
  349. package/dist/heart/versioning/ouro-version-manager.js +432 -0
  350. package/dist/heart/versioning/release-sources.js +173 -0
  351. package/dist/heart/versioning/self-update-defaults.js +294 -0
  352. package/dist/heart/versioning/self-update.js +196 -0
  353. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  354. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  355. package/dist/heart/versioning/update-hooks.js +154 -0
  356. package/dist/heart/versioning/update-state.js +126 -0
  357. package/dist/heart/versioning/updater-launchd.js +150 -0
  358. package/dist/heart/versioning/version-intent.js +114 -0
  359. package/dist/heart/work-card.js +380 -0
  360. package/dist/mailbox-ui/assets/index-Cyv4mw3Y.js +1 -0
  361. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  362. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  363. package/dist/mailbox-ui/index.html +16 -0
  364. package/dist/mailroom/attention.js +167 -0
  365. package/dist/mailroom/autonomy.js +209 -0
  366. package/dist/mailroom/blob-store.js +889 -0
  367. package/dist/mailroom/body-cache.js +61 -0
  368. package/dist/mailroom/cache-sync-cli.js +58 -0
  369. package/dist/mailroom/core.js +803 -0
  370. package/dist/mailroom/entry.js +160 -0
  371. package/dist/mailroom/file-store.js +568 -0
  372. package/dist/mailroom/hosted-cache-sync.js +384 -0
  373. package/dist/mailroom/mbox-import.js +393 -0
  374. package/dist/mailroom/migration.js +164 -0
  375. package/dist/mailroom/outbound.js +380 -0
  376. package/dist/mailroom/policy.js +263 -0
  377. package/dist/mailroom/reader.js +292 -0
  378. package/dist/mailroom/search-cache.js +513 -0
  379. package/dist/mailroom/search-relevance.js +319 -0
  380. package/dist/mailroom/smtp-ingress.js +176 -0
  381. package/dist/mailroom/source-state.js +176 -0
  382. package/dist/mailroom/thread.js +109 -0
  383. package/dist/mailroom/travel-extract.js +89 -0
  384. package/dist/mind/bundle-manifest.js +24 -2
  385. package/dist/mind/context.js +307 -139
  386. package/dist/mind/desk-section.js +362 -0
  387. package/dist/mind/diary-integrity.js +60 -0
  388. package/dist/mind/{memory.js → diary.js} +68 -77
  389. package/dist/mind/embedding-provider.js +60 -0
  390. package/dist/mind/file-state.js +179 -0
  391. package/dist/mind/friend-link-codes.js +209 -0
  392. package/dist/mind/friend-merge.js +330 -0
  393. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  394. package/dist/mind/obligation-steering.js +199 -3
  395. package/dist/mind/pending.js +36 -10
  396. package/dist/mind/prompt-budget.js +479 -0
  397. package/dist/mind/prompt-refresh.js +3 -2
  398. package/dist/mind/prompt.js +1085 -198
  399. package/dist/mind/provenance-trust.js +26 -0
  400. package/dist/mind/record-paths.js +312 -0
  401. package/dist/mind/scrutiny.js +173 -0
  402. package/dist/mind/session-transaction.js +564 -0
  403. package/dist/nerves/cli-logging.js +7 -1
  404. package/dist/nerves/coverage/audit-rules.js +15 -6
  405. package/dist/nerves/coverage/audit.js +28 -2
  406. package/dist/nerves/coverage/cli.js +1 -1
  407. package/dist/nerves/coverage/contract.js +5 -5
  408. package/dist/nerves/coverage/file-completeness.js +139 -5
  409. package/dist/nerves/coverage/run-artifacts.js +55 -35
  410. package/dist/nerves/coverage/source-scanner.js +4 -4
  411. package/dist/nerves/event-buffer.js +111 -0
  412. package/dist/nerves/index.js +293 -9
  413. package/dist/nerves/observation.js +20 -0
  414. package/dist/nerves/redact.js +79 -0
  415. package/dist/nerves/review/cli-main.js +5 -0
  416. package/dist/nerves/review/cli.js +156 -0
  417. package/dist/nerves/review/core.js +159 -0
  418. package/dist/nerves/runtime.js +17 -1
  419. package/dist/repertoire/ado-client.js +15 -56
  420. package/dist/repertoire/ado-semantic.js +16 -10
  421. package/dist/repertoire/api-client.js +97 -0
  422. package/dist/repertoire/bitwarden-store.js +1201 -0
  423. package/dist/repertoire/bundle-templates.js +71 -0
  424. package/dist/repertoire/bw-installer.js +231 -0
  425. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  426. package/dist/repertoire/coding/context-pack.js +331 -0
  427. package/dist/repertoire/coding/feedback.js +174 -32
  428. package/dist/repertoire/coding/index.js +15 -3
  429. package/dist/repertoire/coding/manager.js +159 -10
  430. package/dist/repertoire/coding/spawner.js +40 -11
  431. package/dist/repertoire/coding/tools.js +182 -18
  432. package/dist/repertoire/coding/workbench-client.js +272 -0
  433. package/dist/repertoire/coding/workbench-manager.js +346 -0
  434. package/dist/repertoire/commerce-errors.js +109 -0
  435. package/dist/repertoire/commerce-self-test.js +156 -0
  436. package/dist/repertoire/credential-access.js +183 -0
  437. package/dist/repertoire/desk/classifier.js +362 -0
  438. package/dist/repertoire/duffel-client.js +185 -0
  439. package/dist/repertoire/github-client.js +14 -55
  440. package/dist/repertoire/graph-client.js +11 -52
  441. package/dist/repertoire/guardrails.js +968 -20
  442. package/dist/repertoire/house-sweep.js +469 -0
  443. package/dist/repertoire/mcp-client.js +58 -5
  444. package/dist/repertoire/mcp-manager.js +427 -139
  445. package/dist/repertoire/mcp-tools.js +132 -0
  446. package/dist/repertoire/mcp-write-guard.js +46 -0
  447. package/dist/repertoire/plugin-mcp.js +175 -0
  448. package/dist/repertoire/plugins.js +253 -0
  449. package/dist/repertoire/relationship-authorization.js +322 -0
  450. package/dist/repertoire/sanctuary-container-policy.js +46 -0
  451. package/dist/repertoire/shell-sessions.js +134 -0
  452. package/dist/repertoire/skills.js +48 -4
  453. package/dist/repertoire/stripe-client.js +131 -0
  454. package/dist/repertoire/tool-arguments.js +182 -0
  455. package/dist/repertoire/tool-results.js +29 -0
  456. package/dist/repertoire/tools-a2a.js +699 -0
  457. package/dist/repertoire/tools-attachments.js +322 -0
  458. package/dist/repertoire/tools-awaiting.js +872 -0
  459. package/dist/repertoire/tools-base.js +83 -1168
  460. package/dist/repertoire/tools-bluebubbles.js +2 -0
  461. package/dist/repertoire/tools-bridge.js +144 -0
  462. package/dist/repertoire/tools-bundle.js +995 -0
  463. package/dist/repertoire/tools-commerce.js +253 -0
  464. package/dist/repertoire/tools-config.js +186 -0
  465. package/dist/repertoire/tools-continuity.js +575 -0
  466. package/dist/repertoire/tools-credential.js +383 -0
  467. package/dist/repertoire/tools-escalation.js +84 -0
  468. package/dist/repertoire/tools-evolution.js +527 -0
  469. package/dist/repertoire/tools-files.js +344 -0
  470. package/dist/repertoire/tools-flight.js +290 -0
  471. package/dist/repertoire/tools-flow.js +119 -0
  472. package/dist/repertoire/tools-friend-link.js +57 -0
  473. package/dist/repertoire/tools-github.js +3 -8
  474. package/dist/repertoire/tools-habits.js +103 -0
  475. package/dist/repertoire/tools-house-care.js +174 -0
  476. package/dist/repertoire/tools-mail.js +1828 -0
  477. package/dist/repertoire/tools-notes.js +496 -0
  478. package/dist/repertoire/tools-obligations.js +182 -0
  479. package/dist/repertoire/tools-orientation.js +31 -0
  480. package/dist/repertoire/tools-record.js +482 -0
  481. package/dist/repertoire/tools-rsvp.js +139 -0
  482. package/dist/repertoire/tools-runtime.js +238 -0
  483. package/dist/repertoire/tools-sanctuary-host.js +202 -0
  484. package/dist/repertoire/tools-session.js +1133 -0
  485. package/dist/repertoire/tools-shell.js +149 -0
  486. package/dist/repertoire/tools-shepherd.js +262 -0
  487. package/dist/repertoire/tools-steward-policy.js +147 -0
  488. package/dist/repertoire/tools-stripe.js +224 -0
  489. package/dist/repertoire/tools-surface.js +369 -0
  490. package/dist/repertoire/tools-teams.js +12 -39
  491. package/dist/repertoire/tools-telegram-contacts.js +37 -0
  492. package/dist/repertoire/tools-travel.js +125 -0
  493. package/dist/repertoire/tools-trip.js +982 -0
  494. package/dist/repertoire/tools-unraid.js +556 -0
  495. package/dist/repertoire/tools-user-profile.js +146 -0
  496. package/dist/repertoire/tools-vault.js +40 -0
  497. package/dist/repertoire/tools-voice-local.js +198 -0
  498. package/dist/repertoire/tools-voice.js +145 -0
  499. package/dist/repertoire/tools.js +514 -156
  500. package/dist/repertoire/travel-api-client.js +360 -0
  501. package/dist/repertoire/unraid-client.js +155 -0
  502. package/dist/repertoire/unraid-restart.js +339 -0
  503. package/dist/repertoire/user-profile.js +131 -0
  504. package/dist/repertoire/vault-setup.js +246 -0
  505. package/dist/repertoire/vault-unlock.js +686 -0
  506. package/dist/rsvp/aisleplanner-client.js +354 -0
  507. package/dist/rsvp/cli.js +936 -0
  508. package/dist/rsvp/config.js +327 -0
  509. package/dist/rsvp/cutover.js +433 -0
  510. package/dist/rsvp/diagnostics.js +232 -0
  511. package/dist/rsvp/diff-renderer.js +176 -0
  512. package/dist/rsvp/habit-policy.js +110 -0
  513. package/dist/rsvp/habit-stage.js +123 -0
  514. package/dist/rsvp/incident-bundle.js +97 -0
  515. package/dist/rsvp/migration.js +204 -0
  516. package/dist/rsvp/native-habit-runner.js +630 -0
  517. package/dist/rsvp/outbound-state.js +628 -0
  518. package/dist/rsvp/query.js +118 -0
  519. package/dist/rsvp/replay.js +233 -0
  520. package/dist/rsvp/snapshot.js +232 -0
  521. package/dist/rsvp/spend-ledger.js +175 -0
  522. package/dist/scripts/claude-code-hook.js +41 -0
  523. package/dist/scripts/claude-code-stop-hook.js +47 -0
  524. package/dist/senses/a2a-entry.js +132 -0
  525. package/dist/senses/acp-server.js +386 -0
  526. package/dist/senses/attention-queue.js +186 -0
  527. package/dist/senses/await-turn-message.js +65 -0
  528. package/dist/senses/bluebubbles/active-turns.js +216 -0
  529. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  530. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  531. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +379 -41
  532. package/dist/senses/bluebubbles/context-packet.js +207 -0
  533. package/dist/senses/bluebubbles/context-smoke.js +144 -0
  534. package/dist/senses/bluebubbles/entry.js +90 -0
  535. package/dist/senses/bluebubbles/host-account-verifier.js +88 -0
  536. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
  537. package/dist/senses/bluebubbles/index.js +3878 -0
  538. package/dist/senses/bluebubbles/latest-turn.js +311 -0
  539. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  540. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
  541. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
  542. package/dist/senses/bluebubbles/outbound-state.js +308 -0
  543. package/dist/senses/bluebubbles/processed-log.js +133 -0
  544. package/dist/senses/bluebubbles/reaction-policy.js +47 -0
  545. package/dist/senses/bluebubbles/replay.js +284 -0
  546. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  547. package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
  548. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  549. package/dist/senses/bluebubbles/webhook-registration.js +257 -0
  550. package/dist/senses/bluebubbles-meta-guard.js +39 -0
  551. package/dist/senses/cli/bracketed-paste.js +82 -0
  552. package/dist/senses/cli/image-paste.js +287 -0
  553. package/dist/senses/cli/image-ref-navigation.js +75 -0
  554. package/dist/senses/cli/ink-app.js +156 -0
  555. package/dist/senses/cli/inline-diff.js +64 -0
  556. package/dist/senses/cli/input-keys.js +174 -0
  557. package/dist/senses/cli/kill-ring.js +86 -0
  558. package/dist/senses/cli/message-list.js +51 -0
  559. package/dist/senses/cli/ouro-tui.js +607 -0
  560. package/dist/senses/cli/spinner-imperative.js +135 -0
  561. package/dist/senses/cli/spinner.js +101 -0
  562. package/dist/senses/cli/status-line.js +60 -0
  563. package/dist/senses/cli/streaming-markdown.js +526 -0
  564. package/dist/senses/cli/tool-display.js +85 -0
  565. package/dist/senses/cli/tool-render.js +85 -0
  566. package/dist/senses/cli/tui-store.js +241 -0
  567. package/dist/senses/cli/virtual-list.js +35 -0
  568. package/dist/senses/cli-entry.js +60 -8
  569. package/dist/senses/cli.js +601 -304
  570. package/dist/senses/commands.js +66 -3
  571. package/dist/senses/context-packet-ledger.js +371 -0
  572. package/dist/senses/context-packets.js +154 -0
  573. package/dist/senses/habit-lifecycle-guard.js +24 -0
  574. package/dist/senses/habit-turn-message.js +160 -0
  575. package/dist/senses/ingress-evidence.js +2 -0
  576. package/dist/senses/mail-entry.js +66 -0
  577. package/dist/senses/mail.js +524 -0
  578. package/dist/senses/pipeline.js +1158 -204
  579. package/dist/senses/private-runtime-worker.js +859 -0
  580. package/dist/senses/private-runtime.js +1627 -0
  581. package/dist/senses/proactive-content-guard.js +51 -0
  582. package/dist/senses/root-host-approval-port.js +345 -0
  583. package/dist/senses/root-host-approval-runtime.js +393 -0
  584. package/dist/senses/sanctuary-authority-resident.js +102 -0
  585. package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
  586. package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
  587. package/dist/senses/sanctuary-grounding.js +118 -0
  588. package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
  589. package/dist/senses/sanctuary-health-acceptance-probe.js +774 -0
  590. package/dist/senses/sanctuary-health-runner.js +104 -0
  591. package/dist/senses/sanctuary-health.js +422 -0
  592. package/dist/senses/sanctuary-install-state-contract.js +169 -0
  593. package/dist/senses/sanctuary-interactive-control.js +410 -0
  594. package/dist/senses/sanctuary-media-catalog-contract.js +259 -0
  595. package/dist/senses/sanctuary-media-optimization.js +514 -0
  596. package/dist/senses/sanctuary-runtime.js +369 -0
  597. package/dist/senses/sanctuary-sab.js +85 -0
  598. package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
  599. package/dist/senses/shared-turn.js +793 -0
  600. package/dist/senses/shepherd/client.js +196 -0
  601. package/dist/senses/shepherd/cmux.js +344 -0
  602. package/dist/senses/shepherd/herdr.js +315 -0
  603. package/dist/senses/shepherd/host.js +14 -0
  604. package/dist/senses/shepherd/judge.js +137 -0
  605. package/dist/senses/shepherd/owner-notice.js +245 -0
  606. package/dist/senses/shepherd/redact.js +66 -0
  607. package/dist/senses/shepherd/returns.js +79 -0
  608. package/dist/senses/shepherd/sense.js +309 -0
  609. package/dist/senses/shepherd-entry.js +78 -0
  610. package/dist/senses/surface-tool.js +109 -0
  611. package/dist/senses/teams-entry.js +68 -8
  612. package/dist/senses/teams.js +598 -233
  613. package/dist/senses/telegram-admission.js +718 -0
  614. package/dist/senses/telegram-approval-runtime.js +793 -0
  615. package/dist/senses/telegram-attachments.js +186 -0
  616. package/dist/senses/telegram-audit-ledger.js +220 -0
  617. package/dist/senses/telegram-authority-transport.js +231 -0
  618. package/dist/senses/telegram-client.js +1749 -0
  619. package/dist/senses/telegram-effect-adapter.js +900 -0
  620. package/dist/senses/telegram-entry.js +83 -0
  621. package/dist/senses/telegram-handoff.js +80 -0
  622. package/dist/senses/telegram.js +2405 -0
  623. package/dist/senses/trust-gate.js +104 -9
  624. package/dist/senses/voice/audio-playback.js +237 -0
  625. package/dist/senses/voice/audio-routing.js +119 -0
  626. package/dist/senses/voice/call-auth.js +250 -0
  627. package/dist/senses/voice/elevenlabs.js +202 -0
  628. package/dist/senses/voice/floor-control.js +431 -0
  629. package/dist/senses/voice/floor-controller.js +115 -0
  630. package/dist/senses/voice/golden-path.js +116 -0
  631. package/dist/senses/voice/index.js +29 -0
  632. package/dist/senses/voice/local-audio-control.js +344 -0
  633. package/dist/senses/voice/local-audio-devices.js +516 -0
  634. package/dist/senses/voice/local-audio-disclosure.js +174 -0
  635. package/dist/senses/voice/local-audio-identity.js +103 -0
  636. package/dist/senses/voice/local-audio-join.js +325 -0
  637. package/dist/senses/voice/local-audio-mute.js +199 -0
  638. package/dist/senses/voice/local-audio-notify.js +121 -0
  639. package/dist/senses/voice/local-audio-prompts.js +116 -0
  640. package/dist/senses/voice/local-audio-transport.js +427 -0
  641. package/dist/senses/voice/local-audio.js +281 -0
  642. package/dist/senses/voice/local-media-stream.js +145 -0
  643. package/dist/senses/voice/meeting.js +113 -0
  644. package/dist/senses/voice/outbound.js +190 -0
  645. package/dist/senses/voice/phone.js +33 -0
  646. package/dist/senses/voice/playback.js +139 -0
  647. package/dist/senses/voice/process-guards.js +51 -0
  648. package/dist/senses/voice/realtime-eval.js +496 -0
  649. package/dist/senses/voice/realtime-tool-schema.js +195 -0
  650. package/dist/senses/voice/realtime-trace.js +531 -0
  651. package/dist/senses/voice/transcript.js +70 -0
  652. package/dist/senses/voice/turn.js +191 -0
  653. package/dist/senses/voice/twilio-phone-runtime.js +836 -0
  654. package/dist/senses/voice/twilio-phone.js +5454 -0
  655. package/dist/senses/voice/types.js +2 -0
  656. package/dist/senses/voice/whisper.js +161 -0
  657. package/dist/senses/voice-entry.js +83 -0
  658. package/dist/senses/voice-realtime-eval-command.js +99 -0
  659. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  660. package/dist/senses/voice-twilio-entry.js +87 -0
  661. package/dist/trips/core.js +138 -0
  662. package/dist/trips/store.js +265 -0
  663. package/dist/util/frontmatter.js +69 -0
  664. package/npm-shrinkwrap.json +8100 -0
  665. package/package.json +74 -13
  666. package/skills/agent-commerce.md +113 -0
  667. package/skills/browser-navigation.md +117 -0
  668. package/skills/commerce-setup-guide.md +116 -0
  669. package/skills/commerce-setup.md +84 -0
  670. package/skills/configure-dev-tools.md +99 -0
  671. package/skills/travel-planning.md +138 -0
  672. package/dist/heart/daemon/auth-flow.js +0 -430
  673. package/dist/heart/daemon/ouro-path-installer.js +0 -260
  674. package/dist/heart/daemon/ouro-version-manager.js +0 -171
  675. package/dist/heart/daemon/update-hooks.js +0 -138
  676. package/dist/heart/obligations.js +0 -191
  677. package/dist/heart/safe-workspace.js +0 -362
  678. package/dist/heart/session-recall.js +0 -116
  679. package/dist/mind/friends/channel.js +0 -84
  680. package/dist/mind/friends/group-context.js +0 -144
  681. package/dist/mind/friends/resolver.js +0 -84
  682. package/dist/mind/friends/store-file.js +0 -190
  683. package/dist/mind/friends/store.js +0 -4
  684. package/dist/mind/friends/tokens.js +0 -26
  685. package/dist/mind/friends/trust-explanation.js +0 -74
  686. package/dist/mind/friends/types.js +0 -29
  687. package/dist/repertoire/tasks/board.js +0 -134
  688. package/dist/repertoire/tasks/index.js +0 -224
  689. package/dist/repertoire/tasks/lifecycle.js +0 -80
  690. package/dist/repertoire/tasks/middleware.js +0 -65
  691. package/dist/repertoire/tasks/parser.js +0 -173
  692. package/dist/repertoire/tasks/scanner.js +0 -132
  693. package/dist/repertoire/tasks/transitions.js +0 -144
  694. package/dist/senses/bluebubbles-entry.js +0 -13
  695. package/dist/senses/bluebubbles.js +0 -1181
  696. package/dist/senses/debug-activity.js +0 -154
  697. package/dist/senses/inner-dialog-worker.js +0 -90
  698. package/dist/senses/inner-dialog.js +0 -525
  699. package/subagents/README.md +0 -7
  700. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  701. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  702. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  703. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  704. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  705. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  706. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  707. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  708. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  709. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  710. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  711. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  712. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  713. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  714. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  715. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  716. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -37,8 +37,11 @@ exports.OURO_CLI_TRUST_MANIFEST = void 0;
37
37
  exports.guardInvocation = guardInvocation;
38
38
  const fs = __importStar(require("node:fs"));
39
39
  const os = __importStar(require("node:os"));
40
- const types_1 = require("../mind/friends/types");
40
+ const path = __importStar(require("node:path"));
41
+ const friends_1 = require("@ouro.bot/friends");
42
+ const shell_quote_1 = require("shell-quote");
41
43
  const runtime_1 = require("../nerves/runtime");
44
+ const store_1 = require("../commerce/store");
42
45
  const deny = (reason) => ({ allowed: false, reason });
43
46
  const allow = { allowed: true };
44
47
  // --- reason templates ---
@@ -47,6 +50,7 @@ const REASONS = {
47
50
  readBeforeEdit: "i need to read that file first before i can edit it.",
48
51
  readBeforeOverwrite: "i need to read that file first before i can overwrite it.",
49
52
  protectedPath: "that path is protected — i can read it but not modify it.",
53
+ psychePath: "my psyche files ship from the repository through a pull request and the replay gate; i can read them but not change them. i file the change request with Claude Code instead.",
50
54
  destructiveCommand: "that command is too dangerous to run — it could cause irreversible damage.",
51
55
  // Trust reasons (vary by relationship)
52
56
  needsTrust: "i'd need a closer friend to vouch for you before i can do that.",
@@ -55,17 +59,45 @@ const REASONS = {
55
59
  // --- read-only tools that never need guardrails ---
56
60
  const READ_ONLY_TOOLS = new Set(["read_file", "glob", "grep"]);
57
61
  // --- protected path detection ---
58
- const PROTECTED_PATH_SEGMENTS = [".git/"];
59
- function getProtectedAbsolutePrefixes() {
60
- return [`${os.homedir()}/.agentsecrets/`];
62
+ const PROTECTED_PATH_SEGMENTS = [
63
+ ".git/",
64
+ ".ouro-cli/vault-unlock/",
65
+ ".ouro-cli/vault-unlock-dpapi/",
66
+ "state/policy/",
67
+ // The pre-trust-directory home of the escalation grants; the file is no longer read, and a model must not recreate it.
68
+ "state/a2a/escalation-grants.json",
69
+ "state/outbox/",
70
+ "state/reports/",
71
+ ];
72
+ const PROTECTED_FILENAMES = ["agent.json", "tool-profiles.json"];
73
+ /** The agent's psyche folder ships only from the repository (a pull request and the replay gate), so no tool writes into it. */
74
+ function isPsychePath(filePath, agentRoot) {
75
+ if (!agentRoot || !filePath)
76
+ return false;
77
+ const psyche = path.resolve(agentRoot, "psyche");
78
+ const target = path.resolve(agentRoot, filePath);
79
+ return target === psyche || target.startsWith(`${psyche}${path.sep}`);
80
+ }
81
+ /**
82
+ * The friends store (`friends/` under the agent root) is written by the harness's own code, which the model's file tools and
83
+ * shell redirects must not reach: a model talked into editing a record could rewrite trust, admission or a legacy grant.
84
+ * Scoped to this agent's root, so a project directory that happens to be named `friends` stays editable. Defence in depth
85
+ * only: a shell can still write anywhere its uid can, which is why delegated-command authority lives outside the bundle.
86
+ */
87
+ function isFriendsStorePath(filePath, agentRoot) {
88
+ if (!agentRoot || !filePath)
89
+ return false;
90
+ const store = path.resolve(agentRoot, "friends");
91
+ const target = path.resolve(agentRoot, filePath);
92
+ return target === store || target.startsWith(`${store}${path.sep}`);
61
93
  }
62
94
  function isProtectedPath(filePath) {
63
95
  for (const segment of PROTECTED_PATH_SEGMENTS) {
64
96
  if (filePath.includes(`/${segment}`) || filePath.startsWith(segment))
65
97
  return true;
66
98
  }
67
- for (const prefix of getProtectedAbsolutePrefixes()) {
68
- if (filePath.startsWith(prefix))
99
+ for (const name of PROTECTED_FILENAMES) {
100
+ if (path.basename(filePath) === name)
69
101
  return true;
70
102
  }
71
103
  return false;
@@ -99,6 +131,116 @@ function shellWritesToProtectedPath(command) {
99
131
  return true;
100
132
  return false;
101
133
  }
134
+ // --- the psyche folder in shell commands ---
135
+ // The psyche folder is mounted read-only into the resident at the OS level (the upgrade recreates the container that way). This is the
136
+ // defence in depth in front of that: a shell command that mentions the psyche folder at all runs only if every part of it is
137
+ // a read-only command, because enumerating the ways to write a file (>, >>, tee, cp, mv, sed -i, node -e, python, cd then
138
+ // redirect) is a list the model can always step around.
139
+ const PSYCHE_READ_ONLY_COMMANDS = new Set(["cat", "ls", "head", "tail", "grep", "wc", "sha256sum", "stat", "cd", "pwd"]);
140
+ const SEGMENT_OPERATORS = new Set(["&&", "||", ";", "|"]);
141
+ // --- globs and expansions that could land inside a protected folder ---
142
+ // A word such as /bundle/fr*nds/x.json, /bundle/friend?/x.json or ${F}ends/x.json names no protected folder literally, but the
143
+ // shell could resolve it into one. A word like that counts as mentioning the folder when its directory part can match the folder's
144
+ // path, so the read-only rule below applies to the command.
145
+ const EXPANSION = "\u0001";
146
+ const STABLE_VARIABLES = ["HOME", "TMPDIR", "USER"];
147
+ function neutraliseExpansions(command) {
148
+ return command.replace(/\$\([^)]*\)|`[^`]*`|\$\{([A-Za-z_]\w*)\}|\$([A-Za-z_]\w*)|\$\{[^}]*\}/g, (_match, braced, plain) => {
149
+ const name = braced ?? plain;
150
+ if (name !== undefined && STABLE_VARIABLES.includes(name) && !new RegExp(`\\b${name}=`).test(command) && process.env[name])
151
+ return process.env[name];
152
+ return EXPANSION;
153
+ });
154
+ }
155
+ function wordPattern(word) {
156
+ const generalised = word.replace(/\{[^}]*\}/g, EXPANSION).replace(/\[[^\]]*\]/g, "?");
157
+ let source = "";
158
+ for (const char of generalised)
159
+ source += char === EXPANSION ? ".*" : char === "*" ? "[^/]*" : char === "?" ? "[^/]" : char.replace(/[.+^$()|\\\]{}[]/g, "\\$&");
160
+ return new RegExp(`^${source}$`);
161
+ }
162
+ function globOrExpansionCouldReach(command, folder, agentRoot) {
163
+ const tokens = neutraliseExpansions(command).split(/[\s<>|;&()'"]+/).filter((token) => /[*?[{\u0001]/.test(token));
164
+ return tokens.some((token) => {
165
+ const word = token.startsWith("~") ? expandHome(token) : token;
166
+ const absolute = word.startsWith("/") || word.startsWith(EXPANSION) ? word : `${agentRoot}/${word}`;
167
+ const dir = absolute.slice(0, Math.max(absolute.lastIndexOf("/"), 0));
168
+ return wordPattern(absolute).test(folder) || wordPattern(dir).test(folder);
169
+ });
170
+ }
171
+ function commandMentionsPsyche(command, words, agentRoot) {
172
+ const psyche = path.resolve(agentRoot, "psyche");
173
+ if (globOrExpansionCouldReach(command, psyche, agentRoot))
174
+ return true;
175
+ if (command.includes(psyche) || words.some((word) => word.includes(psyche)))
176
+ return true;
177
+ if (words.some((word) => word === "psyche" || isPsychePath(word, agentRoot)))
178
+ return true;
179
+ // A relative "psyche/..." inside code or a quoted argument, when this agent has such a folder.
180
+ return /(?:^|[\s'"=(])psyche\//.test(command) && fs.existsSync(psyche);
181
+ }
182
+ /**
183
+ * The shared rule: when a shell command mentions a protected folder at all, it runs only if every part of it is a read-only
184
+ * command. The mention test is the only thing that differs between folders.
185
+ */
186
+ function protectedFolderShellWriteRefused(command, mentions) {
187
+ const entries = (0, shell_quote_1.parse)(command);
188
+ const words = entries.filter((entry) => typeof entry === "string");
189
+ if (!mentions(words))
190
+ return false;
191
+ // Substitution, heredocs and any $VAR or ${VAR} expansion: the shell could build a protected path or a command word we cannot see.
192
+ if (/\$[({A-Za-z_]|`|<\(|<</.test(command))
193
+ return true;
194
+ let expectCommandWord = true;
195
+ for (const entry of entries) {
196
+ if (typeof entry === "string") {
197
+ if (expectCommandWord && !/^\w+=/.test(entry)) {
198
+ if (!PSYCHE_READ_ONLY_COMMANDS.has(entry))
199
+ return true;
200
+ expectCommandWord = false;
201
+ }
202
+ continue;
203
+ }
204
+ const op = "op" in entry ? entry.op : "comment";
205
+ if (SEGMENT_OPERATORS.has(op))
206
+ expectCommandWord = true;
207
+ else if (op !== "glob")
208
+ return true;
209
+ }
210
+ return false;
211
+ }
212
+ function psycheShellWriteRefused(command, agentRoot) {
213
+ if (!agentRoot)
214
+ return false;
215
+ return protectedFolderShellWriteRefused(command, (words) => commandMentionsPsyche(command, words, agentRoot));
216
+ }
217
+ // --- the friends store in shell commands ---
218
+ // Same stance as the psyche folder: a command that names this agent's friends store runs only if it is read-only, because a list of
219
+ // the ways to write a file (>, >>, tee, cp, mv, sed -i, node -e, python, cd then redirect, ~ paths) is one the model can step around.
220
+ function expandHome(word) {
221
+ return word === "~" || word.startsWith("~/") ? path.join(os.homedir(), word.slice(1)) : word;
222
+ }
223
+ function commandMentionsFriendsStore(command, words, agentRoot) {
224
+ if (globOrExpansionCouldReach(command, path.resolve(agentRoot, "friends"), agentRoot))
225
+ return true;
226
+ // Only path-shaped words resolve against the store: an ordinary word such as "friends" in prose is not a path.
227
+ if (words.some((word) => word.includes("/") && isFriendsStorePath(expandHome(word), agentRoot)))
228
+ return true;
229
+ // A bare `friends` names the store only as the target of a cd; elsewhere it is an ordinary word ("my friends are kind").
230
+ if (words.some((word, index) => word.startsWith("friends/") || (word === "friends" && words[index - 1] === "cd")))
231
+ return true;
232
+ // A variable or substitution in front of the path ($BUNDLE/friends/x.json): the folder name is still in the command.
233
+ if (/\$[({A-Za-z_]|`/.test(command) && /(?:^|[\/\s'"=])friends(?:$|[\/\s'"])/.test(command))
234
+ return true;
235
+ // An absolute or relative path inside code or a quoted argument, such as node -e "...'/bundle/friends/x.json'...".
236
+ const store = path.resolve(agentRoot, "friends");
237
+ return command.includes(store) || /(?:^|[\s'"=(])friends\//.test(command);
238
+ }
239
+ function friendsShellWriteRefused(command, agentRoot) {
240
+ if (!agentRoot)
241
+ return false;
242
+ return protectedFolderShellWriteRefused(command, (words) => commandMentionsFriendsStore(command, words, agentRoot));
243
+ }
102
244
  // --- structural guardrail checks (always on, all trust levels) ---
103
245
  function checkReadBeforeWrite(toolName, args, context) {
104
246
  if (toolName === "edit_file") {
@@ -127,21 +269,27 @@ function checkDestructiveShellPatterns(toolName, args) {
127
269
  }
128
270
  return allow;
129
271
  }
130
- function checkProtectedPaths(toolName, args) {
272
+ function checkProtectedPaths(toolName, args, context) {
131
273
  if (toolName === "write_file" || toolName === "edit_file") {
132
274
  const filePath = args.path || "";
133
- if (isProtectedPath(filePath))
275
+ if (isPsychePath(filePath, context.agentRoot))
276
+ return deny(REASONS.psychePath);
277
+ if (isProtectedPath(filePath) || isFriendsStorePath(filePath, context.agentRoot))
134
278
  return deny(REASONS.protectedPath);
135
279
  }
136
280
  if (toolName === "shell") {
137
281
  const command = args.command || "";
282
+ if (psycheShellWriteRefused(command, context.agentRoot))
283
+ return deny(REASONS.psychePath);
284
+ if (friendsShellWriteRefused(command, context.agentRoot))
285
+ return deny(REASONS.protectedPath);
138
286
  if (shellWritesToProtectedPath(command))
139
287
  return deny(REASONS.protectedPath);
140
288
  }
141
289
  return allow;
142
290
  }
143
291
  function checkStructuralGuardrails(toolName, args, context) {
144
- const protectedResult = checkProtectedPaths(toolName, args);
292
+ const protectedResult = checkProtectedPaths(toolName, args, context);
145
293
  if (!protectedResult.allowed)
146
294
  return protectedResult;
147
295
  const destructiveResult = checkDestructiveShellPatterns(toolName, args);
@@ -155,18 +303,15 @@ exports.OURO_CLI_TRUST_MANIFEST = {
155
303
  whoami: "acquaintance",
156
304
  changelog: "acquaintance",
157
305
  "session list": "acquaintance",
158
- "task board": "friend",
159
- "task create": "friend",
160
- "task update": "friend",
161
- "task show": "friend",
162
- "task actionable": "friend",
163
- "task deps": "friend",
164
- "task sessions": "friend",
165
306
  "friend list": "friend",
166
307
  "friend show": "friend",
167
308
  "friend create": "friend",
168
309
  "friend update": "family",
169
- "reminder create": "friend",
310
+ // Linking and merging change who the agent believes someone is: family only.
311
+ "friend link": "family",
312
+ "friend unlink": "family",
313
+ "friend merge": "family",
314
+ "friend dedupe": "family",
170
315
  "config model": "friend",
171
316
  "config models": "friend",
172
317
  "mcp list": "acquaintance",
@@ -201,7 +346,8 @@ function resolveOuroSubcommand(command) {
201
346
  /* v8 ignore next -- bare "ouro" is caught upstream by checkShellTrustGuardrails @preserve */
202
347
  if (!afterOuro)
203
348
  return null;
204
- const tokens = afterOuro.split(/\s+/);
349
+ // `--agent <name>` may come before the subcommand; it never changes which subcommand runs.
350
+ const tokens = afterOuro.split(/\s+/).filter((token, index, all) => token !== "--agent" && all[index - 1] !== "--agent");
205
351
  const twoWord = tokens.length >= 2 ? `${tokens[0]} ${tokens[1]}` : null;
206
352
  // Two-word match first (e.g. "task board"), then one-word (e.g. "whoami")
207
353
  if (twoWord && exports.OURO_CLI_TRUST_MANIFEST[twoWord])
@@ -210,6 +356,26 @@ function resolveOuroSubcommand(command) {
210
356
  return tokens[0];
211
357
  return null;
212
358
  }
359
+ // --- MCP server-specific trust rules ---
360
+ const MCP_SERVER_TRUST = {
361
+ browser: { minTrust: "friend", blockGroupChat: true },
362
+ };
363
+ function checkMcpServerTrust(command, context) {
364
+ const match = command.match(/^ouro\s+mcp\s+call\s+(\S+)/);
365
+ if (!match)
366
+ return allow;
367
+ const serverName = match[1];
368
+ const rules = MCP_SERVER_TRUST[serverName];
369
+ if (!rules)
370
+ return allow; // no special rules for this server
371
+ if (!trustLevelSatisfied(rules.minTrust, context.trustLevel ?? "friend")) {
372
+ return deny(REASONS.needsTrust);
373
+ }
374
+ if (rules.blockGroupChat && context.isGroupChat) {
375
+ return deny("browser tools are only available in 1:1 conversations, not group chats.");
376
+ }
377
+ return allow;
378
+ }
213
379
  function checkSingleShellCommandTrust(command, trustLevel) {
214
380
  const trimmed = command.trim();
215
381
  const tokens = trimmed.split(/\s+/);
@@ -261,9 +427,791 @@ function checkWriteTrustGuardrails(toolName, args, context) {
261
427
  return allow;
262
428
  return deny(REASONS.needsTrustForWrite);
263
429
  }
430
+ // --- credential tool trust gating ---
431
+ // Credential write tools: family only
432
+ const CREDENTIAL_FAMILY_TOOLS = new Set([
433
+ "credential_generate_password", "credential_store", "credential_delete", "vault_setup",
434
+ // User profile tools: family only
435
+ "user_profile_store", "user_profile_get", "user_profile_delete",
436
+ // Payment tools: family only
437
+ "stripe_create_card", "stripe_deactivate_card", "stripe_list_cards",
438
+ // Booking tools that involve payment: family only
439
+ "flight_book", "flight_hold", "flight_cancel",
440
+ ]);
441
+ // Credential read tools: friend+
442
+ const CREDENTIAL_TRUSTED_TOOLS = new Set(["credential_get", "credential_list"]);
443
+ // Travel tools: friend+ (weather_lookup accesses vault credentials indirectly;
444
+ // advisory and geocode are public APIs but gated for consistency)
445
+ // Flight search is also friend+ (read-only, no payment)
446
+ const TRAVEL_TRUSTED_TOOLS = new Set(["weather_lookup", "travel_advisory", "geocode_search", "flight_search"]);
447
+ const A2A_TRUSTED_TOOLS = new Set(["a2a_list_peers", "a2a_send_message", "a2a_get_task"]);
448
+ const COMMERCE_FAMILY_TOOLS = new Set(["commerce_checkout_preview", "commerce_checkout_commit", "commerce_receipt_get", "commerce_access_log"]);
449
+ const COMMERCE_AUTHORITY_TOOLS = new Set(["stripe_create_card", "flight_hold", "flight_book"]);
450
+ // The Shepherd tools read the owner's terminals and speak to them through their desktop, so only family may use them.
451
+ // A call with no known trust level fails closed.
452
+ const SHEPHERD_FAMILY_TOOLS = new Set(["shepherd_overview", "shepherd_read", "shepherd_signal", "shepherd_send"]);
453
+ const MAIL_FAMILY_TOOLS = new Set(["mail_screener", "mail_decide", "mail_access_log", "mail_send", "mail_index_refresh"]);
454
+ const MAIL_DELEGATED_READ_TOOLS = new Set(["mail_recent", "mail_search"]);
455
+ function opaqueAnsiShellAtoms(command) {
456
+ const atoms = [];
457
+ let inAnsiQuote = false;
458
+ for (let index = 0; index < command.length;) {
459
+ if (!inAnsiQuote && command.startsWith("$'", index)) {
460
+ inAnsiQuote = true;
461
+ index += 2;
462
+ continue;
463
+ }
464
+ const character = command[index];
465
+ if (inAnsiQuote && character === "'") {
466
+ inAnsiQuote = false;
467
+ index += 1;
468
+ continue;
469
+ }
470
+ if (inAnsiQuote && character === "\\") {
471
+ const escape = command.slice(index).match(/^\\(?:x[0-9a-fA-F]{1,2}|u[0-9a-fA-F]{1,4}|U[0-9a-fA-F]{1,8}|[0-7]{1,3}|c.|.)?/s)[0];
472
+ atoms.push(null);
473
+ index += escape.length;
474
+ continue;
475
+ }
476
+ if (!inAnsiQuote && (character === "'" || character === '"')) {
477
+ index += 1;
478
+ continue;
479
+ }
480
+ if (!inAnsiQuote && character === "\\" && index + 1 < command.length) {
481
+ atoms.push(command[index + 1]);
482
+ index += 2;
483
+ continue;
484
+ }
485
+ atoms.push(character);
486
+ index += 1;
487
+ }
488
+ return atoms;
489
+ }
490
+ function shellContainsAmbiguousAnsiMailCacheSync(command) {
491
+ if (!command.includes("$'"))
492
+ return false;
493
+ const expected = ["ouro", "mail", "sync-cache"];
494
+ let states = new Set(["0:0"]);
495
+ const crossTokenBoundary = (current) => {
496
+ const next = new Set(["0:0"]);
497
+ for (const state of current) {
498
+ const [tokenIndex, characterIndex] = state.split(":").map(Number);
499
+ if (characterIndex !== expected[tokenIndex].length)
500
+ continue;
501
+ if (tokenIndex === expected.length - 1)
502
+ return { matched: true, states: next };
503
+ next.add(`${tokenIndex + 1}:0`);
504
+ }
505
+ return { matched: false, states: next };
506
+ };
507
+ for (const atom of opaqueAnsiShellAtoms(command)) {
508
+ if (atom === null) {
509
+ const next = new Set(states);
510
+ for (const state of states) {
511
+ const [tokenIndex, characterIndex] = state.split(":").map(Number);
512
+ if (characterIndex >= 0 && characterIndex < expected[tokenIndex].length) {
513
+ next.add(`${tokenIndex}:${characterIndex + 1}`);
514
+ }
515
+ }
516
+ const boundary = crossTokenBoundary(states);
517
+ if (boundary.matched)
518
+ return true;
519
+ states = new Set([...next, ...boundary.states]);
520
+ continue;
521
+ }
522
+ if (/\s|[;&|()`]/.test(atom)) {
523
+ const boundary = crossTokenBoundary(states);
524
+ if (boundary.matched)
525
+ return true;
526
+ states = boundary.states;
527
+ continue;
528
+ }
529
+ const next = new Set();
530
+ for (const state of states) {
531
+ const [tokenIndex, characterIndex] = state.split(":").map(Number);
532
+ const wanted = expected[tokenIndex]?.[characterIndex];
533
+ next.add(wanted?.toLowerCase() === atom.toLowerCase() ? `${tokenIndex}:${characterIndex + 1}` : `${tokenIndex}:-1`);
534
+ }
535
+ states = next;
536
+ }
537
+ return crossTokenBoundary(states).matched;
538
+ }
539
+ const SHELL_COMMAND_BOUNDARIES = new Set(["||", "&&", ";;", "|&", "&", ";", "(", ")", "|", "<("]);
540
+ const SHELL_INTERPRETERS = new Set(["sh", "bash", "zsh"]);
541
+ const SHELL_TOKEN_BOUNDARIES = new Set(["{", "}", "then", "elif", "else", "do"]);
542
+ const SHELL_GRAMMAR_PREFIXES = new Set(["!", "if", "until", "while"]);
543
+ const SHELL_PARAMETER_MARKER = "__OURO_SHELL_PARAMETER_";
544
+ const SHELL_ARRAY_EXPANSION = "__OURO_ARRAY_EXPANSION__";
545
+ function hasUnescapedShellSubstitution(value) {
546
+ for (let index = 0; index < value.length; index += 1) {
547
+ if (value[index] === "\\") {
548
+ index += 1;
549
+ continue;
550
+ }
551
+ if (value.startsWith("$(", index) && !value.startsWith("$((", index))
552
+ return true;
553
+ if (value[index] === "`")
554
+ return true;
555
+ }
556
+ return false;
557
+ }
558
+ function stripHereDocBodies(command) {
559
+ const pending = [];
560
+ const lines = command.split("\n");
561
+ return lines.map((sourceLine) => {
562
+ if (pending.length > 0) {
563
+ const active = pending[0];
564
+ const candidate = active.stripTabs ? sourceLine.replace(/^\t+/, "") : sourceLine;
565
+ if (candidate === active.delimiter) {
566
+ pending.shift();
567
+ return "";
568
+ }
569
+ if (active.quoted || !hasUnescapedShellSubstitution(sourceLine))
570
+ return "";
571
+ return exposeShellSubstitutions(sourceLine).split("\n").slice(1).join("\n");
572
+ }
573
+ const pattern = /<<(?!<)(-)?\s*(?:'([^']*)'|"([^"]*)"|\\([^\s;&|]+)|([^\s;&|]+))/g;
574
+ for (const match of stripShellComments(sourceLine).matchAll(pattern)) {
575
+ pending.push({
576
+ stripTabs: match[1] !== undefined,
577
+ delimiter: match[2] ?? match[3] ?? match[4] ?? match[5],
578
+ quoted: match[2] !== undefined || match[3] !== undefined || match[4] !== undefined,
579
+ });
580
+ }
581
+ return sourceLine;
582
+ }).join("\n");
583
+ }
584
+ function stripShellComments(command) {
585
+ let result = "";
586
+ let quote = null;
587
+ for (let index = 0; index < command.length; index += 1) {
588
+ const character = command[index];
589
+ if (character === "\\" && quote !== "single") {
590
+ result += character + (command[index + 1] ?? "");
591
+ index += 1;
592
+ continue;
593
+ }
594
+ if (character === "'" && quote !== "double")
595
+ quote = quote === "single" ? null : "single";
596
+ else if (character === '"' && quote !== "single")
597
+ quote = quote === "double" ? null : "double";
598
+ if (character === "#" && quote === null && (index === 0 || /[\s;&|()]/.test(command[index - 1]))) {
599
+ const newline = command.indexOf("\n", index);
600
+ if (newline < 0)
601
+ break;
602
+ result += " ".repeat(newline - index) + "\n";
603
+ index = newline;
604
+ continue;
605
+ }
606
+ result += character;
607
+ }
608
+ return result;
609
+ }
610
+ const SHELL_ARRAY_ASSIGNMENT = /([A-Za-z_][A-Za-z0-9_]*)(\+?=)\(([^()\n]*)\)/y;
611
+ const SHELL_INDEXED_ASSIGNMENT = /([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=("[^"]*"|'[^']*'|[^\s;&|]+)/y;
612
+ const SHELL_SCALAR_ASSIGNMENT = /([A-Za-z_][A-Za-z0-9_]*)=("[^"]*"|'[^']*'|[^\s;&|()]+)/y;
613
+ const SHELL_ARRAY_PARAMETER = /\$\{([A-Za-z_][A-Za-z0-9_]*)\[(@|\*)\]\}/y;
614
+ const SHELL_SCALAR_PARAMETER = /\$(?:\{([A-Za-z_][A-Za-z0-9_]*)\}|([A-Za-z_][A-Za-z0-9_]*))/y;
615
+ function shellMatchAt(pattern, command, index) {
616
+ pattern.lastIndex = index;
617
+ return pattern.exec(command);
618
+ }
619
+ function shellAssignmentPosition(command, index) {
620
+ let previous = index - 1;
621
+ while (previous >= 0 && /[ \t]/.test(command[previous]))
622
+ previous -= 1;
623
+ return previous < 0 || /[;&|()\n]/.test(command[previous]);
624
+ }
625
+ function parseShellWords(value) {
626
+ if (hasUnescapedShellSubstitution(value) || /(^|[^\\])\$(?!['"])/.test(value))
627
+ return undefined;
628
+ try {
629
+ const entries = (0, shell_quote_1.parse)(value);
630
+ if (entries.some((entry) => typeof entry !== "string"))
631
+ return undefined;
632
+ return entries;
633
+ }
634
+ catch {
635
+ return undefined;
636
+ }
637
+ }
638
+ function shellAssignmentPersists(command, endIndex) {
639
+ let next = endIndex;
640
+ while (next < command.length && /[ \t]/.test(command[next]))
641
+ next += 1;
642
+ return next === command.length || /[;&|\n]/.test(command[next]);
643
+ }
644
+ function shellUnquotedFields(values) {
645
+ const fields = values.flatMap((value) => value.split(/\s+/).filter(Boolean));
646
+ return fields.some((field) => /[*?[]/.test(field)) ? SHELL_ARRAY_EXPANSION : (0, shell_quote_1.quote)(fields);
647
+ }
648
+ function doubleQuotedFragment(value) {
649
+ if (hasUnescapedShellSubstitution(value))
650
+ return undefined;
651
+ try {
652
+ const parsed = (0, shell_quote_1.parse)(`"${value}"`);
653
+ return parsed.length === 1 && typeof parsed[0] === "string" ? parsed[0] : undefined;
654
+ }
655
+ catch {
656
+ return undefined;
657
+ }
658
+ }
659
+ function closingDoubleQuote(command, startIndex) {
660
+ for (let index = startIndex; index < command.length; index += 1) {
661
+ if (command[index] === "\\")
662
+ index += 1;
663
+ else if (command[index] === '"')
664
+ return index;
665
+ }
666
+ return -1;
667
+ }
668
+ function transformOrderedShellVariables(command) {
669
+ const variables = new Map();
670
+ const result = [];
671
+ let quote = null;
672
+ let doubleQuoteStart = -1;
673
+ let doubleQuoteResultIndex = -1;
674
+ for (let index = 0; index < command.length; index += 1) {
675
+ const character = command[index];
676
+ if (character === "\\" && quote !== "single") {
677
+ result.push(character + (command[index + 1] ?? ""));
678
+ index += 1;
679
+ continue;
680
+ }
681
+ if (character === "'") {
682
+ if (quote !== "double")
683
+ quote = quote === "single" ? null : "single";
684
+ result.push(character);
685
+ continue;
686
+ }
687
+ if (character === '"') {
688
+ if (quote !== "single") {
689
+ if (quote === "double") {
690
+ quote = null;
691
+ doubleQuoteStart = -1;
692
+ doubleQuoteResultIndex = -1;
693
+ }
694
+ else {
695
+ quote = "double";
696
+ doubleQuoteStart = index;
697
+ doubleQuoteResultIndex = result.length;
698
+ }
699
+ }
700
+ result.push(character);
701
+ continue;
702
+ }
703
+ if (quote === null && /[A-Za-z_]/.test(character) && shellAssignmentPosition(command, index)) {
704
+ const arrayAssignment = shellMatchAt(SHELL_ARRAY_ASSIGNMENT, command, index);
705
+ if (arrayAssignment) {
706
+ const [, name, operator, body] = arrayAssignment;
707
+ const elements = parseShellWords(body);
708
+ if (elements === undefined)
709
+ variables.delete(name);
710
+ else
711
+ variables.set(name, { array: operator === "+=" ? [...(variables.get(name)?.array ?? []), ...elements] : elements });
712
+ result.push(`${name}=__OURO_ARRAY_LITERAL`);
713
+ index += arrayAssignment[0].length - 1;
714
+ continue;
715
+ }
716
+ const indexedAssignment = shellMatchAt(SHELL_INDEXED_ASSIGNMENT, command, index);
717
+ if (indexedAssignment) {
718
+ const [, name, elementIndex, rawValue] = indexedAssignment;
719
+ const element = parseShellWords(rawValue);
720
+ if (element?.length !== 1)
721
+ variables.delete(name);
722
+ else {
723
+ const array = [...(variables.get(name)?.array ?? [])];
724
+ array[Number(elementIndex)] = element[0];
725
+ variables.set(name, { array });
726
+ }
727
+ result.push(`${name}=__OURO_ARRAY_LITERAL`);
728
+ index += indexedAssignment[0].length - 1;
729
+ continue;
730
+ }
731
+ const scalarAssignment = shellMatchAt(SHELL_SCALAR_ASSIGNMENT, command, index);
732
+ if (scalarAssignment) {
733
+ const [, name, rawValue] = scalarAssignment;
734
+ const scalar = parseShellWords(rawValue);
735
+ if (shellAssignmentPersists(command, index + scalarAssignment[0].length)) {
736
+ if (scalar?.length === 1)
737
+ variables.set(name, { scalar: scalar[0] });
738
+ else
739
+ variables.delete(name);
740
+ }
741
+ result.push(scalarAssignment[0]);
742
+ index += scalarAssignment[0].length - 1;
743
+ continue;
744
+ }
745
+ }
746
+ if (quote !== "single" && character === "$") {
747
+ const arrayExpansion = shellMatchAt(SHELL_ARRAY_PARAMETER, command, index);
748
+ if (arrayExpansion) {
749
+ const [, name, mode] = arrayExpansion;
750
+ const elements = variables.get(name)?.array;
751
+ if (elements === undefined)
752
+ result.push(SHELL_ARRAY_EXPANSION);
753
+ else if (quote === "double" && mode === "@") {
754
+ const closing = closingDoubleQuote(command, index + arrayExpansion[0].length);
755
+ const prefix = doubleQuotedFragment(command.slice(doubleQuoteStart + 1, index));
756
+ const suffix = closing < 0 ? undefined : doubleQuotedFragment(command.slice(index + arrayExpansion[0].length, closing));
757
+ if (closing < 0 || prefix === undefined || suffix === undefined)
758
+ result.push(SHELL_ARRAY_EXPANSION);
759
+ else {
760
+ const presentElements = elements.filter((element) => element !== undefined);
761
+ const expanded = presentElements.length === 0
762
+ ? (prefix.length + suffix.length === 0 ? [] : [`${prefix}${suffix}`])
763
+ : presentElements.map((element, elementIndex) => `${elementIndex === 0 ? prefix : ""}${element}${elementIndex === presentElements.length - 1 ? suffix : ""}`);
764
+ result.splice(doubleQuoteResultIndex);
765
+ result.push((0, shell_quote_1.quote)(expanded));
766
+ quote = null;
767
+ doubleQuoteStart = -1;
768
+ doubleQuoteResultIndex = -1;
769
+ index = closing;
770
+ continue;
771
+ }
772
+ }
773
+ else if (quote === "double")
774
+ result.push(elements.join(" "));
775
+ else
776
+ result.push(shellUnquotedFields(elements));
777
+ index += arrayExpansion[0].length - 1;
778
+ continue;
779
+ }
780
+ const scalarExpansion = shellMatchAt(SHELL_SCALAR_PARAMETER, command, index);
781
+ if (scalarExpansion) {
782
+ const name = scalarExpansion[1] ?? scalarExpansion[2];
783
+ const scalar = variables.get(name)?.scalar;
784
+ if (scalar !== undefined) {
785
+ if (quote === "double")
786
+ result.push(scalar.replace(/["\\$`]/g, "\\$&"));
787
+ else
788
+ result.push(shellUnquotedFields([scalar]));
789
+ index += scalarExpansion[0].length - 1;
790
+ continue;
791
+ }
792
+ if (quote === null) {
793
+ result.push(SHELL_ARRAY_EXPANSION);
794
+ index += scalarExpansion[0].length - 1;
795
+ continue;
796
+ }
797
+ }
798
+ }
799
+ result.push(character);
800
+ }
801
+ return result.join("");
802
+ }
803
+ function findCommandSubstitutionEnd(command, start) {
804
+ let depth = 1;
805
+ let quote = null;
806
+ for (let index = start; index < command.length; index += 1) {
807
+ const character = command[index];
808
+ if (character === "\\" && quote !== "single") {
809
+ index += 1;
810
+ continue;
811
+ }
812
+ if (character === "'" && quote !== "double") {
813
+ quote = quote === "single" ? null : "single";
814
+ continue;
815
+ }
816
+ if (character === '"' && quote !== "single") {
817
+ quote = quote === "double" ? null : "double";
818
+ continue;
819
+ }
820
+ if (quote !== null)
821
+ continue;
822
+ if (character === "(")
823
+ depth += 1;
824
+ else if (character === ")") {
825
+ depth -= 1;
826
+ if (depth === 0)
827
+ return index;
828
+ }
829
+ }
830
+ return -1;
831
+ }
832
+ function exposeShellSubstitutions(command, depth = 0) {
833
+ if (depth >= 32)
834
+ return "ouro mail sync-cache";
835
+ let outer = "";
836
+ const nested = [];
837
+ let quote = null;
838
+ for (let index = 0; index < command.length; index += 1) {
839
+ const character = command[index];
840
+ if (character === "\\" && quote !== "single") {
841
+ outer += character + (command[index + 1] ?? "");
842
+ index += 1;
843
+ continue;
844
+ }
845
+ if (character === "'" && quote !== "double") {
846
+ quote = quote === "single" ? null : "single";
847
+ outer += character;
848
+ continue;
849
+ }
850
+ if (character === '"' && quote !== "single") {
851
+ quote = quote === "double" ? null : "double";
852
+ outer += character;
853
+ continue;
854
+ }
855
+ if (quote !== "single" && command.startsWith("$(", index) && !command.startsWith("$((", index)) {
856
+ const end = findCommandSubstitutionEnd(command, index + 2);
857
+ if (end >= 0) {
858
+ nested.push(exposeShellSubstitutions(command.slice(index + 2, end), depth + 1));
859
+ outer += "${__OURO_COMMAND_SUBSTITUTION}";
860
+ index = end;
861
+ continue;
862
+ }
863
+ }
864
+ if (quote !== "single" && character === "`") {
865
+ let end = index + 1;
866
+ while (end < command.length && command[end] !== "`") {
867
+ if (command[end] === "\\")
868
+ end += 1;
869
+ end += 1;
870
+ }
871
+ if (end < command.length) {
872
+ nested.push(exposeShellSubstitutions(command.slice(index + 1, end), depth + 1));
873
+ outer += "${__OURO_COMMAND_SUBSTITUTION}";
874
+ index = end;
875
+ continue;
876
+ }
877
+ }
878
+ outer += character;
879
+ }
880
+ return [outer, ...nested].join("\n");
881
+ }
882
+ function normalizeShellNewlines(command) {
883
+ let result = "";
884
+ let quote = null;
885
+ for (let index = 0; index < command.length; index += 1) {
886
+ const character = command[index];
887
+ if (character === "\\" && quote !== "single") {
888
+ result += character + (command[index + 1] ?? "");
889
+ index += 1;
890
+ continue;
891
+ }
892
+ if (character === "'" && quote !== "double")
893
+ quote = quote === "single" ? null : "single";
894
+ else if (character === '"' && quote !== "single")
895
+ quote = quote === "double" ? null : "double";
896
+ result += character === "\n" && quote === null ? " ; " : character;
897
+ }
898
+ return result;
899
+ }
900
+ function executableShellView(command) {
901
+ const withoutData = stripShellComments(stripHereDocBodies(command));
902
+ return normalizeShellNewlines(transformOrderedShellVariables(exposeShellSubstitutions(withoutData)));
903
+ }
904
+ function parseShellCommands(command) {
905
+ let parameterIndex = 0;
906
+ const parameterNames = new Map();
907
+ const entries = (0, shell_quote_1.parse)(command, (name) => {
908
+ const marker = `${SHELL_PARAMETER_MARKER}${parameterIndex}__`;
909
+ parameterIndex += 1;
910
+ parameterNames.set(marker, name);
911
+ return marker;
912
+ });
913
+ const commands = [];
914
+ let current = [];
915
+ let skipRedirectionTarget = false;
916
+ const flush = () => {
917
+ if (current.length > 0)
918
+ commands.push(current);
919
+ current = [];
920
+ skipRedirectionTarget = false;
921
+ };
922
+ for (const entry of entries) {
923
+ if (typeof entry === "string") {
924
+ if (skipRedirectionTarget)
925
+ skipRedirectionTarget = false;
926
+ else if (SHELL_TOKEN_BOUNDARIES.has(entry.toLowerCase()))
927
+ flush();
928
+ else
929
+ current.push(entry);
930
+ continue;
931
+ }
932
+ const operation = entry;
933
+ if (operation.op === "glob") {
934
+ current.push(operation.pattern);
935
+ continue;
936
+ }
937
+ if (SHELL_COMMAND_BOUNDARIES.has(operation.op)) {
938
+ flush();
939
+ continue;
940
+ }
941
+ // Every remaining control operator is a redirection. Its next string is
942
+ // a path or descriptor, not an argv token.
943
+ skipRedirectionTarget = true;
944
+ }
945
+ flush();
946
+ return { commands, parameterNames };
947
+ }
948
+ function resolveKnownShellParameters(token, knownVariables, parameterNames) {
949
+ let resolved = token;
950
+ for (const [marker, name] of parameterNames) {
951
+ const known = knownVariables.get(name);
952
+ if (known !== undefined)
953
+ resolved = resolved.replaceAll(marker, known);
954
+ }
955
+ return resolved;
956
+ }
957
+ function shellTokenCanEqual(token, expected) {
958
+ const escaped = token
959
+ .split(new RegExp(`(?:${SHELL_PARAMETER_MARKER}\\d+__|${SHELL_ARRAY_EXPANSION})`, "g"))
960
+ .map((literal) => literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
961
+ .join(".*");
962
+ return new RegExp(`^${escaped}$`, "i").test(expected);
963
+ }
964
+ function shellExecutableCanEqual(token, expected) {
965
+ const basenameToken = token.slice(token.lastIndexOf("/") + 1);
966
+ return shellTokenCanEqual(basenameToken, expected);
967
+ }
968
+ function exactShellExecutable(token) {
969
+ if (token === undefined || token.includes(SHELL_PARAMETER_MARKER))
970
+ return undefined;
971
+ return token.slice(token.lastIndexOf("/") + 1).toLowerCase();
972
+ }
973
+ const SUDO_SHORT_OPERANDS = new Set(["-C", "-D", "-g", "-h", "-p", "-R", "-r", "-T", "-t", "-U", "-u"]);
974
+ const SUDO_LONG_OPERANDS = new Set(["--chdir", "--chroot", "--close-from", "--command-timeout", "--group", "--host", "--other-user", "--prompt", "--role", "--type", "--user"]);
975
+ const TIME_SHORT_OPERANDS = new Set(["-f", "-o"]);
976
+ const TIME_LONG_OPERANDS = new Set(["--format", "--output"]);
977
+ function wrapperOptionAdvance(option, shortOperands, longOperands) {
978
+ if (shortOperands.has(option) || longOperands.has(option))
979
+ return 2;
980
+ if ([...shortOperands].some((candidate) => option.startsWith(candidate) && option.length > candidate.length))
981
+ return 1;
982
+ if ([...longOperands].some((candidate) => option.startsWith(`${candidate}=`)))
983
+ return 1;
984
+ return 0;
985
+ }
986
+ function resolveShellCommand(tokens, startIndex) {
987
+ let index = startIndex;
988
+ while (index < tokens.length) {
989
+ const executable = exactShellExecutable(tokens[index]);
990
+ if (SHELL_GRAMMAR_PREFIXES.has(executable ?? "")) {
991
+ index += 1;
992
+ continue;
993
+ }
994
+ if (executable === "coproc") {
995
+ index += 1;
996
+ const candidate = tokens[index] ?? "";
997
+ if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(candidate) && !shellExecutableCanEqual(candidate, "ouro") && tokens[index + 1] !== undefined)
998
+ index += 1;
999
+ continue;
1000
+ }
1001
+ if (executable === "command" || executable === "nohup") {
1002
+ index += 1;
1003
+ if (executable === "command" && (tokens[index] === "-v" || tokens[index] === "-V"))
1004
+ return { index: tokens.length };
1005
+ while (tokens[index]?.startsWith("-"))
1006
+ index += 1;
1007
+ continue;
1008
+ }
1009
+ if (executable === "env") {
1010
+ index += 1;
1011
+ while (index < tokens.length) {
1012
+ const option = tokens[index];
1013
+ if (option === "-S" || option === "--split-string")
1014
+ return { index, script: `env ${tokens.slice(index + 1).join(" ")}` };
1015
+ if (option.startsWith("--split-string="))
1016
+ return { index, script: `env ${[option.slice("--split-string=".length), ...tokens.slice(index + 1)].join(" ")}` };
1017
+ if (["-u", "-C", "--unset", "--chdir"].includes(option))
1018
+ index += 2;
1019
+ else if (option.startsWith("-") || /^[A-Za-z_][A-Za-z0-9_]*=/.test(option))
1020
+ index += 1;
1021
+ else
1022
+ break;
1023
+ }
1024
+ continue;
1025
+ }
1026
+ if (executable === "sudo") {
1027
+ index += 1;
1028
+ while (tokens[index]?.startsWith("-")) {
1029
+ const advance = wrapperOptionAdvance(tokens[index], SUDO_SHORT_OPERANDS, SUDO_LONG_OPERANDS);
1030
+ index += advance === 0 ? 1 : advance;
1031
+ }
1032
+ continue;
1033
+ }
1034
+ if (executable === "time") {
1035
+ index += 1;
1036
+ while (tokens[index]?.startsWith("-")) {
1037
+ const advance = wrapperOptionAdvance(tokens[index], TIME_SHORT_OPERANDS, TIME_LONG_OPERANDS);
1038
+ index += advance === 0 ? 1 : advance;
1039
+ }
1040
+ continue;
1041
+ }
1042
+ if (executable === "exec") {
1043
+ index += 1;
1044
+ while (tokens[index]?.startsWith("-"))
1045
+ index += tokens[index] === "-a" ? 2 : 1;
1046
+ continue;
1047
+ }
1048
+ break;
1049
+ }
1050
+ return { index };
1051
+ }
1052
+ function shellScriptRequiresFamily(script, variables, depth) {
1053
+ if (script.includes(SHELL_PARAMETER_MARKER) || script.includes(SHELL_ARRAY_EXPANSION))
1054
+ return true;
1055
+ return shellCommandsContainMailCacheSync(script, variables, depth + 1);
1056
+ }
1057
+ function shellTokensContainMailCacheSync(tokens, startIndex, variables, depth) {
1058
+ const resolved = resolveShellCommand(tokens, startIndex);
1059
+ if (resolved.script !== undefined)
1060
+ return shellScriptRequiresFamily(resolved.script, variables, depth);
1061
+ const executableToken = tokens[resolved.index] ?? "";
1062
+ const executable = exactShellExecutable(executableToken);
1063
+ if (executableToken.includes(SHELL_ARRAY_EXPANSION))
1064
+ return true;
1065
+ if (SHELL_INTERPRETERS.has(executable ?? "")) {
1066
+ const commandOption = tokens.findIndex((token, index) => index > resolved.index && /^-[^-]*c/.test(token));
1067
+ return commandOption >= 0
1068
+ && shellScriptRequiresFamily(tokens[commandOption + 1] ?? "", variables, depth);
1069
+ }
1070
+ if (executable === "eval")
1071
+ return shellScriptRequiresFamily(tokens.slice(resolved.index + 1).join(" "), variables, depth);
1072
+ return shellExecutableCanEqual(executableToken, "ouro")
1073
+ && shellTokenCanEqual(tokens[resolved.index + 1] ?? "", "mail")
1074
+ && shellTokenCanEqual(tokens[resolved.index + 2] ?? "", "sync-cache");
1075
+ }
1076
+ function shellCommandsContainMailCacheSync(command, inheritedVariables = new Map(), depth = 0) {
1077
+ if (depth >= 32)
1078
+ return true;
1079
+ let parsed;
1080
+ try {
1081
+ parsed = parseShellCommands(command);
1082
+ }
1083
+ catch {
1084
+ return false;
1085
+ }
1086
+ const knownVariables = new Map(inheritedVariables);
1087
+ for (const rawTokens of parsed.commands) {
1088
+ const tokens = rawTokens.map((token) => resolveKnownShellParameters(token, knownVariables, parsed.parameterNames));
1089
+ const invocationVariables = new Map(knownVariables);
1090
+ let commandIndex = 0;
1091
+ while (commandIndex < tokens.length) {
1092
+ const assignment = tokens[commandIndex].match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/s);
1093
+ if (!assignment)
1094
+ break;
1095
+ if (assignment[2].includes(SHELL_PARAMETER_MARKER))
1096
+ invocationVariables.delete(assignment[1]);
1097
+ else
1098
+ invocationVariables.set(assignment[1], assignment[2]);
1099
+ commandIndex += 1;
1100
+ }
1101
+ if (commandIndex === tokens.length) {
1102
+ knownVariables.clear();
1103
+ for (const [name, value] of invocationVariables)
1104
+ knownVariables.set(name, value);
1105
+ continue;
1106
+ }
1107
+ if (shellTokensContainMailCacheSync(tokens, commandIndex, invocationVariables, depth))
1108
+ return true;
1109
+ }
1110
+ return false;
1111
+ }
1112
+ function shellContainsMailCacheSync(command) {
1113
+ const executableCommand = executableShellView(command);
1114
+ if (shellContainsAmbiguousAnsiMailCacheSync(executableCommand))
1115
+ return true;
1116
+ return shellCommandsContainMailCacheSync(executableCommand);
1117
+ }
1118
+ function mailCacheSyncShellGuardrail(toolName, args, context) {
1119
+ if (toolName !== "shell" || !shellContainsMailCacheSync(args.command ?? ""))
1120
+ return allow;
1121
+ if (context.trustLevel === undefined || context.trustLevel === "family")
1122
+ return allow;
1123
+ return deny("hosted mail cache convergence requires family trust.");
1124
+ }
1125
+ function mailTrustGuardrail(toolName, args, context) {
1126
+ if (MAIL_FAMILY_TOOLS.has(toolName)) {
1127
+ if (context.trustLevel === undefined || context.trustLevel === "family")
1128
+ return allow;
1129
+ if (toolName === "mail_send")
1130
+ return deny("outbound mail sends require family trust.");
1131
+ return deny(toolName === "mail_decide"
1132
+ ? "mail screener decisions require family trust."
1133
+ : "delegated human mail requires family trust.");
1134
+ }
1135
+ if (MAIL_DELEGATED_READ_TOOLS.has(toolName)) {
1136
+ const scope = (args.scope ?? "").trim().toLowerCase();
1137
+ if (scope === "delegated" || scope === "all") {
1138
+ if (context.trustLevel === undefined || context.trustLevel === "family")
1139
+ return allow;
1140
+ return deny("delegated human mail requires family trust.");
1141
+ }
1142
+ }
1143
+ return allow;
1144
+ }
1145
+ function checkCredentialTrustGuardrails(toolName, context) {
1146
+ if (CREDENTIAL_FAMILY_TOOLS.has(toolName) || COMMERCE_FAMILY_TOOLS.has(toolName)) {
1147
+ if (context.trustLevel === "family")
1148
+ return allow;
1149
+ return deny(REASONS.needsTrust);
1150
+ }
1151
+ if (CREDENTIAL_TRUSTED_TOOLS.has(toolName) || TRAVEL_TRUSTED_TOOLS.has(toolName) || A2A_TRUSTED_TOOLS.has(toolName)) {
1152
+ if ((0, friends_1.isTrustedLevel)(context.trustLevel))
1153
+ return allow;
1154
+ return deny(REASONS.needsTrust);
1155
+ }
1156
+ return allow;
1157
+ }
1158
+ function checkCommerceAuthorityGuardrails(toolName, args, context) {
1159
+ if (!COMMERCE_AUTHORITY_TOOLS.has(toolName))
1160
+ return allow;
1161
+ if (!context.agentRoot)
1162
+ return deny("commerce authority unavailable: agent root could not be resolved.");
1163
+ const result = (0, store_1.validateCommerceAuthority)({
1164
+ agentRoot: context.agentRoot,
1165
+ token: args.commerce_authority,
1166
+ toolName,
1167
+ args,
1168
+ friendId: context.friendId,
1169
+ });
1170
+ if (result.ok)
1171
+ return allow;
1172
+ return deny(`commerce authority required: ${result.reason}`);
1173
+ }
1174
+ function checkFirstClassMcpTrust(context) {
1175
+ if (!context.mcpServerName)
1176
+ return allow;
1177
+ const rules = MCP_SERVER_TRUST[context.mcpServerName] ?? { minTrust: "friend", blockGroupChat: false };
1178
+ if (!trustLevelSatisfied(rules.minTrust, context.trustLevel ?? "friend")) {
1179
+ return deny(REASONS.needsTrust);
1180
+ }
1181
+ if (rules.blockGroupChat && context.isGroupChat) {
1182
+ return deny("browser tools are only available in 1:1 conversations, not group chats.");
1183
+ }
1184
+ return allow;
1185
+ }
264
1186
  function checkTrustLevelGuardrails(toolName, args, context) {
265
- // Trusted levels (family/friend) — no trust guardrails. Undefined defaults to friend.
266
- if ((0, types_1.isTrustedLevel)(context.trustLevel))
1187
+ const cacheSyncResult = mailCacheSyncShellGuardrail(toolName, args, context);
1188
+ if (!cacheSyncResult.allowed)
1189
+ return cacheSyncResult;
1190
+ const mailResult = mailTrustGuardrail(toolName, args, context);
1191
+ if (!mailResult.allowed)
1192
+ return mailResult;
1193
+ if (SHEPHERD_FAMILY_TOOLS.has(toolName) && context.trustLevel !== "family") {
1194
+ return deny("the owner's terminals require family trust.");
1195
+ }
1196
+ // Credential tools have their own trust rules that apply at all levels
1197
+ const credentialResult = checkCredentialTrustGuardrails(toolName, context);
1198
+ if (!credentialResult.allowed)
1199
+ return credentialResult;
1200
+ const commerceAuthorityResult = checkCommerceAuthorityGuardrails(toolName, args, context);
1201
+ if (!commerceAuthorityResult.allowed)
1202
+ return commerceAuthorityResult;
1203
+ // First-class MCP tool trust (e.g. browser_navigate) — applies at all trust levels
1204
+ const firstClassMcpResult = checkFirstClassMcpTrust(context);
1205
+ if (!firstClassMcpResult.allowed)
1206
+ return firstClassMcpResult;
1207
+ // MCP server-specific trust via shell (e.g. ouro mcp call browser) — applies at all trust levels
1208
+ if (toolName === "shell") {
1209
+ const mcpResult = checkMcpServerTrust(args.command || "", context);
1210
+ if (!mcpResult.allowed)
1211
+ return mcpResult;
1212
+ }
1213
+ // Trusted levels (family/friend) — no further trust guardrails. Undefined defaults to friend.
1214
+ if ((0, friends_1.isTrustedLevel)(context.trustLevel))
267
1215
  return allow;
268
1216
  if (toolName === "shell") {
269
1217
  return checkShellTrustGuardrails(args.command || "", context.trustLevel);