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