@moretea-labs/forge 1.7.2 → 1.8.1
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/AGENTS.md +121 -62
- package/CHANGELOG.md +40 -0
- package/CLAUDE.md +57 -62
- package/CONTRIBUTING.md +3 -2
- package/README.md +2 -2
- package/SKILL.md +0 -1
- package/THIRD_PARTY_NOTICES.md +5 -2
- package/adapters/browser/index.ts +2 -0
- package/adapters/chatgpt/browser-delivery-host.ts +77 -0
- package/adapters/chatgpt/browser-delivery-runtime.ts +1256 -0
- package/adapters/chatgpt/controller-binding-store.ts +134 -0
- package/adapters/chatgpt/controller-round-host.ts +68 -0
- package/adapters/chatgpt/controller-round-settlement-store.ts +99 -0
- package/adapters/chatgpt/provider-delivery.ts +340 -0
- package/adapters/chatgpt/work-conversation-binding-store.ts +218 -0
- package/adapters/chatgpt/wsl-bridge-delivery-host.ts +63 -0
- package/adapters/computer/chatgpt-extension-target.ts +463 -0
- package/adapters/computer/chatgpt-target-router.ts +103 -0
- package/adapters/computer/chrome-extension/background.js +385 -0
- package/adapters/computer/chrome-extension/content.js +378 -0
- package/adapters/computer/chrome-extension/core.js +24 -0
- package/adapters/computer/chrome-extension/manifest.json +30 -0
- package/adapters/computer/desktop-operator-contract.ts +7 -0
- package/adapters/computer/desktop-operator-discovery.ts +181 -0
- package/adapters/computer/desktop-operator-negotiation.ts +174 -0
- package/adapters/computer/desktop-operator-provider.ts +312 -0
- package/adapters/computer/index.ts +1 -0
- package/adapters/computer/interaction-target-authority.ts +1068 -0
- package/adapters/controller-process/binding-store.ts +34 -0
- package/adapters/controller-process/controller-host.ts +26 -0
- package/adapters/mcp/access-mode.ts +132 -0
- package/adapters/mcp/audit.ts +32 -0
- package/adapters/mcp/auth.ts +406 -0
- package/adapters/mcp/instructions.ts +37 -0
- package/adapters/mcp/legacy-context.ts +18 -0
- package/adapters/mcp/multi-repository.ts +421 -0
- package/adapters/mcp/oauth.ts +464 -0
- package/adapters/mcp/paths.ts +143 -0
- package/adapters/mcp/policy.ts +232 -0
- package/adapters/mcp/proxy-env.ts +62 -0
- package/adapters/mcp/readiness-projection.ts +24 -0
- package/adapters/mcp/redaction.ts +21 -0
- package/adapters/mcp/repo.ts +24 -0
- package/adapters/mcp/runtime-gateway/artifact-adapter.ts +52 -0
- package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
- package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
- package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
- package/adapters/mcp/runtime-gateway/context-adapter.ts +1167 -0
- package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +206 -0
- package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +130 -0
- package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
- package/adapters/mcp/runtime-gateway/execution-control-adapter.ts +28 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +173 -0
- package/adapters/mcp/runtime-gateway/filesystem-adapter.ts +38 -0
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +412 -0
- package/adapters/mcp/runtime-gateway/legacy-ios-tool-adapter.ts +105 -0
- package/adapters/mcp/runtime-gateway/maintenance-adapter.ts +44 -0
- package/adapters/mcp/runtime-gateway/model-adapter.ts +63 -0
- package/adapters/mcp/runtime-gateway/persisted-check-process.ts +3 -0
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +380 -0
- package/adapters/mcp/runtime-gateway/process-tools.ts +457 -0
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +88 -0
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +285 -0
- package/adapters/mcp/runtime-gateway/recovery-client-adapter.ts +70 -0
- package/adapters/mcp/runtime-gateway/recovery-tool-contract.ts +99 -0
- package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +79 -0
- package/adapters/mcp/runtime-gateway/result-adapter.ts +114 -0
- package/adapters/mcp/runtime-gateway/router.ts +242 -0
- package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1200 -0
- package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +574 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-shared.ts +27 -0
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +78 -0
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +187 -0
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +45 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +962 -0
- package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +325 -0
- package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
- package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
- package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
- package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
- package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
- package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
- package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
- package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
- package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
- package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +1 -0
- package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
- package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
- package/adapters/mcp/server.ts +1092 -0
- package/adapters/mcp/setup.ts +789 -0
- package/adapters/mcp/tool-capability-cache.ts +87 -0
- package/adapters/mcp/tool-mapping/access-tools.ts +387 -0
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +5139 -0
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +145 -0
- package/adapters/mcp/tool-mapping/repository-tools.ts +1682 -0
- package/adapters/mcp/tool-mapping/tools.ts +9 -0
- package/adapters/mcp/tool-mapping/umbrella-tools.ts +117 -0
- package/adapters/mcp/toolset-names.ts +79 -0
- package/adapters/mcp/toolset-selection.ts +41 -0
- package/adapters/mcp/toolset.ts +337 -0
- package/adapters/mcp/transports/http-observation.ts +365 -0
- package/adapters/mcp/transports/http.ts +933 -0
- package/adapters/mcp/transports/oauth-http.ts +322 -0
- package/adapters/mcp/transports/session-registry.ts +519 -0
- package/adapters/mcp/transports/stdio.ts +8 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +223 -0
- package/adapters/mcp/types.ts +41 -0
- package/assets/AGENTS.md +2 -16
- package/assets/CLAUDE.md +2 -16
- package/assets/hooks/AGENTS.md +3 -14
- package/assets/hooks/CLAUDE.md +3 -14
- package/assets/hooks/hook-input.sh +9 -2
- package/assets/hooks/lib/workflow-state.sh +28 -10
- package/assets/hooks/prompt-guard.sh +63 -37
- package/assets/hooks/security-sentinel.sh +2 -1
- package/assets/hooks/session-start-context.sh +7 -5
- package/assets/hooks/stop-orchestrator.sh +13 -3
- package/assets/initializer-question-pack.v4.json +11 -7
- package/assets/partials/05-workflow.partial.md +18 -73
- package/assets/partials/07-footer.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +1 -2
- package/assets/partials-agents/04-task-protocol.partial.md +14 -59
- package/assets/partials-agents/06-quality-safety.partial.md +11 -16
- package/assets/partials-agents/08-deep-docs.partial.md +1 -2
- package/assets/plan-map.json +11 -11
- package/assets/plugin-registry.v1.json +11 -3
- package/assets/plugin-trust-policy.v1.json +6 -0
- package/assets/recovery/ForgeRecovery.ps1 +100 -0
- package/assets/recovery/forge-wsl-rescue +271 -0
- package/assets/reference-configs/agentic-development-flow.md +25 -0
- package/assets/reference-configs/development-protocol.md +11 -15
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/global-working-rules.md +28 -1
- package/assets/reference-configs/harness-overview.md +22 -112
- package/assets/reference-configs/hook-operations.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +2 -2
- package/assets/skill-version.json +2 -2
- package/assets/templates/helpers/architecture-event.ts +3 -34
- package/assets/templates/helpers/architecture-queue.sh +61 -10
- package/assets/templates/helpers/archive-workflow.sh +90 -180
- package/assets/templates/helpers/capability-config.ts +8 -11
- package/assets/templates/helpers/capability-resolver.ts +37 -19
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-architecture-sync.sh +1 -9
- package/assets/templates/helpers/check-task-sync.sh +82 -11
- package/assets/templates/helpers/check-task-workflow.sh +1 -3
- package/assets/templates/helpers/context-contract-sync.sh +1 -12
- package/assets/templates/helpers/contract-worktree.sh +26 -24
- package/assets/templates/helpers/ensure-task-workflow.sh +6 -8
- package/assets/templates/helpers/inspect-project-state.ts +1 -1
- package/assets/templates/helpers/migrate-project-template.sh +1 -1
- package/assets/templates/helpers/migrate-workflow-docs.ts +53 -239
- package/assets/templates/helpers/new-plan.sh +2 -2
- package/assets/templates/helpers/plan-to-todo.sh +3 -31
- package/assets/templates/helpers/sprint-backlog.sh +1 -1
- package/assets/templates/helpers/switch-plan.sh +1 -1
- package/assets/templates/helpers/workflow-contract.ts +1 -0
- package/assets/workflow-contract.v1.json +63 -171
- package/assets/workflows/xiaohongshu/xiaohongshu.collect-metrics.v1.draft.json +118 -0
- package/assets/workflows/xiaohongshu/xiaohongshu.publish-image-note.v1.draft.json +316 -0
- package/assets/workflows/xiaohongshu/xiaohongshu.publish-long-text.v1.draft.json +324 -0
- package/docs/architecture/CURRENT.md +233 -28
- package/docs/architecture/EVOLUTION.md +13 -0
- package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +2 -1
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
- package/docs/architecture/decisions/20260831-independent-windows-wsl-host-rescue.md +59 -0
- package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +120 -0
- package/docs/architecture/decisions/20260904-repository-runtime-data-boundary.md +42 -0
- package/docs/architecture/decisions/20260907-assistant-learning-loop.md +37 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +311 -0
- package/docs/architecture/decisions/20260907-maintenance-diagnosis-bounded-read.md +39 -0
- package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
- package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
- package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
- package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
- package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
- package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
- package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
- package/docs/architecture/domains/verification.md +8 -0
- package/docs/architecture/domains/workflow-engine.md +7 -1
- package/docs/architecture/index.md +3 -3
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +19 -8
- package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +124 -0
- package/docs/forge-chatgpt-mcp-setup.md +5 -3
- package/docs/forge-plugin-management.md +20 -4
- package/docs/forge-runtime-self-healing-loop.md +2 -0
- package/docs/operations/benchmark-cross-version-freeze.md +38 -0
- package/docs/operations/controller-browser-plugin.md +3 -1
- package/docs/operations/controller-performance-and-502.md +17 -0
- package/docs/operations/controller-reliability-runbook.md +2 -2
- package/docs/operations/features.md +1 -1
- package/docs/operations/features.zh-CN.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +2 -0
- package/docs/operations/platform-support.md +16 -8
- package/docs/operations/platform-support.zh-CN.md +2 -2
- package/docs/operations/releasing.md +2 -0
- package/docs/operations/standalone-disaster-recovery.md +38 -5
- package/docs/operations/uu-remote-rescue.md +41 -0
- package/docs/operations/windows-wsl-host-rescue.md +133 -0
- package/docs/public-usage-guide.md +1 -1
- package/docs/public-usage-guide.zh-CN.md +1 -1
- package/docs/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/tutorials/02-connect-chatgpt.md +4 -4
- package/docs/tutorials/02-connect-chatgpt.zh-CN.md +4 -4
- package/docs/wiki/Implementation.md +1 -1
- package/package.json +46 -26
- package/packages/kernel/cognition/api/index.ts +6 -0
- package/packages/kernel/cognition/application/activation-service.ts +451 -0
- package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
- package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
- package/packages/kernel/cognition/application/memory-service.ts +64 -0
- package/packages/kernel/cognition/domain/learning.ts +106 -0
- package/packages/kernel/cognition/domain/memory.ts +254 -0
- package/packages/kernel/controller/api/index.ts +3 -0
- package/packages/kernel/controller/application/continuation-service.ts +281 -0
- package/packages/kernel/controller/application/controller-round-service.ts +41 -0
- package/packages/kernel/controller/application/controller-service.ts +30 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +529 -0
- package/packages/kernel/controller/domain/controller-round.ts +110 -0
- package/packages/kernel/controller/domain/execution-quality.ts +135 -0
- package/packages/kernel/controller/domain/types.ts +56 -0
- package/packages/kernel/controller/index.ts +1 -0
- package/packages/kernel/controller/infrastructure/controller-binding-store.ts +84 -0
- package/packages/kernel/controller/infrastructure/controller-round-store.ts +1970 -0
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +804 -0
- package/packages/kernel/controller/ports/controller-host.ts +18 -0
- package/packages/kernel/goal/api/index.ts +1 -0
- package/packages/kernel/goal/domain/types.ts +40 -0
- package/packages/kernel/goal/index.ts +1 -0
- package/packages/kernel/identity/api/index.ts +15 -0
- package/packages/kernel/identity/application/identity-service.ts +67 -0
- package/packages/kernel/identity/domain/activity-projection.ts +43 -0
- package/packages/kernel/identity/domain/capability-broker.ts +60 -0
- package/packages/kernel/identity/domain/grant.ts +72 -0
- package/packages/kernel/identity/domain/owned-resource.ts +116 -0
- package/packages/kernel/identity/domain/scope.ts +63 -0
- package/packages/kernel/identity/domain/semantic-sync.ts +81 -0
- package/packages/kernel/identity/domain/types.ts +44 -0
- package/packages/kernel/identity/domain/user-request.ts +93 -0
- package/packages/kernel/identity/domain/workspace.ts +56 -0
- package/packages/kernel/identity/index.ts +1 -0
- package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
- package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
- package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
- package/packages/kernel/identity/infrastructure/identity-store.ts +75 -0
- package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
- package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
- package/packages/kernel/memory/api/index.ts +5 -0
- package/packages/kernel/memory/application/experience-service.ts +118 -0
- package/packages/kernel/memory/application/outcome-service.ts +77 -0
- package/packages/kernel/memory/domain/experience.ts +103 -0
- package/packages/kernel/memory/domain/operational-prior.ts +92 -0
- package/packages/kernel/memory/index.ts +1 -0
- package/packages/kernel/scheduler/api/index.ts +4 -0
- package/packages/kernel/scheduler/application/eligibility.ts +252 -0
- package/packages/kernel/scheduler/application/schedule-service.ts +27 -0
- package/packages/kernel/scheduler/application/settlement.ts +182 -0
- package/packages/kernel/scheduler/domain/schedule.ts +236 -0
- package/packages/kernel/scheduler/index.ts +1 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +805 -0
- package/packages/kernel/work/api/index.ts +16 -0
- package/packages/kernel/work/application/work-service.ts +123 -0
- package/packages/kernel/work/domain/check-receipt.ts +43 -0
- package/packages/kernel/work/domain/context-closure-receipt.ts +32 -0
- package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
- package/packages/kernel/work/domain/engineering-contracts.ts +157 -0
- package/packages/kernel/work/domain/engineering-design.ts +286 -0
- package/packages/kernel/work/domain/engineering-profile.ts +238 -0
- package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +247 -0
- package/packages/kernel/work/domain/execution-snapshot.ts +2 -0
- package/packages/kernel/work/domain/implementation-review.ts +193 -0
- package/packages/kernel/work/domain/objective-graph.ts +119 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +224 -0
- package/packages/kernel/work/domain/repository-completion-receipt.ts +73 -0
- package/{src/runtime/control-plane/facade/work-state-machine.ts → packages/kernel/work/domain/state-machine.ts} +37 -66
- package/packages/kernel/work/domain/types.ts +534 -0
- package/packages/kernel/work/index.ts +1 -0
- package/packages/kernel/work/infrastructure/work-contract-store.ts +1967 -0
- package/packages/kernel/work/ports/work-contract-store.ts +21 -0
- package/packages/plugin-runtime/browser/index.ts +3 -0
- package/packages/plugin-runtime/browser/provider-registry.ts +110 -0
- package/packages/plugin-runtime/browser/runtime-contract.ts +150 -0
- package/packages/plugin-runtime/browser/session-authority.ts +62 -0
- package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
- package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
- package/packages/plugin-runtime/computer/index.ts +8 -0
- package/packages/plugin-runtime/computer/provider-error.ts +26 -0
- package/packages/plugin-runtime/computer/provider-registration.ts +52 -0
- package/packages/plugin-runtime/computer/provider-registry.ts +63 -0
- package/packages/plugin-runtime/computer/provider.ts +19 -0
- package/packages/plugin-runtime/computer/target-authority.ts +215 -0
- package/packages/plugin-runtime/computer/target-persistence.ts +54 -0
- package/packages/plugin-runtime/external/index.ts +1 -0
- package/packages/plugin-runtime/external/unix-jsonl-transport.ts +581 -0
- package/packages/plugin-runtime/index.ts +3 -0
- package/packages/protocols/browser/index.ts +1 -0
- package/packages/protocols/browser/session.ts +98 -0
- package/packages/protocols/computer/contract.ts +225 -0
- package/packages/protocols/computer/index.ts +1 -0
- package/packages/protocols/failure/contract.ts +158 -0
- package/packages/protocols/failure/index.ts +1 -0
- package/packages/protocols/handoff/index.ts +1 -0
- package/packages/protocols/handoff/status.ts +22 -0
- package/packages/protocols/mcp/execution-context.ts +11 -0
- package/packages/protocols/mcp/index.ts +2 -0
- package/packages/protocols/mcp/tool-contract.ts +42 -0
- package/packages/workflow-runtime/api/index.ts +2 -0
- package/packages/workflow-runtime/application/interpreter.ts +342 -0
- package/packages/workflow-runtime/domain/workflow-asset.ts +223 -0
- package/packages/workflow-runtime/index.ts +1 -0
- package/scripts/activate-source-baseline.ts +7 -9
- package/scripts/assemble-template.ts +1 -1
- package/scripts/bootstrap-runtime-maintenance-recovery.sh +4 -1
- package/scripts/canary-chatgpt-provider-delivery.ts +97 -0
- package/scripts/canary-controller-semantic-wait.ts +183 -0
- package/scripts/canary-global-hook.sh +2 -2
- package/scripts/check-mcp-compatibility.ts +85 -7
- package/scripts/check-platform-support.mjs +28 -2
- package/scripts/check-public-docs.sh +1 -1
- package/scripts/check-repository-hygiene.mjs +92 -0
- package/scripts/check-runtime-architecture.mjs +1643 -127
- package/scripts/check-source-duplication.mjs +9 -1
- package/scripts/controller-ngrok-rotation.sh +5 -4
- package/scripts/create-project-dirs.sh +10 -74
- package/scripts/forge-local-recovery-helper.mjs +282 -0
- package/scripts/forge-uu-remote-rescue-helper.d.mts +31 -0
- package/scripts/forge-uu-remote-rescue-helper.mjs +409 -0
- package/scripts/forge-windows-host-recovery-helper.mjs +136 -0
- package/scripts/hook-shim.sh +2 -2
- package/scripts/init-project.sh +12 -70
- package/scripts/install-desktop-operator-registration.ts +4 -2
- package/scripts/install-independent-windows-wsl-recovery.ts +125 -0
- package/scripts/install-standalone-recovery.ts +122 -10
- package/scripts/install-uu-remote-rescue-registration.ts +74 -0
- package/scripts/install-windows-host-recovery-registration.ts +22 -0
- package/scripts/lib/controller-home-env.sh +6 -3
- package/scripts/lib/project-init-lib.sh +42 -582
- package/scripts/migrate-chatgpt-automation-schedules.ts +2 -2
- package/scripts/migrate-windows-wsl-controller-home.ts +306 -0
- package/scripts/open-source-audit-allowlist.txt +11 -1
- package/scripts/portability-bindings.mjs +70 -0
- package/scripts/run-bounded-command.mjs +60 -0
- package/scripts/run-bun-test-file.ts +22 -6
- package/scripts/run-governed-gate.ts +4 -2
- package/scripts/run-mobile-monitor-bridge.ts +0 -1
- package/scripts/smoke-control-plane-failure-domain.ts +94 -0
- package/scripts/smoke-mcp-http-runtime.ts +6 -1
- package/scripts/smoke-runtime-recovery.ts +13 -11
- package/scripts/smoke-schedule-engine.ts +24 -16
- package/scripts/smoke-unattended-transport-recovery.ts +223 -0
- package/scripts/smoke-user-request-continuation-restart.ts +232 -0
- package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
- package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
- package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
- package/scripts/smoke-workflow-supervisor.ts +103 -0
- package/scripts/test-governance.ts +51 -2
- package/scripts/verify-forge-runtime.sh +2 -1
- package/src/cli/agent-jobs/executor-health.ts +11 -34
- package/src/cli/agent-jobs/integration.ts +18 -49
- package/src/cli/agent-jobs/job-manager.ts +17 -4
- package/src/cli/chatgpt-browser/bind-server.ts +2 -1
- package/src/cli/chatgpt-browser/binding.ts +20 -10
- package/src/cli/chatgpt-browser/bridge-extension.ts +75 -0
- package/src/cli/chatgpt-browser/bridge-provider.ts +376 -11
- package/src/cli/chatgpt-browser/engine.ts +10 -11
- package/src/cli/chatgpt-browser/native-provider.ts +24 -83
- package/src/cli/chatgpt-browser/oracle-provider.ts +5 -3
- package/src/cli/chatgpt-browser/types.ts +1 -0
- package/src/cli/commands/bootstrap-control.ts +334 -0
- package/src/cli/commands/brain-assistant.ts +52 -0
- package/src/cli/commands/brain.ts +191 -40
- package/src/cli/commands/chatgpt.ts +32 -67
- package/src/cli/commands/computer.ts +437 -0
- package/src/cli/commands/doctor.ts +18 -1
- package/src/cli/commands/init-hook.ts +71 -61
- package/src/cli/commands/init.ts +3 -1
- package/src/cli/commands/mcp.ts +16 -10
- package/src/cli/commands/plugin.ts +38 -12
- package/src/cli/commands/recovery.ts +507 -80
- package/src/cli/commands/runtime.ts +12 -7
- package/src/cli/commands/setup-profile.ts +97 -39
- package/src/cli/commands/status.ts +2 -1
- package/src/cli/controller/check-runner.ts +500 -100
- package/src/cli/controller/completion-backlog.ts +3 -3
- package/src/cli/controller/completion-orchestrator.ts +4 -43
- package/src/cli/controller/completion-target.ts +3 -72
- package/src/cli/controller/context/source-materializer.ts +81 -100
- package/src/cli/controller/context/types.ts +7 -1
- package/src/cli/controller/context-pack.ts +28 -6
- package/src/cli/controller/execution-completion.ts +4 -7
- package/src/cli/controller/execution-policy.ts +36 -153
- package/src/cli/controller/governance.ts +2 -3
- package/src/cli/controller/issue-store.ts +4 -99
- package/src/cli/controller/launch-agents.ts +59 -18
- package/src/cli/controller/operational-plan.ts +24 -51
- package/src/cli/controller/runtime-config.ts +5 -1
- package/src/cli/controller/stuck-state-migration.ts +2 -3
- package/src/cli/controller/systemd-user.ts +148 -0
- package/src/cli/controller/types.ts +10 -70
- package/src/cli/controller/worklog.ts +67 -13
- package/src/cli/editing/edit-operation-contract.ts +92 -0
- package/src/cli/editing/edit-session.ts +290 -20
- package/src/cli/github/plugin.ts +17 -12
- package/src/cli/hook/route-registry.ts +3 -5
- package/src/cli/hook/runtime.ts +49 -3
- package/src/cli/index.ts +3 -0
- package/src/cli/local-bridge/connector-freshness.ts +2 -2
- package/src/cli/local-bridge/console-automations.ts +20 -15
- package/src/cli/local-bridge/console-view-models.ts +3 -12
- package/src/cli/local-bridge/facade-api.ts +105 -205
- package/src/cli/local-bridge/job-store.ts +1 -1
- package/src/cli/local-bridge/server.ts +48 -174
- package/src/cli/local-bridge/types.ts +0 -1
- package/src/cli/mcp/access-mode.ts +2 -132
- package/src/cli/mcp/access-tools.ts +2 -387
- package/src/cli/mcp/audit.ts +2 -32
- package/src/cli/mcp/auth.ts +2 -404
- package/src/cli/mcp/instructions.ts +2 -34
- package/src/cli/mcp/legacy-context.ts +2 -16
- package/src/cli/mcp/legacy-tool-service.ts +2 -5308
- package/src/cli/mcp/multi-repository.ts +2 -436
- package/src/cli/mcp/oauth-client-retirement.ts +74 -0
- package/src/cli/mcp/oauth.ts +2 -375
- package/src/cli/mcp/openai-secure-tunnel.ts +2 -0
- package/src/cli/mcp/paths.ts +2 -140
- package/src/cli/mcp/policy.ts +2 -232
- package/src/cli/mcp/post-finalize-work-attribution.ts +2 -150
- package/src/cli/mcp/proxy-env.ts +2 -62
- package/src/cli/mcp/readiness-projection.ts +2 -24
- package/src/cli/mcp/redaction.ts +2 -21
- package/src/cli/mcp/repo.ts +2 -24
- package/src/cli/mcp/repository-tools.ts +2 -1613
- package/src/cli/mcp/server.ts +2 -951
- package/src/cli/mcp/setup.ts +2 -737
- package/src/cli/mcp/tool-capability-cache.ts +2 -87
- package/src/cli/mcp/tool-contract.ts +2 -14
- package/src/cli/mcp/tools.ts +2 -9
- package/src/cli/mcp/toolset-names.ts +2 -70
- package/src/cli/mcp/toolset-selection.ts +2 -41
- package/src/cli/mcp/toolset.ts +2 -336
- package/src/cli/mcp/transports/AGENTS.md +1 -10
- package/src/cli/mcp/transports/CLAUDE.md +1 -10
- package/src/cli/mcp/transports/http.ts +2 -1414
- package/src/cli/mcp/transports/session-registry.ts +2 -490
- package/src/cli/mcp/transports/stdio.ts +2 -8
- package/src/cli/mcp/types.ts +2 -41
- package/src/cli/mcp/umbrella-tools.ts +2 -117
- package/src/cli/repositories/command-executor.ts +91 -39
- package/src/cli/repositories/command-scope.ts +139 -4
- package/src/cli/repositories/controller-home.ts +167 -1
- package/src/cli/repositories/ephemeral-workspace.ts +20 -30
- package/src/cli/repositories/git-command-executor.ts +2 -2
- package/src/cli/repositories/identity.ts +13 -0
- package/src/cli/repositories/registry.ts +145 -60
- package/src/cli/repositories/repository-snapshot.ts +53 -7
- package/src/cli/repositories/runtime-storage.ts +27 -2
- package/src/cli/repositories/safe-patch.ts +34 -38
- package/src/cli/repositories/selected-path-actions.ts +22 -2
- package/src/cli/repositories/structured-git.ts +167 -27
- package/src/cli/repository/session-cache.ts +92 -6
- package/src/cli/runtime/helper-runner.ts +7 -0
- package/src/cli/runtime-invocation.ts +8 -1
- package/src/cli/tools/codegraph.ts +44 -25
- package/src/core/adoption/manifest-templates.ts +1 -1
- package/src/core/adoption/plan.ts +3 -26
- package/src/core/adoption/workflow-contract-plan.ts +17 -9
- package/src/effects/process-runner.ts +8 -14
- package/src/runtime/context/assistant-context.ts +167 -0
- package/src/runtime/context/assistant-work-context.ts +209 -0
- package/src/runtime/context/automatic-learning.ts +565 -0
- package/src/runtime/context/codegraph-cache-boundary.ts +255 -0
- package/src/runtime/context/codegraph-read-provider.ts +55 -22
- package/src/runtime/context/codegraph-sidecar.cjs +8 -1
- package/src/runtime/context/cognitive-attention.ts +173 -0
- package/src/runtime/context/cognitive-skill-canary.ts +158 -0
- package/src/runtime/context/context-closure.ts +305 -0
- package/src/runtime/context/context-pack-process.ts +103 -0
- package/src/runtime/context/context-plane.ts +203 -0
- package/src/runtime/context/direct-controller-learning.ts +298 -0
- package/src/runtime/context/project-engineering-contract.ts +60 -0
- package/src/runtime/context/semantic-navigation-contract.ts +9 -0
- package/src/runtime/context/semantic-navigation.ts +6 -34
- package/src/runtime/context/typescript-navigation-process.ts +145 -0
- package/src/runtime/context/typescript-navigation.ts +89 -3
- package/src/runtime/control-plane/bootstrap/capability-provider.ts +74 -0
- package/src/runtime/control-plane/bootstrap/control-api.ts +57 -0
- package/src/runtime/control-plane/bootstrap/index.ts +5 -0
- package/src/runtime/control-plane/bootstrap/state-machine.ts +141 -0
- package/src/runtime/control-plane/bootstrap/store.ts +21 -0
- package/src/runtime/control-plane/bootstrap/types.ts +87 -0
- package/src/runtime/control-plane/cleanup-artifact-retention.ts +531 -0
- package/src/runtime/control-plane/codegraph-cache-retention.ts +164 -0
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +282 -0
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +380 -0
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +113 -16
- package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
- package/src/runtime/control-plane/execution/implementation-review-content.ts +95 -0
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
- package/src/runtime/control-plane/execution/retained-work-resume.ts +439 -102
- package/src/runtime/control-plane/execution/session-store.ts +31 -1
- package/src/runtime/control-plane/execution/validation.ts +34 -11
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +87 -0
- package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +31 -44
- package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +46 -53
- package/src/runtime/control-plane/execution/work-execution-support.ts +85 -164
- package/src/runtime/control-plane/execution/work-handle-authority.ts +349 -73
- package/src/runtime/control-plane/execution/work-handle-store.ts +55 -2
- package/src/runtime/control-plane/execution/work-head-settlement.ts +108 -0
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +173 -28
- package/src/runtime/control-plane/execution/work-operation-service.ts +92 -40
- package/src/runtime/control-plane/execution/work-preparation-service.ts +145 -269
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
- package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +543 -225
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +59 -45
- package/src/runtime/control-plane/execution/work-verification-context.ts +1 -1
- package/src/runtime/control-plane/execution/work-verification-service.ts +662 -52
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +205 -16
- package/src/runtime/control-plane/facade/capability-registry.ts +380 -44
- package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
- package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
- package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +2 -488
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +6 -22
- package/src/runtime/control-plane/facade/goal-workloop.ts +565 -1202
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +145 -0
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +266 -52
- package/src/runtime/control-plane/facade/index.ts +4 -3
- package/src/runtime/control-plane/facade/operation-digest.ts +34 -73
- package/src/runtime/control-plane/facade/plan-contract-store.ts +671 -245
- package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
- package/src/runtime/control-plane/facade/repository-work-admission.ts +31 -23
- package/src/runtime/control-plane/facade/requirement-authority.ts +121 -0
- package/src/runtime/control-plane/facade/requirement-board.ts +9 -4
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +85 -0
- package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
- package/src/runtime/control-plane/facade/semantic-admission.ts +8 -16
- package/src/runtime/control-plane/facade/suggested-actions.ts +15 -15
- package/src/runtime/control-plane/facade/types.ts +218 -620
- package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
- package/src/runtime/control-plane/facade/work-contract-store.ts +2 -1043
- package/src/runtime/control-plane/generated-cache-retention.ts +336 -19
- package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +13 -2
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +274 -84
- package/src/runtime/control-plane/global-scheduler/periodic-cleanup-entry.ts +55 -0
- package/src/runtime/control-plane/global-scheduler/periodic-cleanup-process.ts +98 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -2
- package/src/runtime/control-plane/global-scheduler/scheduler-worker-entry.ts +10 -0
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +227 -109
- package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +18 -6
- package/src/runtime/control-plane/governance/access-policy.ts +19 -2
- package/src/runtime/control-plane/governance/authorization.ts +20 -3
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +160 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +2 -177
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +139 -670
- package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +25 -6
- package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -194
- package/src/runtime/control-plane/lifecycle-retention-metrics.ts +60 -0
- package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +302 -0
- package/src/runtime/control-plane/persistence/operational-prior-store.ts +348 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +230 -80
- package/src/runtime/control-plane/persistence/sqlite-store.ts +654 -78
- package/src/runtime/control-plane/persistence/workflow-content-store.ts +98 -0
- package/src/runtime/control-plane/persistence/workflow-registry-store.ts +186 -0
- package/src/runtime/control-plane/persistence/workflow-run-store.ts +123 -0
- package/src/runtime/control-plane/release-retention.ts +154 -26
- package/src/runtime/control-plane/repository-namespace-retention.ts +208 -0
- package/src/runtime/control-plane/runtime-cleanup.ts +844 -38
- package/src/runtime/control-plane/runtime-generation.ts +6 -0
- package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +479 -0
- package/src/runtime/control-plane/workspace/workspace-store.ts +249 -0
- package/src/runtime/diagnostics/incident-repair.ts +573 -0
- package/src/runtime/diagnostics/mcp-timing.ts +239 -6
- package/src/runtime/diagnostics/performance.ts +6 -14
- package/src/runtime/diagnostics/read-only-tool.ts +1 -1
- package/src/runtime/evidence/artifact-store.ts +216 -35
- package/src/runtime/evidence/evidence-store.ts +112 -8
- package/src/runtime/evidence/operational-shadow.ts +38 -0
- package/src/runtime/evidence/output-handle-index.ts +225 -0
- package/src/runtime/evidence/process-check-receipt.ts +5 -43
- package/src/runtime/evidence/result-store.ts +158 -44
- package/src/runtime/evidence/sensitive-output.ts +4 -4
- package/src/runtime/execution/jobs/receipt-recovery.ts +1 -1
- package/src/runtime/execution/jobs/store.ts +124 -6
- package/src/runtime/execution/managed-workspace.ts +112 -5
- package/src/runtime/execution/process-runtime/canary.ts +19 -5
- package/src/runtime/execution/process-runtime/check-classification.ts +48 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +24 -10
- package/src/runtime/execution/process-runtime/check-receipt.ts +1 -1
- package/src/runtime/execution/process-runtime/check-result-retention.ts +132 -0
- package/src/runtime/execution/process-runtime/check-result.ts +177 -2
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +58 -9
- package/src/runtime/execution/process-runtime/check-storage.ts +187 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +117 -114
- package/src/runtime/execution/process-runtime/gc.ts +15 -2
- package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
- package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
- package/src/runtime/execution/process-runtime/index.ts +4 -0
- package/src/runtime/execution/process-runtime/interactive-admission.ts +2 -1
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +283 -73
- package/src/runtime/execution/process-runtime/persisted-check.ts +130 -23
- package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
- package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
- package/src/runtime/execution/process-runtime/resource-claims.ts +125 -64
- package/src/runtime/execution/process-runtime/runtime.ts +167 -17
- package/src/runtime/execution/process-runtime/store.ts +30 -2
- package/src/runtime/execution/process-runtime/types.ts +27 -0
- package/src/runtime/execution/workers/executor.ts +18 -19
- package/src/runtime/execution/workers/worker-entry.ts +1 -1
- package/src/runtime/gateway/mcp/execution-tools.ts +2 -207
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +2 -61
- package/src/runtime/gateway/mcp/persisted-check-process.ts +2 -3
- package/src/runtime/gateway/mcp/process-tools.ts +2 -289
- package/src/runtime/gateway/mcp/router.ts +2 -1125
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +2 -565
- package/src/runtime/gateway/mcp/runtime-tools.ts +2 -6655
- package/src/runtime/gateway/mcp/work-validation-reconciler.ts +2 -1
- package/src/runtime/maintenance/cleanup.ts +38 -24
- package/src/runtime/platform/browser-product-discovery.ts +174 -0
- package/src/runtime/platform/computer-platform.ts +14 -0
- package/src/runtime/platform/executable-discovery.ts +54 -0
- package/src/runtime/platform/fetch-http-server.ts +90 -0
- package/src/runtime/platform/service-inventory.ts +130 -0
- package/src/runtime/platform/service-manager.ts +146 -0
- package/src/runtime/platform/windows-host-discovery.ts +118 -0
- package/src/runtime/platform/windows-recovery-deployment.ts +67 -0
- package/src/runtime/plugins/action-application.ts +192 -0
- package/src/runtime/plugins/app-store-connect-adapter.ts +47 -35
- package/src/runtime/plugins/browser-adapter.ts +898 -135
- package/src/runtime/plugins/browser-automation-service.ts +33 -34
- package/src/runtime/plugins/browser-macos-bridge.ts +386 -46
- package/src/runtime/plugins/browser-manifest-surface.ts +75 -17
- package/src/runtime/plugins/browser-native-session-service.ts +64 -14
- package/src/runtime/plugins/browser-provider-registry.ts +2 -109
- package/src/runtime/plugins/browser-registration.ts +32 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +2 -154
- package/src/runtime/plugins/browser-runtime.ts +55 -10
- package/src/runtime/plugins/browser-session-authority.ts +101 -291
- package/src/runtime/plugins/browser-session-legacy-migration.ts +203 -0
- package/src/runtime/plugins/browser-session-store.ts +243 -80
- package/src/runtime/plugins/browser-session-types.ts +2 -98
- package/src/runtime/plugins/capability-authorization-grants.ts +272 -59
- package/src/runtime/plugins/catalog-trust.ts +82 -0
- package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
- package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
- package/src/runtime/plugins/computer-registration.ts +1050 -0
- package/src/runtime/plugins/config-store.ts +119 -0
- package/src/runtime/plugins/desktop-operator-external-policy.ts +964 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +123 -12
- package/src/runtime/plugins/errors.ts +8 -1
- package/src/runtime/plugins/external-adapter.ts +82 -323
- package/src/runtime/plugins/external-provider-policy.ts +48 -0
- package/src/runtime/plugins/external-registration.ts +30 -2
- package/src/runtime/plugins/external-unix-socket-probe.cjs +9 -3
- package/src/runtime/plugins/external-unix-socket.ts +64 -193
- package/src/runtime/plugins/first-party-external-registration.ts +163 -0
- package/src/runtime/plugins/first-party-registry.ts +3 -1
- package/src/runtime/plugins/github-adapter.ts +1 -2
- package/src/runtime/plugins/gmail-adapter.ts +29 -8
- package/src/runtime/plugins/google-calendar-adapter.ts +8 -8
- package/src/runtime/plugins/google-shared.ts +45 -53
- package/src/runtime/plugins/google-tasks-adapter.ts +8 -8
- package/src/runtime/plugins/ios-adapter.ts +2 -3
- package/src/runtime/plugins/lightweight-action.ts +208 -2
- package/src/runtime/plugins/local-system-adapter.ts +192 -2
- package/src/runtime/plugins/macos-capability-broker.ts +15 -105
- package/src/runtime/plugins/managed-process-adapter.ts +12 -5
- package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
- package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
- package/src/runtime/plugins/resend-adapter.ts +15 -24
- package/src/runtime/plugins/store.ts +1003 -387
- package/src/runtime/plugins/types.ts +28 -1
- package/src/runtime/plugins/uu-remote-rescue-registration.ts +155 -0
- package/src/runtime/plugins/windows-host-recovery-install.ts +68 -0
- package/src/runtime/plugins/windows-host-recovery-registration.ts +85 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +102 -430
- package/src/runtime/projections/controller-context.ts +12 -6
- package/src/runtime/projections/git-status-sampler.ts +73 -22
- package/src/runtime/projections/invalidation.ts +7 -3
- package/src/runtime/projections/materialized-view.ts +93 -43
- package/src/runtime/recovery/actions.ts +3 -3
- package/src/runtime/recovery/capability-action-application.ts +229 -0
- package/src/runtime/recovery/index.ts +3 -0
- package/src/runtime/recovery/lifecycle-inventory.ts +338 -0
- package/src/runtime/recovery/local-jobs-repair.ts +14 -14
- package/src/runtime/recovery/maintenance-executor.ts +701 -168
- package/src/runtime/recovery/quarantine-retention.ts +256 -0
- package/src/runtime/recovery/store.ts +29 -11
- package/src/runtime/release/identity.ts +6 -0
- package/src/runtime/release/release-coordinator.ts +296 -0
- package/src/runtime/release/release-session.ts +716 -0
- package/src/runtime/release/release-state-migration.ts +25 -0
- package/src/runtime/resources/leases/store.ts +56 -25
- package/src/runtime/root/active-execution-power-assertion.ts +139 -0
- package/src/runtime/root/assistant-learning-loop.ts +45 -0
- package/src/runtime/root/browser-session-composition.ts +59 -0
- package/src/runtime/root/computer-composition.ts +376 -0
- package/src/runtime/root/computer-target-composition.ts +16 -0
- package/src/runtime/root/computer-target-persistence.ts +39 -0
- package/src/runtime/root/controller-progression-composition.ts +192 -0
- package/src/runtime/root/controller-round-composition.ts +126 -0
- package/src/runtime/root/controller-services.ts +2 -0
- package/src/runtime/root/deployment-topology.ts +106 -0
- package/src/runtime/root/entry.ts +8 -6
- package/src/runtime/root/gateway-adapter.ts +3 -3
- package/src/runtime/root/known-good-recovery.ts +184 -0
- package/src/runtime/root/local-bridge.ts +5 -3
- package/src/runtime/root/mcp-transport.ts +116 -23
- package/src/runtime/root/ownership.ts +261 -9
- package/src/runtime/root/package-connector-service.ts +212 -74
- package/src/runtime/root/package-runtime-release.ts +199 -33
- package/src/runtime/root/package-runtime-service.ts +77 -108
- package/src/runtime/root/release-execution-canary.ts +103 -0
- package/src/runtime/root/release-loader.ts +150 -0
- package/src/runtime/root/release-manifest.ts +185 -7
- package/src/runtime/root/release-materialize.ts +474 -31
- package/src/runtime/root/release-store.ts +425 -37
- package/src/runtime/root/runtime-lane.ts +191 -0
- package/src/runtime/root/runtime.ts +379 -32
- package/src/runtime/root/scheduled-controller-composition.ts +76 -0
- package/src/runtime/root/scheduler.ts +12 -4
- package/src/runtime/root/service-runner.ts +3 -3
- package/src/runtime/root/service.ts +73 -45
- package/src/runtime/root/status.ts +49 -0
- package/src/runtime/root/types.ts +55 -3
- package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
- package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
- package/src/runtime/root/write-fence.ts +50 -2
- package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
- package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
- package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
- package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
- package/src/runtime/shared/local-bridge-surface.ts +1 -1
- package/src/runtime/shared/process-environment.ts +36 -10
- package/src/runtime/shared/response-budget.ts +1 -3
- package/src/runtime/shared/storage-capacity.ts +68 -0
- package/src/runtime/standalone-recovery/controller-home-migration.ts +1108 -0
- package/src/runtime/standalone-recovery/core.ts +4609 -495
- package/src/runtime/standalone-recovery/entry.ts +642 -81
- package/src/runtime/standalone-recovery/independent-host-rescue.ts +172 -0
- package/src/runtime/standalone-recovery/installer.ts +399 -177
- package/src/runtime/standalone-recovery/mcp-server.ts +79 -0
- package/src/runtime/standalone-recovery/mutation-identity-contract.ts +21 -0
- package/src/runtime/standalone-recovery/operation-lock.ts +160 -0
- package/src/runtime/standalone-recovery/performance.ts +173 -0
- package/src/runtime/standalone-recovery/release.ts +58 -5
- package/src/runtime/standalone-recovery/service-labels.ts +5 -2
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
- package/src/runtime/watchdog/workflow-watchdog.ts +1 -1
- package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +11 -4
- package/src/runtime/workflow/schedules/engine.ts +298 -484
- package/src/runtime/workflow/schedules/pending-activation.ts +1 -1
- package/src/runtime/workflow/schedules/settlement.ts +2 -191
- package/src/runtime/workflow/schedules/store.ts +2 -607
- package/src/runtime/workflow/schedules/types.ts +2 -127
- package/src/runtime/workflow/schedules/work-continuation.ts +220 -16
- package/src/runtime/workflows/first-party/xiaohongshu.ts +122 -0
- package/src/runtime/workflows/runtime.ts +482 -0
- package/src/testing/test-governance.ts +95 -30
- package/supervisor/chatgpt-conversation.ts +23 -0
- package/supervisor/client.ts +201 -0
- package/supervisor/control-plane.ts +868 -0
- package/supervisor/entry.ts +15 -0
- package/supervisor/forge-validators.ts +80 -0
- package/supervisor/index.ts +5 -0
- package/supervisor/native-browser-adapter.ts +786 -0
- package/supervisor/native-messaging/host.ts +39 -0
- package/supervisor/native-messaging/manifest.ts +26 -0
- package/supervisor/native-messaging/protocol.ts +27 -0
- package/supervisor/paths.ts +18 -0
- package/supervisor/protocol.ts +202 -0
- package/supervisor/server.ts +404 -0
- package/supervisor/store.ts +1451 -0
- package/supervisor/tsconfig.json +8 -0
- package/supervisor/types.ts +255 -0
- package/assets/templates/helpers/archive-architecture-request.sh +0 -244
- package/docs/architecture/history/README.md +0 -7
- package/docs/architecture/history/chatgpt-handoff-facade.md +0 -397
- package/docs/architecture/history/global-hook-runtime.md +0 -166
- package/docs/architecture/history/ios-semantic-automation-provider-v2.md +0 -170
- package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +0 -63
- package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +0 -68
- package/docs/architecture/requests/archive/2026/root.md +0 -68
- package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +0 -76
- package/docs/architecture/requests/archive/2026/verification-evals-checks.md +0 -68
- package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +0 -69
- package/scripts/archive-architecture-request.sh +0 -4
- package/scripts/benchmark-background-check-overlap.ts +0 -228
- package/scripts/benchmark-controller-hotpath.ts +0 -212
- package/scripts/benchmark-controller-round2.ts +0 -139
- package/scripts/benchmark-ios-agent-device.ts +0 -514
- package/scripts/benchmark-mcp-host.sh +0 -117
- package/scripts/benchmark-mcp-transport.ts +0 -170
- package/scripts/benchmark-quality-harness.ts +0 -146
- package/scripts/benchmark-route-session-concurrency.ts +0 -915
- package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
- package/scripts/benchmark-thin-harness.ts +0 -251
- package/scripts/benchmark-typescript-navigation.ts +0 -186
- package/scripts/benchmark-work-efficiency.ts +0 -334
- package/scripts/build-controller-ui.ts +0 -28
- package/scripts/check-npm-release.sh +0 -32
- package/scripts/check-public-release-surface.sh +0 -19
- package/scripts/check-release-published.sh +0 -57
- package/scripts/check-release-readiness.sh +0 -37
- package/scripts/check-release-version.mjs +0 -74
- package/scripts/check-tarball-install-smoke.sh +0 -67
- package/scripts/package-source-archive.sh +0 -147
- package/scripts/public-release-files.txt +0 -39
- package/scripts/public-release.ts +0 -174
- package/scripts/publish-release-tarball.sh +0 -27
- package/scripts/route-nl-vs-ts-eval.ts +0 -679
- package/scripts/run-skill-evals.ts +0 -1022
- package/scripts/stage-runtime-release.ts +0 -39
- package/src/cli/controller/progress.ts +0 -656
- package/src/cli/controller/work-mode.ts +0 -181
- package/src/cli/local-bridge/console-assets.ts +0 -17
- package/src/cli/local-bridge/dashboard.ts +0 -17
- package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
- package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
- package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
- package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
- package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/styles.css +0 -28
- package/src/cli/local-bridge/frontend/src/types.ts +0 -15
- package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
- package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
- package/src/cli/local-bridge/ui-dist/app.css +0 -1
- package/src/cli/local-bridge/ui-dist/app.js +0 -11228
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -385
- package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -1913
- package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
- package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -449
- package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -1118
- package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -93
- package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
- package/src/runtime/control-plane/routing/index.ts +0 -1
- package/src/runtime/control-plane/routing/route-policy.ts +0 -382
- package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import { createRequire } from 'node:module';
|
|
2
|
-
import { copyFileSync, existsSync, mkdirSync, renameSync, unlinkSync } from 'fs';
|
|
3
|
+
import { closeSync, copyFileSync, existsSync, mkdirSync, openSync, readSync, renameSync, statSync, unlinkSync } from 'fs';
|
|
3
4
|
import { dirname, join } from 'path';
|
|
4
5
|
import { durableControllerHome } from '../../../cli/repositories/controller-home';
|
|
5
6
|
|
|
@@ -15,6 +16,8 @@ interface SqliteStatement {
|
|
|
15
16
|
get(...parameters: unknown[]): unknown;
|
|
16
17
|
all(...parameters: unknown[]): unknown[];
|
|
17
18
|
run(...parameters: unknown[]): unknown;
|
|
19
|
+
/** Bun statements retain native resources until finalized; Node's StatementSync does not expose this method. */
|
|
20
|
+
finalize?(): void;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
export interface SqliteDatabase {
|
|
@@ -59,10 +62,114 @@ export interface ControlPlaneDatabaseInspection {
|
|
|
59
62
|
orphanRecordCount: number;
|
|
60
63
|
}
|
|
61
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Ephemeral database-wide change fence. SQLite data_version changes whenever a
|
|
67
|
+
* different connection commits to the same database, including domain tables
|
|
68
|
+
* that do not participate in control_plane_audit.
|
|
69
|
+
*/
|
|
70
|
+
export interface ControlPlaneDatabaseChangeObserver {
|
|
71
|
+
path: string;
|
|
72
|
+
dataVersion(): number;
|
|
73
|
+
close(): void;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const CONTROL_PLANE_DATABASE_HASH_CHUNK_BYTES = 1024 * 1024;
|
|
77
|
+
|
|
78
|
+
/** Full snapshot identity without allocating the whole SQLite file. */
|
|
79
|
+
export function sha256ControlPlaneDatabaseFile(path: string): string {
|
|
80
|
+
const descriptor = openSync(path, 'r');
|
|
81
|
+
const hash = createHash('sha256');
|
|
82
|
+
const buffer = Buffer.allocUnsafe(CONTROL_PLANE_DATABASE_HASH_CHUNK_BYTES);
|
|
83
|
+
try {
|
|
84
|
+
for (;;) {
|
|
85
|
+
const bytesRead = readSync(descriptor, buffer, 0, buffer.length, null);
|
|
86
|
+
if (bytesRead === 0) break;
|
|
87
|
+
hash.update(buffer.subarray(0, bytesRead));
|
|
88
|
+
}
|
|
89
|
+
return hash.digest('hex');
|
|
90
|
+
} finally {
|
|
91
|
+
closeSync(descriptor);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const CONTROL_PLANE_SQLITE_MAINTENANCE_POLICY_VERSION = 'control-plane-sqlite-maintenance-v1' as const;
|
|
96
|
+
export const DEFAULT_CONTROL_PLANE_SQLITE_VACUUM_MIN_RECLAIMABLE_BYTES = 64 * 1024 * 1024;
|
|
97
|
+
export const DEFAULT_CONTROL_PLANE_SQLITE_VACUUM_MIN_RECLAIMABLE_RATIO = 0.20;
|
|
98
|
+
|
|
99
|
+
export interface ControlPlaneDatabaseMaintenanceOptions {
|
|
100
|
+
minimumReclaimableBytes?: number;
|
|
101
|
+
minimumReclaimableRatio?: number;
|
|
102
|
+
allowVacuum?: boolean;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface ControlPlaneDatabaseMaintenanceReport {
|
|
106
|
+
policyVersion: typeof CONTROL_PLANE_SQLITE_MAINTENANCE_POLICY_VERSION;
|
|
107
|
+
path: string;
|
|
108
|
+
checkpointMode: 'passive';
|
|
109
|
+
checkpointed: boolean;
|
|
110
|
+
pageSize: number;
|
|
111
|
+
pageCountBefore: number;
|
|
112
|
+
freePageCountBefore: number;
|
|
113
|
+
reclaimableBytesBefore: number;
|
|
114
|
+
reclaimableRatioBefore: number;
|
|
115
|
+
vacuumEligible: boolean;
|
|
116
|
+
vacuumAttempted: boolean;
|
|
117
|
+
vacuumed: boolean;
|
|
118
|
+
pageCountAfter: number;
|
|
119
|
+
freePageCountAfter: number;
|
|
120
|
+
reclaimableBytesAfter: number;
|
|
121
|
+
reclaimableRatioAfter: number;
|
|
122
|
+
reclaimedBytes: number;
|
|
123
|
+
skippedReason?: 'database_missing' | 'below_threshold' | 'vacuum_disabled' | 'database_busy';
|
|
124
|
+
}
|
|
125
|
+
|
|
62
126
|
export const CONTROL_PLANE_SCHEMA_VERSION = 1;
|
|
63
127
|
const DATABASE_FILE = 'control-plane.sqlite';
|
|
64
128
|
const require = createRequire(import.meta.url);
|
|
65
129
|
|
|
130
|
+
interface ReusableReadDatabase {
|
|
131
|
+
database: SqliteDatabase;
|
|
132
|
+
fileIdentity: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const reusableReadDatabasePaths = new Set<string>();
|
|
136
|
+
const reusableReadDatabases = new Map<string, ReusableReadDatabase>();
|
|
137
|
+
|
|
138
|
+
function databaseFileIdentity(path: string): string | undefined {
|
|
139
|
+
try {
|
|
140
|
+
const stat = statSync(path);
|
|
141
|
+
// Content changes must not invalidate a WAL reader. Identity changes only
|
|
142
|
+
// when the live database file itself is replaced.
|
|
143
|
+
return stat.ino
|
|
144
|
+
? `${stat.dev}:${stat.ino}`
|
|
145
|
+
: `${stat.dev}:birth:${stat.birthtimeMs}`;
|
|
146
|
+
} catch {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function closeReusableReadDatabase(path: string): void {
|
|
152
|
+
const cached = reusableReadDatabases.get(path);
|
|
153
|
+
if (!cached) return;
|
|
154
|
+
reusableReadDatabases.delete(path);
|
|
155
|
+
cached.database.close();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Opt in only for the long-lived Canonical Runtime. CLI, tests, and short-lived
|
|
160
|
+
* workers retain one-open-per-operation semantics so process exit and temporary
|
|
161
|
+
* Controller Home cleanup never depend on hidden SQLite handles.
|
|
162
|
+
*/
|
|
163
|
+
export function enableControlPlaneReadConnectionReuse(controllerHome: string): void {
|
|
164
|
+
reusableReadDatabasePaths.add(controlPlaneDatabasePath(controllerHome));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function disableControlPlaneReadConnectionReuse(controllerHome: string): void {
|
|
168
|
+
const path = controlPlaneDatabasePath(controllerHome);
|
|
169
|
+
reusableReadDatabasePaths.delete(path);
|
|
170
|
+
closeReusableReadDatabase(path);
|
|
171
|
+
}
|
|
172
|
+
|
|
66
173
|
function now(): string {
|
|
67
174
|
return new Date().toISOString();
|
|
68
175
|
}
|
|
@@ -98,9 +205,28 @@ function scalar(row: unknown): unknown {
|
|
|
98
205
|
return Object.values(row as Record<string, unknown>)[0];
|
|
99
206
|
}
|
|
100
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Keep native statement lifetime inside the SQLite adapter. Bun retains a
|
|
210
|
+
* Windows file handle for each unfinalized statement even after db.close(),
|
|
211
|
+
* while Node's StatementSync has no explicit finalizer. The optional call
|
|
212
|
+
* gives both runtimes identical Controller Home release semantics.
|
|
213
|
+
*/
|
|
214
|
+
function withSqliteStatement<T>(
|
|
215
|
+
database: SqliteDatabase,
|
|
216
|
+
sql: string,
|
|
217
|
+
operation: (statement: SqliteStatement) => T,
|
|
218
|
+
): T {
|
|
219
|
+
const statement = database.prepare(sql);
|
|
220
|
+
try {
|
|
221
|
+
return operation(statement);
|
|
222
|
+
} finally {
|
|
223
|
+
statement.finalize?.();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
101
227
|
function assertDatabaseIntegrity(database: SqliteDatabase, path: string): void {
|
|
102
228
|
try {
|
|
103
|
-
const result =
|
|
229
|
+
const result = withSqliteStatement(database, 'PRAGMA quick_check', (statement) => scalar(statement.get()));
|
|
104
230
|
if (result !== 'ok') throw new Error(String(result ?? 'missing quick_check result'));
|
|
105
231
|
} catch (error) {
|
|
106
232
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -110,13 +236,21 @@ function assertDatabaseIntegrity(database: SqliteDatabase, path: string): void {
|
|
|
110
236
|
}
|
|
111
237
|
|
|
112
238
|
function tableExists(database: SqliteDatabase, table: string): boolean {
|
|
113
|
-
const row =
|
|
239
|
+
const row = withSqliteStatement(
|
|
240
|
+
database,
|
|
241
|
+
"SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?",
|
|
242
|
+
(statement) => statement.get(table) as { name?: string } | undefined,
|
|
243
|
+
);
|
|
114
244
|
return row?.name === table;
|
|
115
245
|
}
|
|
116
246
|
|
|
117
247
|
function currentSchemaVersion(database: SqliteDatabase): number | undefined {
|
|
118
248
|
if (!tableExists(database, 'control_plane_schema')) return undefined;
|
|
119
|
-
const value =
|
|
249
|
+
const value = withSqliteStatement(
|
|
250
|
+
database,
|
|
251
|
+
'SELECT MAX(version) AS version FROM control_plane_schema',
|
|
252
|
+
(statement) => scalar(statement.get()),
|
|
253
|
+
);
|
|
120
254
|
return typeof value === 'number' && Number.isInteger(value) ? value : undefined;
|
|
121
255
|
}
|
|
122
256
|
|
|
@@ -163,7 +297,11 @@ function initializeSchema(database: SqliteDatabase): void {
|
|
|
163
297
|
CREATE INDEX IF NOT EXISTS control_plane_audit_lookup
|
|
164
298
|
ON control_plane_audit (namespace, scope, record_key, revision);
|
|
165
299
|
`);
|
|
166
|
-
|
|
300
|
+
withSqliteStatement(
|
|
301
|
+
database,
|
|
302
|
+
'INSERT OR IGNORE INTO control_plane_schema (version, applied_at) VALUES (?, ?)',
|
|
303
|
+
(statement) => statement.run(CONTROL_PLANE_SCHEMA_VERSION, now()),
|
|
304
|
+
);
|
|
167
305
|
}
|
|
168
306
|
|
|
169
307
|
export function controlPlaneDatabasePath(controllerHome: string): string {
|
|
@@ -186,9 +324,10 @@ function openDatabase(controllerHome: string): SqliteDatabase {
|
|
|
186
324
|
// inspectOpenDatabase(), which is the authoritative integrity boundary.
|
|
187
325
|
// Keep schema fail-closed on every open, but reserve the full integrity scan
|
|
188
326
|
// for those lifecycle/inspection boundaries.
|
|
327
|
+
let schemaVersion: number | undefined;
|
|
189
328
|
if (existed) {
|
|
190
329
|
try {
|
|
191
|
-
assertSupportedSchema(database, path);
|
|
330
|
+
schemaVersion = assertSupportedSchema(database, path);
|
|
192
331
|
} catch (error) {
|
|
193
332
|
const busy = sqliteBusyError(path, error);
|
|
194
333
|
if (busy) throw busy;
|
|
@@ -198,8 +337,14 @@ function openDatabase(controllerHome: string): SqliteDatabase {
|
|
|
198
337
|
}
|
|
199
338
|
}
|
|
200
339
|
database.exec('PRAGMA journal_mode = WAL;');
|
|
201
|
-
|
|
202
|
-
|
|
340
|
+
// Schema DDL is bootstrap work, not transaction work. Existing supported
|
|
341
|
+
// databases have already crossed the fail-closed schema boundary above;
|
|
342
|
+
// rerunning CREATE INDEX/TABLE + INSERT OR IGNORE on every write only burns
|
|
343
|
+
// allocations/SQLite preparation and then validates the same schema twice.
|
|
344
|
+
if (schemaVersion === undefined) {
|
|
345
|
+
initializeSchema(database);
|
|
346
|
+
assertSupportedSchema(database, path, true);
|
|
347
|
+
}
|
|
203
348
|
return database;
|
|
204
349
|
} catch (error) {
|
|
205
350
|
database.close();
|
|
@@ -238,6 +383,68 @@ function openDatabaseForRead(controllerHome: string): SqliteDatabase {
|
|
|
238
383
|
return openDatabase(controllerHome);
|
|
239
384
|
}
|
|
240
385
|
|
|
386
|
+
export function openControlPlaneDatabaseChangeObserver(controllerHome: string): ControlPlaneDatabaseChangeObserver {
|
|
387
|
+
const path = controlPlaneDatabasePath(controllerHome);
|
|
388
|
+
const database = openDatabaseForRead(controllerHome);
|
|
389
|
+
let closed = false;
|
|
390
|
+
const dataVersion = () => {
|
|
391
|
+
if (closed) throw new Error('CONTROL_PLANE_DATABASE_CHANGE_OBSERVER_CLOSED');
|
|
392
|
+
return integerPragma(database, 'PRAGMA data_version', 'data_version');
|
|
393
|
+
};
|
|
394
|
+
// Prime the connection before returning it so the first caller observation
|
|
395
|
+
// is relative to an established SQLite connection, not connection startup.
|
|
396
|
+
dataVersion();
|
|
397
|
+
return {
|
|
398
|
+
path,
|
|
399
|
+
dataVersion,
|
|
400
|
+
close() {
|
|
401
|
+
if (closed) return;
|
|
402
|
+
closed = true;
|
|
403
|
+
database.close();
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function withDatabaseForRead<T>(controllerHome: string, operation: (database: SqliteDatabase) => T): T {
|
|
409
|
+
const path = controlPlaneDatabasePath(controllerHome);
|
|
410
|
+
if (!reusableReadDatabasePaths.has(path)) {
|
|
411
|
+
const database = openDatabaseForRead(controllerHome);
|
|
412
|
+
try {
|
|
413
|
+
return operation(database);
|
|
414
|
+
} finally {
|
|
415
|
+
database.close();
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const liveIdentity = databaseFileIdentity(path);
|
|
420
|
+
const cached = reusableReadDatabases.get(path);
|
|
421
|
+
if (cached && liveIdentity && cached.fileIdentity === liveIdentity) {
|
|
422
|
+
return operation(cached.database);
|
|
423
|
+
}
|
|
424
|
+
if (cached) closeReusableReadDatabase(path);
|
|
425
|
+
|
|
426
|
+
const database = openDatabaseForRead(controllerHome);
|
|
427
|
+
const openedIdentity = databaseFileIdentity(path);
|
|
428
|
+
if (!openedIdentity) {
|
|
429
|
+
database.close();
|
|
430
|
+
throw new Error(`CONTROL_PLANE_SQLITE_MISSING: ${path}`);
|
|
431
|
+
}
|
|
432
|
+
reusableReadDatabases.set(path, { database, fileIdentity: openedIdentity });
|
|
433
|
+
try {
|
|
434
|
+
return operation(database);
|
|
435
|
+
} catch (error) {
|
|
436
|
+
// Do not retain a reader that failed while evaluating a query/schema. The
|
|
437
|
+
// next operation gets a clean connection and repeats the fail-closed checks.
|
|
438
|
+
closeReusableReadDatabase(path);
|
|
439
|
+
throw error;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/** Read-only snapshot boundary for domain stores that need several indexed lookups in one hot-path operation. */
|
|
444
|
+
export function withControlPlaneReadDatabase<T>(controllerHome: string, operation: (database: SqliteDatabase) => T): T {
|
|
445
|
+
return withDatabaseForRead(controllerHome, operation);
|
|
446
|
+
}
|
|
447
|
+
|
|
241
448
|
function rowToRecord<T>(row: StoredRecordRow): ControlPlaneRecord<T> {
|
|
242
449
|
let value: T;
|
|
243
450
|
try {
|
|
@@ -258,11 +465,11 @@ function rowToRecord<T>(row: StoredRecordRow): ControlPlaneRecord<T> {
|
|
|
258
465
|
}
|
|
259
466
|
|
|
260
467
|
function selectRecord<T>(database: SqliteDatabase, namespace: string, scope: string, key: string): ControlPlaneRecord<T> | undefined {
|
|
261
|
-
const row = database
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
468
|
+
const row = withSqliteStatement(database, `
|
|
469
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
470
|
+
FROM control_plane_records
|
|
471
|
+
WHERE namespace = ? AND scope = ? AND record_key = ?
|
|
472
|
+
`, (statement) => statement.get(namespace, scope, key) as StoredRecordRow | undefined);
|
|
266
473
|
return row ? rowToRecord<T>(row) : undefined;
|
|
267
474
|
}
|
|
268
475
|
|
|
@@ -272,22 +479,30 @@ function writeRecord<T>(
|
|
|
272
479
|
existing?: ControlPlaneRecord<T>,
|
|
273
480
|
): ControlPlaneRecord<T> {
|
|
274
481
|
const at = now();
|
|
275
|
-
const
|
|
482
|
+
const previousAuditRevision = Number(withSqliteStatement(database, `
|
|
483
|
+
SELECT MAX(revision) AS revision FROM control_plane_audit
|
|
484
|
+
WHERE namespace = ? AND scope = ? AND record_key = ?
|
|
485
|
+
`, (statement) => scalar(statement.get(input.namespace, input.scope, input.key))) ?? 0);
|
|
486
|
+
const revision = existing
|
|
487
|
+
? existing.revision + 1
|
|
488
|
+
: Math.max(0, Number.isSafeInteger(previousAuditRevision) ? previousAuditRevision : 0) + 1;
|
|
276
489
|
const createdAt = existing?.createdAt ?? at;
|
|
277
|
-
database
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
490
|
+
withSqliteStatement(database, `
|
|
491
|
+
INSERT INTO control_plane_records (
|
|
492
|
+
namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
493
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
494
|
+
ON CONFLICT(namespace, scope, record_key) DO UPDATE SET
|
|
495
|
+
schema_version = excluded.schema_version,
|
|
496
|
+
revision = excluded.revision,
|
|
497
|
+
payload = excluded.payload,
|
|
498
|
+
updated_at = excluded.updated_at
|
|
499
|
+
`, (statement) => statement.run(
|
|
500
|
+
input.namespace, input.scope, input.key, input.schemaVersion, revision, JSON.stringify(input.value), createdAt, at,
|
|
501
|
+
));
|
|
502
|
+
withSqliteStatement(database, `
|
|
503
|
+
INSERT INTO control_plane_audit (namespace, scope, record_key, action, revision, occurred_at)
|
|
504
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
505
|
+
`, (statement) => statement.run(input.namespace, input.scope, input.key, input.action, revision, at));
|
|
291
506
|
return {
|
|
292
507
|
namespace: input.namespace,
|
|
293
508
|
scope: input.scope,
|
|
@@ -352,12 +567,24 @@ export function withControlPlaneTransaction<T>(controllerHome: string, operation
|
|
|
352
567
|
}
|
|
353
568
|
|
|
354
569
|
export function readControlPlaneRecord<T>(controllerHome: string, namespace: string, scope: string, key: string): ControlPlaneRecord<T> | undefined {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
570
|
+
return withDatabaseForRead(controllerHome, (database) =>
|
|
571
|
+
selectRecord<T>(database, namespace, scope, key));
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
export function listControlPlaneRecordKeys(
|
|
575
|
+
controllerHome: string,
|
|
576
|
+
input: { namespace: string; scope: string; limit?: number },
|
|
577
|
+
): string[] {
|
|
578
|
+
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 5_000), 5_000));
|
|
579
|
+
return withDatabaseForRead(controllerHome, (database) =>
|
|
580
|
+
withSqliteStatement(database, `
|
|
581
|
+
SELECT record_key
|
|
582
|
+
FROM control_plane_records
|
|
583
|
+
WHERE namespace = ? AND scope = ?
|
|
584
|
+
ORDER BY record_key ASC
|
|
585
|
+
LIMIT ?
|
|
586
|
+
`, (statement) => (statement.all(input.namespace, input.scope, limit) as Array<{ record_key: string }>)
|
|
587
|
+
.map((row) => row.record_key)));
|
|
361
588
|
}
|
|
362
589
|
|
|
363
590
|
export function writeControlPlaneRecord<T>(
|
|
@@ -376,6 +603,72 @@ export function writeControlPlaneRecord<T>(
|
|
|
376
603
|
writeControlPlaneRecordWithinTransaction(database, input));
|
|
377
604
|
}
|
|
378
605
|
|
|
606
|
+
export function deleteControlPlaneRecordWithinTransaction(
|
|
607
|
+
database: SqliteDatabase,
|
|
608
|
+
input: { namespace: string; scope: string; key: string; action?: string; expectedRevision?: number },
|
|
609
|
+
): boolean {
|
|
610
|
+
const existing = selectRecord(database, input.namespace, input.scope, input.key);
|
|
611
|
+
if (input.expectedRevision !== undefined && existing?.revision !== input.expectedRevision) {
|
|
612
|
+
throw new ControlPlaneConflictError(input.namespace, input.scope, input.key, input.expectedRevision, existing?.revision);
|
|
613
|
+
}
|
|
614
|
+
if (!existing) return false;
|
|
615
|
+
const revision = existing.revision + 1;
|
|
616
|
+
const at = now();
|
|
617
|
+
withSqliteStatement(database, `
|
|
618
|
+
DELETE FROM control_plane_records
|
|
619
|
+
WHERE namespace = ? AND scope = ? AND record_key = ?
|
|
620
|
+
`, (statement) => statement.run(input.namespace, input.scope, input.key));
|
|
621
|
+
withSqliteStatement(database, `
|
|
622
|
+
INSERT INTO control_plane_audit (namespace, scope, record_key, action, revision, occurred_at)
|
|
623
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
624
|
+
`, (statement) => statement.run(input.namespace, input.scope, input.key, input.action ?? 'delete', revision, at));
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
export function deleteControlPlaneRecord(
|
|
629
|
+
controllerHome: string,
|
|
630
|
+
input: { namespace: string; scope: string; key: string; action?: string; expectedRevision?: number },
|
|
631
|
+
): boolean {
|
|
632
|
+
return withControlPlaneTransaction(controllerHome, (database) =>
|
|
633
|
+
deleteControlPlaneRecordWithinTransaction(database, input));
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
export function deleteControlPlaneRecordsWithinTransaction(
|
|
637
|
+
database: SqliteDatabase,
|
|
638
|
+
input: { namespace: string; scope: string; action?: string },
|
|
639
|
+
): number {
|
|
640
|
+
const rows = withSqliteStatement(database, `
|
|
641
|
+
SELECT record_key, revision
|
|
642
|
+
FROM control_plane_records
|
|
643
|
+
WHERE namespace = ? AND scope = ?
|
|
644
|
+
ORDER BY record_key ASC
|
|
645
|
+
`, (statement) => statement.all(input.namespace, input.scope) as Array<{ record_key: string; revision: number }>);
|
|
646
|
+
if (rows.length === 0) return 0;
|
|
647
|
+
|
|
648
|
+
const at = now();
|
|
649
|
+
withSqliteStatement(database, `
|
|
650
|
+
DELETE FROM control_plane_records
|
|
651
|
+
WHERE namespace = ? AND scope = ? AND record_key = ?
|
|
652
|
+
`, (remove) => withSqliteStatement(database, `
|
|
653
|
+
INSERT INTO control_plane_audit (namespace, scope, record_key, action, revision, occurred_at)
|
|
654
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
655
|
+
`, (audit) => {
|
|
656
|
+
for (const row of rows) {
|
|
657
|
+
remove.run(input.namespace, input.scope, row.record_key);
|
|
658
|
+
audit.run(input.namespace, input.scope, row.record_key, input.action ?? 'delete_scope', row.revision + 1, at);
|
|
659
|
+
}
|
|
660
|
+
}));
|
|
661
|
+
return rows.length;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
export function deleteControlPlaneRecords(
|
|
665
|
+
controllerHome: string,
|
|
666
|
+
input: { namespace: string; scope: string; action?: string },
|
|
667
|
+
): number {
|
|
668
|
+
return withControlPlaneTransaction(controllerHome, (database) =>
|
|
669
|
+
deleteControlPlaneRecordsWithinTransaction(database, input));
|
|
670
|
+
}
|
|
671
|
+
|
|
379
672
|
export class ControlPlaneConflictError extends Error {
|
|
380
673
|
readonly expectedRevision: number | null;
|
|
381
674
|
readonly actualRevision: number | undefined;
|
|
@@ -388,32 +681,162 @@ export class ControlPlaneConflictError extends Error {
|
|
|
388
681
|
}
|
|
389
682
|
}
|
|
390
683
|
|
|
684
|
+
export function listControlPlaneRecordsWithinTransaction<T>(
|
|
685
|
+
database: SqliteDatabase,
|
|
686
|
+
input: { namespace: string; scope?: string; limit?: number },
|
|
687
|
+
): ControlPlaneRecord<T>[] {
|
|
688
|
+
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 1000), 5000));
|
|
689
|
+
const rows = input.scope === undefined
|
|
690
|
+
? withSqliteStatement(database, `
|
|
691
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
692
|
+
FROM control_plane_records
|
|
693
|
+
WHERE namespace = ?
|
|
694
|
+
ORDER BY updated_at ASC, record_key ASC
|
|
695
|
+
LIMIT ?
|
|
696
|
+
`, (statement) => statement.all(input.namespace, limit))
|
|
697
|
+
: withSqliteStatement(database, `
|
|
698
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
699
|
+
FROM control_plane_records
|
|
700
|
+
WHERE namespace = ? AND scope = ?
|
|
701
|
+
ORDER BY updated_at ASC, record_key ASC
|
|
702
|
+
LIMIT ?
|
|
703
|
+
`, (statement) => statement.all(input.namespace, input.scope, limit));
|
|
704
|
+
return (rows as StoredRecordRow[]).map((row) => rowToRecord<T>(row));
|
|
705
|
+
}
|
|
706
|
+
|
|
391
707
|
export function listControlPlaneRecords<T>(
|
|
392
708
|
controllerHome: string,
|
|
393
709
|
input: { namespace: string; scope?: string; limit?: number },
|
|
394
710
|
): ControlPlaneRecord<T>[] {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
711
|
+
return withDatabaseForRead(controllerHome, (database) =>
|
|
712
|
+
listControlPlaneRecordsWithinTransaction<T>(database, input));
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/** Exact stable-key lookup across scopes. This is a read of the existing Control Plane authority, not a second id registry. */
|
|
716
|
+
export function findControlPlaneRecordsByKey<T>(
|
|
717
|
+
controllerHome: string,
|
|
718
|
+
input: { namespace: string; key: string; limit?: number },
|
|
719
|
+
): ControlPlaneRecord<T>[] {
|
|
720
|
+
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 2), 100));
|
|
721
|
+
return withDatabaseForRead(controllerHome, (database) => {
|
|
722
|
+
const rows = withSqliteStatement(database, `
|
|
723
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
724
|
+
FROM control_plane_records
|
|
725
|
+
WHERE namespace = ? AND record_key = ?
|
|
726
|
+
ORDER BY scope ASC
|
|
727
|
+
LIMIT ?
|
|
728
|
+
`, (statement) => statement.all(input.namespace, input.key, limit));
|
|
413
729
|
return (rows as StoredRecordRow[]).map((row) => rowToRecord<T>(row));
|
|
414
|
-
}
|
|
415
|
-
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Candidate-only read optimization for top-level JSON text fields. This never
|
|
735
|
+
* establishes domain authority: missing/null/non-text values remain candidates,
|
|
736
|
+
* and callers must still run their canonical semantic validation.
|
|
737
|
+
*/
|
|
738
|
+
export interface PayloadTextExclusion {
|
|
739
|
+
namespace: string;
|
|
740
|
+
field: string;
|
|
741
|
+
excludedValues: readonly string[];
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
function payloadTextExclusionPredicate(input: PayloadTextExclusion): string {
|
|
745
|
+
const field = input.field.trim();
|
|
746
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(field)) {
|
|
747
|
+
throw new Error(`CONTROL_PLANE_JSON_FIELD_INVALID: ${input.field}`);
|
|
416
748
|
}
|
|
749
|
+
const values = [...new Set(input.excludedValues.map((value) => value.trim()).filter(Boolean))].sort();
|
|
750
|
+
if (values.length > 32) throw new Error('CONTROL_PLANE_JSON_EXCLUSION_LIMIT_EXCEEDED');
|
|
751
|
+
// These literals are escaped here, never supplied as SQL by a domain caller.
|
|
752
|
+
// SQLite must see identical literals in the query and partial-index predicate.
|
|
753
|
+
const literal = (value: string) => `'${value.replaceAll("'", "''")}'`;
|
|
754
|
+
const namespace = `namespace = ${literal(input.namespace)}`;
|
|
755
|
+
if (values.length === 0) return namespace;
|
|
756
|
+
const extraction = `json_extract(payload, ${literal(`$.${field}`)})`;
|
|
757
|
+
return `${namespace} AND (${extraction} IS NULL OR ${extraction} NOT IN (${values.map(literal).join(', ')}))`;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
function payloadTextExclusionIndexName(input: PayloadTextExclusion, predicate = payloadTextExclusionPredicate(input)): string {
|
|
761
|
+
const prefix = `control_plane_candidate_${createHash('sha256').update(`${input.namespace}/${input.field}`).digest('hex').slice(0, 16)}_`;
|
|
762
|
+
return `${prefix}${createHash('sha256').update(predicate).digest('hex').slice(0, 16)}`;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/** Explicit startup DDL. JSON remains authority; SQLite maintains the derived index in every write transaction. */
|
|
766
|
+
export function initializeControlPlanePayloadTextExclusionIndex(
|
|
767
|
+
controllerHome: string,
|
|
768
|
+
input: PayloadTextExclusion,
|
|
769
|
+
): void {
|
|
770
|
+
const predicate = payloadTextExclusionPredicate(input);
|
|
771
|
+
const prefix = `control_plane_candidate_${createHash('sha256').update(`${input.namespace}/${input.field}`).digest('hex').slice(0, 16)}_`;
|
|
772
|
+
const name = payloadTextExclusionIndexName(input, predicate);
|
|
773
|
+
withControlPlaneTransaction(controllerHome, (database) => {
|
|
774
|
+
database.exec(`CREATE INDEX IF NOT EXISTS ${name} ON control_plane_records (scope, updated_at, record_key) WHERE ${predicate}`);
|
|
775
|
+
// Retire obsolete predicates for this domain field in the same transaction.
|
|
776
|
+
const old = withSqliteStatement(database, "SELECT name FROM sqlite_master WHERE type = 'index' AND substr(name, 1, ?) = ?",
|
|
777
|
+
(statement) => statement.all(prefix.length, prefix)) as Array<{ name: string }>;
|
|
778
|
+
for (const index of old) {
|
|
779
|
+
if (index.name !== name && /^control_plane_candidate_[a-f0-9]{16}_[a-f0-9]{16}$/.test(index.name)) {
|
|
780
|
+
database.exec(`DROP INDEX ${index.name}`);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
export function listControlPlaneRecordsExcludingPayloadTextValues<T>(
|
|
787
|
+
controllerHome: string,
|
|
788
|
+
input: PayloadTextExclusion & { scope: string; limit?: number },
|
|
789
|
+
): ControlPlaneRecord<T>[] {
|
|
790
|
+
const predicate = payloadTextExclusionPredicate(input);
|
|
791
|
+
const candidateIndex = payloadTextExclusionIndexName(input, predicate);
|
|
792
|
+
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 1_000), 5_000));
|
|
793
|
+
return withDatabaseForRead(controllerHome, (database) => {
|
|
794
|
+
const candidateIndexExists = withSqliteStatement(database,
|
|
795
|
+
"SELECT 1 AS present FROM sqlite_master WHERE type = 'index' AND name = ? LIMIT 1",
|
|
796
|
+
(statement) => statement.get(candidateIndex) != null);
|
|
797
|
+
const indexHint = candidateIndexExists ? ` INDEXED BY ${candidateIndex}` : '';
|
|
798
|
+
const rows = withSqliteStatement(database, `
|
|
799
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
800
|
+
FROM control_plane_records${indexHint}
|
|
801
|
+
WHERE ${predicate} AND scope = ?
|
|
802
|
+
ORDER BY updated_at ASC, record_key ASC
|
|
803
|
+
LIMIT ?
|
|
804
|
+
`, (statement) => statement.all(input.scope, limit));
|
|
805
|
+
return (rows as StoredRecordRow[]).map((row) => rowToRecord<T>(row));
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* Internal correctness surface for authorities that must observe every durable
|
|
811
|
+
* fact in a namespace/scope. User-facing and diagnostic list APIs should keep
|
|
812
|
+
* using listControlPlaneRecords so their output remains bounded.
|
|
813
|
+
*/
|
|
814
|
+
export function listAllControlPlaneRecordsWithinTransaction<T>(
|
|
815
|
+
database: SqliteDatabase,
|
|
816
|
+
input: { namespace: string; scope?: string },
|
|
817
|
+
): ControlPlaneRecord<T>[] {
|
|
818
|
+
const rows = input.scope === undefined
|
|
819
|
+
? withSqliteStatement(database, `
|
|
820
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
821
|
+
FROM control_plane_records
|
|
822
|
+
WHERE namespace = ?
|
|
823
|
+
ORDER BY updated_at ASC, record_key ASC
|
|
824
|
+
`, (statement) => statement.all(input.namespace))
|
|
825
|
+
: withSqliteStatement(database, `
|
|
826
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
827
|
+
FROM control_plane_records
|
|
828
|
+
WHERE namespace = ? AND scope = ?
|
|
829
|
+
ORDER BY updated_at ASC, record_key ASC
|
|
830
|
+
`, (statement) => statement.all(input.namespace, input.scope));
|
|
831
|
+
return (rows as StoredRecordRow[]).map((row) => rowToRecord<T>(row));
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
export function listAllControlPlaneRecords<T>(
|
|
835
|
+
controllerHome: string,
|
|
836
|
+
input: { namespace: string; scope?: string },
|
|
837
|
+
): ControlPlaneRecord<T>[] {
|
|
838
|
+
return withDatabaseForRead(controllerHome, (database) =>
|
|
839
|
+
listAllControlPlaneRecordsWithinTransaction<T>(database, input));
|
|
417
840
|
}
|
|
418
841
|
|
|
419
842
|
function inspectOpenDatabase(database: SqliteDatabase, path: string): ControlPlaneDatabaseInspection {
|
|
@@ -422,34 +845,42 @@ function inspectOpenDatabase(database: SqliteDatabase, path: string): ControlPla
|
|
|
422
845
|
if (!tableExists(database, 'control_plane_records') || !tableExists(database, 'control_plane_audit')) {
|
|
423
846
|
throw new Error(`CONTROL_PLANE_BACKUP_INVALID: ${path}: required tables are missing`);
|
|
424
847
|
}
|
|
425
|
-
const recordCount = Number(
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
SELECT
|
|
440
|
-
FROM control_plane_audit audit
|
|
441
|
-
WHERE audit.namespace = record.namespace
|
|
442
|
-
AND audit.scope = record.scope
|
|
443
|
-
AND audit.record_key = record.record_key
|
|
444
|
-
), 0) != 1
|
|
445
|
-
OR COALESCE((
|
|
446
|
-
SELECT MAX(audit.revision)
|
|
848
|
+
const recordCount = Number(withSqliteStatement(
|
|
849
|
+
database,
|
|
850
|
+
'SELECT COUNT(*) AS count FROM control_plane_records',
|
|
851
|
+
(statement) => scalar(statement.get()),
|
|
852
|
+
) ?? 0);
|
|
853
|
+
const auditEventCount = Number(withSqliteStatement(
|
|
854
|
+
database,
|
|
855
|
+
'SELECT COUNT(*) AS count FROM control_plane_audit',
|
|
856
|
+
(statement) => scalar(statement.get()),
|
|
857
|
+
) ?? 0);
|
|
858
|
+
const orphanRecordCount = Number(withSqliteStatement(database, `
|
|
859
|
+
SELECT COUNT(*) AS count
|
|
860
|
+
FROM control_plane_records record
|
|
861
|
+
WHERE (
|
|
862
|
+
SELECT COUNT(DISTINCT audit.revision)
|
|
447
863
|
FROM control_plane_audit audit
|
|
448
864
|
WHERE audit.namespace = record.namespace
|
|
449
865
|
AND audit.scope = record.scope
|
|
450
866
|
AND audit.record_key = record.record_key
|
|
451
|
-
|
|
452
|
-
|
|
867
|
+
AND audit.revision BETWEEN 1 AND record.revision
|
|
868
|
+
) != record.revision
|
|
869
|
+
OR COALESCE((
|
|
870
|
+
SELECT MIN(audit.revision)
|
|
871
|
+
FROM control_plane_audit audit
|
|
872
|
+
WHERE audit.namespace = record.namespace
|
|
873
|
+
AND audit.scope = record.scope
|
|
874
|
+
AND audit.record_key = record.record_key
|
|
875
|
+
), 0) != 1
|
|
876
|
+
OR COALESCE((
|
|
877
|
+
SELECT MAX(audit.revision)
|
|
878
|
+
FROM control_plane_audit audit
|
|
879
|
+
WHERE audit.namespace = record.namespace
|
|
880
|
+
AND audit.scope = record.scope
|
|
881
|
+
AND audit.record_key = record.record_key
|
|
882
|
+
), 0) != record.revision
|
|
883
|
+
`, (statement) => scalar(statement.get())) ?? 0);
|
|
453
884
|
if (orphanRecordCount > 0) {
|
|
454
885
|
throw new Error(`CONTROL_PLANE_AUDIT_CONTINUITY_INVALID: ${path}: discontinuous_records=${orphanRecordCount}`);
|
|
455
886
|
}
|
|
@@ -476,6 +907,147 @@ export function inspectControlPlaneDatabaseFile(path: string): ControlPlaneDatab
|
|
|
476
907
|
}
|
|
477
908
|
}
|
|
478
909
|
|
|
910
|
+
interface ControlPlaneDatabasePageSnapshot {
|
|
911
|
+
pageSize: number;
|
|
912
|
+
pageCount: number;
|
|
913
|
+
freePageCount: number;
|
|
914
|
+
reclaimableBytes: number;
|
|
915
|
+
reclaimableRatio: number;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
function integerPragma(database: SqliteDatabase, sql: string, label: string): number {
|
|
919
|
+
const value = Number(withSqliteStatement(database, sql, (statement) => scalar(statement.get())));
|
|
920
|
+
if (!Number.isFinite(value) || value < 0) throw new Error(`CONTROL_PLANE_SQLITE_PRAGMA_INVALID: ${label}`);
|
|
921
|
+
return Math.floor(value);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
function controlPlaneDatabasePageSnapshot(database: SqliteDatabase): ControlPlaneDatabasePageSnapshot {
|
|
925
|
+
const pageSize = integerPragma(database, 'PRAGMA page_size', 'page_size');
|
|
926
|
+
const pageCount = integerPragma(database, 'PRAGMA page_count', 'page_count');
|
|
927
|
+
const freePageCount = integerPragma(database, 'PRAGMA freelist_count', 'freelist_count');
|
|
928
|
+
const reclaimableBytes = freePageCount * pageSize;
|
|
929
|
+
return {
|
|
930
|
+
pageSize,
|
|
931
|
+
pageCount,
|
|
932
|
+
freePageCount,
|
|
933
|
+
reclaimableBytes,
|
|
934
|
+
reclaimableRatio: pageCount > 0 ? freePageCount / pageCount : 0,
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Physical SQLite maintenance only. Domain lifecycles own row deletion; this
|
|
940
|
+
* boundary never decides semantic terminality or removes canonical records.
|
|
941
|
+
* PASSIVE checkpointing is non-blocking, and VACUUM is attempted only when
|
|
942
|
+
* already-reclaimable free pages exceed both configured thresholds. A live
|
|
943
|
+
* writer causes a fail-closed busy skip instead of lock stealing or corruption
|
|
944
|
+
* recovery.
|
|
945
|
+
*/
|
|
946
|
+
export function maintainControlPlaneDatabase(
|
|
947
|
+
controllerHome: string,
|
|
948
|
+
options: ControlPlaneDatabaseMaintenanceOptions = {},
|
|
949
|
+
): ControlPlaneDatabaseMaintenanceReport {
|
|
950
|
+
const path = controlPlaneDatabasePath(controllerHome);
|
|
951
|
+
const report: ControlPlaneDatabaseMaintenanceReport = {
|
|
952
|
+
policyVersion: CONTROL_PLANE_SQLITE_MAINTENANCE_POLICY_VERSION,
|
|
953
|
+
path,
|
|
954
|
+
checkpointMode: 'passive',
|
|
955
|
+
checkpointed: false,
|
|
956
|
+
pageSize: 0,
|
|
957
|
+
pageCountBefore: 0,
|
|
958
|
+
freePageCountBefore: 0,
|
|
959
|
+
reclaimableBytesBefore: 0,
|
|
960
|
+
reclaimableRatioBefore: 0,
|
|
961
|
+
vacuumEligible: false,
|
|
962
|
+
vacuumAttempted: false,
|
|
963
|
+
vacuumed: false,
|
|
964
|
+
pageCountAfter: 0,
|
|
965
|
+
freePageCountAfter: 0,
|
|
966
|
+
reclaimableBytesAfter: 0,
|
|
967
|
+
reclaimableRatioAfter: 0,
|
|
968
|
+
reclaimedBytes: 0,
|
|
969
|
+
};
|
|
970
|
+
if (!existsSync(path)) {
|
|
971
|
+
report.skippedReason = 'database_missing';
|
|
972
|
+
return report;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
let database: SqliteDatabase;
|
|
976
|
+
try {
|
|
977
|
+
database = openRawDatabase(path);
|
|
978
|
+
} catch (error) {
|
|
979
|
+
if ((error instanceof Error ? error.message : String(error)).startsWith('CONTROL_PLANE_SQLITE_BUSY:')) {
|
|
980
|
+
report.skippedReason = 'database_busy';
|
|
981
|
+
return report;
|
|
982
|
+
}
|
|
983
|
+
throw error;
|
|
984
|
+
}
|
|
985
|
+
try {
|
|
986
|
+
database.exec('PRAGMA busy_timeout = 0; PRAGMA foreign_keys = ON;');
|
|
987
|
+
assertSupportedSchema(database, path, true);
|
|
988
|
+
try {
|
|
989
|
+
database.exec('PRAGMA wal_checkpoint(PASSIVE);');
|
|
990
|
+
report.checkpointed = true;
|
|
991
|
+
} catch (error) {
|
|
992
|
+
const busy = sqliteBusyError(path, error);
|
|
993
|
+
if (busy) {
|
|
994
|
+
report.skippedReason = 'database_busy';
|
|
995
|
+
return report;
|
|
996
|
+
}
|
|
997
|
+
throw error;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
const before = controlPlaneDatabasePageSnapshot(database);
|
|
1001
|
+
report.pageSize = before.pageSize;
|
|
1002
|
+
report.pageCountBefore = before.pageCount;
|
|
1003
|
+
report.freePageCountBefore = before.freePageCount;
|
|
1004
|
+
report.reclaimableBytesBefore = before.reclaimableBytes;
|
|
1005
|
+
report.reclaimableRatioBefore = before.reclaimableRatio;
|
|
1006
|
+
report.pageCountAfter = before.pageCount;
|
|
1007
|
+
report.freePageCountAfter = before.freePageCount;
|
|
1008
|
+
report.reclaimableBytesAfter = before.reclaimableBytes;
|
|
1009
|
+
report.reclaimableRatioAfter = before.reclaimableRatio;
|
|
1010
|
+
|
|
1011
|
+
const minimumReclaimableBytes = Math.max(0, Math.floor(options.minimumReclaimableBytes ?? DEFAULT_CONTROL_PLANE_SQLITE_VACUUM_MIN_RECLAIMABLE_BYTES));
|
|
1012
|
+
const configuredRatio = Number(options.minimumReclaimableRatio ?? DEFAULT_CONTROL_PLANE_SQLITE_VACUUM_MIN_RECLAIMABLE_RATIO);
|
|
1013
|
+
const minimumReclaimableRatio = Number.isFinite(configuredRatio) ? Math.min(1, Math.max(0, configuredRatio)) : DEFAULT_CONTROL_PLANE_SQLITE_VACUUM_MIN_RECLAIMABLE_RATIO;
|
|
1014
|
+
report.vacuumEligible = before.freePageCount > 0
|
|
1015
|
+
&& before.reclaimableBytes >= minimumReclaimableBytes
|
|
1016
|
+
&& before.reclaimableRatio >= minimumReclaimableRatio;
|
|
1017
|
+
if (!report.vacuumEligible) {
|
|
1018
|
+
report.skippedReason = 'below_threshold';
|
|
1019
|
+
return report;
|
|
1020
|
+
}
|
|
1021
|
+
if (options.allowVacuum === false) {
|
|
1022
|
+
report.skippedReason = 'vacuum_disabled';
|
|
1023
|
+
return report;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
report.vacuumAttempted = true;
|
|
1027
|
+
try {
|
|
1028
|
+
database.exec('VACUUM;');
|
|
1029
|
+
} catch (error) {
|
|
1030
|
+
const busy = sqliteBusyError(path, error);
|
|
1031
|
+
if (busy) {
|
|
1032
|
+
report.skippedReason = 'database_busy';
|
|
1033
|
+
return report;
|
|
1034
|
+
}
|
|
1035
|
+
throw error;
|
|
1036
|
+
}
|
|
1037
|
+
assertDatabaseIntegrity(database, path);
|
|
1038
|
+
const after = controlPlaneDatabasePageSnapshot(database);
|
|
1039
|
+
report.vacuumed = true;
|
|
1040
|
+
report.pageCountAfter = after.pageCount;
|
|
1041
|
+
report.freePageCountAfter = after.freePageCount;
|
|
1042
|
+
report.reclaimableBytesAfter = after.reclaimableBytes;
|
|
1043
|
+
report.reclaimableRatioAfter = after.reclaimableRatio;
|
|
1044
|
+
report.reclaimedBytes = Math.max(0, (before.pageCount - after.pageCount) * before.pageSize);
|
|
1045
|
+
return report;
|
|
1046
|
+
} finally {
|
|
1047
|
+
database.close();
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
479
1051
|
export function backupControlPlaneDatabase(controllerHome: string, destinationPath: string): ControlPlaneDatabaseInspection {
|
|
480
1052
|
const destination = join(destinationPath);
|
|
481
1053
|
if (existsSync(destination)) throw new Error(`CONTROL_PLANE_BACKUP_EXISTS: ${destination}`);
|
|
@@ -497,6 +1069,10 @@ export function backupControlPlaneDatabase(controllerHome: string, destinationPa
|
|
|
497
1069
|
export function restoreControlPlaneDatabase(controllerHome: string, backupPath: string): ControlPlaneDatabaseInspection {
|
|
498
1070
|
if (!existsSync(backupPath)) throw new Error(`CONTROL_PLANE_BACKUP_MISSING: ${backupPath}`);
|
|
499
1071
|
const target = controlPlaneDatabasePath(controllerHome);
|
|
1072
|
+
// A reusable Runtime reader refers to the current inode, not the pathname.
|
|
1073
|
+
// Close it before replacing the live authority; reuse remains enabled and the
|
|
1074
|
+
// next read opens the verified replacement.
|
|
1075
|
+
closeReusableReadDatabase(target);
|
|
500
1076
|
const staging = `${target}.restore-${process.pid}-${Date.now()}`;
|
|
501
1077
|
copyFileSync(backupPath, staging);
|
|
502
1078
|
try {
|