@ouro.bot/cli 0.1.0-alpha.83 → 0.1.0-alpha.831
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +5308 -16
- package/deploy/unraid/Dockerfile +54 -0
- package/deploy/unraid/README.txt +2983 -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-deployment-target.mjs +710 -0
- package/deploy/unraid/sanctuary-safe-rename.py +24 -0
- package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2084 -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/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 +795 -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 +15 -0
- package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +25 -0
- package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +15 -0
- package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
- package/deploy/unraid/sanctuary.ouro/tool-profiles.json +135 -0
- package/deploy/unraid/sanctuary.xml +28 -0
- package/dist/a2a/card.js +57 -0
- package/dist/a2a/client.js +180 -0
- package/dist/a2a/config.js +50 -0
- package/dist/a2a/delegation-stores.js +56 -0
- package/dist/a2a/did-resolution.js +93 -0
- package/dist/a2a/identity.js +170 -0
- package/dist/a2a/inbound-share.js +107 -0
- package/dist/a2a/mission-result-wire.js +196 -0
- package/dist/a2a/onboarding.js +115 -0
- package/dist/a2a/pin-store.js +132 -0
- package/dist/a2a/seen-ledger.js +120 -0
- package/dist/a2a/server.js +604 -0
- package/dist/a2a/task-store.js +69 -0
- package/dist/a2a/transport.js +45 -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/await-alert.js +148 -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 +149 -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 +2169 -581
- 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 +8822 -0
- package/dist/heart/daemon/cli-help.js +716 -0
- package/dist/heart/daemon/cli-parse.js +2771 -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 +229 -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 +930 -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 +256 -0
- package/dist/heart/daemon/sanctuary-authority-installation.js +140 -0
- package/dist/heart/daemon/sanctuary-authority-ledger.js +241 -0
- package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +819 -0
- package/dist/heart/daemon/sanctuary-authority-vault-migration.js +79 -0
- package/dist/heart/daemon/sanctuary-bundle-migration.js +729 -0
- package/dist/heart/daemon/sanctuary-host-authority.js +1008 -0
- package/dist/heart/daemon/sanctuary-host-detached-supervisor.js +494 -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 +445 -0
- package/dist/heart/daemon/sanctuary-telegram-authority-gateway.js +585 -0
- package/dist/heart/daemon/sanctuary-telegram-authority-service.js +630 -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 +1430 -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 +129 -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/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/start-of-turn-packet.js +372 -0
- package/dist/heart/steward-policy.js +618 -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 +449 -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 +200 -0
- package/dist/heart/turn-context.js +482 -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 +309 -111
- 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 +1050 -189
- 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 +811 -18
- package/dist/repertoire/mcp-client.js +44 -3
- package/dist/repertoire/mcp-manager.js +427 -139
- package/dist/repertoire/mcp-tools.js +124 -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 +170 -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 +575 -0
- package/dist/repertoire/tools-base.js +77 -1138
- 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-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-mail.js +1828 -0
- package/dist/repertoire/tools-notes.js +485 -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 +150 -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 +119 -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 +531 -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 +494 -148
- 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 +115 -0
- package/dist/senses/acp-server.js +386 -0
- package/dist/senses/attention-queue.js +186 -0
- package/dist/senses/await-turn-message.js +58 -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 +604 -320
- 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 +1517 -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 +100 -0
- package/dist/senses/sanctuary-health.js +408 -0
- package/dist/senses/sanctuary-install-state-contract.js +126 -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 +340 -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 +772 -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 +896 -0
- package/dist/senses/telegram-entry.js +83 -0
- package/dist/senses/telegram.js +2324 -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/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/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 +807 -0
- package/dist/senses/voice/twilio-phone.js +5031 -0
- package/dist/senses/voice/types.js +2 -0
- package/dist/senses/voice/whisper.js +161 -0
- package/dist/senses/voice-entry.js +81 -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 +8138 -0
- package/package.json +72 -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 -228
- 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
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.readStewardPolicy = readStewardPolicy;
|
|
37
|
+
exports.updateStewardPolicy = updateStewardPolicy;
|
|
38
|
+
exports.readRoutineActionReceipts = readRoutineActionReceipts;
|
|
39
|
+
exports.inspectRoutineActionGrant = inspectRoutineActionGrant;
|
|
40
|
+
exports.consumeRoutineActionGrant = consumeRoutineActionGrant;
|
|
41
|
+
exports.withStewardPolicyLease = withStewardPolicyLease;
|
|
42
|
+
exports.withRoutineActionAttempt = withRoutineActionAttempt;
|
|
43
|
+
exports.transitionRoutineActionReceipt = transitionRoutineActionReceipt;
|
|
44
|
+
exports.recoverRoutineActionReceipts = recoverRoutineActionReceipts;
|
|
45
|
+
const fs = __importStar(require("node:fs"));
|
|
46
|
+
const path = __importStar(require("node:path"));
|
|
47
|
+
const node_crypto_1 = require("node:crypto");
|
|
48
|
+
const node_util_1 = require("node:util");
|
|
49
|
+
const runtime_1 = require("../nerves/runtime");
|
|
50
|
+
const session_transaction_1 = require("../mind/session-transaction");
|
|
51
|
+
const EMPTY_POLICY = { schemaVersion: 1, version: 0, desiredStates: {}, routineActionGrants: {}, updatedAt: null };
|
|
52
|
+
const MAX_POLICY_BYTES = 1024 * 1024;
|
|
53
|
+
const MAX_AUDIT_ROW_BYTES = 16 * MAX_POLICY_BYTES;
|
|
54
|
+
function sha256(bytes) {
|
|
55
|
+
return (0, node_crypto_1.createHash)("sha256").update(bytes, "utf8").digest("hex");
|
|
56
|
+
}
|
|
57
|
+
function record(value) {
|
|
58
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
59
|
+
}
|
|
60
|
+
function exactKeys(value, required, optional = []) {
|
|
61
|
+
return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => required.includes(key) || optional.includes(key));
|
|
62
|
+
}
|
|
63
|
+
function text(value) {
|
|
64
|
+
return typeof value === "string" && value.length > 0 && value.trim() === value;
|
|
65
|
+
}
|
|
66
|
+
function canonicalTime(value) {
|
|
67
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value)) && new Date(Date.parse(value)).toISOString() === value;
|
|
68
|
+
}
|
|
69
|
+
function positiveInteger(value) {
|
|
70
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
71
|
+
}
|
|
72
|
+
function textArray(value) {
|
|
73
|
+
return Array.isArray(value) && value.every(text) && new Set(value).size === value.length;
|
|
74
|
+
}
|
|
75
|
+
function ownerAuthorization(value) {
|
|
76
|
+
return record(value) && exactKeys(value, ["profileId", "profileVersion", "requestId", "sessionKey", "receiptId"])
|
|
77
|
+
&& value.profileId === "sanctuary-owner" && positiveInteger(value.profileVersion)
|
|
78
|
+
&& text(value.requestId) && text(value.sessionKey) && text(value.receiptId);
|
|
79
|
+
}
|
|
80
|
+
function desiredEntry(value, version) {
|
|
81
|
+
return record(value) && exactKeys(value, ["value", "provenance", "version", "source"], ["expiresAt"])
|
|
82
|
+
&& text(value.value) && text(value.source) && positiveInteger(value.version) && value.version <= version
|
|
83
|
+
&& (value.provenance === "stated" || value.provenance === "observed" || value.provenance === "default")
|
|
84
|
+
&& (value.expiresAt === undefined || canonicalTime(value.expiresAt));
|
|
85
|
+
}
|
|
86
|
+
function grantEntry(value, version) {
|
|
87
|
+
return record(value) && exactKeys(value, ["action", "targets", "maxCount", "windowMs", "verificationRequired", "exclusions", "provenance", "issuer", "authorizedAt", "authorizingSessionEvent", "version"], ["expiresAt"])
|
|
88
|
+
&& text(value.action) && textArray(value.targets) && value.targets.length > 0 && textArray(value.exclusions)
|
|
89
|
+
&& positiveInteger(value.maxCount) && positiveInteger(value.windowMs) && value.verificationRequired === true
|
|
90
|
+
&& (value.provenance === "stated" || value.provenance === "installed_explicit_policy")
|
|
91
|
+
&& text(value.issuer) && text(value.authorizingSessionEvent) && canonicalTime(value.authorizedAt)
|
|
92
|
+
&& positiveInteger(value.version) && value.version <= version && (value.expiresAt === undefined || canonicalTime(value.expiresAt));
|
|
93
|
+
}
|
|
94
|
+
function policyRecord(value) {
|
|
95
|
+
if (!record(value) || !exactKeys(value, ["schemaVersion", "version", "desiredStates", "routineActionGrants", "updatedAt"])
|
|
96
|
+
|| value.schemaVersion !== 1 || typeof value.version !== "number" || !Number.isSafeInteger(value.version) || value.version < 0
|
|
97
|
+
|| !record(value.desiredStates) || !record(value.routineActionGrants)
|
|
98
|
+
|| !(value.updatedAt === null ? value.version === 0 : canonicalTime(value.updatedAt)))
|
|
99
|
+
return false;
|
|
100
|
+
const version = value.version;
|
|
101
|
+
return Object.entries(value.desiredStates).every(([key, entry]) => text(key) && desiredEntry(entry, version))
|
|
102
|
+
&& Object.entries(value.routineActionGrants).every(([key, entry]) => text(key) && grantEntry(entry, version));
|
|
103
|
+
}
|
|
104
|
+
function policyImage(bytes) {
|
|
105
|
+
if (Buffer.byteLength(bytes) > MAX_POLICY_BYTES)
|
|
106
|
+
throw new Error("steward policy audit image exceeds its bound");
|
|
107
|
+
if (bytes === "")
|
|
108
|
+
return structuredClone(EMPTY_POLICY);
|
|
109
|
+
let value;
|
|
110
|
+
try {
|
|
111
|
+
value = JSON.parse(bytes);
|
|
112
|
+
}
|
|
113
|
+
catch (cause) {
|
|
114
|
+
throw new Error("steward policy audit image is invalid", { cause });
|
|
115
|
+
}
|
|
116
|
+
if (!policyRecord(value))
|
|
117
|
+
throw new Error("steward policy audit image is invalid");
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
function mutationFingerprint(kind, key, result) {
|
|
121
|
+
const generated = ["version", "issuer", "authorizedAt", "authorizingSessionEvent"];
|
|
122
|
+
const input = Object.fromEntries(Object.entries(result).filter(([field]) => !generated.includes(field)).sort(([left], [right]) => left.localeCompare(right)));
|
|
123
|
+
return sha256(JSON.stringify([kind, key, input]));
|
|
124
|
+
}
|
|
125
|
+
function operationIdentity(issuer, event, requestId, kind, key) {
|
|
126
|
+
return JSON.stringify([issuer, event, requestId, kind, key]);
|
|
127
|
+
}
|
|
128
|
+
function auditRow(value) {
|
|
129
|
+
if (!record(value) || !exactKeys(value, ["schemaVersion", "transactionId", "precedingBytesSha256", "mutationKind", "key", "mutationFingerprint", "affectedKeyResult", "affectedKeyResultSha256", "issuer", "authorizingSessionEvent", "authorization", "preimage", "preimageVersion", "preimageSha256", "postimage", "postimageVersion", "postimageSha256", "at"])
|
|
130
|
+
|| value.schemaVersion !== 2 || (value.mutationKind !== "set_desired_state" && value.mutationKind !== "grant_routine_action")
|
|
131
|
+
|| !text(value.key) || !text(value.issuer) || !text(value.authorizingSessionEvent) || !ownerAuthorization(value.authorization)
|
|
132
|
+
|| typeof value.preimage !== "string" || typeof value.postimage !== "string" || !canonicalTime(value.at))
|
|
133
|
+
return false;
|
|
134
|
+
const before = policyImage(value.preimage);
|
|
135
|
+
const after = policyImage(value.postimage);
|
|
136
|
+
const result = value.mutationKind === "set_desired_state" ? after.desiredStates[value.key] : after.routineActionGrants[value.key];
|
|
137
|
+
if (!result || value.preimageVersion !== before.version || value.postimageVersion !== after.version
|
|
138
|
+
|| after.version !== before.version + 1 || result.version !== after.version || after.updatedAt !== value.at
|
|
139
|
+
|| value.preimageSha256 !== sha256(value.preimage) || value.postimageSha256 !== sha256(value.postimage)
|
|
140
|
+
|| value.postimage !== JSON.stringify(after, null, 2) || !(0, node_util_1.isDeepStrictEqual)(value.affectedKeyResult, result)
|
|
141
|
+
|| value.affectedKeyResultSha256 !== sha256(JSON.stringify(result))
|
|
142
|
+
|| value.mutationFingerprint !== mutationFingerprint(value.mutationKind, value.key, result)
|
|
143
|
+
|| value.transactionId !== sha256(JSON.stringify([operationIdentity(value.issuer, value.authorizingSessionEvent, value.authorization.requestId, value.mutationKind, value.key), value.mutationFingerprint])))
|
|
144
|
+
return false;
|
|
145
|
+
if ("action" in result && (result.issuer !== value.issuer || result.authorizingSessionEvent !== value.authorizingSessionEvent || result.authorizedAt !== value.at))
|
|
146
|
+
return false;
|
|
147
|
+
const expected = {
|
|
148
|
+
...before, version: after.version, updatedAt: value.at,
|
|
149
|
+
desiredStates: value.mutationKind === "set_desired_state" ? { ...before.desiredStates, [value.key]: result } : before.desiredStates,
|
|
150
|
+
routineActionGrants: value.mutationKind === "grant_routine_action" ? { ...before.routineActionGrants, [value.key]: result } : before.routineActionGrants,
|
|
151
|
+
};
|
|
152
|
+
return (0, node_util_1.isDeepStrictEqual)(after, expected);
|
|
153
|
+
}
|
|
154
|
+
function policyDir(agentRoot) {
|
|
155
|
+
return path.join(agentRoot, "state", "policy");
|
|
156
|
+
}
|
|
157
|
+
function policyPath(agentRoot) {
|
|
158
|
+
return path.join(policyDir(agentRoot), "steward.json");
|
|
159
|
+
}
|
|
160
|
+
function receiptsPath(agentRoot) {
|
|
161
|
+
return path.join(policyDir(agentRoot), "action-receipts.ndjson");
|
|
162
|
+
}
|
|
163
|
+
function auditPath(agentRoot) {
|
|
164
|
+
return path.join(policyDir(agentRoot), "policy-audit.ndjson");
|
|
165
|
+
}
|
|
166
|
+
function ensureDirectory(agentRoot) {
|
|
167
|
+
fs.mkdirSync(policyDir(agentRoot), { recursive: true, mode: 0o700 });
|
|
168
|
+
fs.chmodSync(policyDir(agentRoot), 0o700);
|
|
169
|
+
}
|
|
170
|
+
function syncParentDirectory(filePath) {
|
|
171
|
+
const directory = fs.openSync(path.dirname(filePath), fs.constants.O_RDONLY | fs.constants.O_DIRECTORY | fs.constants.O_NOFOLLOW);
|
|
172
|
+
try {
|
|
173
|
+
fs.fsyncSync(directory);
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
fs.closeSync(directory);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function appendReceipt(filePath, value) {
|
|
180
|
+
const creating = !fs.existsSync(filePath);
|
|
181
|
+
const fd = fs.openSync(filePath, "a", 0o600);
|
|
182
|
+
try {
|
|
183
|
+
fs.writeFileSync(fd, `${JSON.stringify(value)}\n`, "utf8");
|
|
184
|
+
fs.fsyncSync(fd);
|
|
185
|
+
}
|
|
186
|
+
finally {
|
|
187
|
+
fs.closeSync(fd);
|
|
188
|
+
}
|
|
189
|
+
fs.chmodSync(filePath, 0o600);
|
|
190
|
+
if (creating)
|
|
191
|
+
syncParentDirectory(filePath);
|
|
192
|
+
}
|
|
193
|
+
function requireText(value, label) {
|
|
194
|
+
const result = typeof value === "string" ? value.trim() : "";
|
|
195
|
+
if (!result)
|
|
196
|
+
throw new Error(`${label} must be nonempty`);
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
function optionalExpiry(value, now) {
|
|
200
|
+
if (!value)
|
|
201
|
+
return undefined;
|
|
202
|
+
const epoch = Date.parse(value);
|
|
203
|
+
if (!Number.isFinite(epoch) || new Date(epoch).toISOString() !== value || (now !== undefined && epoch <= Date.parse(now)))
|
|
204
|
+
throw new Error("policy expiry must be a future canonical timestamp");
|
|
205
|
+
return value;
|
|
206
|
+
}
|
|
207
|
+
function validateStewardPolicy(value) {
|
|
208
|
+
if (!policyRecord(value))
|
|
209
|
+
throw new Error("steward policy is invalid");
|
|
210
|
+
return value;
|
|
211
|
+
}
|
|
212
|
+
function readAuditBytes(agentRoot) {
|
|
213
|
+
try {
|
|
214
|
+
const bytes = fs.readFileSync(auditPath(agentRoot));
|
|
215
|
+
const decoded = bytes.toString("utf8");
|
|
216
|
+
if (!Buffer.from(decoded, "utf8").equals(bytes))
|
|
217
|
+
throw new Error("steward policy audit encoding is invalid");
|
|
218
|
+
return decoded;
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
222
|
+
return "";
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function readPolicyTransaction(filePath, lease) {
|
|
227
|
+
const exists = fs.existsSync(filePath);
|
|
228
|
+
if (exists && fs.statSync(filePath).size > MAX_POLICY_BYTES)
|
|
229
|
+
throw new Error("steward policy exceeds its bound");
|
|
230
|
+
const snapshot = (0, session_transaction_1.readSessionTransaction)(filePath, lease);
|
|
231
|
+
const raw = exists ? fs.readFileSync(filePath) : Buffer.alloc(0);
|
|
232
|
+
if (!Buffer.from(snapshot.bytes, "utf8").equals(raw))
|
|
233
|
+
throw new Error("steward policy encoding or bytes changed");
|
|
234
|
+
return { ...snapshot, exists };
|
|
235
|
+
}
|
|
236
|
+
function readAuditedPolicy(agentRoot, lease) {
|
|
237
|
+
const filePath = policyPath(agentRoot);
|
|
238
|
+
let snapshot = readPolicyTransaction(filePath, lease);
|
|
239
|
+
let policy = !snapshot.exists && snapshot.bytes === "" ? structuredClone(EMPTY_POLICY) : validateStewardPolicy(snapshot.value);
|
|
240
|
+
const auditBytes = readAuditBytes(agentRoot);
|
|
241
|
+
const rows = [];
|
|
242
|
+
const seen = new Set();
|
|
243
|
+
const preceding = (0, node_crypto_1.createHash)("sha256");
|
|
244
|
+
let legacyVersion = 0;
|
|
245
|
+
if (auditBytes && !auditBytes.endsWith("\n"))
|
|
246
|
+
throw new Error("steward policy audit has a partial final row");
|
|
247
|
+
for (const line of auditBytes ? auditBytes.slice(0, -1).split("\n") : []) {
|
|
248
|
+
if (Buffer.byteLength(line) > MAX_AUDIT_ROW_BYTES)
|
|
249
|
+
throw new Error("steward policy audit row exceeds its bound");
|
|
250
|
+
let row;
|
|
251
|
+
try {
|
|
252
|
+
row = JSON.parse(line);
|
|
253
|
+
}
|
|
254
|
+
catch (cause) {
|
|
255
|
+
throw new Error("steward policy audit row is invalid", { cause });
|
|
256
|
+
}
|
|
257
|
+
if (record(row) && row.schemaVersion === 1) {
|
|
258
|
+
if (rows.length || !positiveInteger(row.policyVersion) || row.policyVersion <= legacyVersion)
|
|
259
|
+
throw new Error("steward policy audit legacy prefix is invalid");
|
|
260
|
+
legacyVersion = row.policyVersion;
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
if (!auditRow(row) || row.precedingBytesSha256 !== preceding.copy().digest("hex"))
|
|
264
|
+
throw new Error("steward policy audit row is invalid");
|
|
265
|
+
const prior = rows.at(-1);
|
|
266
|
+
if (prior ? row.preimage !== prior.postimage || row.preimageVersion !== prior.postimageVersion : row.preimageVersion !== legacyVersion)
|
|
267
|
+
throw new Error("steward policy audit chain is invalid");
|
|
268
|
+
const identity = operationIdentity(row.issuer, row.authorizingSessionEvent, row.authorization.requestId, row.mutationKind, row.key);
|
|
269
|
+
if (seen.has(identity))
|
|
270
|
+
throw new Error("steward policy audit contains a duplicate transaction");
|
|
271
|
+
seen.add(identity);
|
|
272
|
+
rows.push(row);
|
|
273
|
+
}
|
|
274
|
+
preceding.update(`${line}\n`, "utf8");
|
|
275
|
+
}
|
|
276
|
+
const last = rows.at(-1);
|
|
277
|
+
if (!last) {
|
|
278
|
+
if (policy.version !== legacyVersion)
|
|
279
|
+
throw new Error("steward policy audit does not match the policy head");
|
|
280
|
+
}
|
|
281
|
+
else if (snapshot.bytes !== last.postimage) {
|
|
282
|
+
if (snapshot.bytes !== last.preimage)
|
|
283
|
+
throw new Error("steward policy audit does not match the policy head");
|
|
284
|
+
const fd = fs.openSync(auditPath(agentRoot), "r");
|
|
285
|
+
try {
|
|
286
|
+
fs.fsyncSync(fd);
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
fs.closeSync(fd);
|
|
290
|
+
}
|
|
291
|
+
syncParentDirectory(auditPath(agentRoot));
|
|
292
|
+
(0, session_transaction_1.writeSessionTransaction)(filePath, policyImage(last.postimage), { lease, expectedRevision: snapshot.revision });
|
|
293
|
+
snapshot = readPolicyTransaction(filePath, lease);
|
|
294
|
+
if (snapshot.bytes !== last.postimage)
|
|
295
|
+
throw new Error("steward policy audit recovery readback differs");
|
|
296
|
+
policy = validateStewardPolicy(snapshot.value);
|
|
297
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "heart.steward_policy_recovered", message: "recovered an authorized steward policy write", meta: { version: policy.version } });
|
|
298
|
+
}
|
|
299
|
+
return { ...snapshot, policy, rows, auditBytes };
|
|
300
|
+
}
|
|
301
|
+
function readPolicyState(agentRoot) {
|
|
302
|
+
if (!fs.existsSync(policyPath(agentRoot)) && !fs.existsSync(auditPath(agentRoot))) {
|
|
303
|
+
return { policy: structuredClone(EMPTY_POLICY), rows: [] };
|
|
304
|
+
}
|
|
305
|
+
return (0, session_transaction_1.withImmediateSessionTurnLease)(policyPath(agentRoot), (lease) => readAuditedPolicy(agentRoot, lease));
|
|
306
|
+
}
|
|
307
|
+
function readStewardPolicy(agentRoot) {
|
|
308
|
+
return readPolicyState(agentRoot).policy;
|
|
309
|
+
}
|
|
310
|
+
function updateStewardPolicy(agentRoot, input) {
|
|
311
|
+
if (input.actor.trustLevel !== "family")
|
|
312
|
+
throw new Error("steward policy mutation requires family authority");
|
|
313
|
+
const authorizingSessionEvent = requireText(input.actor.sessionEventId, "authorizing session event");
|
|
314
|
+
const issuer = requireText(input.actor.friendId, "issuer");
|
|
315
|
+
const authorization = input.actor.authorization;
|
|
316
|
+
if (!ownerAuthorization(authorization))
|
|
317
|
+
throw new Error("steward policy mutation requires current owner authorization");
|
|
318
|
+
if (input.mutation.kind !== "set_desired_state" && input.mutation.kind !== "grant_routine_action")
|
|
319
|
+
throw new Error("steward policy mutation kind is invalid");
|
|
320
|
+
return (0, session_transaction_1.withImmediateSessionTurnLease)(policyPath(agentRoot), (lease) => {
|
|
321
|
+
const snapshot = readAuditedPolicy(agentRoot, lease);
|
|
322
|
+
const current = snapshot.policy;
|
|
323
|
+
const now = input.now ?? new Date().toISOString();
|
|
324
|
+
if (!canonicalTime(now))
|
|
325
|
+
throw new Error("policy update time must be canonical");
|
|
326
|
+
const expiresAt = optionalExpiry(input.mutation.expiresAt);
|
|
327
|
+
const version = current.version + 1;
|
|
328
|
+
if (!positiveInteger(version))
|
|
329
|
+
throw new Error("steward policy version is exhausted");
|
|
330
|
+
const next = { ...current, version, desiredStates: { ...current.desiredStates }, routineActionGrants: { ...current.routineActionGrants }, updatedAt: now };
|
|
331
|
+
const key = requireText(input.mutation.key, input.mutation.kind === "set_desired_state" ? "desired state key" : "routine action key");
|
|
332
|
+
let affectedKeyResult;
|
|
333
|
+
if (input.mutation.kind === "set_desired_state") {
|
|
334
|
+
if (input.mutation.provenance !== "stated" && input.mutation.provenance !== "observed" && input.mutation.provenance !== "default")
|
|
335
|
+
throw new Error("desired state provenance is invalid");
|
|
336
|
+
affectedKeyResult = {
|
|
337
|
+
value: requireText(input.mutation.value, "desired state value"),
|
|
338
|
+
provenance: input.mutation.provenance,
|
|
339
|
+
version,
|
|
340
|
+
source: requireText(input.mutation.source, "desired state source"),
|
|
341
|
+
...(expiresAt ? { expiresAt } : {}),
|
|
342
|
+
};
|
|
343
|
+
next.desiredStates = { ...current.desiredStates, [key]: affectedKeyResult };
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
if (input.mutation.provenance !== "stated" && input.mutation.provenance !== "installed_explicit_policy")
|
|
347
|
+
throw new Error("routine action grants require explicit authority");
|
|
348
|
+
if (!positiveInteger(input.mutation.maxCount) || !positiveInteger(input.mutation.windowMs))
|
|
349
|
+
throw new Error("routine action grant bounds are invalid");
|
|
350
|
+
if (input.mutation.verificationRequired !== true)
|
|
351
|
+
throw new Error("routine action grants require post-action verification");
|
|
352
|
+
if (!Array.isArray(input.mutation.targets) || !Array.isArray(input.mutation.exclusions))
|
|
353
|
+
throw new Error("routine action targets and exclusions must be arrays");
|
|
354
|
+
const targets = [...new Set(input.mutation.targets.map((value) => requireText(value, "routine action target")))].sort();
|
|
355
|
+
if (targets.length === 0)
|
|
356
|
+
throw new Error("routine action grant requires a target");
|
|
357
|
+
affectedKeyResult = {
|
|
358
|
+
action: requireText(input.mutation.action, "routine action"), targets, maxCount: input.mutation.maxCount, windowMs: input.mutation.windowMs,
|
|
359
|
+
verificationRequired: input.mutation.verificationRequired, exclusions: [...new Set(input.mutation.exclusions.map((value) => requireText(value, "routine action exclusion")))].sort(), provenance: input.mutation.provenance,
|
|
360
|
+
issuer, authorizedAt: now, authorizingSessionEvent, version, ...(expiresAt ? { expiresAt } : {}),
|
|
361
|
+
};
|
|
362
|
+
next.routineActionGrants = { ...current.routineActionGrants, [key]: affectedKeyResult };
|
|
363
|
+
}
|
|
364
|
+
const fingerprint = mutationFingerprint(input.mutation.kind, key, affectedKeyResult);
|
|
365
|
+
const identity = operationIdentity(issuer, authorizingSessionEvent, authorization.requestId, input.mutation.kind, key);
|
|
366
|
+
const previousIndex = snapshot.rows.findIndex((row) => operationIdentity(row.issuer, row.authorizingSessionEvent, row.authorization.requestId, row.mutationKind, row.key) === identity);
|
|
367
|
+
if (previousIndex >= 0) {
|
|
368
|
+
const previous = snapshot.rows[previousIndex];
|
|
369
|
+
const currentResult = previous.mutationKind === "set_desired_state" ? current.desiredStates[key] : current.routineActionGrants[key];
|
|
370
|
+
if (previous.mutationFingerprint !== fingerprint || snapshot.rows.slice(previousIndex + 1).some((row) => row.mutationKind === previous.mutationKind && row.key === key)
|
|
371
|
+
|| !(0, node_util_1.isDeepStrictEqual)(currentResult, previous.affectedKeyResult))
|
|
372
|
+
throw new Error("steward policy transaction replay changed");
|
|
373
|
+
return current;
|
|
374
|
+
}
|
|
375
|
+
if (current.version !== input.expectedVersion)
|
|
376
|
+
throw new Error(`steward policy version changed: expected ${input.expectedVersion}, got ${current.version}`);
|
|
377
|
+
optionalExpiry(expiresAt, now);
|
|
378
|
+
const postimage = JSON.stringify(next, null, 2);
|
|
379
|
+
if (Buffer.byteLength(postimage) > MAX_POLICY_BYTES)
|
|
380
|
+
throw new Error("steward policy exceeds its bound");
|
|
381
|
+
const row = {
|
|
382
|
+
schemaVersion: 2, transactionId: sha256(JSON.stringify([identity, fingerprint])), precedingBytesSha256: sha256(snapshot.auditBytes),
|
|
383
|
+
mutationKind: input.mutation.kind, key, mutationFingerprint: fingerprint, affectedKeyResult, affectedKeyResultSha256: sha256(JSON.stringify(affectedKeyResult)),
|
|
384
|
+
issuer, authorizingSessionEvent, authorization: { ...authorization },
|
|
385
|
+
preimage: snapshot.bytes, preimageVersion: current.version, preimageSha256: snapshot.revision,
|
|
386
|
+
postimage, postimageVersion: version, postimageSha256: sha256(postimage), at: now,
|
|
387
|
+
};
|
|
388
|
+
if (Buffer.byteLength(JSON.stringify(row)) > MAX_AUDIT_ROW_BYTES)
|
|
389
|
+
throw new Error("steward policy audit row exceeds its bound");
|
|
390
|
+
ensureDirectory(agentRoot);
|
|
391
|
+
appendReceipt(auditPath(agentRoot), row);
|
|
392
|
+
(0, session_transaction_1.writeSessionTransaction)(policyPath(agentRoot), next, { lease, expectedRevision: snapshot.revision });
|
|
393
|
+
if (readPolicyTransaction(policyPath(agentRoot), lease).bytes !== postimage)
|
|
394
|
+
throw new Error("steward policy publication readback differs");
|
|
395
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "heart.steward_policy_updated", message: "updated steward policy", meta: { version, mutationKind: input.mutation.kind, issuer } });
|
|
396
|
+
return next;
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
function readActionReceiptHistory(agentRoot) {
|
|
400
|
+
const filePath = receiptsPath(agentRoot);
|
|
401
|
+
if (!fs.existsSync(filePath))
|
|
402
|
+
return [];
|
|
403
|
+
return fs.readFileSync(filePath, "utf8").split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
404
|
+
}
|
|
405
|
+
function readRoutineActionReceipts(agentRoot) {
|
|
406
|
+
const latest = new Map();
|
|
407
|
+
for (const receipt of readActionReceiptHistory(agentRoot))
|
|
408
|
+
latest.set(receipt.id, receipt);
|
|
409
|
+
return [...latest.values()];
|
|
410
|
+
}
|
|
411
|
+
function currentRequester(value, target) {
|
|
412
|
+
if (!record(value) || !text(value.friendId))
|
|
413
|
+
return false;
|
|
414
|
+
if (value.kind === "owner" || value.kind === "household_request") {
|
|
415
|
+
return exactKeys(value, ["kind", "friendId", "profileId", "requestId", "sessionEventId", "origin"])
|
|
416
|
+
&& value.profileId === (value.kind === "owner" ? "sanctuary-owner" : "sanctuary-household")
|
|
417
|
+
&& text(value.requestId) && text(value.sessionEventId) && record(value.origin)
|
|
418
|
+
&& exactKeys(value.origin, ["friendId", "channel", "key"])
|
|
419
|
+
&& value.origin.friendId === value.friendId && value.origin.channel === "telegram" && text(value.origin.key);
|
|
420
|
+
}
|
|
421
|
+
return value.kind === "owner_event" && exactKeys(value, ["kind", "friendId", "profileId", "event", "target"])
|
|
422
|
+
&& value.profileId === "sanctuary-event" && record(value.target) && exactKeys(value.target, ["id", "name"])
|
|
423
|
+
&& text(value.target.id) && value.target.name === target && record(value.event)
|
|
424
|
+
&& exactKeys(value.event, ["schemaVersion", "recordPath", "agent", "source", "eventId", "generation", "observationRevision", "claimOwner"])
|
|
425
|
+
&& value.event.schemaVersion === 1 && value.event.source === "sanctuary-health"
|
|
426
|
+
&& value.event.eventId === `container:${value.target.id}:availability`
|
|
427
|
+
&& text(value.event.recordPath) && text(value.event.agent) && positiveInteger(value.event.generation)
|
|
428
|
+
&& text(value.event.observationRevision) && text(value.event.claimOwner);
|
|
429
|
+
}
|
|
430
|
+
function appliedEntry(rows, kind, key, entry) {
|
|
431
|
+
return rows.some((row) => row.mutationKind === kind && row.key === key && row.postimageVersion === entry.version && (0, node_util_1.isDeepStrictEqual)(row.affectedKeyResult, entry));
|
|
432
|
+
}
|
|
433
|
+
const UNRESOLVED_ACTION_STATES = new Set(["reserved", "attempting", "effect_acknowledged", "recovery_pending", "indeterminate"]);
|
|
434
|
+
function inspectRoutineActionGrantSnapshot(policy, rows, receipts, input) {
|
|
435
|
+
const now = input.now === undefined ? new Date().toISOString() : input.now;
|
|
436
|
+
if (!canonicalTime(now))
|
|
437
|
+
return { allowed: false, reason: "routine action time must be canonical" };
|
|
438
|
+
if (!text(input.key) || !text(input.action) || !text(input.target))
|
|
439
|
+
return { allowed: false, reason: "routine action requires an exact key, action, and target" };
|
|
440
|
+
if (input.expectedPolicyVersion !== undefined && policy.version !== input.expectedPolicyVersion)
|
|
441
|
+
return { allowed: false, reason: "routine action policy version changed" };
|
|
442
|
+
if (!currentRequester(input.requester, input.target) || !positiveInteger(input.authorizationVersion))
|
|
443
|
+
return { allowed: false, reason: "routine action requires a current versioned requester" };
|
|
444
|
+
const desiredKey = `container:${input.target}`;
|
|
445
|
+
const desired = policy.desiredStates[desiredKey];
|
|
446
|
+
if (input.expectedDesiredStateVersion !== undefined && desired?.version !== input.expectedDesiredStateVersion)
|
|
447
|
+
return { allowed: false, reason: "routine action desired state version changed" };
|
|
448
|
+
const activeDesired = desired && (desired.expiresAt === undefined || Date.parse(desired.expiresAt) > Date.parse(now));
|
|
449
|
+
const desiredValue = desired?.value.toLowerCase();
|
|
450
|
+
if (activeDesired && /^(?:off|disabled|paused|intentionally_off|intentionally_paused)$/u.test(desiredValue))
|
|
451
|
+
return { allowed: false, reason: "container is expected off" };
|
|
452
|
+
const grant = policy.routineActionGrants[input.key];
|
|
453
|
+
if (input.expectedGrantVersion !== undefined && grant?.version !== input.expectedGrantVersion)
|
|
454
|
+
return { allowed: false, reason: "routine action grant version changed" };
|
|
455
|
+
const fallback = input.requester.kind === "owner" ? { approvalFallback: true } : {};
|
|
456
|
+
if (!grant)
|
|
457
|
+
return { allowed: false, reason: "routine action grant is missing", ...fallback };
|
|
458
|
+
if (grant.provenance !== "stated")
|
|
459
|
+
return { allowed: false, reason: "routine action grant must be owner-stated" };
|
|
460
|
+
if (!appliedEntry(rows, "grant_routine_action", input.key, grant))
|
|
461
|
+
return { allowed: false, reason: "routine action grant has no applied owner authorization" };
|
|
462
|
+
if (grant.action !== input.action)
|
|
463
|
+
return { allowed: false, reason: "routine action does not match the grant" };
|
|
464
|
+
if (!grant.targets.includes(input.target) || grant.exclusions.includes(input.target))
|
|
465
|
+
return { allowed: false, reason: "routine action target is not authorized" };
|
|
466
|
+
if (grant.expiresAt && Date.parse(grant.expiresAt) <= Date.parse(now))
|
|
467
|
+
return { allowed: false, reason: "routine action grant expired", ...fallback };
|
|
468
|
+
if (!activeDesired || desired.provenance !== "stated" || !appliedEntry(rows, "set_desired_state", desiredKey, desired))
|
|
469
|
+
return { allowed: false, reason: "container has no active applied owner-stated desired state" };
|
|
470
|
+
if (!["on", "always_on", "expected_on"].includes(desiredValue) && !(desiredValue === "on_demand" && input.requester.kind !== "owner_event"))
|
|
471
|
+
return { allowed: false, reason: "container desired state does not authorize this request" };
|
|
472
|
+
if (receipts.some((receipt) => receipt.action === input.action && receipt.target === input.target && UNRESOLVED_ACTION_STATES.has(receipt.state))) {
|
|
473
|
+
return { allowed: false, reason: "routine action has an unresolved receipt for this target" };
|
|
474
|
+
}
|
|
475
|
+
const windowStart = Date.parse(now) - grant.windowMs;
|
|
476
|
+
if (receipts.filter((receipt) => receipt.key === input.key && Date.parse(receipt.reservedAt) > windowStart).length >= grant.maxCount)
|
|
477
|
+
return { allowed: false, reason: "routine action rate limit reached" };
|
|
478
|
+
return { allowed: true, policyVersion: policy.version, desiredStateVersion: desired.version, grantVersion: grant.version, key: input.key, action: grant.action, target: input.target, requester: input.requester, authorizationVersion: input.authorizationVersion };
|
|
479
|
+
}
|
|
480
|
+
function inspectRoutineActionGrant(agentRoot, input) {
|
|
481
|
+
try {
|
|
482
|
+
const { policy, rows } = readPolicyState(agentRoot);
|
|
483
|
+
return inspectRoutineActionGrantSnapshot(policy, rows, readRoutineActionReceipts(agentRoot), input);
|
|
484
|
+
}
|
|
485
|
+
catch (error) {
|
|
486
|
+
return { allowed: false, reason: error instanceof Error ? error.message : "routine action policy is unavailable" };
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
function consumeRoutineActionGrant(agentRoot, input) {
|
|
490
|
+
if (!text(input.authorizationReceiptId))
|
|
491
|
+
throw new Error("routine action requires a current authorization receipt");
|
|
492
|
+
const authorizationReceiptId = input.authorizationReceiptId;
|
|
493
|
+
return (0, session_transaction_1.withImmediateSessionTurnLease)(policyPath(agentRoot), (lease) => {
|
|
494
|
+
const snapshot = readAuditedPolicy(agentRoot, lease);
|
|
495
|
+
const policy = snapshot.policy;
|
|
496
|
+
const grant = policy.routineActionGrants[input.key];
|
|
497
|
+
const now = input.now === undefined ? new Date().toISOString() : input.now;
|
|
498
|
+
const action = input.action === undefined ? grant?.action ?? "" : input.action;
|
|
499
|
+
const receipts = readRoutineActionReceipts(agentRoot);
|
|
500
|
+
const decision = inspectRoutineActionGrantSnapshot(policy, snapshot.rows, receipts, { ...input, action, now });
|
|
501
|
+
if (!decision.allowed)
|
|
502
|
+
throw new Error(decision.reason);
|
|
503
|
+
const resolvedTarget = input.resolvedTarget === undefined
|
|
504
|
+
? decision.requester.kind === "owner_event" ? decision.requester.target : { id: "unresolved", name: input.target }
|
|
505
|
+
: input.resolvedTarget;
|
|
506
|
+
if (!record(resolvedTarget) || !text(resolvedTarget.id) || resolvedTarget.name !== input.target)
|
|
507
|
+
throw new Error("routine action resolved target is invalid");
|
|
508
|
+
if (decision.requester.kind === "owner_event" && resolvedTarget.id !== decision.requester.target.id)
|
|
509
|
+
throw new Error("routine action event target binding changed");
|
|
510
|
+
ensureDirectory(agentRoot);
|
|
511
|
+
const id = `action-${(0, node_crypto_1.randomUUID)()}`;
|
|
512
|
+
const receipt = {
|
|
513
|
+
schemaVersion: 2,
|
|
514
|
+
id,
|
|
515
|
+
state: "reserved",
|
|
516
|
+
key: input.key,
|
|
517
|
+
action,
|
|
518
|
+
target: input.target,
|
|
519
|
+
policyVersion: policy.version,
|
|
520
|
+
grantVersion: grant.version,
|
|
521
|
+
desiredStateVersion: decision.desiredStateVersion,
|
|
522
|
+
requester: structuredClone(decision.requester),
|
|
523
|
+
reservedAt: now,
|
|
524
|
+
updatedAt: now,
|
|
525
|
+
authorizationReceiptId,
|
|
526
|
+
authorizationVersion: decision.authorizationVersion,
|
|
527
|
+
attemptId: input.attemptId ?? `attempt-${(0, node_crypto_1.randomUUID)()}`,
|
|
528
|
+
attempt: 1,
|
|
529
|
+
expectedBeforeState: input.expectedBeforeState ?? null,
|
|
530
|
+
resolvedTarget: { id: resolvedTarget.id, name: resolvedTarget.name },
|
|
531
|
+
effect: input.effect ?? { operation: action, targetId: resolvedTarget.id },
|
|
532
|
+
effectReceipt: null,
|
|
533
|
+
verifiedAfterState: null,
|
|
534
|
+
recoveryState: { state: "not_needed", compensation: "none" },
|
|
535
|
+
};
|
|
536
|
+
appendReceipt(receiptsPath(agentRoot), receipt);
|
|
537
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "heart.routine_action_reserved", message: "reserved routine action grant", meta: { key: input.key, target: input.target, policyVersion: policy.version } });
|
|
538
|
+
return receipt;
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
function withStewardPolicyLease(agentRoot, operation) {
|
|
542
|
+
return (0, session_transaction_1.withSessionTurnLease)(policyPath(agentRoot), operation);
|
|
543
|
+
}
|
|
544
|
+
async function withRoutineActionAttempt(agentRoot, reservation, validate, attempt) {
|
|
545
|
+
await withStewardPolicyLease(agentRoot, async (lease) => {
|
|
546
|
+
await validate();
|
|
547
|
+
const snapshot = readAuditedPolicy(agentRoot, lease);
|
|
548
|
+
const receipts = readRoutineActionReceipts(agentRoot);
|
|
549
|
+
const current = receipts.find((receipt) => receipt.id === reservation.id);
|
|
550
|
+
if (!current || current.state !== "reserved" || !(0, node_util_1.isDeepStrictEqual)(current, reservation))
|
|
551
|
+
throw new Error("routine action reservation changed");
|
|
552
|
+
if (!reservation.requester || reservation.desiredStateVersion === undefined)
|
|
553
|
+
throw new Error("routine action reservation has no current requester binding");
|
|
554
|
+
const now = new Date().toISOString();
|
|
555
|
+
const decision = inspectRoutineActionGrantSnapshot(snapshot.policy, snapshot.rows, receipts.filter((receipt) => receipt.id !== reservation.id), {
|
|
556
|
+
key: reservation.key, action: reservation.action, target: reservation.target, requester: reservation.requester,
|
|
557
|
+
authorizationVersion: reservation.authorizationVersion, expectedPolicyVersion: reservation.policyVersion,
|
|
558
|
+
expectedDesiredStateVersion: reservation.desiredStateVersion, expectedGrantVersion: reservation.grantVersion, now,
|
|
559
|
+
});
|
|
560
|
+
if (!decision.allowed)
|
|
561
|
+
throw new Error(decision.reason);
|
|
562
|
+
const reservedAt = Date.parse(reservation.reservedAt);
|
|
563
|
+
const windowStart = Date.parse(now) - snapshot.policy.routineActionGrants[reservation.key].windowMs;
|
|
564
|
+
if (!(reservedAt > windowStart && reservedAt <= Date.parse(now)))
|
|
565
|
+
throw new Error("routine action reservation is outside its rate window");
|
|
566
|
+
await attempt();
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
function transitionRoutineActionReceipt(agentRoot, input) {
|
|
570
|
+
return (0, session_transaction_1.withImmediateSessionTurnLease)(policyPath(agentRoot), () => {
|
|
571
|
+
const current = readRoutineActionReceipts(agentRoot).find((receipt) => receipt.id === input.id);
|
|
572
|
+
if (!current)
|
|
573
|
+
throw new Error("routine action receipt is missing");
|
|
574
|
+
if (current.state !== input.expectedState)
|
|
575
|
+
throw new Error(`routine action receipt state changed: expected ${input.expectedState}, got ${current.state}`);
|
|
576
|
+
const now = input.at ?? new Date().toISOString();
|
|
577
|
+
const recoveryState = input.recoveryState ?? current.recoveryState;
|
|
578
|
+
const next = {
|
|
579
|
+
...current,
|
|
580
|
+
state: input.state,
|
|
581
|
+
updatedAt: now,
|
|
582
|
+
...(input.effectReceipt !== undefined ? { effectReceipt: input.effectReceipt } : {}),
|
|
583
|
+
...(input.verifiedAfterState !== undefined ? { verifiedAfterState: input.verifiedAfterState } : {}),
|
|
584
|
+
recoveryState,
|
|
585
|
+
};
|
|
586
|
+
appendReceipt(receiptsPath(agentRoot), next);
|
|
587
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "heart.routine_action_transitioned", message: "transitioned routine action receipt", meta: { id: next.id, state: next.state, target: next.target } });
|
|
588
|
+
return next;
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
async function recoverRoutineActionReceipts(agentRoot, options) {
|
|
592
|
+
const recovered = [];
|
|
593
|
+
for (const receipt of readRoutineActionReceipts(agentRoot)) {
|
|
594
|
+
if (receipt.state === "reserved") {
|
|
595
|
+
recovered.push(transitionRoutineActionReceipt(agentRoot, { id: receipt.id, expectedState: "reserved", state: "recovered_no_effect", recoveryState: { state: "completed", compensation: "none" } }));
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
if (receipt.state === "attempting") {
|
|
599
|
+
recovered.push(transitionRoutineActionReceipt(agentRoot, { id: receipt.id, expectedState: "attempting", state: "indeterminate", recoveryState: { state: "manual_inspection_required", compensation: "none" } }));
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
if (receipt.state !== "effect_acknowledged" && receipt.state !== "recovery_pending")
|
|
603
|
+
continue;
|
|
604
|
+
const pending = receipt.state === "effect_acknowledged"
|
|
605
|
+
? transitionRoutineActionReceipt(agentRoot, { id: receipt.id, expectedState: "effect_acknowledged", state: "recovery_pending", recoveryState: { state: "pending", compensation: "none" } })
|
|
606
|
+
: receipt;
|
|
607
|
+
options.afterRecoveryClaim?.(pending);
|
|
608
|
+
const observed = await options.observeTarget(pending.resolvedTarget);
|
|
609
|
+
if (observed.id === pending.resolvedTarget.id && observed.name === pending.resolvedTarget.name && observed.state === "running") {
|
|
610
|
+
recovered.push(transitionRoutineActionReceipt(agentRoot, { id: pending.id, expectedState: "recovery_pending", state: "verified", verifiedAfterState: observed.state, recoveryState: { state: "completed", compensation: "none" } }));
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
recovered.push(transitionRoutineActionReceipt(agentRoot, { id: pending.id, expectedState: "recovery_pending", state: "indeterminate", recoveryState: { state: "manual_inspection_required", compensation: "none" } }));
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "heart.routine_action_recovery", message: "reconciled interrupted routine action receipts", meta: { recoveredCount: recovered.length } });
|
|
617
|
+
return recovered;
|
|
618
|
+
}
|