@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,960 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.ApprovalStoreError = void 0;
|
|
40
|
+
exports.canonicalApprovalArguments = canonicalApprovalArguments;
|
|
41
|
+
exports.parseApprovalRecord = parseApprovalRecord;
|
|
42
|
+
exports.openApprovalStore = openApprovalStore;
|
|
43
|
+
exports.readApprovalsByScenarioHandleDigest = readApprovalsByScenarioHandleDigest;
|
|
44
|
+
const node_crypto_1 = require("node:crypto");
|
|
45
|
+
const fs = __importStar(require("node:fs"));
|
|
46
|
+
const path = __importStar(require("node:path"));
|
|
47
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
48
|
+
const runtime_1 = require("../nerves/runtime");
|
|
49
|
+
class ApprovalStoreError extends Error {
|
|
50
|
+
code;
|
|
51
|
+
constructor(code, message = code) {
|
|
52
|
+
super(message);
|
|
53
|
+
this.name = "ApprovalStoreError";
|
|
54
|
+
this.code = code;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.ApprovalStoreError = ApprovalStoreError;
|
|
58
|
+
const HASH = /^[a-f0-9]{64}$/;
|
|
59
|
+
const UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i;
|
|
60
|
+
const RECORD_KEYS = [
|
|
61
|
+
"approvalId", "state", "toolCallId", "toolName", "arguments", "argumentDigest", "schemaDigest",
|
|
62
|
+
"toolDigest", "policyDigest", "policyId", "sessionKey", "sessionPath", "baseSessionRevision",
|
|
63
|
+
"suspendedSessionRevision", "checkpointDigest", "requesterId", "transport", "transportUserId",
|
|
64
|
+
"transportChatId", "transportMessageId", "decisionTokenDigest", "expiresAt", "createdAt", "updatedAt",
|
|
65
|
+
"ownerId", "epoch", "attemptedAt", "result", "reason", "frozenAssistantMessage",
|
|
66
|
+
];
|
|
67
|
+
const STATES = new Set([
|
|
68
|
+
"preparing", "awaiting_prompt_binding", "proposed", "claimed", "attempted", "succeeded", "failed",
|
|
69
|
+
"attempted_indeterminate", "denied", "expired", "drifted", "session_head_changed", "abandoned_before_attempt",
|
|
70
|
+
]);
|
|
71
|
+
const ATTEMPT_TERMINALS = new Set(["succeeded", "failed", "attempted_indeterminate"]);
|
|
72
|
+
function fail(code) {
|
|
73
|
+
throw new ApprovalStoreError(code);
|
|
74
|
+
}
|
|
75
|
+
function isObject(value) {
|
|
76
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
77
|
+
}
|
|
78
|
+
function isTimestamp(value) {
|
|
79
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
|
|
80
|
+
}
|
|
81
|
+
function isNonEmpty(value) {
|
|
82
|
+
return typeof value === "string" && value.length > 0;
|
|
83
|
+
}
|
|
84
|
+
function processIsAlive(pid) {
|
|
85
|
+
try {
|
|
86
|
+
process.kill(pid, 0);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function assertJsonValue(value) {
|
|
94
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
95
|
+
return;
|
|
96
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
97
|
+
return;
|
|
98
|
+
if (Array.isArray(value)) {
|
|
99
|
+
for (const item of value)
|
|
100
|
+
assertJsonValue(item);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (isObject(value)) {
|
|
104
|
+
for (const item of Object.values(value))
|
|
105
|
+
assertJsonValue(item);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
fail("invalid_json_value");
|
|
109
|
+
}
|
|
110
|
+
function canonicalize(value) {
|
|
111
|
+
if (value === null || typeof value !== "object")
|
|
112
|
+
return JSON.stringify(value);
|
|
113
|
+
if (Array.isArray(value))
|
|
114
|
+
return `[${value.map(canonicalize).join(",")}]`;
|
|
115
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalize(value[key])}`).join(",")}}`;
|
|
116
|
+
}
|
|
117
|
+
function sha256(value) {
|
|
118
|
+
return (0, node_crypto_1.createHash)("sha256").update(value, "utf8").digest("hex");
|
|
119
|
+
}
|
|
120
|
+
function canonicalApprovalArguments(value) {
|
|
121
|
+
if (!isObject(value))
|
|
122
|
+
fail("arguments_not_object");
|
|
123
|
+
assertJsonValue(value);
|
|
124
|
+
const canonical = canonicalize(value);
|
|
125
|
+
return { canonical, digest: sha256(canonical) };
|
|
126
|
+
}
|
|
127
|
+
function hasExactKeys(value) {
|
|
128
|
+
const actual = Object.keys(value).sort();
|
|
129
|
+
const expected = [...RECORD_KEYS, ...("ownerBinding" in value ? ["ownerBinding"] : [])].sort();
|
|
130
|
+
return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
|
|
131
|
+
}
|
|
132
|
+
function validOwnerBinding(value) {
|
|
133
|
+
return isObject(value) && Object.keys(value).length === 5
|
|
134
|
+
&& ["friendId", "requestId", "sessionEventId", "sessionKey"].every((key) => isNonEmpty(value[key]) && value[key] === value[key].trim())
|
|
135
|
+
&& typeof value.profileVersion === "number" && Number.isSafeInteger(value.profileVersion) && value.profileVersion > 0;
|
|
136
|
+
}
|
|
137
|
+
function validStateShape(record) {
|
|
138
|
+
const hasOwner = isNonEmpty(record.ownerId);
|
|
139
|
+
const hasAttempt = isTimestamp(record.attemptedAt);
|
|
140
|
+
const hasSuspension = typeof record.suspendedSessionRevision === "string"
|
|
141
|
+
&& HASH.test(record.suspendedSessionRevision);
|
|
142
|
+
const hasPromptBinding = isNonEmpty(record.transportMessageId);
|
|
143
|
+
const hasValidOwnershipEpoch = hasOwner ? record.epoch > 0 : record.epoch === 0;
|
|
144
|
+
if (record.state === "preparing") {
|
|
145
|
+
return record.suspendedSessionRevision === null && record.transportMessageId === null
|
|
146
|
+
&& !hasOwner && record.epoch === 0 && !hasAttempt && record.result === null && record.reason === null;
|
|
147
|
+
}
|
|
148
|
+
if (record.state === "awaiting_prompt_binding") {
|
|
149
|
+
return hasSuspension && record.transportMessageId === null
|
|
150
|
+
&& !hasOwner && record.epoch === 0 && !hasAttempt && record.result === null && record.reason === null;
|
|
151
|
+
}
|
|
152
|
+
if (record.state === "proposed") {
|
|
153
|
+
return hasSuspension && hasPromptBinding
|
|
154
|
+
&& !hasOwner && record.epoch === 0 && !hasAttempt && record.result === null && record.reason === null;
|
|
155
|
+
}
|
|
156
|
+
if (record.state === "claimed") {
|
|
157
|
+
return hasSuspension && hasPromptBinding && hasOwner && record.epoch > 0
|
|
158
|
+
&& !hasAttempt && record.result === null && record.reason === null;
|
|
159
|
+
}
|
|
160
|
+
if (record.state === "attempted") {
|
|
161
|
+
return hasSuspension && hasPromptBinding && hasOwner && record.epoch > 0
|
|
162
|
+
&& hasAttempt && record.result === null && record.reason === null;
|
|
163
|
+
}
|
|
164
|
+
if (ATTEMPT_TERMINALS.has(record.state)) {
|
|
165
|
+
return hasSuspension && hasPromptBinding && hasOwner && record.epoch > 0
|
|
166
|
+
&& hasAttempt && isNonEmpty(record.result) && record.reason === null;
|
|
167
|
+
}
|
|
168
|
+
if (record.state === "abandoned_before_attempt") {
|
|
169
|
+
const validPreparingRecovery = !hasOwner && record.epoch === 0
|
|
170
|
+
&& record.suspendedSessionRevision === null && record.transportMessageId === null;
|
|
171
|
+
const validPromptBindingRecovery = !hasOwner && record.epoch === 0
|
|
172
|
+
&& hasSuspension && record.transportMessageId === null;
|
|
173
|
+
const validClaimRecovery = hasOwner && record.epoch > 0 && hasSuspension && hasPromptBinding;
|
|
174
|
+
return (validPreparingRecovery || validPromptBindingRecovery || validClaimRecovery)
|
|
175
|
+
&& !hasAttempt && record.result === null && isNonEmpty(record.reason);
|
|
176
|
+
}
|
|
177
|
+
if (record.state === "drifted") {
|
|
178
|
+
const validPreparingRecovery = !hasOwner && record.epoch === 0
|
|
179
|
+
&& record.suspendedSessionRevision === null && record.transportMessageId === null;
|
|
180
|
+
const validPostCheckpoint = !hasOwner && record.epoch === 0 && hasSuspension
|
|
181
|
+
&& (hasPromptBinding || record.transportMessageId === null);
|
|
182
|
+
const validPostClaim = hasOwner && record.epoch > 0 && hasSuspension && hasPromptBinding;
|
|
183
|
+
return (validPreparingRecovery || validPostCheckpoint || validPostClaim)
|
|
184
|
+
&& !hasAttempt && record.result === null && isNonEmpty(record.reason);
|
|
185
|
+
}
|
|
186
|
+
if (record.state === "denied") {
|
|
187
|
+
return hasValidOwnershipEpoch && hasSuspension && hasPromptBinding
|
|
188
|
+
&& !hasAttempt && record.result === null && record.reason === null;
|
|
189
|
+
}
|
|
190
|
+
if (record.state === "expired") {
|
|
191
|
+
return !hasOwner && record.epoch === 0 && hasSuspension
|
|
192
|
+
&& (hasPromptBinding || record.transportMessageId === null)
|
|
193
|
+
&& !hasAttempt && record.result === null && record.reason === null;
|
|
194
|
+
}
|
|
195
|
+
if (record.state === "session_head_changed") {
|
|
196
|
+
return hasValidOwnershipEpoch && hasSuspension && hasPromptBinding
|
|
197
|
+
&& !hasAttempt && record.result === null && isNonEmpty(record.reason);
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
function parseApprovalRecord(value) {
|
|
202
|
+
if (!isObject(value) || !hasExactKeys(value))
|
|
203
|
+
fail("corrupt_record");
|
|
204
|
+
if ("ownerBinding" in value && !validOwnerBinding(value.ownerBinding))
|
|
205
|
+
fail("corrupt_record");
|
|
206
|
+
const record = value;
|
|
207
|
+
if (!UUID.test(record.approvalId))
|
|
208
|
+
fail("corrupt_record");
|
|
209
|
+
for (const field of [
|
|
210
|
+
"toolCallId", "toolName", "policyId", "sessionKey", "sessionPath", "requesterId", "transport",
|
|
211
|
+
"transportUserId", "transportChatId",
|
|
212
|
+
])
|
|
213
|
+
if (!isNonEmpty(record[field]))
|
|
214
|
+
fail("corrupt_record");
|
|
215
|
+
for (const field of [
|
|
216
|
+
"argumentDigest", "schemaDigest", "toolDigest", "policyDigest", "baseSessionRevision", "checkpointDigest",
|
|
217
|
+
"decisionTokenDigest",
|
|
218
|
+
])
|
|
219
|
+
if (typeof record[field] !== "string" || !HASH.test(record[field]))
|
|
220
|
+
fail("corrupt_record");
|
|
221
|
+
if (!isObject(record.arguments) || !isObject(record.frozenAssistantMessage))
|
|
222
|
+
fail("corrupt_record");
|
|
223
|
+
assertJsonValue(record.arguments);
|
|
224
|
+
assertJsonValue(record.frozenAssistantMessage);
|
|
225
|
+
if (canonicalApprovalArguments(record.arguments).digest !== record.argumentDigest)
|
|
226
|
+
fail("corrupt_record");
|
|
227
|
+
if (!isTimestamp(record.expiresAt) || !isTimestamp(record.createdAt) || !isTimestamp(record.updatedAt))
|
|
228
|
+
fail("corrupt_record");
|
|
229
|
+
if (record.ownerId !== null && !isNonEmpty(record.ownerId))
|
|
230
|
+
fail("corrupt_record");
|
|
231
|
+
if (record.attemptedAt !== null && !isTimestamp(record.attemptedAt))
|
|
232
|
+
fail("corrupt_record");
|
|
233
|
+
if (record.reason !== null && !isNonEmpty(record.reason))
|
|
234
|
+
fail("corrupt_record");
|
|
235
|
+
if (record.result !== null && !isNonEmpty(record.result))
|
|
236
|
+
fail("corrupt_record");
|
|
237
|
+
if (record.transportMessageId !== null && !isNonEmpty(record.transportMessageId))
|
|
238
|
+
fail("corrupt_record");
|
|
239
|
+
if (record.suspendedSessionRevision !== null
|
|
240
|
+
&& (typeof record.suspendedSessionRevision !== "string" || !HASH.test(record.suspendedSessionRevision)))
|
|
241
|
+
fail("corrupt_record");
|
|
242
|
+
if (!Number.isInteger(record.epoch) || record.epoch < 0 || !validStateShape(record) || !STATES.has(record.state))
|
|
243
|
+
fail("corrupt_record");
|
|
244
|
+
return structuredClone(record);
|
|
245
|
+
}
|
|
246
|
+
function assertHash(value, code) {
|
|
247
|
+
if (!HASH.test(value))
|
|
248
|
+
fail(code);
|
|
249
|
+
}
|
|
250
|
+
function assertPrepareInput(input) {
|
|
251
|
+
if (input.ownerBinding !== undefined && !validOwnerBinding(input.ownerBinding))
|
|
252
|
+
fail("invalid_proposal");
|
|
253
|
+
for (const value of [input.toolCallId, input.toolName, input.policyId, input.sessionKey, input.sessionPath,
|
|
254
|
+
input.requesterId, input.transport, input.transportUserId, input.transportChatId]) {
|
|
255
|
+
if (!isNonEmpty(value))
|
|
256
|
+
fail("invalid_proposal");
|
|
257
|
+
}
|
|
258
|
+
for (const value of [input.schemaDigest, input.toolDigest, input.policyDigest, input.baseSessionRevision, input.checkpointDigest]) {
|
|
259
|
+
assertHash(value, "invalid_proposal");
|
|
260
|
+
}
|
|
261
|
+
if (!isTimestamp(input.expiresAt) || !isObject(input.arguments) || !isObject(input.frozenAssistantMessage))
|
|
262
|
+
fail("invalid_proposal");
|
|
263
|
+
assertJsonValue(input.arguments);
|
|
264
|
+
assertJsonValue(input.frozenAssistantMessage);
|
|
265
|
+
}
|
|
266
|
+
function tokenMatches(token, digest) {
|
|
267
|
+
const actual = Buffer.from(sha256(token), "hex");
|
|
268
|
+
const expected = Buffer.from(digest, "hex");
|
|
269
|
+
return actual.length === expected.length && (0, node_crypto_1.timingSafeEqual)(actual, expected);
|
|
270
|
+
}
|
|
271
|
+
function sameDecisionBinding(record, input) {
|
|
272
|
+
return tokenMatches(input.decisionToken, record.decisionTokenDigest)
|
|
273
|
+
&& input.requesterId === record.requesterId
|
|
274
|
+
&& input.transport === record.transport
|
|
275
|
+
&& input.transportUserId === record.transportUserId
|
|
276
|
+
&& input.transportChatId === record.transportChatId
|
|
277
|
+
&& input.transportMessageId === record.transportMessageId
|
|
278
|
+
&& input.sessionKey === record.sessionKey;
|
|
279
|
+
}
|
|
280
|
+
function operationErrorMeta(operation, error) {
|
|
281
|
+
return {
|
|
282
|
+
operation,
|
|
283
|
+
outcome: "error",
|
|
284
|
+
code: error instanceof ApprovalStoreError ? error.code : "unexpected_error",
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function observePrepare(operation) {
|
|
288
|
+
try {
|
|
289
|
+
const result = operation();
|
|
290
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_prepare", message: "approval store prepare completed", meta: { operation: "prepare", outcome: "success" } });
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_prepare", message: "approval store prepare failed", meta: operationErrorMeta("prepare", error) });
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function observeActivate(operation) {
|
|
299
|
+
try {
|
|
300
|
+
const result = operation();
|
|
301
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_activate", message: "approval store activation completed", meta: { operation: "activate", outcome: "success" } });
|
|
302
|
+
return result;
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_activate", message: "approval store activation failed", meta: operationErrorMeta("activate", error) });
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function observeBindPrompt(operation) {
|
|
310
|
+
try {
|
|
311
|
+
const result = operation();
|
|
312
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_bind_prompt", message: "approval prompt binding completed", meta: { operation: "bind_prompt", outcome: "success" } });
|
|
313
|
+
return result;
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_bind_prompt", message: "approval prompt binding failed", meta: operationErrorMeta("bind_prompt", error) });
|
|
317
|
+
throw error;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function observeDecide(operation) {
|
|
321
|
+
try {
|
|
322
|
+
const result = operation();
|
|
323
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_decide", message: "approval decision completed", meta: { operation: "decide", outcome: "success" } });
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_decide", message: "approval decision failed", meta: operationErrorMeta("decide", error) });
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function observeExpire(operation) {
|
|
332
|
+
try {
|
|
333
|
+
const result = operation();
|
|
334
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_expire", message: "approval expiry completed", meta: { operation: "expire", outcome: "success" } });
|
|
335
|
+
return result;
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_expire", message: "approval expiry failed", meta: operationErrorMeta("expire", error) });
|
|
339
|
+
throw error;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
function observeMarkAttempted(operation) {
|
|
343
|
+
try {
|
|
344
|
+
const result = operation();
|
|
345
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_mark_attempted", message: "approval attempt marker completed", meta: { operation: "mark_attempted", outcome: "success" } });
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_mark_attempted", message: "approval attempt marker failed", meta: operationErrorMeta("mark_attempted", error) });
|
|
350
|
+
throw error;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function observeTerminalizeBeforeAttempt(operation) {
|
|
354
|
+
try {
|
|
355
|
+
const result = operation();
|
|
356
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_terminalize_before_attempt", message: "approval pre-attempt terminalization completed", meta: { operation: "terminalize_before_attempt", outcome: "success" } });
|
|
357
|
+
return result;
|
|
358
|
+
}
|
|
359
|
+
catch (error) {
|
|
360
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_terminalize_before_attempt", message: "approval pre-attempt terminalization failed", meta: operationErrorMeta("terminalize_before_attempt", error) });
|
|
361
|
+
throw error;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function observeAbandonBeforeAttempt(operation) {
|
|
365
|
+
try {
|
|
366
|
+
const result = operation();
|
|
367
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_abandon_before_attempt", message: "approval abandonment completed", meta: { operation: "abandon_before_attempt", outcome: "success" } });
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_abandon_before_attempt", message: "approval abandonment failed", meta: operationErrorMeta("abandon_before_attempt", error) });
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
function observeComplete(operation) {
|
|
376
|
+
try {
|
|
377
|
+
const result = operation();
|
|
378
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_complete", message: "approval completion completed", meta: { operation: "complete", outcome: "success" } });
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_complete", message: "approval completion failed", meta: operationErrorMeta("complete", error) });
|
|
383
|
+
throw error;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
function observeClaimContinuation(operation) {
|
|
387
|
+
try {
|
|
388
|
+
const result = operation();
|
|
389
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_claim_continuation", message: "approval continuation claim completed", meta: { operation: "claim_continuation", outcome: "success" } });
|
|
390
|
+
return result;
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_claim_continuation", message: "approval continuation claim failed", meta: operationErrorMeta("claim_continuation", error) });
|
|
394
|
+
throw error;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function observeCompleteContinuation(operation) {
|
|
398
|
+
try {
|
|
399
|
+
const result = operation();
|
|
400
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_complete_continuation", message: "approval continuation completion completed", meta: { operation: "complete_continuation", outcome: "success" } });
|
|
401
|
+
return result;
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_complete_continuation", message: "approval continuation completion failed", meta: operationErrorMeta("complete_continuation", error) });
|
|
405
|
+
throw error;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function observeMaterializeContinuation(operation) {
|
|
409
|
+
try {
|
|
410
|
+
const result = operation();
|
|
411
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_materialize_continuation", message: "approval continuation materialization completed", meta: { operation: "materialize_continuation", outcome: "success" } });
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_materialize_continuation", message: "approval continuation materialization failed", meta: operationErrorMeta("materialize_continuation", error) });
|
|
416
|
+
throw error;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function observeAttemptContinuation(operation) {
|
|
420
|
+
try {
|
|
421
|
+
const result = operation();
|
|
422
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_attempt_continuation", message: "approval continuation attempt completed", meta: { operation: "attempt_continuation", outcome: "success" } });
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_attempt_continuation", message: "approval continuation attempt failed", meta: operationErrorMeta("attempt_continuation", error) });
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function observeRead(operation) {
|
|
431
|
+
try {
|
|
432
|
+
const result = operation();
|
|
433
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_read", message: "approval store read completed", meta: { operation: "read", outcome: "success" } });
|
|
434
|
+
return result;
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_read", message: "approval store read failed", meta: operationErrorMeta("read", error) });
|
|
438
|
+
throw error;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function observeListPreparing(operation) {
|
|
442
|
+
try {
|
|
443
|
+
const result = operation();
|
|
444
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_list_preparing", message: "preparing approval listing completed", meta: { operation: "list_preparing", outcome: "success" } });
|
|
445
|
+
return result;
|
|
446
|
+
}
|
|
447
|
+
catch (error) {
|
|
448
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_list_preparing", message: "preparing approval listing failed", meta: operationErrorMeta("list_preparing", error) });
|
|
449
|
+
throw error;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function observeRecoverPreparing(operation) {
|
|
453
|
+
try {
|
|
454
|
+
const result = operation();
|
|
455
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_recover_preparing", message: "preparing approval recovery completed", meta: { operation: "recover_preparing", outcome: "success" } });
|
|
456
|
+
return result;
|
|
457
|
+
}
|
|
458
|
+
catch (error) {
|
|
459
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_recover_preparing", message: "preparing approval recovery failed", meta: operationErrorMeta("recover_preparing", error) });
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
function observeClose(operation) {
|
|
464
|
+
try {
|
|
465
|
+
const result = operation();
|
|
466
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.store_close", message: "approval store close completed", meta: { operation: "close", outcome: "success" } });
|
|
467
|
+
return result;
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
(0, runtime_1.emitNervesEvent)({ level: "error", component: "heart", event: "approval.store_close", message: "approval store close failed", meta: operationErrorMeta("close", error) });
|
|
471
|
+
throw error;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
function openApprovalStore(options) {
|
|
475
|
+
fs.mkdirSync(path.dirname(options.databasePath), { recursive: true });
|
|
476
|
+
const database = new better_sqlite3_1.default(options.databasePath);
|
|
477
|
+
database.pragma("journal_mode = WAL");
|
|
478
|
+
database.pragma("busy_timeout = 5000");
|
|
479
|
+
database.exec(`
|
|
480
|
+
CREATE TABLE IF NOT EXISTS approval_actions (
|
|
481
|
+
approval_id TEXT PRIMARY KEY,
|
|
482
|
+
state TEXT NOT NULL,
|
|
483
|
+
epoch INTEGER NOT NULL,
|
|
484
|
+
record_json TEXT NOT NULL
|
|
485
|
+
)
|
|
486
|
+
;
|
|
487
|
+
CREATE TABLE IF NOT EXISTS approval_continuations (
|
|
488
|
+
approval_id TEXT PRIMARY KEY,
|
|
489
|
+
owner_id TEXT NOT NULL,
|
|
490
|
+
owner_pid INTEGER NOT NULL,
|
|
491
|
+
epoch INTEGER NOT NULL,
|
|
492
|
+
state TEXT NOT NULL,
|
|
493
|
+
claimed_at TEXT NOT NULL,
|
|
494
|
+
materialized_at TEXT,
|
|
495
|
+
attempted_at TEXT,
|
|
496
|
+
continued_at TEXT
|
|
497
|
+
)
|
|
498
|
+
;
|
|
499
|
+
CREATE TABLE IF NOT EXISTS approval_acceptance_scenarios (
|
|
500
|
+
approval_id TEXT PRIMARY KEY,
|
|
501
|
+
scenario_handle_digest TEXT NOT NULL,
|
|
502
|
+
FOREIGN KEY (approval_id) REFERENCES approval_actions(approval_id)
|
|
503
|
+
)
|
|
504
|
+
;
|
|
505
|
+
CREATE INDEX IF NOT EXISTS approval_acceptance_scenario_digest
|
|
506
|
+
ON approval_acceptance_scenarios (scenario_handle_digest)
|
|
507
|
+
`);
|
|
508
|
+
const now = options.now ?? (() => new Date());
|
|
509
|
+
const randomUUID = options.randomUUID ?? node_crypto_1.randomUUID;
|
|
510
|
+
const randomBytes = options.randomBytes ?? node_crypto_1.randomBytes;
|
|
511
|
+
const rawRead = (approvalId) => {
|
|
512
|
+
const row = database.prepare("SELECT record_json FROM approval_actions WHERE approval_id = ?")
|
|
513
|
+
.get(approvalId);
|
|
514
|
+
if (!row)
|
|
515
|
+
return null;
|
|
516
|
+
try {
|
|
517
|
+
return parseApprovalRecord(JSON.parse(row.record_json));
|
|
518
|
+
}
|
|
519
|
+
catch (error) {
|
|
520
|
+
if (error instanceof ApprovalStoreError)
|
|
521
|
+
throw error;
|
|
522
|
+
fail("corrupt_record");
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
const insert = (record, scenarioHandleDigest) => {
|
|
526
|
+
const transaction = database.transaction(() => {
|
|
527
|
+
database.prepare("INSERT INTO approval_actions (approval_id, state, epoch, record_json) VALUES (?, ?, ?, ?)")
|
|
528
|
+
.run(record.approvalId, record.state, record.epoch, JSON.stringify(record));
|
|
529
|
+
if (scenarioHandleDigest)
|
|
530
|
+
database.prepare("INSERT INTO approval_acceptance_scenarios (approval_id, scenario_handle_digest) VALUES (?, ?)")
|
|
531
|
+
.run(record.approvalId, scenarioHandleDigest);
|
|
532
|
+
});
|
|
533
|
+
transaction();
|
|
534
|
+
if (scenarioHandleDigest)
|
|
535
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.acceptance_transition", message: "acceptance-bound approval transitioned", meta: { approvalId: record.approvalId, scenarioHandleDigest, toolName: record.toolName, argumentDigest: record.argumentDigest, state: record.state } });
|
|
536
|
+
};
|
|
537
|
+
const acceptanceDigest = (approvalId) => {
|
|
538
|
+
const row = database.prepare("SELECT scenario_handle_digest FROM approval_acceptance_scenarios WHERE approval_id = ?")
|
|
539
|
+
.get(approvalId);
|
|
540
|
+
return row?.scenario_handle_digest ?? null;
|
|
541
|
+
};
|
|
542
|
+
const cas = (previous, next) => {
|
|
543
|
+
const changed = database.prepare(`
|
|
544
|
+
UPDATE approval_actions SET state = ?, epoch = ?, record_json = ?
|
|
545
|
+
WHERE approval_id = ? AND state = ? AND epoch = ? AND record_json = ?
|
|
546
|
+
`).run(next.state, next.epoch, JSON.stringify(next), previous.approvalId, previous.state, previous.epoch, JSON.stringify(previous));
|
|
547
|
+
if (changed.changes !== 1)
|
|
548
|
+
fail("transition_conflict");
|
|
549
|
+
const scenarioHandleDigest = acceptanceDigest(next.approvalId);
|
|
550
|
+
if (scenarioHandleDigest)
|
|
551
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.acceptance_transition", message: "acceptance-bound approval transitioned", meta: { approvalId: next.approvalId, scenarioHandleDigest, toolName: next.toolName, argumentDigest: next.argumentDigest, state: next.state } });
|
|
552
|
+
return structuredClone(next);
|
|
553
|
+
};
|
|
554
|
+
const requireRecord = (approvalId) => rawRead(approvalId) ?? fail("approval_not_found");
|
|
555
|
+
const timestamp = () => now().toISOString();
|
|
556
|
+
const readContinuationRow = (approvalId) => database.prepare(`
|
|
557
|
+
SELECT owner_id, owner_pid, epoch, state, claimed_at, materialized_at, attempted_at, continued_at
|
|
558
|
+
FROM approval_continuations WHERE approval_id = ?
|
|
559
|
+
`).get(approvalId);
|
|
560
|
+
const combineContinuation = (approval, row) => ({
|
|
561
|
+
...approval,
|
|
562
|
+
continuationOwnerId: row.owner_id,
|
|
563
|
+
continuationOwnerPid: row.owner_pid,
|
|
564
|
+
continuationEpoch: row.epoch,
|
|
565
|
+
continuationState: row.state,
|
|
566
|
+
continuationClaimedAt: row.claimed_at,
|
|
567
|
+
continuationMaterializedAt: row.materialized_at,
|
|
568
|
+
continuationAttemptedAt: row.attempted_at,
|
|
569
|
+
continuedAt: row.continued_at,
|
|
570
|
+
});
|
|
571
|
+
const transitionContinuation = (input, from, to, timestampColumn) => {
|
|
572
|
+
const approval = requireRecord(input.approvalId);
|
|
573
|
+
const changed = database.prepare(`
|
|
574
|
+
UPDATE approval_continuations SET state = ?, ${timestampColumn} = ?
|
|
575
|
+
WHERE approval_id = ? AND owner_id = ? AND epoch = ? AND state = ?
|
|
576
|
+
`).run(to, timestamp(), input.approvalId, input.ownerId, input.epoch, from);
|
|
577
|
+
if (changed.changes !== 1)
|
|
578
|
+
fail(`continuation_${to}_not_eligible`);
|
|
579
|
+
const scenarioHandleDigest = acceptanceDigest(input.approvalId);
|
|
580
|
+
if (scenarioHandleDigest)
|
|
581
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.acceptance_continuation_transition", message: "acceptance-bound approval continuation transitioned", meta: { approvalId: approval.approvalId, scenarioHandleDigest, toolName: approval.toolName, argumentDigest: approval.argumentDigest, state: to } });
|
|
582
|
+
return combineContinuation(approval, readContinuationRow(input.approvalId));
|
|
583
|
+
};
|
|
584
|
+
return {
|
|
585
|
+
prepare(input) {
|
|
586
|
+
return observePrepare(() => {
|
|
587
|
+
assertPrepareInput(input);
|
|
588
|
+
const approvalId = randomUUID();
|
|
589
|
+
if (!UUID.test(approvalId))
|
|
590
|
+
fail("invalid_approval_id");
|
|
591
|
+
const tokenBytes = randomBytes(32);
|
|
592
|
+
if (tokenBytes.length !== 32)
|
|
593
|
+
fail("invalid_token_entropy");
|
|
594
|
+
const decisionToken = tokenBytes.toString("base64url");
|
|
595
|
+
const createdAt = timestamp();
|
|
596
|
+
const record = {
|
|
597
|
+
approvalId,
|
|
598
|
+
state: "preparing",
|
|
599
|
+
toolCallId: input.toolCallId,
|
|
600
|
+
toolName: input.toolName,
|
|
601
|
+
arguments: structuredClone(input.arguments),
|
|
602
|
+
argumentDigest: canonicalApprovalArguments(input.arguments).digest,
|
|
603
|
+
schemaDigest: input.schemaDigest,
|
|
604
|
+
toolDigest: input.toolDigest,
|
|
605
|
+
policyDigest: input.policyDigest,
|
|
606
|
+
policyId: input.policyId,
|
|
607
|
+
sessionKey: input.sessionKey,
|
|
608
|
+
sessionPath: input.sessionPath,
|
|
609
|
+
baseSessionRevision: input.baseSessionRevision,
|
|
610
|
+
suspendedSessionRevision: null,
|
|
611
|
+
checkpointDigest: input.checkpointDigest,
|
|
612
|
+
requesterId: input.requesterId,
|
|
613
|
+
transport: input.transport,
|
|
614
|
+
transportUserId: input.transportUserId,
|
|
615
|
+
transportChatId: input.transportChatId,
|
|
616
|
+
transportMessageId: null,
|
|
617
|
+
decisionTokenDigest: sha256(decisionToken),
|
|
618
|
+
expiresAt: input.expiresAt,
|
|
619
|
+
createdAt,
|
|
620
|
+
updatedAt: createdAt,
|
|
621
|
+
ownerId: null,
|
|
622
|
+
epoch: 0,
|
|
623
|
+
attemptedAt: null,
|
|
624
|
+
result: null,
|
|
625
|
+
reason: null,
|
|
626
|
+
frozenAssistantMessage: structuredClone(input.frozenAssistantMessage),
|
|
627
|
+
...(input.ownerBinding ? { ownerBinding: structuredClone(input.ownerBinding) } : {}),
|
|
628
|
+
};
|
|
629
|
+
if (input.scenarioHandleDigest !== undefined)
|
|
630
|
+
assertHash(input.scenarioHandleDigest, "invalid_proposal");
|
|
631
|
+
insert(parseApprovalRecord(record), input.scenarioHandleDigest);
|
|
632
|
+
return { record: structuredClone(record), decisionToken };
|
|
633
|
+
});
|
|
634
|
+
},
|
|
635
|
+
activate(input) {
|
|
636
|
+
return observeActivate(() => {
|
|
637
|
+
const previous = requireRecord(input.approvalId);
|
|
638
|
+
if (previous.state !== "preparing" || input.checkpointDigest !== previous.checkpointDigest)
|
|
639
|
+
fail("invalid_activation");
|
|
640
|
+
assertHash(input.suspendedSessionRevision, "invalid_activation");
|
|
641
|
+
return cas(previous, { ...previous, state: "awaiting_prompt_binding", suspendedSessionRevision: input.suspendedSessionRevision, updatedAt: timestamp() });
|
|
642
|
+
});
|
|
643
|
+
},
|
|
644
|
+
bindPrompt(input) {
|
|
645
|
+
return observeBindPrompt(() => {
|
|
646
|
+
const previous = requireRecord(input.approvalId);
|
|
647
|
+
if (previous.state !== "awaiting_prompt_binding" || input.transport !== previous.transport
|
|
648
|
+
|| input.transportChatId !== previous.transportChatId || !isNonEmpty(input.transportMessageId)
|
|
649
|
+
|| (input.expiresAt !== undefined && !isTimestamp(input.expiresAt)))
|
|
650
|
+
fail("invalid_prompt_binding");
|
|
651
|
+
return cas(previous, { ...previous, state: "proposed", transportMessageId: input.transportMessageId, expiresAt: input.expiresAt ?? previous.expiresAt, updatedAt: timestamp() });
|
|
652
|
+
});
|
|
653
|
+
},
|
|
654
|
+
abandonPromptBinding(input) {
|
|
655
|
+
return observeAbandonBeforeAttempt(() => {
|
|
656
|
+
const previous = requireRecord(input.approvalId);
|
|
657
|
+
if (previous.state === "abandoned_before_attempt" && previous.ownerId === null
|
|
658
|
+
&& previous.epoch === 0 && previous.reason === input.reason)
|
|
659
|
+
return previous;
|
|
660
|
+
if (previous.state !== "awaiting_prompt_binding" || !isNonEmpty(input.reason))
|
|
661
|
+
fail("prompt_abandon_not_eligible");
|
|
662
|
+
return cas(previous, {
|
|
663
|
+
...previous,
|
|
664
|
+
state: "abandoned_before_attempt",
|
|
665
|
+
reason: input.reason,
|
|
666
|
+
updatedAt: timestamp(),
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
},
|
|
670
|
+
decide(input) {
|
|
671
|
+
return observeDecide(() => {
|
|
672
|
+
const previous = requireRecord(input.approvalId);
|
|
673
|
+
const decisionAt = input.decisionAt ?? now().getTime();
|
|
674
|
+
if (!Number.isSafeInteger(decisionAt))
|
|
675
|
+
fail("invalid_decision_time");
|
|
676
|
+
if (!sameDecisionBinding(previous, input))
|
|
677
|
+
fail("decision_binding_mismatch");
|
|
678
|
+
if (previous.state === "denied" && input.decision === "deny")
|
|
679
|
+
return previous;
|
|
680
|
+
if (previous.state !== "proposed")
|
|
681
|
+
fail("decision_not_eligible");
|
|
682
|
+
if (decisionAt >= Date.parse(previous.expiresAt)) {
|
|
683
|
+
return cas(previous, { ...previous, state: "expired", updatedAt: timestamp() });
|
|
684
|
+
}
|
|
685
|
+
if (input.decision === "deny") {
|
|
686
|
+
return cas(previous, { ...previous, state: "denied", updatedAt: timestamp() });
|
|
687
|
+
}
|
|
688
|
+
if (!isNonEmpty(input.ownerId))
|
|
689
|
+
fail("invalid_owner");
|
|
690
|
+
options.hooks?.beforeClaimCas?.();
|
|
691
|
+
if ((input.decisionAt ?? now().getTime()) >= Date.parse(previous.expiresAt)) {
|
|
692
|
+
return cas(previous, { ...previous, state: "expired", updatedAt: timestamp() });
|
|
693
|
+
}
|
|
694
|
+
return cas(previous, { ...previous, state: "claimed", ownerId: input.ownerId, epoch: previous.epoch + 1, updatedAt: timestamp() });
|
|
695
|
+
});
|
|
696
|
+
},
|
|
697
|
+
expire(input) {
|
|
698
|
+
return observeExpire(() => {
|
|
699
|
+
const previous = requireRecord(input.approvalId);
|
|
700
|
+
if (previous.state === "expired")
|
|
701
|
+
return previous;
|
|
702
|
+
if ((previous.state !== "proposed" && previous.state !== "awaiting_prompt_binding")
|
|
703
|
+
|| now().getTime() < Date.parse(previous.expiresAt))
|
|
704
|
+
fail("expiry_not_eligible");
|
|
705
|
+
return cas(previous, { ...previous, state: "expired", updatedAt: timestamp() });
|
|
706
|
+
});
|
|
707
|
+
},
|
|
708
|
+
markAttempted(input) {
|
|
709
|
+
return observeMarkAttempted(() => {
|
|
710
|
+
const previous = requireRecord(input.approvalId);
|
|
711
|
+
if (previous.state !== "claimed" || previous.ownerId !== input.ownerId || previous.epoch !== input.epoch)
|
|
712
|
+
fail("attempt_not_eligible");
|
|
713
|
+
options.hooks?.beforeAttemptCas?.();
|
|
714
|
+
return cas(previous, { ...previous, state: "attempted", attemptedAt: timestamp(), updatedAt: timestamp() });
|
|
715
|
+
});
|
|
716
|
+
},
|
|
717
|
+
terminalizeBeforeAttempt(input) {
|
|
718
|
+
return observeTerminalizeBeforeAttempt(() => {
|
|
719
|
+
const previous = requireRecord(input.approvalId);
|
|
720
|
+
if (previous.state !== "claimed" || previous.ownerId !== input.ownerId || previous.epoch !== input.epoch
|
|
721
|
+
|| (input.state !== "drifted" && input.state !== "session_head_changed") || !isNonEmpty(input.reason)) {
|
|
722
|
+
fail("pre_attempt_terminalization_not_eligible");
|
|
723
|
+
}
|
|
724
|
+
return cas(previous, { ...previous, state: input.state, reason: input.reason, updatedAt: timestamp() });
|
|
725
|
+
});
|
|
726
|
+
},
|
|
727
|
+
abandonBeforeAttempt(input) {
|
|
728
|
+
return observeAbandonBeforeAttempt(() => {
|
|
729
|
+
const previous = requireRecord(input.approvalId);
|
|
730
|
+
if (previous.state === "abandoned_before_attempt" && previous.ownerId === input.ownerId
|
|
731
|
+
&& previous.epoch === input.epoch && previous.reason === input.reason)
|
|
732
|
+
return previous;
|
|
733
|
+
if (previous.state !== "claimed" || previous.ownerId !== input.ownerId || previous.epoch !== input.epoch
|
|
734
|
+
|| !isNonEmpty(input.reason))
|
|
735
|
+
fail("abandon_not_eligible");
|
|
736
|
+
return cas(previous, { ...previous, state: "abandoned_before_attempt", reason: input.reason, updatedAt: timestamp() });
|
|
737
|
+
});
|
|
738
|
+
},
|
|
739
|
+
complete(input) {
|
|
740
|
+
return observeComplete(() => {
|
|
741
|
+
const previous = requireRecord(input.approvalId);
|
|
742
|
+
if (ATTEMPT_TERMINALS.has(previous.state)) {
|
|
743
|
+
if (previous.state === input.state && previous.ownerId === input.ownerId && previous.epoch === input.epoch
|
|
744
|
+
&& previous.result === input.result)
|
|
745
|
+
return previous;
|
|
746
|
+
fail("completion_conflict");
|
|
747
|
+
}
|
|
748
|
+
if (previous.state !== "attempted" || previous.ownerId !== input.ownerId || previous.epoch !== input.epoch
|
|
749
|
+
|| !ATTEMPT_TERMINALS.has(input.state) || !isNonEmpty(input.result))
|
|
750
|
+
fail("completion_not_eligible");
|
|
751
|
+
return cas(previous, { ...previous, state: input.state, result: input.result, updatedAt: timestamp() });
|
|
752
|
+
});
|
|
753
|
+
},
|
|
754
|
+
listPreparing() {
|
|
755
|
+
return observeListPreparing(() => {
|
|
756
|
+
const rows = database.prepare("SELECT record_json FROM approval_actions WHERE state = ? ORDER BY approval_id")
|
|
757
|
+
.all("preparing");
|
|
758
|
+
return rows.map((row) => {
|
|
759
|
+
try {
|
|
760
|
+
return parseApprovalRecord(JSON.parse(row.record_json));
|
|
761
|
+
}
|
|
762
|
+
catch (error) {
|
|
763
|
+
if (error instanceof ApprovalStoreError)
|
|
764
|
+
throw error;
|
|
765
|
+
return fail("corrupt_record");
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
});
|
|
769
|
+
},
|
|
770
|
+
recoverPreparing(input) {
|
|
771
|
+
return observeRecoverPreparing(() => {
|
|
772
|
+
const previous = requireRecord(input.approvalId);
|
|
773
|
+
if (!isNonEmpty(input.reason))
|
|
774
|
+
fail("recovery_not_eligible");
|
|
775
|
+
if (previous.state === input.state && previous.ownerId === null && previous.epoch === 0
|
|
776
|
+
&& previous.attemptedAt === null && previous.reason === input.reason)
|
|
777
|
+
return previous;
|
|
778
|
+
if (previous.state !== "preparing")
|
|
779
|
+
fail("recovery_not_eligible");
|
|
780
|
+
return cas(previous, { ...previous, state: input.state, reason: input.reason, updatedAt: timestamp() });
|
|
781
|
+
});
|
|
782
|
+
},
|
|
783
|
+
claimContinuation(input) {
|
|
784
|
+
return observeClaimContinuation(() => {
|
|
785
|
+
if (!isNonEmpty(input.ownerId))
|
|
786
|
+
fail("invalid_continuation_owner");
|
|
787
|
+
const approval = requireRecord(input.approvalId);
|
|
788
|
+
if (!["succeeded", "failed", "denied", "expired", "drifted", "session_head_changed", "abandoned_before_attempt", "attempted_indeterminate"].includes(approval.state)) {
|
|
789
|
+
fail("continuation_not_eligible");
|
|
790
|
+
}
|
|
791
|
+
const ownerPid = input.ownerPid ?? process.pid;
|
|
792
|
+
const claimedAt = timestamp();
|
|
793
|
+
const inserted = database.prepare(`
|
|
794
|
+
INSERT OR IGNORE INTO approval_continuations
|
|
795
|
+
(approval_id, owner_id, owner_pid, epoch, state, claimed_at, materialized_at, attempted_at, continued_at)
|
|
796
|
+
VALUES (?, ?, ?, 1, 'claimed', ?, NULL, NULL, NULL)
|
|
797
|
+
`).run(input.approvalId, input.ownerId, ownerPid, claimedAt);
|
|
798
|
+
let row = readContinuationRow(input.approvalId);
|
|
799
|
+
let claimed = inserted.changes === 1;
|
|
800
|
+
let interruptedAfterAttempt = false;
|
|
801
|
+
if (!claimed && (row.state === "claimed" || row.state === "materialized") && !processIsAlive(row.owner_pid)) {
|
|
802
|
+
const reclaimed = database.prepare(`
|
|
803
|
+
UPDATE approval_continuations
|
|
804
|
+
SET owner_id = ?, owner_pid = ?, epoch = epoch + 1, claimed_at = ?
|
|
805
|
+
WHERE approval_id = ? AND owner_id = ? AND owner_pid = ? AND epoch = ? AND state = ?
|
|
806
|
+
`).run(input.ownerId, ownerPid, claimedAt, input.approvalId, row.owner_id, row.owner_pid, row.epoch, row.state);
|
|
807
|
+
claimed = reclaimed.changes === 1;
|
|
808
|
+
row = readContinuationRow(input.approvalId);
|
|
809
|
+
}
|
|
810
|
+
if (!claimed && row.state === "attempted" && !processIsAlive(row.owner_pid)) {
|
|
811
|
+
const terminalized = database.prepare(`
|
|
812
|
+
UPDATE approval_continuations
|
|
813
|
+
SET owner_id = ?, owner_pid = ?, epoch = epoch + 1, state = 'completed', claimed_at = ?, continued_at = ?
|
|
814
|
+
WHERE approval_id = ? AND owner_id = ? AND owner_pid = ? AND epoch = ? AND state = 'attempted'
|
|
815
|
+
`).run(input.ownerId, ownerPid, claimedAt, claimedAt, input.approvalId, row.owner_id, row.owner_pid, row.epoch);
|
|
816
|
+
interruptedAfterAttempt = terminalized.changes === 1;
|
|
817
|
+
row = readContinuationRow(input.approvalId);
|
|
818
|
+
}
|
|
819
|
+
const scenarioHandleDigest = acceptanceDigest(input.approvalId);
|
|
820
|
+
if (scenarioHandleDigest)
|
|
821
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.acceptance_continuation_transition", message: "acceptance-bound approval continuation transitioned", meta: { approvalId: approval.approvalId, scenarioHandleDigest, toolName: approval.toolName, argumentDigest: approval.argumentDigest, state: row.state } });
|
|
822
|
+
return {
|
|
823
|
+
claimed,
|
|
824
|
+
interruptedAfterAttempt,
|
|
825
|
+
record: combineContinuation(approval, row),
|
|
826
|
+
};
|
|
827
|
+
});
|
|
828
|
+
},
|
|
829
|
+
markContinuationMaterialized(input) {
|
|
830
|
+
return observeMaterializeContinuation(() => transitionContinuation(input, "claimed", "materialized", "materialized_at"));
|
|
831
|
+
},
|
|
832
|
+
markContinuationAttempted(input) {
|
|
833
|
+
return observeAttemptContinuation(() => transitionContinuation(input, "materialized", "attempted", "attempted_at"));
|
|
834
|
+
},
|
|
835
|
+
completeContinuation(input) {
|
|
836
|
+
return observeCompleteContinuation(() => {
|
|
837
|
+
const approval = requireRecord(input.approvalId);
|
|
838
|
+
const completedAt = timestamp();
|
|
839
|
+
const changed = database.prepare(`
|
|
840
|
+
UPDATE approval_continuations SET state = 'completed', continued_at = ?
|
|
841
|
+
WHERE approval_id = ? AND owner_id = ? AND epoch = ?
|
|
842
|
+
AND state IN ('materialized', 'attempted') AND continued_at IS NULL
|
|
843
|
+
`).run(completedAt, input.approvalId, input.ownerId, input.epoch);
|
|
844
|
+
if (changed.changes !== 1)
|
|
845
|
+
fail("continuation_completion_not_eligible");
|
|
846
|
+
const scenarioHandleDigest = acceptanceDigest(input.approvalId);
|
|
847
|
+
if (scenarioHandleDigest)
|
|
848
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "approval.acceptance_continuation_transition", message: "acceptance-bound approval continuation transitioned", meta: { approvalId: approval.approvalId, scenarioHandleDigest, toolName: approval.toolName, argumentDigest: approval.argumentDigest, state: "completed" } });
|
|
849
|
+
return combineContinuation(approval, readContinuationRow(input.approvalId));
|
|
850
|
+
});
|
|
851
|
+
},
|
|
852
|
+
read(approvalId) { return observeRead(() => rawRead(approvalId)); },
|
|
853
|
+
readByScenarioHandleDigest(scenarioHandleDigest) {
|
|
854
|
+
assertHash(scenarioHandleDigest, "invalid_scenario_handle_digest");
|
|
855
|
+
const rows = database.prepare(`
|
|
856
|
+
SELECT a.record_json
|
|
857
|
+
FROM approval_actions a
|
|
858
|
+
INNER JOIN approval_acceptance_scenarios s ON s.approval_id = a.approval_id
|
|
859
|
+
WHERE s.scenario_handle_digest = ?
|
|
860
|
+
ORDER BY a.approval_id
|
|
861
|
+
`).all(scenarioHandleDigest);
|
|
862
|
+
return rows.map((row) => parseApprovalRecord(JSON.parse(row.record_json)));
|
|
863
|
+
},
|
|
864
|
+
listTelegramIdentitySubjects() {
|
|
865
|
+
const subjects = new Set();
|
|
866
|
+
const add = (value) => {
|
|
867
|
+
if (/^tg_[A-Za-z0-9_-]{43}$/u.test(value))
|
|
868
|
+
subjects.add(value);
|
|
869
|
+
};
|
|
870
|
+
const rows = database.prepare("SELECT record_json FROM approval_actions ORDER BY approval_id")
|
|
871
|
+
.all();
|
|
872
|
+
for (const row of rows) {
|
|
873
|
+
const record = parseApprovalRecord(JSON.parse(row.record_json));
|
|
874
|
+
if (record.transport !== "telegram")
|
|
875
|
+
continue;
|
|
876
|
+
add(record.requesterId);
|
|
877
|
+
add(record.transportUserId);
|
|
878
|
+
add(record.transportChatId);
|
|
879
|
+
if (record.sessionKey.startsWith("telegram:"))
|
|
880
|
+
add(record.sessionKey.slice("telegram:".length));
|
|
881
|
+
for (const match of record.sessionPath.matchAll(/tg_[A-Za-z0-9_-]{43}/gu))
|
|
882
|
+
add(match[0]);
|
|
883
|
+
}
|
|
884
|
+
return [...subjects].sort();
|
|
885
|
+
},
|
|
886
|
+
migrateTelegramIdentity(input) {
|
|
887
|
+
if (!isNonEmpty(input.legacyUserId) || !isNonEmpty(input.legacyChatId) || !/^tg_[A-Za-z0-9_-]{43}$/u.test(input.subject)) {
|
|
888
|
+
fail("invalid_telegram_identity_migration");
|
|
889
|
+
}
|
|
890
|
+
const rows = database.prepare("SELECT approval_id, record_json FROM approval_actions ORDER BY approval_id")
|
|
891
|
+
.all();
|
|
892
|
+
const migrate = database.transaction(() => {
|
|
893
|
+
let migrated = 0;
|
|
894
|
+
for (const row of rows) {
|
|
895
|
+
const previous = parseApprovalRecord(JSON.parse(row.record_json));
|
|
896
|
+
if (previous.transport !== "telegram")
|
|
897
|
+
continue;
|
|
898
|
+
const next = {
|
|
899
|
+
...previous,
|
|
900
|
+
sessionKey: previous.sessionKey === `telegram:${input.legacyChatId}` ? `telegram:${input.subject}` : previous.sessionKey,
|
|
901
|
+
sessionPath: previous.sessionPath
|
|
902
|
+
.replace(`telegram-user:${input.legacyUserId}`, `telegram-user:${input.subject}`)
|
|
903
|
+
.replace(`telegram_${input.legacyChatId}.json`, `telegram_${input.subject}.json`),
|
|
904
|
+
requesterId: previous.requesterId === input.legacyUserId ? input.subject : previous.requesterId,
|
|
905
|
+
transportUserId: previous.transportUserId === input.legacyUserId ? input.subject : previous.transportUserId,
|
|
906
|
+
transportChatId: previous.transportChatId === input.legacyChatId ? input.subject : previous.transportChatId,
|
|
907
|
+
transportMessageId: previous.transportMessageId && !previous.transportMessageId.startsWith("tgm_")
|
|
908
|
+
? `tgm_${(0, node_crypto_1.createHmac)("sha256", input.subject).update(`message:${previous.transportMessageId}`, "utf8").digest("base64url")}`
|
|
909
|
+
: previous.transportMessageId,
|
|
910
|
+
};
|
|
911
|
+
const nextJson = JSON.stringify(parseApprovalRecord(next));
|
|
912
|
+
if (nextJson === row.record_json)
|
|
913
|
+
continue;
|
|
914
|
+
const changed = database.prepare("UPDATE approval_actions SET record_json = ? WHERE approval_id = ? AND record_json = ?")
|
|
915
|
+
.run(nextJson, row.approval_id, row.record_json);
|
|
916
|
+
if (changed.changes !== 1)
|
|
917
|
+
fail("telegram_identity_migration_conflict");
|
|
918
|
+
migrated += 1;
|
|
919
|
+
}
|
|
920
|
+
return migrated;
|
|
921
|
+
});
|
|
922
|
+
const migrated = migrate();
|
|
923
|
+
if (migrated > 0)
|
|
924
|
+
database.exec("VACUUM");
|
|
925
|
+
return migrated;
|
|
926
|
+
},
|
|
927
|
+
close() {
|
|
928
|
+
return observeClose(() => {
|
|
929
|
+
options.hooks?.beforeClose?.();
|
|
930
|
+
database.close();
|
|
931
|
+
});
|
|
932
|
+
},
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
function readApprovalsByScenarioHandleDigest(databasePath, scenarioHandleDigest) {
|
|
936
|
+
assertHash(scenarioHandleDigest, "invalid_scenario_handle_digest");
|
|
937
|
+
const database = new better_sqlite3_1.default(databasePath, { readonly: true, fileMustExist: true });
|
|
938
|
+
try {
|
|
939
|
+
const rows = database.prepare(`
|
|
940
|
+
SELECT a.record_json, c.owner_id, c.owner_pid, c.epoch AS continuation_epoch, c.state AS continuation_state,
|
|
941
|
+
c.claimed_at, c.materialized_at, c.attempted_at AS continuation_attempted_at, c.continued_at
|
|
942
|
+
FROM approval_actions a
|
|
943
|
+
INNER JOIN approval_acceptance_scenarios s ON s.approval_id = a.approval_id
|
|
944
|
+
LEFT JOIN approval_continuations c ON c.approval_id = a.approval_id
|
|
945
|
+
WHERE s.scenario_handle_digest = ?
|
|
946
|
+
ORDER BY a.approval_id
|
|
947
|
+
`).all(scenarioHandleDigest);
|
|
948
|
+
return rows.map((row) => ({
|
|
949
|
+
approval: parseApprovalRecord(JSON.parse(row.record_json)),
|
|
950
|
+
continuation: row.continuation_state === null ? null : {
|
|
951
|
+
continuationOwnerId: row.owner_id, continuationOwnerPid: row.owner_pid, continuationEpoch: row.continuation_epoch,
|
|
952
|
+
continuationState: row.continuation_state, continuationClaimedAt: row.claimed_at, continuationMaterializedAt: row.materialized_at,
|
|
953
|
+
continuationAttemptedAt: row.continuation_attempted_at, continuedAt: row.continued_at,
|
|
954
|
+
},
|
|
955
|
+
}));
|
|
956
|
+
}
|
|
957
|
+
finally {
|
|
958
|
+
database.close();
|
|
959
|
+
}
|
|
960
|
+
}
|