@moretea-labs/forge 1.7.1 → 1.8.0
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 +58 -62
- package/CHANGELOG.md +39 -0
- package/CLAUDE.md +42 -62
- 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 +71 -0
- package/adapters/chatgpt/browser-delivery-runtime.ts +783 -0
- package/adapters/chatgpt/controller-binding-store.ts +55 -0
- package/adapters/chatgpt/controller-host.ts +119 -0
- package/adapters/chatgpt/controller-round-host.ts +78 -0
- package/adapters/chatgpt/controller-round-settlement-store.ts +45 -0
- package/adapters/chatgpt/provider-delivery.ts +113 -0
- package/adapters/chatgpt/work-conversation-binding-store.ts +192 -0
- package/adapters/chatgpt/wsl-bridge-delivery-host.ts +63 -0
- package/adapters/computer/desktop-operator-contract.ts +7 -0
- package/adapters/computer/desktop-operator-discovery.ts +201 -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 +944 -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 +407 -0
- package/adapters/mcp/controller-round-compatibility.ts +184 -0
- package/adapters/mcp/frozen-client-semantic-compatibility.ts +292 -0
- package/adapters/mcp/instructions.ts +36 -0
- package/adapters/mcp/legacy-context.ts +18 -0
- package/adapters/mcp/multi-repository.ts +437 -0
- package/adapters/mcp/oauth.ts +391 -0
- package/adapters/mcp/paths.ts +140 -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/context-adapter.ts +829 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +191 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +147 -0
- package/adapters/mcp/runtime-gateway/execution-control-adapter.ts +28 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +207 -0
- package/adapters/mcp/runtime-gateway/filesystem-adapter.ts +38 -0
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +411 -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 +308 -0
- package/adapters/mcp/runtime-gateway/process-tools.ts +289 -0
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +76 -0
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +268 -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 +110 -0
- package/adapters/mcp/runtime-gateway/result-adapter.ts +108 -0
- package/adapters/mcp/runtime-gateway/router.ts +728 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1251 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +634 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-shared.ts +27 -0
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +68 -0
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +186 -0
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +25 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +870 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +3186 -0
- package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +502 -0
- package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +1 -0
- package/adapters/mcp/server.ts +1048 -0
- package/adapters/mcp/setup.ts +791 -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 +5265 -0
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +150 -0
- package/adapters/mcp/tool-mapping/repository-tools.ts +1691 -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 +74 -0
- package/adapters/mcp/toolset-selection.ts +41 -0
- package/adapters/mcp/toolset.ts +336 -0
- package/adapters/mcp/transports/http.ts +1456 -0
- package/adapters/mcp/transports/session-registry.ts +513 -0
- package/adapters/mcp/transports/stdio.ts +8 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +139 -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 +9 -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/development-protocol.md +11 -15
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/global-working-rules.md +9 -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 +148 -13
- package/docs/architecture/EVOLUTION.md +13 -0
- package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +2 -1
- 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 +35 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +296 -0
- package/docs/architecture/decisions/20260907-maintenance-diagnosis-bounded-read.md +39 -0
- package/docs/architecture/domains/verification.md +7 -0
- package/docs/architecture/domains/workflow-engine.md +1 -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/homebrew.md +2 -2
- package/docs/operations/platform-support.md +16 -8
- package/docs/operations/platform-support.zh-CN.md +2 -2
- package/docs/operations/standalone-disaster-recovery.md +26 -1
- 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 +23 -14
- package/packages/kernel/controller/api/index.ts +2 -0
- package/packages/kernel/controller/application/controller-round-service.ts +29 -0
- package/packages/kernel/controller/application/controller-service.ts +30 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +308 -0
- package/packages/kernel/controller/domain/controller-round.ts +107 -0
- package/packages/kernel/controller/domain/execution-quality.ts +133 -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 +1384 -0
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +578 -0
- package/packages/kernel/controller/ports/controller-host.ts +16 -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 +5 -0
- package/packages/kernel/identity/application/identity-service.ts +67 -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/workspace.ts +56 -0
- package/packages/kernel/identity/index.ts +1 -0
- package/packages/kernel/identity/infrastructure/identity-store.ts +75 -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/progression/api/index.ts +2 -0
- package/packages/kernel/progression/application/projector.ts +211 -0
- package/packages/kernel/progression/domain/types.ts +116 -0
- package/packages/kernel/progression/index.ts +1 -0
- package/packages/kernel/scheduler/api/index.ts +6 -0
- package/packages/kernel/scheduler/application/continuation-service.ts +212 -0
- package/packages/kernel/scheduler/application/eligibility.ts +252 -0
- package/packages/kernel/scheduler/application/schedule-service.ts +24 -0
- package/packages/kernel/scheduler/application/settlement.ts +197 -0
- package/packages/kernel/scheduler/domain/continuation.ts +38 -0
- package/packages/kernel/scheduler/domain/schedule.ts +149 -0
- package/packages/kernel/scheduler/index.ts +1 -0
- package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +38 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +785 -0
- package/packages/kernel/work/api/index.ts +15 -0
- package/packages/kernel/work/application/work-service.ts +148 -0
- package/packages/kernel/work/domain/admission-policy.ts +34 -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/engineering-contracts.ts +157 -0
- package/packages/kernel/work/domain/engineering-design.ts +281 -0
- package/packages/kernel/work/domain/engineering-profile.ts +242 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +254 -0
- package/packages/kernel/work/domain/execution-snapshot.ts +33 -0
- package/packages/kernel/work/domain/implementation-review.ts +510 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +202 -0
- package/packages/kernel/work/domain/repository-completion-receipt.ts +73 -0
- package/packages/kernel/work/domain/state-machine.ts +259 -0
- package/packages/kernel/work/domain/types.ts +528 -0
- package/packages/kernel/work/index.ts +1 -0
- package/packages/kernel/work/infrastructure/work-contract-store.ts +1876 -0
- package/packages/kernel/work/ports/work-contract-store.ts +18 -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 +61 -0
- package/packages/plugin-runtime/computer/index.ts +6 -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 +190 -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 +457 -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 +199 -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/assemble-template.ts +1 -1
- package/scripts/benchmark-computer-hotpath.ts +255 -0
- package/scripts/benchmark-controller-round2.ts +54 -2
- package/scripts/benchmark-ios-agent-device.ts +3 -6
- package/scripts/benchmark-mcp-transport.ts +3 -4
- package/scripts/benchmark-operational-memory-activation.ts +235 -0
- package/scripts/benchmark-operational-shadow.ts +28 -0
- 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 +195 -0
- package/scripts/canary-global-hook.sh +2 -2
- package/scripts/check-mcp-compatibility.ts +173 -7
- package/scripts/check-platform-support.mjs +28 -2
- package/scripts/check-public-docs.sh +1 -1
- package/scripts/check-release-readiness.sh +1 -1
- package/scripts/check-repository-hygiene.mjs +92 -0
- package/scripts/check-runtime-architecture.mjs +1206 -95
- package/scripts/check-source-duplication.mjs +9 -1
- package/scripts/check-tarball-install-smoke.sh +98 -15
- package/scripts/controller-ngrok-rotation.sh +5 -4
- package/scripts/create-project-dirs.sh +10 -74
- package/scripts/forge-local-recovery-helper.mjs +204 -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 +39 -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 +12 -1
- package/scripts/portability-bindings.mjs +70 -0
- package/scripts/run-bounded-command.mjs +55 -0
- package/scripts/run-bun-test-file.ts +22 -6
- package/scripts/run-governed-gate.ts +4 -1
- package/scripts/smoke-mcp-http-runtime.ts +1 -1
- package/scripts/smoke-runtime-recovery.ts +34 -1
- package/scripts/smoke-schedule-engine.ts +1 -1
- package/scripts/stage-runtime-release.ts +6 -1
- package/scripts/test-governance.ts +51 -2
- package/src/cli/agent-jobs/job-manager.ts +10 -1
- 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 +38 -0
- package/src/cli/commands/brain.ts +193 -40
- package/src/cli/commands/chatgpt.ts +127 -0
- 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 +493 -80
- package/src/cli/commands/runtime.ts +9 -4
- package/src/cli/commands/setup-profile.ts +89 -39
- package/src/cli/commands/status.ts +2 -1
- package/src/cli/controller/check-runner.ts +487 -98
- package/src/cli/controller/context/types.ts +7 -1
- package/src/cli/controller/context-pack.ts +23 -3
- package/src/cli/controller/issue-store.ts +1 -1
- package/src/cli/controller/systemd-user.ts +110 -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 +289 -13
- 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 +2 -2
- package/src/cli/local-bridge/facade-api.ts +41 -14
- package/src/cli/local-bridge/job-store.ts +1 -1
- package/src/cli/local-bridge/server.ts +24 -27
- 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.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 -1585
- 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 +64 -18
- package/src/cli/repositories/command-scope.ts +117 -1
- package/src/cli/repositories/controller-home.ts +119 -1
- package/src/cli/repositories/identity.ts +13 -0
- package/src/cli/repositories/registry.ts +68 -49
- 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 +105 -25
- 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 +154 -0
- package/src/runtime/context/assistant-work-context.ts +147 -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/context-closure.ts +268 -0
- package/src/runtime/context/context-plane.ts +211 -0
- package/src/runtime/context/project-engineering-contract.ts +60 -0
- 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 +328 -0
- package/src/runtime/control-plane/codegraph-cache-retention.ts +164 -0
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +320 -0
- package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +169 -0
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +350 -0
- package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +85 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +417 -100
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +103 -15
- package/src/runtime/control-plane/execution/implementation-review-content.ts +95 -0
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +2 -2
- package/src/runtime/control-plane/execution/retained-work-resume.ts +336 -6
- package/src/runtime/control-plane/execution/validation.ts +28 -3
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +116 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +44 -2
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +34 -3
- package/src/runtime/control-plane/execution/work-execution-support.ts +42 -22
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1103 -166
- package/src/runtime/control-plane/execution/work-handle-authority.ts +267 -16
- package/src/runtime/control-plane/execution/work-handle-store.ts +77 -0
- package/src/runtime/control-plane/execution/work-head-settlement.ts +75 -0
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +145 -23
- package/src/runtime/control-plane/execution/work-operation-service.ts +49 -13
- package/src/runtime/control-plane/execution/work-preparation-service.ts +31 -15
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +1 -1
- package/src/runtime/control-plane/execution/work-task-receipt.ts +20 -1
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +407 -76
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +88 -18
- package/src/runtime/control-plane/execution/work-verification-context.ts +1 -1
- package/src/runtime/control-plane/execution/work-verification-service.ts +258 -4
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +200 -15
- package/src/runtime/control-plane/facade/capability-registry.ts +21 -10
- package/src/runtime/control-plane/facade/controller-round-relay.ts +3 -1118
- package/src/runtime/control-plane/facade/controller-session-store.ts +2 -488
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +6 -3
- package/src/runtime/control-plane/facade/goal-workloop.ts +972 -137
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +158 -0
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +10 -0
- package/src/runtime/control-plane/facade/index.ts +4 -2
- package/src/runtime/control-plane/facade/operation-digest.ts +22 -58
- package/src/runtime/control-plane/facade/plan-contract-store.ts +1004 -38
- package/src/runtime/control-plane/facade/repository-work-admission.ts +19 -1
- package/src/runtime/control-plane/facade/requirement-authority.ts +218 -0
- package/src/runtime/control-plane/facade/requirement-board.ts +6 -1
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +48 -0
- package/src/runtime/control-plane/facade/semantic-admission.ts +8 -16
- package/src/runtime/control-plane/facade/suggested-actions.ts +4 -1
- package/src/runtime/control-plane/facade/types.ts +189 -532
- package/src/runtime/control-plane/facade/work-admission-policy.ts +84 -35
- package/src/runtime/control-plane/facade/work-contract-store.ts +2 -1043
- package/src/runtime/control-plane/facade/work-implementation-review.ts +2 -0
- package/src/runtime/control-plane/facade/work-state-machine.ts +2 -250
- package/src/runtime/control-plane/generated-cache-retention.ts +239 -18
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +12 -1
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +76 -13
- 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 +1 -1
- package/src/runtime/control-plane/global-scheduler/scheduler-worker-entry.ts +10 -0
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +173 -81
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +18 -6
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +397 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +2 -177
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +301 -560
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +20 -4
- package/src/runtime/control-plane/launcher/thin-launcher.ts +50 -4
- package/src/runtime/control-plane/lifecycle-retention-metrics.ts +60 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +169 -0
- package/src/runtime/control-plane/persistence/operational-prior-store.ts +348 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +30 -22
- package/src/runtime/control-plane/persistence/sqlite-store.ts +545 -76
- 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 +56 -16
- package/src/runtime/control-plane/repository-namespace-retention.ts +208 -0
- package/src/runtime/control-plane/routing/route-policy.ts +19 -0
- package/src/runtime/control-plane/runtime-cleanup.ts +574 -37
- package/src/runtime/control-plane/runtime-generation.ts +6 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +465 -0
- package/src/runtime/control-plane/workspace/workspace-store.ts +80 -0
- package/src/runtime/diagnostics/incident-repair.ts +406 -0
- package/src/runtime/diagnostics/mcp-timing.ts +125 -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 +65 -2
- package/src/runtime/evidence/operational-shadow.ts +38 -0
- package/src/runtime/evidence/process-check-receipt.ts +5 -43
- 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 +121 -2
- package/src/runtime/execution/managed-workspace.ts +55 -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 +23 -9
- 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 +73 -2
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +42 -3
- package/src/runtime/execution/process-runtime/check-storage.ts +187 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +38 -87
- package/src/runtime/execution/process-runtime/index.ts +1 -0
- package/src/runtime/execution/process-runtime/interactive-admission.ts +2 -1
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +32 -1
- package/src/runtime/execution/process-runtime/persisted-check.ts +128 -21
- package/src/runtime/execution/process-runtime/resource-claims.ts +60 -3
- package/src/runtime/execution/process-runtime/runtime.ts +132 -15
- package/src/runtime/execution/process-runtime/types.ts +22 -0
- package/src/runtime/execution/workers/executor.ts +16 -13
- 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 -6651
- 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-manager.ts +138 -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 +135 -0
- package/src/runtime/plugins/app-store-connect-adapter.ts +9 -21
- package/src/runtime/plugins/browser-adapter.ts +140 -100
- package/src/runtime/plugins/browser-automation-service.ts +15 -36
- package/src/runtime/plugins/browser-macos-bridge.ts +69 -21
- package/src/runtime/plugins/browser-manifest-surface.ts +30 -6
- package/src/runtime/plugins/browser-native-session-service.ts +1 -1
- package/src/runtime/plugins/browser-provider-registry.ts +2 -109
- package/src/runtime/plugins/browser-registration.ts +16 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +2 -154
- package/src/runtime/plugins/browser-runtime.ts +41 -9
- 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 +229 -36
- package/src/runtime/plugins/browser-session-types.ts +2 -98
- package/src/runtime/plugins/capability-authorization-grants.ts +17 -0
- package/src/runtime/plugins/catalog-trust.ts +82 -0
- package/src/runtime/plugins/computer-registration.ts +839 -0
- package/src/runtime/plugins/config-store.ts +119 -0
- package/src/runtime/plugins/desktop-operator-external-policy.ts +932 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +111 -8
- package/src/runtime/plugins/errors.ts +8 -1
- package/src/runtime/plugins/external-adapter.ts +45 -322
- package/src/runtime/plugins/external-provider-policy.ts +48 -0
- package/src/runtime/plugins/external-registration.ts +9 -1
- 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 +6 -6
- package/src/runtime/plugins/google-calendar-adapter.ts +6 -6
- package/src/runtime/plugins/google-shared.ts +31 -46
- package/src/runtime/plugins/google-tasks-adapter.ts +6 -6
- package/src/runtime/plugins/ios-adapter.ts +1 -2
- package/src/runtime/plugins/local-system-adapter.ts +180 -0
- package/src/runtime/plugins/macos-capability-broker.ts +15 -105
- package/src/runtime/plugins/resend-adapter.ts +15 -24
- package/src/runtime/plugins/store.ts +493 -51
- package/src/runtime/plugins/types.ts +8 -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 +86 -430
- package/src/runtime/projections/controller-context.ts +12 -6
- package/src/runtime/projections/git-status-sampler.ts +73 -22
- package/src/runtime/projections/materialized-view.ts +14 -8
- package/src/runtime/recovery/capability-action-application.ts +228 -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 +358 -76
- package/src/runtime/recovery/quarantine-retention.ts +256 -0
- package/src/runtime/release/identity.ts +6 -0
- package/src/runtime/resources/leases/store.ts +1 -1
- 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 +191 -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-round-composition.ts +107 -0
- package/src/runtime/root/controller-services.ts +2 -0
- package/src/runtime/root/entry.ts +4 -3
- package/src/runtime/root/gateway-adapter.ts +3 -3
- package/src/runtime/root/local-bridge.ts +5 -2
- package/src/runtime/root/mcp-transport.ts +5 -5
- package/src/runtime/root/package-connector-service.ts +108 -56
- package/src/runtime/root/package-runtime-release.ts +86 -18
- package/src/runtime/root/package-runtime-service.ts +63 -86
- package/src/runtime/root/release-execution-canary.ts +71 -0
- package/src/runtime/root/release-loader.ts +68 -0
- package/src/runtime/root/release-manifest.ts +106 -2
- package/src/runtime/root/release-materialize.ts +103 -4
- package/src/runtime/root/release-store.ts +31 -2
- package/src/runtime/root/runtime.ts +240 -25
- package/src/runtime/root/scheduled-controller-composition.ts +51 -0
- package/src/runtime/root/scheduler.ts +12 -4
- package/src/runtime/root/service-runner.ts +1 -1
- package/src/runtime/root/service.ts +41 -16
- package/src/runtime/root/status.ts +1 -0
- package/src/runtime/root/types.ts +24 -1
- package/src/runtime/shared/local-bridge-surface.ts +1 -1
- package/src/runtime/shared/process-environment.ts +19 -4
- package/src/runtime/shared/storage-capacity.ts +68 -0
- package/src/runtime/standalone-recovery/controller-home-migration.ts +1116 -0
- package/src/runtime/standalone-recovery/core.ts +984 -230
- package/src/runtime/standalone-recovery/entry.ts +182 -51
- package/src/runtime/standalone-recovery/independent-host-rescue.ts +172 -0
- package/src/runtime/standalone-recovery/installer.ts +212 -104
- package/src/runtime/standalone-recovery/mcp-server.ts +243 -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 +135 -0
- package/src/runtime/standalone-recovery/release.ts +5 -0
- package/src/runtime/watchdog/workflow-watchdog.ts +1 -1
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +1 -1
- package/src/runtime/workflow/schedules/engine.ts +191 -343
- 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 +180 -15
- package/src/runtime/workflows/first-party/xiaohongshu.ts +122 -0
- package/src/runtime/workflows/runtime.ts +486 -0
- package/src/testing/test-governance.ts +90 -29
- 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/run-skill-evals.ts +0 -1022
|
@@ -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 { copyFileSync, existsSync, mkdirSync, 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,84 @@ export interface ControlPlaneDatabaseInspection {
|
|
|
59
62
|
orphanRecordCount: number;
|
|
60
63
|
}
|
|
61
64
|
|
|
65
|
+
export const CONTROL_PLANE_SQLITE_MAINTENANCE_POLICY_VERSION = 'control-plane-sqlite-maintenance-v1' as const;
|
|
66
|
+
export const DEFAULT_CONTROL_PLANE_SQLITE_VACUUM_MIN_RECLAIMABLE_BYTES = 64 * 1024 * 1024;
|
|
67
|
+
export const DEFAULT_CONTROL_PLANE_SQLITE_VACUUM_MIN_RECLAIMABLE_RATIO = 0.20;
|
|
68
|
+
|
|
69
|
+
export interface ControlPlaneDatabaseMaintenanceOptions {
|
|
70
|
+
minimumReclaimableBytes?: number;
|
|
71
|
+
minimumReclaimableRatio?: number;
|
|
72
|
+
allowVacuum?: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface ControlPlaneDatabaseMaintenanceReport {
|
|
76
|
+
policyVersion: typeof CONTROL_PLANE_SQLITE_MAINTENANCE_POLICY_VERSION;
|
|
77
|
+
path: string;
|
|
78
|
+
checkpointMode: 'passive';
|
|
79
|
+
checkpointed: boolean;
|
|
80
|
+
pageSize: number;
|
|
81
|
+
pageCountBefore: number;
|
|
82
|
+
freePageCountBefore: number;
|
|
83
|
+
reclaimableBytesBefore: number;
|
|
84
|
+
reclaimableRatioBefore: number;
|
|
85
|
+
vacuumEligible: boolean;
|
|
86
|
+
vacuumAttempted: boolean;
|
|
87
|
+
vacuumed: boolean;
|
|
88
|
+
pageCountAfter: number;
|
|
89
|
+
freePageCountAfter: number;
|
|
90
|
+
reclaimableBytesAfter: number;
|
|
91
|
+
reclaimableRatioAfter: number;
|
|
92
|
+
reclaimedBytes: number;
|
|
93
|
+
skippedReason?: 'database_missing' | 'below_threshold' | 'vacuum_disabled' | 'database_busy';
|
|
94
|
+
}
|
|
95
|
+
|
|
62
96
|
export const CONTROL_PLANE_SCHEMA_VERSION = 1;
|
|
63
97
|
const DATABASE_FILE = 'control-plane.sqlite';
|
|
64
98
|
const require = createRequire(import.meta.url);
|
|
65
99
|
|
|
100
|
+
interface ReusableReadDatabase {
|
|
101
|
+
database: SqliteDatabase;
|
|
102
|
+
fileIdentity: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const reusableReadDatabasePaths = new Set<string>();
|
|
106
|
+
const reusableReadDatabases = new Map<string, ReusableReadDatabase>();
|
|
107
|
+
|
|
108
|
+
function databaseFileIdentity(path: string): string | undefined {
|
|
109
|
+
try {
|
|
110
|
+
const stat = statSync(path);
|
|
111
|
+
// Content changes must not invalidate a WAL reader. Identity changes only
|
|
112
|
+
// when the live database file itself is replaced.
|
|
113
|
+
return stat.ino
|
|
114
|
+
? `${stat.dev}:${stat.ino}`
|
|
115
|
+
: `${stat.dev}:birth:${stat.birthtimeMs}`;
|
|
116
|
+
} catch {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function closeReusableReadDatabase(path: string): void {
|
|
122
|
+
const cached = reusableReadDatabases.get(path);
|
|
123
|
+
if (!cached) return;
|
|
124
|
+
reusableReadDatabases.delete(path);
|
|
125
|
+
cached.database.close();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Opt in only for the long-lived Canonical Runtime. CLI, tests, and short-lived
|
|
130
|
+
* workers retain one-open-per-operation semantics so process exit and temporary
|
|
131
|
+
* Controller Home cleanup never depend on hidden SQLite handles.
|
|
132
|
+
*/
|
|
133
|
+
export function enableControlPlaneReadConnectionReuse(controllerHome: string): void {
|
|
134
|
+
reusableReadDatabasePaths.add(controlPlaneDatabasePath(controllerHome));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function disableControlPlaneReadConnectionReuse(controllerHome: string): void {
|
|
138
|
+
const path = controlPlaneDatabasePath(controllerHome);
|
|
139
|
+
reusableReadDatabasePaths.delete(path);
|
|
140
|
+
closeReusableReadDatabase(path);
|
|
141
|
+
}
|
|
142
|
+
|
|
66
143
|
function now(): string {
|
|
67
144
|
return new Date().toISOString();
|
|
68
145
|
}
|
|
@@ -98,9 +175,28 @@ function scalar(row: unknown): unknown {
|
|
|
98
175
|
return Object.values(row as Record<string, unknown>)[0];
|
|
99
176
|
}
|
|
100
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Keep native statement lifetime inside the SQLite adapter. Bun retains a
|
|
180
|
+
* Windows file handle for each unfinalized statement even after db.close(),
|
|
181
|
+
* while Node's StatementSync has no explicit finalizer. The optional call
|
|
182
|
+
* gives both runtimes identical Controller Home release semantics.
|
|
183
|
+
*/
|
|
184
|
+
function withSqliteStatement<T>(
|
|
185
|
+
database: SqliteDatabase,
|
|
186
|
+
sql: string,
|
|
187
|
+
operation: (statement: SqliteStatement) => T,
|
|
188
|
+
): T {
|
|
189
|
+
const statement = database.prepare(sql);
|
|
190
|
+
try {
|
|
191
|
+
return operation(statement);
|
|
192
|
+
} finally {
|
|
193
|
+
statement.finalize?.();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
101
197
|
function assertDatabaseIntegrity(database: SqliteDatabase, path: string): void {
|
|
102
198
|
try {
|
|
103
|
-
const result =
|
|
199
|
+
const result = withSqliteStatement(database, 'PRAGMA quick_check', (statement) => scalar(statement.get()));
|
|
104
200
|
if (result !== 'ok') throw new Error(String(result ?? 'missing quick_check result'));
|
|
105
201
|
} catch (error) {
|
|
106
202
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -110,13 +206,21 @@ function assertDatabaseIntegrity(database: SqliteDatabase, path: string): void {
|
|
|
110
206
|
}
|
|
111
207
|
|
|
112
208
|
function tableExists(database: SqliteDatabase, table: string): boolean {
|
|
113
|
-
const row =
|
|
209
|
+
const row = withSqliteStatement(
|
|
210
|
+
database,
|
|
211
|
+
"SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?",
|
|
212
|
+
(statement) => statement.get(table) as { name?: string } | undefined,
|
|
213
|
+
);
|
|
114
214
|
return row?.name === table;
|
|
115
215
|
}
|
|
116
216
|
|
|
117
217
|
function currentSchemaVersion(database: SqliteDatabase): number | undefined {
|
|
118
218
|
if (!tableExists(database, 'control_plane_schema')) return undefined;
|
|
119
|
-
const value =
|
|
219
|
+
const value = withSqliteStatement(
|
|
220
|
+
database,
|
|
221
|
+
'SELECT MAX(version) AS version FROM control_plane_schema',
|
|
222
|
+
(statement) => scalar(statement.get()),
|
|
223
|
+
);
|
|
120
224
|
return typeof value === 'number' && Number.isInteger(value) ? value : undefined;
|
|
121
225
|
}
|
|
122
226
|
|
|
@@ -163,7 +267,11 @@ function initializeSchema(database: SqliteDatabase): void {
|
|
|
163
267
|
CREATE INDEX IF NOT EXISTS control_plane_audit_lookup
|
|
164
268
|
ON control_plane_audit (namespace, scope, record_key, revision);
|
|
165
269
|
`);
|
|
166
|
-
|
|
270
|
+
withSqliteStatement(
|
|
271
|
+
database,
|
|
272
|
+
'INSERT OR IGNORE INTO control_plane_schema (version, applied_at) VALUES (?, ?)',
|
|
273
|
+
(statement) => statement.run(CONTROL_PLANE_SCHEMA_VERSION, now()),
|
|
274
|
+
);
|
|
167
275
|
}
|
|
168
276
|
|
|
169
277
|
export function controlPlaneDatabasePath(controllerHome: string): string {
|
|
@@ -238,6 +346,42 @@ function openDatabaseForRead(controllerHome: string): SqliteDatabase {
|
|
|
238
346
|
return openDatabase(controllerHome);
|
|
239
347
|
}
|
|
240
348
|
|
|
349
|
+
|
|
350
|
+
function withDatabaseForRead<T>(controllerHome: string, operation: (database: SqliteDatabase) => T): T {
|
|
351
|
+
const path = controlPlaneDatabasePath(controllerHome);
|
|
352
|
+
if (!reusableReadDatabasePaths.has(path)) {
|
|
353
|
+
const database = openDatabaseForRead(controllerHome);
|
|
354
|
+
try {
|
|
355
|
+
return operation(database);
|
|
356
|
+
} finally {
|
|
357
|
+
database.close();
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const liveIdentity = databaseFileIdentity(path);
|
|
362
|
+
const cached = reusableReadDatabases.get(path);
|
|
363
|
+
if (cached && liveIdentity && cached.fileIdentity === liveIdentity) {
|
|
364
|
+
return operation(cached.database);
|
|
365
|
+
}
|
|
366
|
+
if (cached) closeReusableReadDatabase(path);
|
|
367
|
+
|
|
368
|
+
const database = openDatabaseForRead(controllerHome);
|
|
369
|
+
const openedIdentity = databaseFileIdentity(path);
|
|
370
|
+
if (!openedIdentity) {
|
|
371
|
+
database.close();
|
|
372
|
+
throw new Error(`CONTROL_PLANE_SQLITE_MISSING: ${path}`);
|
|
373
|
+
}
|
|
374
|
+
reusableReadDatabases.set(path, { database, fileIdentity: openedIdentity });
|
|
375
|
+
try {
|
|
376
|
+
return operation(database);
|
|
377
|
+
} catch (error) {
|
|
378
|
+
// Do not retain a reader that failed while evaluating a query/schema. The
|
|
379
|
+
// next operation gets a clean connection and repeats the fail-closed checks.
|
|
380
|
+
closeReusableReadDatabase(path);
|
|
381
|
+
throw error;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
241
385
|
function rowToRecord<T>(row: StoredRecordRow): ControlPlaneRecord<T> {
|
|
242
386
|
let value: T;
|
|
243
387
|
try {
|
|
@@ -258,11 +402,11 @@ function rowToRecord<T>(row: StoredRecordRow): ControlPlaneRecord<T> {
|
|
|
258
402
|
}
|
|
259
403
|
|
|
260
404
|
function selectRecord<T>(database: SqliteDatabase, namespace: string, scope: string, key: string): ControlPlaneRecord<T> | undefined {
|
|
261
|
-
const row = database
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
405
|
+
const row = withSqliteStatement(database, `
|
|
406
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
407
|
+
FROM control_plane_records
|
|
408
|
+
WHERE namespace = ? AND scope = ? AND record_key = ?
|
|
409
|
+
`, (statement) => statement.get(namespace, scope, key) as StoredRecordRow | undefined);
|
|
266
410
|
return row ? rowToRecord<T>(row) : undefined;
|
|
267
411
|
}
|
|
268
412
|
|
|
@@ -272,22 +416,30 @@ function writeRecord<T>(
|
|
|
272
416
|
existing?: ControlPlaneRecord<T>,
|
|
273
417
|
): ControlPlaneRecord<T> {
|
|
274
418
|
const at = now();
|
|
275
|
-
const
|
|
419
|
+
const previousAuditRevision = Number(withSqliteStatement(database, `
|
|
420
|
+
SELECT MAX(revision) AS revision FROM control_plane_audit
|
|
421
|
+
WHERE namespace = ? AND scope = ? AND record_key = ?
|
|
422
|
+
`, (statement) => scalar(statement.get(input.namespace, input.scope, input.key))) ?? 0);
|
|
423
|
+
const revision = existing
|
|
424
|
+
? existing.revision + 1
|
|
425
|
+
: Math.max(0, Number.isSafeInteger(previousAuditRevision) ? previousAuditRevision : 0) + 1;
|
|
276
426
|
const createdAt = existing?.createdAt ?? at;
|
|
277
|
-
database
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
427
|
+
withSqliteStatement(database, `
|
|
428
|
+
INSERT INTO control_plane_records (
|
|
429
|
+
namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
430
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
431
|
+
ON CONFLICT(namespace, scope, record_key) DO UPDATE SET
|
|
432
|
+
schema_version = excluded.schema_version,
|
|
433
|
+
revision = excluded.revision,
|
|
434
|
+
payload = excluded.payload,
|
|
435
|
+
updated_at = excluded.updated_at
|
|
436
|
+
`, (statement) => statement.run(
|
|
437
|
+
input.namespace, input.scope, input.key, input.schemaVersion, revision, JSON.stringify(input.value), createdAt, at,
|
|
438
|
+
));
|
|
439
|
+
withSqliteStatement(database, `
|
|
440
|
+
INSERT INTO control_plane_audit (namespace, scope, record_key, action, revision, occurred_at)
|
|
441
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
442
|
+
`, (statement) => statement.run(input.namespace, input.scope, input.key, input.action, revision, at));
|
|
291
443
|
return {
|
|
292
444
|
namespace: input.namespace,
|
|
293
445
|
scope: input.scope,
|
|
@@ -352,12 +504,8 @@ export function withControlPlaneTransaction<T>(controllerHome: string, operation
|
|
|
352
504
|
}
|
|
353
505
|
|
|
354
506
|
export function readControlPlaneRecord<T>(controllerHome: string, namespace: string, scope: string, key: string): ControlPlaneRecord<T> | undefined {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
return selectRecord<T>(database, namespace, scope, key);
|
|
358
|
-
} finally {
|
|
359
|
-
database.close();
|
|
360
|
-
}
|
|
507
|
+
return withDatabaseForRead(controllerHome, (database) =>
|
|
508
|
+
selectRecord<T>(database, namespace, scope, key));
|
|
361
509
|
}
|
|
362
510
|
|
|
363
511
|
export function writeControlPlaneRecord<T>(
|
|
@@ -376,6 +524,72 @@ export function writeControlPlaneRecord<T>(
|
|
|
376
524
|
writeControlPlaneRecordWithinTransaction(database, input));
|
|
377
525
|
}
|
|
378
526
|
|
|
527
|
+
export function deleteControlPlaneRecordWithinTransaction(
|
|
528
|
+
database: SqliteDatabase,
|
|
529
|
+
input: { namespace: string; scope: string; key: string; action?: string; expectedRevision?: number },
|
|
530
|
+
): boolean {
|
|
531
|
+
const existing = selectRecord(database, input.namespace, input.scope, input.key);
|
|
532
|
+
if (input.expectedRevision !== undefined && existing?.revision !== input.expectedRevision) {
|
|
533
|
+
throw new ControlPlaneConflictError(input.namespace, input.scope, input.key, input.expectedRevision, existing?.revision);
|
|
534
|
+
}
|
|
535
|
+
if (!existing) return false;
|
|
536
|
+
const revision = existing.revision + 1;
|
|
537
|
+
const at = now();
|
|
538
|
+
withSqliteStatement(database, `
|
|
539
|
+
DELETE FROM control_plane_records
|
|
540
|
+
WHERE namespace = ? AND scope = ? AND record_key = ?
|
|
541
|
+
`, (statement) => statement.run(input.namespace, input.scope, input.key));
|
|
542
|
+
withSqliteStatement(database, `
|
|
543
|
+
INSERT INTO control_plane_audit (namespace, scope, record_key, action, revision, occurred_at)
|
|
544
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
545
|
+
`, (statement) => statement.run(input.namespace, input.scope, input.key, input.action ?? 'delete', revision, at));
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
export function deleteControlPlaneRecord(
|
|
550
|
+
controllerHome: string,
|
|
551
|
+
input: { namespace: string; scope: string; key: string; action?: string; expectedRevision?: number },
|
|
552
|
+
): boolean {
|
|
553
|
+
return withControlPlaneTransaction(controllerHome, (database) =>
|
|
554
|
+
deleteControlPlaneRecordWithinTransaction(database, input));
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
export function deleteControlPlaneRecordsWithinTransaction(
|
|
558
|
+
database: SqliteDatabase,
|
|
559
|
+
input: { namespace: string; scope: string; action?: string },
|
|
560
|
+
): number {
|
|
561
|
+
const rows = withSqliteStatement(database, `
|
|
562
|
+
SELECT record_key, revision
|
|
563
|
+
FROM control_plane_records
|
|
564
|
+
WHERE namespace = ? AND scope = ?
|
|
565
|
+
ORDER BY record_key ASC
|
|
566
|
+
`, (statement) => statement.all(input.namespace, input.scope) as Array<{ record_key: string; revision: number }>);
|
|
567
|
+
if (rows.length === 0) return 0;
|
|
568
|
+
|
|
569
|
+
const at = now();
|
|
570
|
+
withSqliteStatement(database, `
|
|
571
|
+
DELETE FROM control_plane_records
|
|
572
|
+
WHERE namespace = ? AND scope = ? AND record_key = ?
|
|
573
|
+
`, (remove) => withSqliteStatement(database, `
|
|
574
|
+
INSERT INTO control_plane_audit (namespace, scope, record_key, action, revision, occurred_at)
|
|
575
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
576
|
+
`, (audit) => {
|
|
577
|
+
for (const row of rows) {
|
|
578
|
+
remove.run(input.namespace, input.scope, row.record_key);
|
|
579
|
+
audit.run(input.namespace, input.scope, row.record_key, input.action ?? 'delete_scope', row.revision + 1, at);
|
|
580
|
+
}
|
|
581
|
+
}));
|
|
582
|
+
return rows.length;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
export function deleteControlPlaneRecords(
|
|
586
|
+
controllerHome: string,
|
|
587
|
+
input: { namespace: string; scope: string; action?: string },
|
|
588
|
+
): number {
|
|
589
|
+
return withControlPlaneTransaction(controllerHome, (database) =>
|
|
590
|
+
deleteControlPlaneRecordsWithinTransaction(database, input));
|
|
591
|
+
}
|
|
592
|
+
|
|
379
593
|
export class ControlPlaneConflictError extends Error {
|
|
380
594
|
readonly expectedRevision: number | null;
|
|
381
595
|
readonly actualRevision: number | undefined;
|
|
@@ -388,32 +602,134 @@ export class ControlPlaneConflictError extends Error {
|
|
|
388
602
|
}
|
|
389
603
|
}
|
|
390
604
|
|
|
605
|
+
export function listControlPlaneRecordsWithinTransaction<T>(
|
|
606
|
+
database: SqliteDatabase,
|
|
607
|
+
input: { namespace: string; scope?: string; limit?: number },
|
|
608
|
+
): ControlPlaneRecord<T>[] {
|
|
609
|
+
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 1000), 5000));
|
|
610
|
+
const rows = input.scope === undefined
|
|
611
|
+
? withSqliteStatement(database, `
|
|
612
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
613
|
+
FROM control_plane_records
|
|
614
|
+
WHERE namespace = ?
|
|
615
|
+
ORDER BY updated_at ASC, record_key ASC
|
|
616
|
+
LIMIT ?
|
|
617
|
+
`, (statement) => statement.all(input.namespace, limit))
|
|
618
|
+
: withSqliteStatement(database, `
|
|
619
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
620
|
+
FROM control_plane_records
|
|
621
|
+
WHERE namespace = ? AND scope = ?
|
|
622
|
+
ORDER BY updated_at ASC, record_key ASC
|
|
623
|
+
LIMIT ?
|
|
624
|
+
`, (statement) => statement.all(input.namespace, input.scope, limit));
|
|
625
|
+
return (rows as StoredRecordRow[]).map((row) => rowToRecord<T>(row));
|
|
626
|
+
}
|
|
627
|
+
|
|
391
628
|
export function listControlPlaneRecords<T>(
|
|
392
629
|
controllerHome: string,
|
|
393
630
|
input: { namespace: string; scope?: string; limit?: number },
|
|
394
631
|
): ControlPlaneRecord<T>[] {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
} finally {
|
|
415
|
-
database.close();
|
|
632
|
+
return withDatabaseForRead(controllerHome, (database) =>
|
|
633
|
+
listControlPlaneRecordsWithinTransaction<T>(database, input));
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Candidate-only read optimization for top-level JSON text fields. This never
|
|
638
|
+
* establishes domain authority: missing/null/non-text values remain candidates,
|
|
639
|
+
* and callers must still run their canonical semantic validation.
|
|
640
|
+
*/
|
|
641
|
+
export interface PayloadTextExclusion {
|
|
642
|
+
namespace: string;
|
|
643
|
+
field: string;
|
|
644
|
+
excludedValues: readonly string[];
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function payloadTextExclusionPredicate(input: PayloadTextExclusion): string {
|
|
648
|
+
const field = input.field.trim();
|
|
649
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(field)) {
|
|
650
|
+
throw new Error(`CONTROL_PLANE_JSON_FIELD_INVALID: ${input.field}`);
|
|
416
651
|
}
|
|
652
|
+
const values = [...new Set(input.excludedValues.map((value) => value.trim()).filter(Boolean))].sort();
|
|
653
|
+
if (values.length > 32) throw new Error('CONTROL_PLANE_JSON_EXCLUSION_LIMIT_EXCEEDED');
|
|
654
|
+
// These literals are escaped here, never supplied as SQL by a domain caller.
|
|
655
|
+
// SQLite must see identical literals in the query and partial-index predicate.
|
|
656
|
+
const literal = (value: string) => `'${value.replaceAll("'", "''")}'`;
|
|
657
|
+
const namespace = `namespace = ${literal(input.namespace)}`;
|
|
658
|
+
if (values.length === 0) return namespace;
|
|
659
|
+
const extraction = `json_extract(payload, ${literal(`$.${field}`)})`;
|
|
660
|
+
return `${namespace} AND (${extraction} IS NULL OR ${extraction} NOT IN (${values.map(literal).join(', ')}))`;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/** Explicit startup DDL. JSON remains authority; SQLite maintains the derived index in every write transaction. */
|
|
664
|
+
export function initializeControlPlanePayloadTextExclusionIndex(
|
|
665
|
+
controllerHome: string,
|
|
666
|
+
input: PayloadTextExclusion,
|
|
667
|
+
): void {
|
|
668
|
+
const predicate = payloadTextExclusionPredicate(input);
|
|
669
|
+
const prefix = `control_plane_candidate_${createHash('sha256').update(`${input.namespace}/${input.field}`).digest('hex').slice(0, 16)}_`;
|
|
670
|
+
const name = `${prefix}${createHash('sha256').update(predicate).digest('hex').slice(0, 16)}`;
|
|
671
|
+
withControlPlaneTransaction(controllerHome, (database) => {
|
|
672
|
+
database.exec(`CREATE INDEX IF NOT EXISTS ${name} ON control_plane_records (scope, updated_at, record_key) WHERE ${predicate}`);
|
|
673
|
+
// Retire obsolete predicates for this domain field in the same transaction.
|
|
674
|
+
const old = withSqliteStatement(database, "SELECT name FROM sqlite_master WHERE type = 'index' AND substr(name, 1, ?) = ?",
|
|
675
|
+
(statement) => statement.all(prefix.length, prefix)) as Array<{ name: string }>;
|
|
676
|
+
for (const index of old) {
|
|
677
|
+
if (index.name !== name && /^control_plane_candidate_[a-f0-9]{16}_[a-f0-9]{16}$/.test(index.name)) {
|
|
678
|
+
database.exec(`DROP INDEX ${index.name}`);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
export function listControlPlaneRecordsExcludingPayloadTextValues<T>(
|
|
685
|
+
controllerHome: string,
|
|
686
|
+
input: PayloadTextExclusion & { scope: string; limit?: number },
|
|
687
|
+
): ControlPlaneRecord<T>[] {
|
|
688
|
+
const predicate = payloadTextExclusionPredicate(input);
|
|
689
|
+
const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 1_000), 5_000));
|
|
690
|
+
return withDatabaseForRead(controllerHome, (database) => {
|
|
691
|
+
const rows = withSqliteStatement(database, `
|
|
692
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
693
|
+
FROM control_plane_records
|
|
694
|
+
WHERE ${predicate} AND scope = ?
|
|
695
|
+
ORDER BY updated_at ASC, record_key ASC
|
|
696
|
+
LIMIT ?
|
|
697
|
+
`, (statement) => statement.all(input.scope, limit));
|
|
698
|
+
return (rows as StoredRecordRow[]).map((row) => rowToRecord<T>(row));
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Internal correctness surface for authorities that must observe every durable
|
|
704
|
+
* fact in a namespace/scope. User-facing and diagnostic list APIs should keep
|
|
705
|
+
* using listControlPlaneRecords so their output remains bounded.
|
|
706
|
+
*/
|
|
707
|
+
export function listAllControlPlaneRecordsWithinTransaction<T>(
|
|
708
|
+
database: SqliteDatabase,
|
|
709
|
+
input: { namespace: string; scope?: string },
|
|
710
|
+
): ControlPlaneRecord<T>[] {
|
|
711
|
+
const rows = input.scope === undefined
|
|
712
|
+
? withSqliteStatement(database, `
|
|
713
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
714
|
+
FROM control_plane_records
|
|
715
|
+
WHERE namespace = ?
|
|
716
|
+
ORDER BY updated_at ASC, record_key ASC
|
|
717
|
+
`, (statement) => statement.all(input.namespace))
|
|
718
|
+
: withSqliteStatement(database, `
|
|
719
|
+
SELECT namespace, scope, record_key, schema_version, revision, payload, created_at, updated_at
|
|
720
|
+
FROM control_plane_records
|
|
721
|
+
WHERE namespace = ? AND scope = ?
|
|
722
|
+
ORDER BY updated_at ASC, record_key ASC
|
|
723
|
+
`, (statement) => statement.all(input.namespace, input.scope));
|
|
724
|
+
return (rows as StoredRecordRow[]).map((row) => rowToRecord<T>(row));
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
export function listAllControlPlaneRecords<T>(
|
|
728
|
+
controllerHome: string,
|
|
729
|
+
input: { namespace: string; scope?: string },
|
|
730
|
+
): ControlPlaneRecord<T>[] {
|
|
731
|
+
return withDatabaseForRead(controllerHome, (database) =>
|
|
732
|
+
listAllControlPlaneRecordsWithinTransaction<T>(database, input));
|
|
417
733
|
}
|
|
418
734
|
|
|
419
735
|
function inspectOpenDatabase(database: SqliteDatabase, path: string): ControlPlaneDatabaseInspection {
|
|
@@ -422,34 +738,42 @@ function inspectOpenDatabase(database: SqliteDatabase, path: string): ControlPla
|
|
|
422
738
|
if (!tableExists(database, 'control_plane_records') || !tableExists(database, 'control_plane_audit')) {
|
|
423
739
|
throw new Error(`CONTROL_PLANE_BACKUP_INVALID: ${path}: required tables are missing`);
|
|
424
740
|
}
|
|
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)
|
|
741
|
+
const recordCount = Number(withSqliteStatement(
|
|
742
|
+
database,
|
|
743
|
+
'SELECT COUNT(*) AS count FROM control_plane_records',
|
|
744
|
+
(statement) => scalar(statement.get()),
|
|
745
|
+
) ?? 0);
|
|
746
|
+
const auditEventCount = Number(withSqliteStatement(
|
|
747
|
+
database,
|
|
748
|
+
'SELECT COUNT(*) AS count FROM control_plane_audit',
|
|
749
|
+
(statement) => scalar(statement.get()),
|
|
750
|
+
) ?? 0);
|
|
751
|
+
const orphanRecordCount = Number(withSqliteStatement(database, `
|
|
752
|
+
SELECT COUNT(*) AS count
|
|
753
|
+
FROM control_plane_records record
|
|
754
|
+
WHERE (
|
|
755
|
+
SELECT COUNT(DISTINCT audit.revision)
|
|
447
756
|
FROM control_plane_audit audit
|
|
448
757
|
WHERE audit.namespace = record.namespace
|
|
449
758
|
AND audit.scope = record.scope
|
|
450
759
|
AND audit.record_key = record.record_key
|
|
451
|
-
|
|
452
|
-
|
|
760
|
+
AND audit.revision BETWEEN 1 AND record.revision
|
|
761
|
+
) != record.revision
|
|
762
|
+
OR COALESCE((
|
|
763
|
+
SELECT MIN(audit.revision)
|
|
764
|
+
FROM control_plane_audit audit
|
|
765
|
+
WHERE audit.namespace = record.namespace
|
|
766
|
+
AND audit.scope = record.scope
|
|
767
|
+
AND audit.record_key = record.record_key
|
|
768
|
+
), 0) != 1
|
|
769
|
+
OR COALESCE((
|
|
770
|
+
SELECT MAX(audit.revision)
|
|
771
|
+
FROM control_plane_audit audit
|
|
772
|
+
WHERE audit.namespace = record.namespace
|
|
773
|
+
AND audit.scope = record.scope
|
|
774
|
+
AND audit.record_key = record.record_key
|
|
775
|
+
), 0) != record.revision
|
|
776
|
+
`, (statement) => scalar(statement.get())) ?? 0);
|
|
453
777
|
if (orphanRecordCount > 0) {
|
|
454
778
|
throw new Error(`CONTROL_PLANE_AUDIT_CONTINUITY_INVALID: ${path}: discontinuous_records=${orphanRecordCount}`);
|
|
455
779
|
}
|
|
@@ -476,6 +800,147 @@ export function inspectControlPlaneDatabaseFile(path: string): ControlPlaneDatab
|
|
|
476
800
|
}
|
|
477
801
|
}
|
|
478
802
|
|
|
803
|
+
interface ControlPlaneDatabasePageSnapshot {
|
|
804
|
+
pageSize: number;
|
|
805
|
+
pageCount: number;
|
|
806
|
+
freePageCount: number;
|
|
807
|
+
reclaimableBytes: number;
|
|
808
|
+
reclaimableRatio: number;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
function integerPragma(database: SqliteDatabase, sql: string, label: string): number {
|
|
812
|
+
const value = Number(withSqliteStatement(database, sql, (statement) => scalar(statement.get())));
|
|
813
|
+
if (!Number.isFinite(value) || value < 0) throw new Error(`CONTROL_PLANE_SQLITE_PRAGMA_INVALID: ${label}`);
|
|
814
|
+
return Math.floor(value);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
function controlPlaneDatabasePageSnapshot(database: SqliteDatabase): ControlPlaneDatabasePageSnapshot {
|
|
818
|
+
const pageSize = integerPragma(database, 'PRAGMA page_size', 'page_size');
|
|
819
|
+
const pageCount = integerPragma(database, 'PRAGMA page_count', 'page_count');
|
|
820
|
+
const freePageCount = integerPragma(database, 'PRAGMA freelist_count', 'freelist_count');
|
|
821
|
+
const reclaimableBytes = freePageCount * pageSize;
|
|
822
|
+
return {
|
|
823
|
+
pageSize,
|
|
824
|
+
pageCount,
|
|
825
|
+
freePageCount,
|
|
826
|
+
reclaimableBytes,
|
|
827
|
+
reclaimableRatio: pageCount > 0 ? freePageCount / pageCount : 0,
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Physical SQLite maintenance only. Domain lifecycles own row deletion; this
|
|
833
|
+
* boundary never decides semantic terminality or removes canonical records.
|
|
834
|
+
* PASSIVE checkpointing is non-blocking, and VACUUM is attempted only when
|
|
835
|
+
* already-reclaimable free pages exceed both configured thresholds. A live
|
|
836
|
+
* writer causes a fail-closed busy skip instead of lock stealing or corruption
|
|
837
|
+
* recovery.
|
|
838
|
+
*/
|
|
839
|
+
export function maintainControlPlaneDatabase(
|
|
840
|
+
controllerHome: string,
|
|
841
|
+
options: ControlPlaneDatabaseMaintenanceOptions = {},
|
|
842
|
+
): ControlPlaneDatabaseMaintenanceReport {
|
|
843
|
+
const path = controlPlaneDatabasePath(controllerHome);
|
|
844
|
+
const report: ControlPlaneDatabaseMaintenanceReport = {
|
|
845
|
+
policyVersion: CONTROL_PLANE_SQLITE_MAINTENANCE_POLICY_VERSION,
|
|
846
|
+
path,
|
|
847
|
+
checkpointMode: 'passive',
|
|
848
|
+
checkpointed: false,
|
|
849
|
+
pageSize: 0,
|
|
850
|
+
pageCountBefore: 0,
|
|
851
|
+
freePageCountBefore: 0,
|
|
852
|
+
reclaimableBytesBefore: 0,
|
|
853
|
+
reclaimableRatioBefore: 0,
|
|
854
|
+
vacuumEligible: false,
|
|
855
|
+
vacuumAttempted: false,
|
|
856
|
+
vacuumed: false,
|
|
857
|
+
pageCountAfter: 0,
|
|
858
|
+
freePageCountAfter: 0,
|
|
859
|
+
reclaimableBytesAfter: 0,
|
|
860
|
+
reclaimableRatioAfter: 0,
|
|
861
|
+
reclaimedBytes: 0,
|
|
862
|
+
};
|
|
863
|
+
if (!existsSync(path)) {
|
|
864
|
+
report.skippedReason = 'database_missing';
|
|
865
|
+
return report;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
let database: SqliteDatabase;
|
|
869
|
+
try {
|
|
870
|
+
database = openRawDatabase(path);
|
|
871
|
+
} catch (error) {
|
|
872
|
+
if ((error instanceof Error ? error.message : String(error)).startsWith('CONTROL_PLANE_SQLITE_BUSY:')) {
|
|
873
|
+
report.skippedReason = 'database_busy';
|
|
874
|
+
return report;
|
|
875
|
+
}
|
|
876
|
+
throw error;
|
|
877
|
+
}
|
|
878
|
+
try {
|
|
879
|
+
database.exec('PRAGMA busy_timeout = 0; PRAGMA foreign_keys = ON;');
|
|
880
|
+
assertSupportedSchema(database, path, true);
|
|
881
|
+
try {
|
|
882
|
+
database.exec('PRAGMA wal_checkpoint(PASSIVE);');
|
|
883
|
+
report.checkpointed = true;
|
|
884
|
+
} catch (error) {
|
|
885
|
+
const busy = sqliteBusyError(path, error);
|
|
886
|
+
if (busy) {
|
|
887
|
+
report.skippedReason = 'database_busy';
|
|
888
|
+
return report;
|
|
889
|
+
}
|
|
890
|
+
throw error;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
const before = controlPlaneDatabasePageSnapshot(database);
|
|
894
|
+
report.pageSize = before.pageSize;
|
|
895
|
+
report.pageCountBefore = before.pageCount;
|
|
896
|
+
report.freePageCountBefore = before.freePageCount;
|
|
897
|
+
report.reclaimableBytesBefore = before.reclaimableBytes;
|
|
898
|
+
report.reclaimableRatioBefore = before.reclaimableRatio;
|
|
899
|
+
report.pageCountAfter = before.pageCount;
|
|
900
|
+
report.freePageCountAfter = before.freePageCount;
|
|
901
|
+
report.reclaimableBytesAfter = before.reclaimableBytes;
|
|
902
|
+
report.reclaimableRatioAfter = before.reclaimableRatio;
|
|
903
|
+
|
|
904
|
+
const minimumReclaimableBytes = Math.max(0, Math.floor(options.minimumReclaimableBytes ?? DEFAULT_CONTROL_PLANE_SQLITE_VACUUM_MIN_RECLAIMABLE_BYTES));
|
|
905
|
+
const configuredRatio = Number(options.minimumReclaimableRatio ?? DEFAULT_CONTROL_PLANE_SQLITE_VACUUM_MIN_RECLAIMABLE_RATIO);
|
|
906
|
+
const minimumReclaimableRatio = Number.isFinite(configuredRatio) ? Math.min(1, Math.max(0, configuredRatio)) : DEFAULT_CONTROL_PLANE_SQLITE_VACUUM_MIN_RECLAIMABLE_RATIO;
|
|
907
|
+
report.vacuumEligible = before.freePageCount > 0
|
|
908
|
+
&& before.reclaimableBytes >= minimumReclaimableBytes
|
|
909
|
+
&& before.reclaimableRatio >= minimumReclaimableRatio;
|
|
910
|
+
if (!report.vacuumEligible) {
|
|
911
|
+
report.skippedReason = 'below_threshold';
|
|
912
|
+
return report;
|
|
913
|
+
}
|
|
914
|
+
if (options.allowVacuum === false) {
|
|
915
|
+
report.skippedReason = 'vacuum_disabled';
|
|
916
|
+
return report;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
report.vacuumAttempted = true;
|
|
920
|
+
try {
|
|
921
|
+
database.exec('VACUUM;');
|
|
922
|
+
} catch (error) {
|
|
923
|
+
const busy = sqliteBusyError(path, error);
|
|
924
|
+
if (busy) {
|
|
925
|
+
report.skippedReason = 'database_busy';
|
|
926
|
+
return report;
|
|
927
|
+
}
|
|
928
|
+
throw error;
|
|
929
|
+
}
|
|
930
|
+
assertDatabaseIntegrity(database, path);
|
|
931
|
+
const after = controlPlaneDatabasePageSnapshot(database);
|
|
932
|
+
report.vacuumed = true;
|
|
933
|
+
report.pageCountAfter = after.pageCount;
|
|
934
|
+
report.freePageCountAfter = after.freePageCount;
|
|
935
|
+
report.reclaimableBytesAfter = after.reclaimableBytes;
|
|
936
|
+
report.reclaimableRatioAfter = after.reclaimableRatio;
|
|
937
|
+
report.reclaimedBytes = Math.max(0, (before.pageCount - after.pageCount) * before.pageSize);
|
|
938
|
+
return report;
|
|
939
|
+
} finally {
|
|
940
|
+
database.close();
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
479
944
|
export function backupControlPlaneDatabase(controllerHome: string, destinationPath: string): ControlPlaneDatabaseInspection {
|
|
480
945
|
const destination = join(destinationPath);
|
|
481
946
|
if (existsSync(destination)) throw new Error(`CONTROL_PLANE_BACKUP_EXISTS: ${destination}`);
|
|
@@ -497,6 +962,10 @@ export function backupControlPlaneDatabase(controllerHome: string, destinationPa
|
|
|
497
962
|
export function restoreControlPlaneDatabase(controllerHome: string, backupPath: string): ControlPlaneDatabaseInspection {
|
|
498
963
|
if (!existsSync(backupPath)) throw new Error(`CONTROL_PLANE_BACKUP_MISSING: ${backupPath}`);
|
|
499
964
|
const target = controlPlaneDatabasePath(controllerHome);
|
|
965
|
+
// A reusable Runtime reader refers to the current inode, not the pathname.
|
|
966
|
+
// Close it before replacing the live authority; reuse remains enabled and the
|
|
967
|
+
// next read opens the verified replacement.
|
|
968
|
+
closeReusableReadDatabase(target);
|
|
500
969
|
const staging = `${target}.restore-${process.pid}-${Date.now()}`;
|
|
501
970
|
copyFileSync(backupPath, staging);
|
|
502
971
|
try {
|