@moretea-labs/forge 1.6.0 → 1.7.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 +4 -0
- package/CHANGELOG.md +39 -0
- package/CLAUDE.md +4 -0
- package/README.md +2 -2
- package/README.zh-CN.md +1 -1
- package/SKILL.md +2 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/hooks/hook-input.sh +11 -8
- package/assets/hooks/lib/session-state.sh +10 -7
- package/assets/hooks/lib/workflow-state.sh +13 -177
- package/assets/hooks/post-tool-observer.sh +8 -2
- package/assets/hooks/prompt-guard.sh +5 -81
- package/assets/hooks/session-start-context.sh +56 -1
- package/assets/partials/05-workflow.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +2 -0
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +3 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/contract.template.md +2 -7
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-architecture-sync.sh +17 -0
- package/assets/templates/helpers/check-task-workflow.sh +4 -4
- package/assets/templates/helpers/contract-worktree.sh +1 -21
- package/assets/templates/helpers/ensure-task-workflow.sh +11 -36
- package/assets/templates/helpers/inspect-project-state.ts +8 -6
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
- package/assets/templates/helpers/new-plan.sh +1 -1
- package/assets/templates/helpers/plan-to-todo.sh +12 -37
- package/assets/templates/helpers/ship-worktrees.sh +2 -29
- package/assets/templates/helpers/verify-contract.sh +1 -111
- package/assets/templates/helpers/verify-sprint.sh +3 -180
- package/assets/templates/helpers/workflow-contract.ts +5 -1
- package/assets/templates/plan.template.md +1 -1
- package/assets/templates/review.template.md +9 -34
- package/assets/workflow-contract.v1.json +10 -19
- package/docs/README.md +10 -10
- package/docs/architecture/CURRENT.md +178 -0
- package/docs/architecture/EVOLUTION.md +42 -0
- package/docs/architecture/current/README.md +4 -156
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
- package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
- package/docs/architecture/history/README.md +7 -0
- package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
- package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
- package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
- package/docs/architecture/history.md +3 -34
- package/docs/architecture/index.md +15 -98
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
- package/docs/architecture/versions/1.6.md +38 -0
- package/docs/architecture/versions/1.7.md +41 -0
- package/docs/forge-chatgpt-browser-engine.md +2 -2
- package/docs/forge-chatgpt-mcp-setup.md +4 -28
- package/docs/forge-chatgpt-supervised-automation.md +3 -3
- package/docs/forge-github-issue-launcher.md +1 -1
- package/docs/forge-plugin-management.md +1 -1
- package/docs/forge-runtime-self-healing-loop.md +1 -1
- package/docs/operations/controller-browser-plugin.md +26 -6
- package/docs/operations/controller-performance-and-502.md +143 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +2 -2
- package/docs/operations/github-repository.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +5 -3
- package/docs/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/package.json +33 -11
- package/scripts/activate-source-baseline.ts +17 -13
- package/scripts/architecture-event.ts +2 -820
- package/scripts/architecture-queue.sh +2 -645
- package/scripts/archive-architecture-request.sh +2 -242
- package/scripts/archive-workflow.sh +1 -291
- package/scripts/benchmark-background-check-overlap.ts +228 -0
- package/scripts/benchmark-mcp-host.sh +117 -0
- package/scripts/benchmark-mcp-transport.ts +170 -0
- package/scripts/benchmark-quality-harness.ts +146 -0
- package/scripts/benchmark-route-session-concurrency.ts +207 -6
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
- package/scripts/benchmark-typescript-navigation.ts +186 -0
- package/scripts/benchmark-work-efficiency.ts +334 -0
- package/scripts/capability-config.ts +2 -392
- package/scripts/capability-resolver.ts +2 -503
- package/scripts/capture-plan.sh +1 -332
- package/scripts/check-agent-tooling.sh +2 -1558
- package/scripts/check-architecture-sync.sh +2 -371
- package/scripts/check-brain-manifest.sh +2 -253
- package/scripts/check-context-files.sh +2 -47
- package/scripts/check-deploy-sql-order.sh +2 -115
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-runtime-architecture.mjs +349 -79
- package/scripts/check-skill-version.ts +3 -191
- package/scripts/check-source-duplication.mjs +61 -0
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-sync.sh +2 -63
- package/scripts/check-task-workflow.sh +2 -1000
- package/scripts/codex-handoff-resume.sh +2 -267
- package/scripts/context-contract-sync.sh +2 -514
- package/scripts/contract-run.ts +2 -463
- package/scripts/contract-worktree.sh +1 -722
- package/scripts/ensure-task-workflow.sh +1 -1225
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/inspect-project-state.ts +4 -279
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +22 -46
- package/scripts/lib/run-forge-helper.sh +19 -0
- package/scripts/lib/run-forge-helper.ts +26 -0
- package/scripts/migrate-project-template.sh +1 -1189
- package/scripts/migrate-workflow-docs.ts +4 -412
- package/scripts/new-plan.sh +1 -180
- package/scripts/new-spec.sh +1 -47
- package/scripts/new-sprint.sh +1 -46
- package/scripts/plan-to-todo.sh +1 -796
- package/scripts/prepare-codex-handoff.sh +2 -201
- package/scripts/prepare-handoff.sh +1 -78
- package/scripts/refresh-current-status.sh +2 -467
- package/scripts/run-governed-gate.ts +5 -1
- package/scripts/select-agent-context-blocks.sh +2 -64
- package/scripts/ship-worktrees.sh +1 -558
- package/scripts/smoke-ios-physical-device.ts +4 -2
- package/scripts/smoke-runtime-recovery.ts +1 -35
- package/scripts/smoke-schedule-engine.ts +1 -20
- package/scripts/sprint-backlog.sh +1 -834
- package/scripts/stage-runtime-release.ts +2 -1
- package/scripts/summarize-failures.sh +2 -123
- package/scripts/switch-plan.sh +1 -150
- package/scripts/sync-brain-docs.sh +2 -379
- package/scripts/sync-generated-authority.mjs +175 -0
- package/scripts/verify-contract.sh +2 -703
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +1 -677
- package/scripts/workflow-contract.ts +4 -205
- package/scripts/workstream-sync.sh +2 -261
- package/src/cli/agent-jobs/executor-health.ts +1 -1
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +12 -3
- package/src/cli/commands/recovery.ts +25 -3
- package/src/cli/commands/runtime.ts +55 -3
- package/src/cli/commands/security.ts +12 -1
- package/src/cli/commands/setup-profile.ts +31 -21
- package/src/cli/controller/check-runner.ts +113 -5
- package/src/cli/controller/composite-result.ts +1 -1
- package/src/cli/controller/context/focus.ts +51 -0
- package/src/cli/controller/context/instruction-context.ts +114 -0
- package/src/cli/controller/context/known-paths.ts +76 -0
- package/src/cli/controller/context/query-planning.ts +110 -0
- package/src/cli/controller/context/rule-resolution.ts +532 -0
- package/src/cli/controller/context/source-materializer.ts +278 -0
- package/src/cli/controller/context/structural.ts +16 -0
- package/src/cli/controller/context/types.ts +286 -0
- package/src/cli/controller/context-pack.ts +828 -487
- package/src/cli/controller/launch-agents.ts +77 -2
- package/src/cli/controller/operational-plan.ts +2 -2
- package/src/cli/controller/work-mode.ts +6 -4
- package/src/cli/editing/edit-session.ts +60 -7
- package/src/cli/github/contracts.ts +16 -0
- package/src/cli/github/github.ts +135 -16
- package/src/cli/github/session.ts +2 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +54 -78
- package/src/cli/local-bridge/console-view-models.ts +1 -35
- package/src/cli/local-bridge/facade-api.ts +37 -264
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
- package/src/cli/local-bridge/frontend/src/styles.css +1 -1
- package/src/cli/local-bridge/frontend/src/types.ts +5 -8
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +2 -515
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
- package/src/cli/mcp/auth.ts +5 -5
- package/src/cli/mcp/instructions.ts +3 -2
- package/src/cli/mcp/legacy-tool-service.ts +10 -222
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
- package/src/cli/mcp/repository-tools.ts +282 -146
- package/src/cli/mcp/server.ts +586 -116
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/tool-contract.ts +14 -0
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +44 -7
- package/src/cli/mcp/transports/http.ts +124 -14
- package/src/cli/mcp/transports/session-registry.ts +43 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +103 -21
- package/src/cli/repositories/command-executor.ts +78 -526
- package/src/cli/repositories/command-process.ts +108 -0
- package/src/cli/repositories/command-scope.ts +99 -41
- package/src/cli/repositories/controller-home.ts +7 -8
- package/src/cli/repositories/git-command-executor.ts +2 -0
- package/src/cli/repositories/locks.ts +53 -16
- package/src/cli/repositories/repository-snapshot.ts +124 -0
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +118 -6
- package/src/cli/repository/inspector.ts +563 -65
- package/src/cli/repository/session-cache.ts +58 -17
- package/src/cli/v81-entry.ts +1 -4
- package/src/effects/fs-transaction.ts +85 -17
- package/src/runtime/context/codegraph-read-provider.ts +233 -2
- package/src/runtime/context/codegraph-sidecar.cjs +74 -40
- package/src/runtime/context/generic-lsp-provider.ts +355 -0
- package/src/runtime/context/lsp-client.ts +283 -0
- package/src/runtime/context/semantic-navigation-contract.ts +61 -0
- package/src/runtime/context/semantic-navigation.ts +223 -0
- package/src/runtime/context/swift-navigation.ts +565 -0
- package/src/runtime/context/typescript-navigation.ts +226 -0
- package/src/runtime/control-plane/dispatch-priority.ts +28 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +48 -16
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
- package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
- package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
- package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
- package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
- package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
- package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
- package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
- package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
- package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +22 -18
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +156 -11
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
- package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
- package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +90 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +1118 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +302 -12
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +17 -1
- package/src/runtime/control-plane/facade/goal-workloop.ts +928 -190
- package/src/runtime/control-plane/facade/index.ts +3 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +275 -42
- package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
- package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
- package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
- package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
- package/src/runtime/control-plane/facade/types.ts +90 -10
- package/src/runtime/control-plane/facade/work-contract-store.ts +157 -261
- package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
- package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
- package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
- package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +152 -0
- package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +278 -543
- package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
- package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
- package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
- package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
- package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +63 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +365 -117
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +89 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +244 -11
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
- package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
- package/src/runtime/control-plane/release-retention.ts +62 -2
- package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
- package/src/runtime/control-plane/routing/route-policy.ts +24 -21
- package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
- package/src/runtime/control-plane/runtime-status-client.ts +0 -2
- package/src/runtime/diagnostics/mcp-timing.ts +13 -0
- package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
- package/src/runtime/diagnostics/performance.ts +24 -1
- package/src/runtime/evidence/event-ledger.ts +1 -1
- package/src/runtime/evidence/process-check-execution.ts +18 -0
- package/src/runtime/execution/jobs/child-reference.ts +6 -2
- package/src/runtime/execution/jobs/store.ts +58 -4
- package/src/runtime/execution/jobs/types.ts +1 -1
- package/src/runtime/execution/managed-workspace.ts +203 -1
- package/src/runtime/execution/process-runtime/check-facade.ts +51 -4
- package/src/runtime/execution/process-runtime/check-result.ts +88 -0
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +367 -40
- package/src/runtime/execution/process-runtime/gc.ts +38 -6
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1201 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +51 -5
- package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
- package/src/runtime/execution/process-runtime/runtime.ts +53 -3
- package/src/runtime/execution/process-runtime/store.ts +1 -0
- package/src/runtime/execution/process-runtime/types.ts +4 -12
- package/src/runtime/execution/thin-harness/async-process.ts +12 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
- package/src/runtime/execution/work-activity.ts +21 -0
- package/src/runtime/execution/workers/executor.ts +18 -61
- package/src/runtime/gateway/mcp/execution-tools.ts +35 -1852
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +186 -84
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +565 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2378 -1947
- package/src/runtime/plugins/app-store-connect-adapter.ts +216 -47
- package/src/runtime/plugins/browser-adapter.ts +2662 -829
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +2 -25
- package/src/runtime/plugins/browser-handoff.ts +110 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +701 -63
- package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
- package/src/runtime/plugins/browser-native-session-service.ts +222 -0
- package/src/runtime/plugins/browser-node-bridge.ts +6 -34
- package/src/runtime/plugins/browser-provider-registry.ts +109 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +154 -0
- package/src/runtime/plugins/browser-runtime.ts +193 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/browser-session-store.ts +121 -0
- package/src/runtime/plugins/browser-session-types.ts +98 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +10 -4
- package/src/runtime/plugins/external-adapter.ts +358 -3
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +2 -0
- package/src/runtime/plugins/github-adapter.ts +125 -0
- package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
- package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
- package/src/runtime/plugins/ios-adapter.ts +106 -16
- package/src/runtime/plugins/ios-agent-device.ts +234 -64
- package/src/runtime/plugins/ios-physical-device.ts +1143 -392
- package/src/runtime/plugins/lightweight-action.ts +153 -0
- package/src/runtime/plugins/local-system-adapter.ts +123 -6
- package/src/runtime/plugins/macos-capability-broker.ts +47 -9
- package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
- package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +330 -33
- package/src/runtime/plugins/types.ts +38 -3
- package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
- package/src/runtime/projections/git-status-sampler.ts +16 -16
- package/src/runtime/projections/materialized-view.ts +28 -10
- package/src/runtime/recovery/maintenance-executor.ts +426 -25
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +230 -10
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +461 -22
- package/src/runtime/root/release-manifest.ts +144 -18
- package/src/runtime/root/release-materialize.ts +125 -32
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -29
- package/src/runtime/root/types.ts +12 -0
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- package/src/runtime/shared/trusted-executable.ts +62 -0
- package/src/runtime/shared/trusted-node-executable.ts +48 -0
- package/src/runtime/standalone-recovery/core.ts +1079 -240
- package/src/runtime/standalone-recovery/entry.ts +100 -24
- package/src/runtime/standalone-recovery/installer.ts +20 -4
- package/src/runtime/standalone-recovery/service-labels.ts +2 -0
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
- package/src/runtime/workflow/schedules/browser-probe.ts +81 -3
- package/src/runtime/workflow/schedules/engine.ts +364 -202
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +64 -17
- package/src/runtime/workflow/schedules/store.ts +209 -19
- package/src/runtime/workflow/schedules/types.ts +2 -4
- package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
- package/src/testing/test-governance.ts +8 -40
- package/assets/reference-configs/heartbeat-triage.md +0 -57
- package/assets/templates/helpers/harness-trace-grade.sh +0 -150
- package/assets/templates/helpers/heartbeat-triage.sh +0 -361
- package/assets/templates/helpers/maintenance-triage.sh +0 -167
- package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
- package/docs/architecture/current/architecture-invariants.md +0 -331
- package/docs/architecture/current/automation-and-schedule-engine.md +0 -459
- package/docs/architecture/current/codegraph-context-provider.md +0 -238
- package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
- package/docs/architecture/current/controller-repository-decoupling.md +0 -148
- package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -373
- package/docs/architecture/current/entity-model.md +0 -612
- package/docs/architecture/current/external-plugin-governance.md +0 -396
- package/docs/architecture/current/failure-recovery.md +0 -447
- package/docs/architecture/current/governance.md +0 -213
- package/docs/architecture/current/human-interaction-plane.md +0 -87
- package/docs/architecture/current/implementation-status.md +0 -128
- package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
- package/docs/architecture/current/legacy-governance.md +0 -58
- package/docs/architecture/current/local-workspace-target-grants.md +0 -70
- package/docs/architecture/current/migration-roadmap.md +0 -105
- package/docs/architecture/current/multi-repository-execution.md +0 -371
- package/docs/architecture/current/operations-runbook.md +0 -45
- package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
- package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
- package/docs/architecture/current/repository-access-modes.md +0 -102
- package/docs/architecture/current/route-policy.md +0 -15
- package/docs/architecture/current/route-session-concurrency.md +0 -85
- package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
- package/docs/architecture/current/runtime-directory-map.md +0 -49
- package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
- package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
- package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
- package/docs/architecture/current/system-overview.md +0 -169
- package/docs/architecture/current/target-requirements-traceability.md +0 -202
- package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
- package/docs/architecture/current/thin-harness-v1.md +0 -321
- package/docs/architecture/current/verification-and-release-gates.md +0 -391
- package/docs/forge-autonomous-goal-loop.md +0 -9
- package/docs/forge-provider-configuration.md +0 -7
- package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -93
- package/docs/operations/gmail-assistant-routines.md +0 -186
- package/docs/operations/personal-assistant-operator-guide.md +0 -61
- package/docs/operations/provider-configuration.md +0 -31
- package/scripts/harness-trace-grade.sh +0 -150
- package/scripts/heartbeat-triage.sh +0 -361
- package/scripts/maintenance-triage.sh +0 -167
- package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
- package/src/cli/repositories/goal-registry.ts +0 -239
- package/src/runtime/assistant/action-proposals.ts +0 -279
- package/src/runtime/assistant/intent.ts +0 -395
- package/src/runtime/assistant/model-provider.ts +0 -460
- package/src/runtime/assistant/openapi.ts +0 -223
- package/src/runtime/assistant/policy.ts +0 -89
- package/src/runtime/assistant/readiness.ts +0 -258
- package/src/runtime/assistant/routine-runtime.ts +0 -477
- package/src/runtime/assistant/schedule-binding.ts +0 -171
- package/src/runtime/assistant/standing-grants.ts +0 -375
- package/src/runtime/assistant/store.ts +0 -243
- package/src/runtime/assistant/types.ts +0 -135
- package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
- package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
- package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
- package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
- package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
- package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
- package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
- package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
- package/src/runtime/control-plane/goal-loop/index.ts +0 -13
- package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
- package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
- package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
- package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
- package/src/runtime/control-plane/goal-loop/types.ts +0 -378
- package/src/runtime/control-plane/startup-recovery.ts +0 -198
- package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
- package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
- package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
- package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
- package/src/runtime/workflow/findings/store.ts +0 -204
- package/src/runtime/workflow/findings/types.ts +0 -58
- package/src/runtime/workflow/portfolio/engine.ts +0 -20
- package/src/runtime/workflow/portfolio/store.ts +0 -185
- package/src/runtime/workflow/portfolio/types.ts +0 -29
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync } from 'fs';
|
|
1
|
+
import { existsSync, readFileSync, realpathSync } from 'fs';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
3
|
import { CONTROL_PLANE_SCHEMA_VERSION } from '../control-plane/persistence/sqlite-store';
|
|
4
4
|
import type { RuntimeReleaseManifest } from './types';
|
|
@@ -8,6 +8,82 @@ function requireString(value: unknown, field: string): string {
|
|
|
8
8
|
return value.trim();
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
function canonicalExistingPathIdentity(path: string): string {
|
|
12
|
+
const resolved = resolve(path);
|
|
13
|
+
return existsSync(resolved) ? realpathSync(resolved) : resolved;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function requireSha256Identity(value: unknown, field: string): string {
|
|
17
|
+
const identity = requireString(value, field);
|
|
18
|
+
if (!/^sha256:[a-f0-9]{64}$/i.test(identity)) {
|
|
19
|
+
throw new Error(`RELEASE_MANIFEST_INVALID: ${field} must be sha256:<64 hex>`);
|
|
20
|
+
}
|
|
21
|
+
return identity;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type RuntimeComponentPair<KEntry extends keyof RuntimeReleaseManifest, KIdentity extends keyof RuntimeReleaseManifest> = Pick<
|
|
25
|
+
RuntimeReleaseManifest,
|
|
26
|
+
KEntry | KIdentity
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
function optionalRuntimeComponent<
|
|
30
|
+
KEntry extends keyof RuntimeReleaseManifest,
|
|
31
|
+
KIdentity extends keyof RuntimeReleaseManifest,
|
|
32
|
+
>(input: {
|
|
33
|
+
value: Record<string, unknown>;
|
|
34
|
+
entryField: KEntry;
|
|
35
|
+
identityField: KIdentity;
|
|
36
|
+
canonicalEntry: RuntimeReleaseManifest[KEntry];
|
|
37
|
+
}): RuntimeComponentPair<KEntry, KIdentity> | undefined {
|
|
38
|
+
const rawEntry = input.value[input.entryField as string];
|
|
39
|
+
const rawIdentity = input.value[input.identityField as string];
|
|
40
|
+
if (rawEntry === undefined && rawIdentity === undefined) return undefined;
|
|
41
|
+
const entry = requireString(rawEntry, input.entryField as string);
|
|
42
|
+
if (entry !== input.canonicalEntry) {
|
|
43
|
+
throw new Error(`RELEASE_MANIFEST_INVALID: ${String(input.entryField)} must be ${String(input.canonicalEntry)}, got ${entry}`);
|
|
44
|
+
}
|
|
45
|
+
const identity = requireSha256Identity(rawIdentity, input.identityField as string);
|
|
46
|
+
return {
|
|
47
|
+
[input.entryField]: input.canonicalEntry,
|
|
48
|
+
[input.identityField]: identity,
|
|
49
|
+
} as RuntimeComponentPair<KEntry, KIdentity>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const COMPILED_RUNTIME_RELEASE_COMPONENT_FIELDS = [
|
|
53
|
+
'diagnosticEntrypoint', 'diagnosticArtifactIdentity',
|
|
54
|
+
'browserNodeBridgeEntrypoint', 'browserNodeBridgeArtifactIdentity',
|
|
55
|
+
'browserHandoffEntrypoint', 'browserHandoffArtifactIdentity',
|
|
56
|
+
'processRunnerEntrypoint', 'processRunnerArtifactIdentity',
|
|
57
|
+
'checkRunnerEntrypoint', 'checkRunnerArtifactIdentity',
|
|
58
|
+
'pluginActionSidecarEntrypoint', 'pluginActionSidecarArtifactIdentity',
|
|
59
|
+
'externalPluginProbeEntrypoint', 'externalPluginProbeArtifactIdentity',
|
|
60
|
+
'codeGraphNodeEntrypoint', 'codeGraphNodeArtifactIdentity',
|
|
61
|
+
'codeGraphSidecarEntrypoint', 'codeGraphSidecarArtifactIdentity',
|
|
62
|
+
'codeGraphLibraryRoot', 'codeGraphLibraryArtifactIdentity',
|
|
63
|
+
'packageRoot', 'packageArtifactIdentity',
|
|
64
|
+
'controllerUiRoot', 'controllerUiArtifactIdentity',
|
|
65
|
+
] as const satisfies readonly (keyof RuntimeReleaseManifest)[];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Compiled self-host candidates have a closed execution surface. Package
|
|
69
|
+
* launcher releases are a separate source-backed release form and therefore
|
|
70
|
+
* intentionally do not satisfy this contract.
|
|
71
|
+
*/
|
|
72
|
+
export type CompleteCompiledRuntimeReleaseManifest = RuntimeReleaseManifest & Required<Pick<
|
|
73
|
+
RuntimeReleaseManifest,
|
|
74
|
+
typeof COMPILED_RUNTIME_RELEASE_COMPONENT_FIELDS[number]
|
|
75
|
+
>>;
|
|
76
|
+
|
|
77
|
+
export function requireCompleteCompiledRuntimeReleaseManifest(
|
|
78
|
+
manifest: RuntimeReleaseManifest,
|
|
79
|
+
): asserts manifest is CompleteCompiledRuntimeReleaseManifest {
|
|
80
|
+
for (const field of COMPILED_RUNTIME_RELEASE_COMPONENT_FIELDS) {
|
|
81
|
+
if (manifest[field] === undefined) {
|
|
82
|
+
throw new Error(`RUNTIME_RELEASE_COMPILED_COMPONENT_MISSING: ${field}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
11
87
|
export function loadRuntimeReleaseManifest(
|
|
12
88
|
path: string,
|
|
13
89
|
expectedControllerHome: string,
|
|
@@ -31,7 +107,7 @@ export function loadRuntimeReleaseManifest(
|
|
|
31
107
|
throw new Error('RELEASE_MANIFEST_INVALID: configurationSchemaVersion must be 1');
|
|
32
108
|
}
|
|
33
109
|
const controllerHome = resolve(requireString(value.controllerHome, 'controllerHome'));
|
|
34
|
-
if (controllerHome !==
|
|
110
|
+
if (canonicalExistingPathIdentity(controllerHome) !== canonicalExistingPathIdentity(expectedControllerHome)) {
|
|
35
111
|
throw new Error('RELEASE_MANIFEST_CONTROLLER_HOME_MISMATCH');
|
|
36
112
|
}
|
|
37
113
|
const compatibility = value.databaseSchemaCompatibility as Record<string, unknown> | undefined;
|
|
@@ -45,18 +121,60 @@ export function loadRuntimeReleaseManifest(
|
|
|
45
121
|
`RELEASE_DATABASE_SCHEMA_INCOMPATIBLE: runtime=${CONTROL_PLANE_SCHEMA_VERSION} supported=${minimum}-${maximum}`,
|
|
46
122
|
);
|
|
47
123
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
124
|
+
const diagnostic = optionalRuntimeComponent({
|
|
125
|
+
value,
|
|
126
|
+
entryField: 'diagnosticEntrypoint',
|
|
127
|
+
identityField: 'diagnosticArtifactIdentity',
|
|
128
|
+
canonicalEntry: 'forge-cli',
|
|
129
|
+
});
|
|
130
|
+
const browserNodeBridge = optionalRuntimeComponent({
|
|
131
|
+
value,
|
|
132
|
+
entryField: 'browserNodeBridgeEntrypoint',
|
|
133
|
+
identityField: 'browserNodeBridgeArtifactIdentity',
|
|
134
|
+
canonicalEntry: 'browser-node-bridge-host.js',
|
|
135
|
+
});
|
|
136
|
+
const browserHandoff = optionalRuntimeComponent({
|
|
137
|
+
value,
|
|
138
|
+
entryField: 'browserHandoffEntrypoint',
|
|
139
|
+
identityField: 'browserHandoffArtifactIdentity',
|
|
140
|
+
canonicalEntry: 'browser-handoff-host.js',
|
|
141
|
+
});
|
|
142
|
+
const processRunner = optionalRuntimeComponent({
|
|
143
|
+
value,
|
|
144
|
+
entryField: 'processRunnerEntrypoint',
|
|
145
|
+
identityField: 'processRunnerArtifactIdentity',
|
|
146
|
+
canonicalEntry: 'process-runner.js',
|
|
147
|
+
});
|
|
148
|
+
const checkRunner = optionalRuntimeComponent({
|
|
149
|
+
value,
|
|
150
|
+
entryField: 'checkRunnerEntrypoint',
|
|
151
|
+
identityField: 'checkRunnerArtifactIdentity',
|
|
152
|
+
canonicalEntry: 'forge-check-runner',
|
|
153
|
+
});
|
|
154
|
+
const pluginActionSidecar = optionalRuntimeComponent({
|
|
155
|
+
value,
|
|
156
|
+
entryField: 'pluginActionSidecarEntrypoint',
|
|
157
|
+
identityField: 'pluginActionSidecarArtifactIdentity',
|
|
158
|
+
canonicalEntry: 'forge-plugin-action-sidecar',
|
|
159
|
+
});
|
|
160
|
+
const externalPluginProbe = optionalRuntimeComponent({
|
|
161
|
+
value,
|
|
162
|
+
entryField: 'externalPluginProbeEntrypoint',
|
|
163
|
+
identityField: 'externalPluginProbeArtifactIdentity',
|
|
164
|
+
canonicalEntry: 'external-unix-socket-probe.cjs',
|
|
165
|
+
});
|
|
166
|
+
const packageSnapshot = optionalRuntimeComponent({
|
|
167
|
+
value,
|
|
168
|
+
entryField: 'packageRoot',
|
|
169
|
+
identityField: 'packageArtifactIdentity',
|
|
170
|
+
canonicalEntry: 'package',
|
|
171
|
+
});
|
|
172
|
+
const controllerUi = optionalRuntimeComponent({
|
|
173
|
+
value,
|
|
174
|
+
entryField: 'controllerUiRoot',
|
|
175
|
+
identityField: 'controllerUiArtifactIdentity',
|
|
176
|
+
canonicalEntry: 'ui-dist',
|
|
177
|
+
});
|
|
60
178
|
const browserAutomationHelperFields = [
|
|
61
179
|
value.browserAutomationHelperEntrypoint,
|
|
62
180
|
value.browserAutomationHelperArtifactIdentity,
|
|
@@ -107,11 +225,11 @@ export function loadRuntimeReleaseManifest(
|
|
|
107
225
|
}
|
|
108
226
|
codeGraphRuntime = {
|
|
109
227
|
codeGraphNodeEntrypoint: 'codegraph-node',
|
|
110
|
-
codeGraphNodeArtifactIdentity:
|
|
228
|
+
codeGraphNodeArtifactIdentity: requireSha256Identity(value.codeGraphNodeArtifactIdentity, 'codeGraphNodeArtifactIdentity'),
|
|
111
229
|
codeGraphSidecarEntrypoint: 'codegraph-sidecar.cjs',
|
|
112
|
-
codeGraphSidecarArtifactIdentity:
|
|
230
|
+
codeGraphSidecarArtifactIdentity: requireSha256Identity(value.codeGraphSidecarArtifactIdentity, 'codeGraphSidecarArtifactIdentity'),
|
|
113
231
|
codeGraphLibraryRoot: 'codegraph-lib',
|
|
114
|
-
codeGraphLibraryArtifactIdentity:
|
|
232
|
+
codeGraphLibraryArtifactIdentity: requireSha256Identity(value.codeGraphLibraryArtifactIdentity, 'codeGraphLibraryArtifactIdentity'),
|
|
115
233
|
};
|
|
116
234
|
}
|
|
117
235
|
|
|
@@ -131,9 +249,17 @@ export function loadRuntimeReleaseManifest(
|
|
|
131
249
|
releaseId: requireString(value.releaseId, 'releaseId'),
|
|
132
250
|
artifactIdentity: requireString(value.artifactIdentity, 'artifactIdentity'),
|
|
133
251
|
entrypoint: 'forge-runtime',
|
|
134
|
-
...(
|
|
252
|
+
...(diagnostic ?? {}),
|
|
253
|
+
...(browserNodeBridge ?? {}),
|
|
254
|
+
...(browserHandoff ?? {}),
|
|
255
|
+
...(processRunner ?? {}),
|
|
256
|
+
...(checkRunner ?? {}),
|
|
257
|
+
...(pluginActionSidecar ?? {}),
|
|
258
|
+
...(externalPluginProbe ?? {}),
|
|
135
259
|
...(browserAutomationHelper ?? {}),
|
|
136
260
|
...(codeGraphRuntime ?? {}),
|
|
261
|
+
...(packageSnapshot ?? {}),
|
|
262
|
+
...(controllerUi ?? {}),
|
|
137
263
|
arguments: argumentsValue as string[],
|
|
138
264
|
configurationSchemaVersion: 1,
|
|
139
265
|
controllerHome,
|
|
@@ -5,6 +5,8 @@ import { dirname, join, relative, resolve } from 'path';
|
|
|
5
5
|
import { runProcess } from '../../effects/process-runner';
|
|
6
6
|
import { resolveBunExecutable } from '../shared/process-environment';
|
|
7
7
|
import { CONTROL_PLANE_SCHEMA_VERSION } from '../control-plane/persistence/sqlite-store';
|
|
8
|
+
import { loadRuntimeReleaseManifest, requireCompleteCompiledRuntimeReleaseManifest } from './release-manifest';
|
|
9
|
+
import { packageRuntimeFileIndex, stagePackageRuntimeSnapshot } from './package-runtime-release';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Stage one immutable Forge Runtime release below Controller Home. The staged
|
|
@@ -24,6 +26,7 @@ export interface MacOSRuntimeCodeSigning {
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export interface StagedRuntimeRelease {
|
|
29
|
+
controllerHome: string;
|
|
27
30
|
releasePath: string;
|
|
28
31
|
manifestPath: string;
|
|
29
32
|
releaseId: string;
|
|
@@ -33,10 +36,12 @@ export interface StagedRuntimeRelease {
|
|
|
33
36
|
browserHandoffArtifactIdentity?: string;
|
|
34
37
|
processRunnerArtifactIdentity?: string;
|
|
35
38
|
checkRunnerArtifactIdentity?: string;
|
|
39
|
+
pluginActionSidecarArtifactIdentity?: string;
|
|
36
40
|
externalPluginProbeArtifactIdentity?: string;
|
|
37
41
|
codeGraphNodeArtifactIdentity?: string;
|
|
38
42
|
codeGraphSidecarArtifactIdentity?: string;
|
|
39
43
|
codeGraphLibraryArtifactIdentity?: string;
|
|
44
|
+
packageArtifactIdentity?: string;
|
|
40
45
|
controllerUiArtifactIdentity?: string;
|
|
41
46
|
macosCodeSigning?: MacOSRuntimeCodeSigning;
|
|
42
47
|
manifestSha256: string;
|
|
@@ -308,6 +313,13 @@ export function stageRuntimeReleaseFromCandidateSource(input: {
|
|
|
308
313
|
let rawManifest: Record<string, unknown>;
|
|
309
314
|
try { rawManifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as Record<string, unknown>; }
|
|
310
315
|
catch (error) { throw new Error(`RUNTIME_RELEASE_CANDIDATE_MANIFEST_INVALID: ${error instanceof Error ? error.message : String(error)}`); }
|
|
316
|
+
const manifest = loadRuntimeReleaseManifest(manifestPath, controllerHome);
|
|
317
|
+
requireCompleteCompiledRuntimeReleaseManifest(manifest);
|
|
318
|
+
if (manifest.releaseId !== receipt.releaseId
|
|
319
|
+
|| manifest.artifactIdentity !== receipt.artifactIdentity
|
|
320
|
+
|| manifest.sourceCommit !== receipt.sourceCommit) {
|
|
321
|
+
throw new Error('RUNTIME_RELEASE_CANDIDATE_MANIFEST_RECEIPT_MISMATCH');
|
|
322
|
+
}
|
|
311
323
|
const platform = dependencies.platform ?? process.platform;
|
|
312
324
|
const macosCodeSigning = parseMacOSRuntimeCodeSigning(rawManifest.macosCodeSigning, 'RUNTIME_RELEASE_CANDIDATE_SIGNING_INVALID');
|
|
313
325
|
if (platform === 'darwin') {
|
|
@@ -321,15 +333,30 @@ export function stageRuntimeReleaseFromCandidateSource(input: {
|
|
|
321
333
|
}
|
|
322
334
|
}
|
|
323
335
|
|
|
324
|
-
|
|
336
|
+
const staged: StagedRuntimeRelease = {
|
|
337
|
+
controllerHome,
|
|
325
338
|
releasePath,
|
|
326
339
|
manifestPath,
|
|
327
340
|
releaseId: receipt.releaseId,
|
|
328
341
|
artifactIdentity: receipt.artifactIdentity,
|
|
342
|
+
diagnosticArtifactIdentity: manifest.diagnosticArtifactIdentity,
|
|
343
|
+
browserNodeBridgeArtifactIdentity: manifest.browserNodeBridgeArtifactIdentity,
|
|
344
|
+
browserHandoffArtifactIdentity: manifest.browserHandoffArtifactIdentity,
|
|
345
|
+
processRunnerArtifactIdentity: manifest.processRunnerArtifactIdentity,
|
|
346
|
+
checkRunnerArtifactIdentity: manifest.checkRunnerArtifactIdentity,
|
|
347
|
+
pluginActionSidecarArtifactIdentity: manifest.pluginActionSidecarArtifactIdentity,
|
|
348
|
+
externalPluginProbeArtifactIdentity: manifest.externalPluginProbeArtifactIdentity,
|
|
349
|
+
codeGraphNodeArtifactIdentity: manifest.codeGraphNodeArtifactIdentity,
|
|
350
|
+
codeGraphSidecarArtifactIdentity: manifest.codeGraphSidecarArtifactIdentity,
|
|
351
|
+
codeGraphLibraryArtifactIdentity: manifest.codeGraphLibraryArtifactIdentity,
|
|
352
|
+
packageArtifactIdentity: manifest.packageArtifactIdentity,
|
|
353
|
+
controllerUiArtifactIdentity: manifest.controllerUiArtifactIdentity,
|
|
329
354
|
...(macosCodeSigning ? { macosCodeSigning } : {}),
|
|
330
355
|
manifestSha256: receipt.manifestSha256,
|
|
331
356
|
sourceCommit: receipt.sourceCommit,
|
|
332
357
|
};
|
|
358
|
+
assertRuntimeReleaseFiles(staged, dependencies);
|
|
359
|
+
return staged;
|
|
333
360
|
}
|
|
334
361
|
|
|
335
362
|
function defaultCompileBinary(input: { sourceRoot: string; outputPath: string; entryPath?: string }): { ok: boolean; stderr?: string; stdout?: string; error?: string } {
|
|
@@ -491,6 +518,19 @@ export function stageRuntimeRelease(input: {
|
|
|
491
518
|
chmodSync(checkRunnerPath, 0o700);
|
|
492
519
|
const checkRunnerArtifactIdentity = `sha256:${sha256(checkRunnerPath)}`;
|
|
493
520
|
|
|
521
|
+
const pluginActionSidecarEntrypoint = 'forge-plugin-action-sidecar' as const;
|
|
522
|
+
const pluginActionSidecarPath = join(staging, pluginActionSidecarEntrypoint);
|
|
523
|
+
const pluginActionSidecarCompile = compileBinary({
|
|
524
|
+
sourceRoot,
|
|
525
|
+
outputPath: pluginActionSidecarPath,
|
|
526
|
+
entryPath: join(sourceRoot, 'src/runtime/plugins/plugin-action-sidecar.ts'),
|
|
527
|
+
});
|
|
528
|
+
if (!pluginActionSidecarCompile.ok) {
|
|
529
|
+
throw new Error(`RUNTIME_RELEASE_PLUGIN_ACTION_SIDECAR_BUILD_FAILED: ${pluginActionSidecarCompile.stderr || pluginActionSidecarCompile.stdout || pluginActionSidecarCompile.error}`.slice(0, 2_000));
|
|
530
|
+
}
|
|
531
|
+
chmodSync(pluginActionSidecarPath, 0o700);
|
|
532
|
+
const pluginActionSidecarArtifactIdentity = `sha256:${sha256(pluginActionSidecarPath)}`;
|
|
533
|
+
|
|
494
534
|
const externalPluginProbeEntrypoint = 'external-unix-socket-probe.cjs' as const;
|
|
495
535
|
const sourceExternalPluginProbePath = join(sourceRoot, 'src', 'runtime', 'plugins', externalPluginProbeEntrypoint);
|
|
496
536
|
if (!existsSync(sourceExternalPluginProbePath)) {
|
|
@@ -533,6 +573,16 @@ export function stageRuntimeRelease(input: {
|
|
|
533
573
|
cpSync(sourceControllerUiPath, controllerUiPath, { recursive: true, force: false });
|
|
534
574
|
const controllerUiArtifactIdentity = `sha256:${sha256Directory(controllerUiPath)}`;
|
|
535
575
|
|
|
576
|
+
// The persistent OAuth/Connector is source-backed even when the primary
|
|
577
|
+
// Runtime itself is compiled. Co-locate one immutable package snapshot in
|
|
578
|
+
// the same release so standalone Recovery can bind the Connector to the
|
|
579
|
+
// exact active release instead of retaining an older package release.
|
|
580
|
+
const packageRoot = 'package' as const;
|
|
581
|
+
const packagePath = join(staging, packageRoot);
|
|
582
|
+
const packageRecords = packageRuntimeFileIndex(sourceRoot);
|
|
583
|
+
stagePackageRuntimeSnapshot(sourceRoot, packagePath, packageRecords);
|
|
584
|
+
const packageArtifactIdentity = `sha256:${sha256Directory(packagePath)}`;
|
|
585
|
+
|
|
536
586
|
const manifest = {
|
|
537
587
|
schemaVersion: 1,
|
|
538
588
|
releaseId,
|
|
@@ -549,6 +599,8 @@ export function stageRuntimeRelease(input: {
|
|
|
549
599
|
processRunnerArtifactIdentity,
|
|
550
600
|
checkRunnerEntrypoint,
|
|
551
601
|
checkRunnerArtifactIdentity,
|
|
602
|
+
pluginActionSidecarEntrypoint,
|
|
603
|
+
pluginActionSidecarArtifactIdentity,
|
|
552
604
|
externalPluginProbeEntrypoint,
|
|
553
605
|
externalPluginProbeArtifactIdentity,
|
|
554
606
|
codeGraphNodeEntrypoint,
|
|
@@ -557,6 +609,8 @@ export function stageRuntimeRelease(input: {
|
|
|
557
609
|
codeGraphSidecarArtifactIdentity,
|
|
558
610
|
codeGraphLibraryRoot,
|
|
559
611
|
codeGraphLibraryArtifactIdentity,
|
|
612
|
+
packageRoot,
|
|
613
|
+
packageArtifactIdentity,
|
|
560
614
|
controllerUiRoot,
|
|
561
615
|
controllerUiArtifactIdentity,
|
|
562
616
|
arguments: [],
|
|
@@ -576,6 +630,7 @@ export function stageRuntimeRelease(input: {
|
|
|
576
630
|
writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, { mode: 0o600 });
|
|
577
631
|
renameSync(staging, releasePath);
|
|
578
632
|
return {
|
|
633
|
+
controllerHome: resolve(input.controllerHome),
|
|
579
634
|
releasePath,
|
|
580
635
|
manifestPath: join(releasePath, 'manifest.json'),
|
|
581
636
|
releaseId,
|
|
@@ -586,10 +641,12 @@ export function stageRuntimeRelease(input: {
|
|
|
586
641
|
browserHandoffArtifactIdentity,
|
|
587
642
|
processRunnerArtifactIdentity,
|
|
588
643
|
checkRunnerArtifactIdentity,
|
|
644
|
+
pluginActionSidecarArtifactIdentity,
|
|
589
645
|
externalPluginProbeArtifactIdentity,
|
|
590
646
|
codeGraphNodeArtifactIdentity,
|
|
591
647
|
codeGraphSidecarArtifactIdentity,
|
|
592
648
|
codeGraphLibraryArtifactIdentity,
|
|
649
|
+
packageArtifactIdentity,
|
|
593
650
|
controllerUiArtifactIdentity,
|
|
594
651
|
manifestSha256: createHash('sha256').update(`${JSON.stringify(manifest, null, 2)}\n`).digest('hex'),
|
|
595
652
|
sourceCommit,
|
|
@@ -601,13 +658,53 @@ export function stageRuntimeRelease(input: {
|
|
|
601
658
|
}
|
|
602
659
|
|
|
603
660
|
export function assertRuntimeReleaseFiles(release: StagedRuntimeRelease, dependencies: { platform?: NodeJS.Platform; inspectMacOSRuntime?: (executable: string) => MacOSRuntimeCodeSigning } = {}): void {
|
|
661
|
+
const assertRegularFile = (path: string, missingCode: string): void => {
|
|
662
|
+
if (!existsSync(path)) throw new Error(`${missingCode}: ${path}`);
|
|
663
|
+
const status = lstatSync(path);
|
|
664
|
+
if (status.isSymbolicLink() || !status.isFile()) throw new Error(`RUNTIME_RELEASE_PATH_NOT_REGULAR_FILE: ${path}`);
|
|
665
|
+
};
|
|
666
|
+
const assertExecutable = (path: string): void => {
|
|
667
|
+
if ((statSync(path).mode & 0o111) === 0) throw new Error(`RUNTIME_RELEASE_ENTRYPOINT_NOT_EXECUTABLE: ${path}`);
|
|
668
|
+
};
|
|
669
|
+
const assertFileIdentity = (path: string, expected: string): void => {
|
|
670
|
+
const actual = `sha256:${sha256(path)}`;
|
|
671
|
+
if (actual !== expected) throw new Error(`RUNTIME_RELEASE_ARTIFACT_IDENTITY_MISMATCH: ${path}`);
|
|
672
|
+
};
|
|
673
|
+
const assertDirectoryIdentity = (path: string, expected: string): void => {
|
|
674
|
+
if (!existsSync(path)) throw new Error(`RUNTIME_RELEASE_DIRECTORY_MISSING: ${path}`);
|
|
675
|
+
const status = lstatSync(path);
|
|
676
|
+
if (status.isSymbolicLink() || !status.isDirectory()) throw new Error(`RUNTIME_RELEASE_PATH_NOT_DIRECTORY: ${path}`);
|
|
677
|
+
const actual = `sha256:${sha256Directory(path)}`;
|
|
678
|
+
if (actual !== expected) throw new Error(`RUNTIME_RELEASE_ARTIFACT_IDENTITY_MISMATCH: ${path}`);
|
|
679
|
+
};
|
|
680
|
+
const assertComponentFile = (input: { path: string; identity?: string; missingCode: string; executable?: boolean }): void => {
|
|
681
|
+
if (!input.identity) return;
|
|
682
|
+
assertRegularFile(input.path, input.missingCode);
|
|
683
|
+
assertFileIdentity(input.path, input.identity);
|
|
684
|
+
if (input.executable) assertExecutable(input.path);
|
|
685
|
+
};
|
|
686
|
+
|
|
604
687
|
if (!existsSync(release.releasePath) || !existsSync(release.manifestPath)) {
|
|
605
688
|
throw new Error(`RUNTIME_RELEASE_FILES_MISSING: ${release.releasePath}`);
|
|
606
689
|
}
|
|
607
|
-
const
|
|
608
|
-
if (
|
|
609
|
-
|
|
690
|
+
const releasesRoot = join(resolve(release.controllerHome), 'runtime', 'releases');
|
|
691
|
+
if (resolve(release.releasePath) !== join(releasesRoot, release.releaseId)
|
|
692
|
+
|| resolve(release.manifestPath) !== join(release.releasePath, 'manifest.json')) {
|
|
693
|
+
throw new Error('RUNTIME_RELEASE_PATH_OUTSIDE_CONTROLLER_HOME');
|
|
694
|
+
}
|
|
695
|
+
const releaseStatus = lstatSync(release.releasePath);
|
|
696
|
+
const manifestStatus = lstatSync(release.manifestPath);
|
|
697
|
+
if (releaseStatus.isSymbolicLink() || !releaseStatus.isDirectory()
|
|
698
|
+
|| manifestStatus.isSymbolicLink() || !manifestStatus.isFile()) {
|
|
699
|
+
throw new Error(`RUNTIME_RELEASE_PATH_NOT_PHYSICAL: ${release.releasePath}`);
|
|
610
700
|
}
|
|
701
|
+
if (sha256(release.manifestPath) !== release.manifestSha256) {
|
|
702
|
+
throw new Error('RUNTIME_RELEASE_MANIFEST_IDENTITY_MISMATCH');
|
|
703
|
+
}
|
|
704
|
+
const runtimePath = join(release.releasePath, 'forge-runtime');
|
|
705
|
+
assertRegularFile(runtimePath, 'RUNTIME_RELEASE_ENTRYPOINT_MISSING');
|
|
706
|
+
assertExecutable(runtimePath);
|
|
707
|
+
assertFileIdentity(runtimePath, release.artifactIdentity);
|
|
611
708
|
const platform = dependencies.platform ?? process.platform;
|
|
612
709
|
if (platform === 'darwin' && release.macosCodeSigning) {
|
|
613
710
|
const actual = (dependencies.inspectMacOSRuntime ?? inspectMacOSRuntimeCodeSigning)(runtimePath);
|
|
@@ -618,35 +715,31 @@ export function assertRuntimeReleaseFiles(release: StagedRuntimeRelease, depende
|
|
|
618
715
|
throw new Error('RUNTIME_RELEASE_MACOS_SIGNING_MISMATCH');
|
|
619
716
|
}
|
|
620
717
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}
|
|
630
|
-
if (release.
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
if (release.externalPluginProbeArtifactIdentity && !existsSync(join(release.releasePath, 'external-unix-socket-probe.cjs'))) {
|
|
637
|
-
throw new Error(`RUNTIME_RELEASE_EXTERNAL_PLUGIN_PROBE_MISSING: ${join(release.releasePath, 'external-unix-socket-probe.cjs')}`);
|
|
638
|
-
}
|
|
639
|
-
if (release.codeGraphNodeArtifactIdentity && !existsSync(join(release.releasePath, 'codegraph-node'))) {
|
|
640
|
-
throw new Error(`RUNTIME_RELEASE_CODEGRAPH_NODE_MISSING: ${join(release.releasePath, 'codegraph-node')}`);
|
|
641
|
-
}
|
|
642
|
-
if (release.codeGraphSidecarArtifactIdentity && !existsSync(join(release.releasePath, 'codegraph-sidecar.cjs'))) {
|
|
643
|
-
throw new Error(`RUNTIME_RELEASE_CODEGRAPH_SIDECAR_MISSING: ${join(release.releasePath, 'codegraph-sidecar.cjs')}`);
|
|
718
|
+
assertComponentFile({ path: join(release.releasePath, 'forge-cli'), identity: release.diagnosticArtifactIdentity, missingCode: 'RUNTIME_RELEASE_DIAGNOSTIC_ENTRYPOINT_MISSING', executable: true });
|
|
719
|
+
assertComponentFile({ path: join(release.releasePath, 'browser-node-bridge-host.js'), identity: release.browserNodeBridgeArtifactIdentity, missingCode: 'RUNTIME_RELEASE_BROWSER_NODE_HOST_MISSING', executable: true });
|
|
720
|
+
assertComponentFile({ path: join(release.releasePath, 'browser-handoff-host.js'), identity: release.browserHandoffArtifactIdentity, missingCode: 'RUNTIME_RELEASE_BROWSER_HANDOFF_HOST_MISSING', executable: true });
|
|
721
|
+
assertComponentFile({ path: join(release.releasePath, 'process-runner.js'), identity: release.processRunnerArtifactIdentity, missingCode: 'RUNTIME_RELEASE_PROCESS_RUNNER_MISSING', executable: true });
|
|
722
|
+
assertComponentFile({ path: join(release.releasePath, 'forge-check-runner'), identity: release.checkRunnerArtifactIdentity, missingCode: 'RUNTIME_RELEASE_CHECK_RUNNER_MISSING', executable: true });
|
|
723
|
+
assertComponentFile({ path: join(release.releasePath, 'forge-plugin-action-sidecar'), identity: release.pluginActionSidecarArtifactIdentity, missingCode: 'RUNTIME_RELEASE_PLUGIN_ACTION_SIDECAR_MISSING', executable: true });
|
|
724
|
+
assertComponentFile({ path: join(release.releasePath, 'external-unix-socket-probe.cjs'), identity: release.externalPluginProbeArtifactIdentity, missingCode: 'RUNTIME_RELEASE_EXTERNAL_PLUGIN_PROBE_MISSING', executable: true });
|
|
725
|
+
assertComponentFile({ path: join(release.releasePath, 'codegraph-node'), identity: release.codeGraphNodeArtifactIdentity, missingCode: 'RUNTIME_RELEASE_CODEGRAPH_NODE_MISSING', executable: true });
|
|
726
|
+
assertComponentFile({ path: join(release.releasePath, 'codegraph-sidecar.cjs'), identity: release.codeGraphSidecarArtifactIdentity, missingCode: 'RUNTIME_RELEASE_CODEGRAPH_SIDECAR_MISSING', executable: true });
|
|
727
|
+
if (release.codeGraphLibraryArtifactIdentity) {
|
|
728
|
+
const libraryRoot = join(release.releasePath, 'codegraph-lib');
|
|
729
|
+
if (!existsSync(join(libraryRoot, 'dist', 'index.js'))) {
|
|
730
|
+
throw new Error(`RUNTIME_RELEASE_CODEGRAPH_LIBRARY_MISSING: ${join(libraryRoot, 'dist', 'index.js')}`);
|
|
731
|
+
}
|
|
732
|
+
assertDirectoryIdentity(libraryRoot, release.codeGraphLibraryArtifactIdentity);
|
|
644
733
|
}
|
|
645
|
-
if (release.
|
|
646
|
-
|
|
734
|
+
if (release.packageArtifactIdentity) {
|
|
735
|
+
const packageRoot = join(release.releasePath, 'package');
|
|
736
|
+
assertDirectoryIdentity(packageRoot, release.packageArtifactIdentity);
|
|
647
737
|
}
|
|
648
|
-
if (release.controllerUiArtifactIdentity
|
|
649
|
-
|
|
650
|
-
|
|
738
|
+
if (release.controllerUiArtifactIdentity) {
|
|
739
|
+
const uiRoot = join(release.releasePath, 'ui-dist');
|
|
740
|
+
if (!existsSync(join(uiRoot, 'app.js')) || !existsSync(join(uiRoot, 'app.css'))) {
|
|
741
|
+
throw new Error(`RUNTIME_RELEASE_CONTROLLER_UI_MISSING: ${uiRoot}`);
|
|
742
|
+
}
|
|
743
|
+
assertDirectoryIdentity(uiRoot, release.controllerUiArtifactIdentity);
|
|
651
744
|
}
|
|
652
745
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'crypto';
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'fs';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'fs';
|
|
3
3
|
import { dirname, join, resolve } from 'path';
|
|
4
4
|
import { ensureControllerHome } from '../../cli/repositories/controller-home';
|
|
5
5
|
import {
|
|
@@ -102,9 +102,14 @@ function validRelease(controllerHome: string, release: RuntimePublishedRelease |
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
type RuntimeReleaseAuthorityRead =
|
|
106
|
+
| { state: 'missing' }
|
|
107
|
+
| { state: 'valid'; authority: RuntimeReleaseAuthority }
|
|
108
|
+
| { state: 'invalid'; reason: string };
|
|
109
|
+
|
|
110
|
+
function inspectRuntimeReleaseAuthority(controllerHome: string): RuntimeReleaseAuthorityRead {
|
|
106
111
|
const path = runtimeReleaseAuthorityPath(controllerHome);
|
|
107
|
-
if (!existsSync(path)) return
|
|
112
|
+
if (!existsSync(path)) return { state: 'missing' };
|
|
108
113
|
try {
|
|
109
114
|
const value = JSON.parse(readFileSync(path, 'utf8')) as RuntimeReleaseAuthority;
|
|
110
115
|
if (
|
|
@@ -117,11 +122,24 @@ export function readRuntimeReleaseAuthority(controllerHome: string): RuntimeRele
|
|
|
117
122
|
|| !Number.isFinite(Date.parse(value.committedAt))
|
|
118
123
|
|| !validRelease(controllerHome, value.active)
|
|
119
124
|
|| (value.previous !== undefined && !validRelease(controllerHome, value.previous))
|
|
120
|
-
) return
|
|
121
|
-
return value;
|
|
122
|
-
} catch {
|
|
123
|
-
return
|
|
125
|
+
) return { state: 'invalid', reason: 'authority fields or referenced release evidence are invalid' };
|
|
126
|
+
return { state: 'valid', authority: value };
|
|
127
|
+
} catch (error) {
|
|
128
|
+
return { state: 'invalid', reason: error instanceof Error ? error.message : String(error) };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function mutableRuntimeReleaseAuthority(controllerHome: string): RuntimeReleaseAuthority | undefined {
|
|
133
|
+
const observed = inspectRuntimeReleaseAuthority(controllerHome);
|
|
134
|
+
if (observed.state === 'invalid') {
|
|
135
|
+
throw new Error(`RUNTIME_RELEASE_AUTHORITY_INVALID_EXISTING: ${observed.reason}`);
|
|
124
136
|
}
|
|
137
|
+
return observed.state === 'valid' ? observed.authority : undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function readRuntimeReleaseAuthority(controllerHome: string): RuntimeReleaseAuthority | undefined {
|
|
141
|
+
const observed = inspectRuntimeReleaseAuthority(controllerHome);
|
|
142
|
+
return observed.state === 'valid' ? observed.authority : undefined;
|
|
125
143
|
}
|
|
126
144
|
|
|
127
145
|
function writeRuntimeReleaseAuthority(controllerHome: string, authority: RuntimeReleaseAuthority): RuntimeReleaseAuthority {
|
|
@@ -145,7 +163,7 @@ export function ensureActiveRuntimeRelease(
|
|
|
145
163
|
operationId = 'runtime-start',
|
|
146
164
|
): RuntimeReleaseAuthority {
|
|
147
165
|
const active = manifestRecord(controllerHome, manifestPath);
|
|
148
|
-
const current =
|
|
166
|
+
const current = mutableRuntimeReleaseAuthority(controllerHome);
|
|
149
167
|
if (current) {
|
|
150
168
|
if (!sameRelease(current.active, active)) throw new Error('RUNTIME_RELEASE_AUTHORITY_MISMATCH');
|
|
151
169
|
return current;
|
|
@@ -169,8 +187,18 @@ export function publishRuntimeRelease(
|
|
|
169
187
|
): RuntimeReleaseAuthority {
|
|
170
188
|
if (!operationId.trim()) throw new Error('RUNTIME_RELEASE_OPERATION_ID_REQUIRED');
|
|
171
189
|
const candidate = manifestRecord(controllerHome, manifestPath);
|
|
172
|
-
const current =
|
|
173
|
-
if (!current)
|
|
190
|
+
const current = mutableRuntimeReleaseAuthority(controllerHome);
|
|
191
|
+
if (!current) {
|
|
192
|
+
return writeRuntimeReleaseAuthority(controllerHome, {
|
|
193
|
+
schemaVersion: 1,
|
|
194
|
+
status: 'committed',
|
|
195
|
+
revision: 1,
|
|
196
|
+
fencingToken: randomUUID(),
|
|
197
|
+
active: candidate,
|
|
198
|
+
operationId,
|
|
199
|
+
committedAt: new Date().toISOString(),
|
|
200
|
+
});
|
|
201
|
+
}
|
|
174
202
|
if (sameRelease(current.active, candidate)) return current;
|
|
175
203
|
const backup = backupPath(controllerHome, current.active.releaseId, operationId);
|
|
176
204
|
const inspection = dependencies.backupDatabase(controllerHome, backup);
|
|
@@ -190,13 +218,22 @@ export function publishRuntimeRelease(
|
|
|
190
218
|
});
|
|
191
219
|
}
|
|
192
220
|
|
|
221
|
+
export function revertInitialRuntimeReleasePublication(controllerHome: string, operationId: string): void {
|
|
222
|
+
const current = mutableRuntimeReleaseAuthority(controllerHome);
|
|
223
|
+
if (!current) return;
|
|
224
|
+
if (current.revision !== 1 || current.previous !== undefined || current.operationId !== operationId) {
|
|
225
|
+
throw new Error('RUNTIME_RELEASE_INITIAL_PUBLICATION_REVERT_MISMATCH');
|
|
226
|
+
}
|
|
227
|
+
rmSync(runtimeReleaseAuthorityPath(controllerHome), { force: true });
|
|
228
|
+
}
|
|
229
|
+
|
|
193
230
|
export function rollbackRuntimeRelease(
|
|
194
231
|
controllerHome: string,
|
|
195
232
|
operationId: string,
|
|
196
233
|
dependencies: RuntimeReleaseStoreDependencies = DEFAULT_DEPENDENCIES,
|
|
197
234
|
): RuntimeReleaseAuthority {
|
|
198
235
|
if (!operationId.trim()) throw new Error('RUNTIME_RELEASE_OPERATION_ID_REQUIRED');
|
|
199
|
-
const current =
|
|
236
|
+
const current = mutableRuntimeReleaseAuthority(controllerHome);
|
|
200
237
|
const target = current?.previous;
|
|
201
238
|
if (!current || !target?.databaseBackup) throw new Error('RUNTIME_PREVIOUS_RELEASE_UNAVAILABLE');
|
|
202
239
|
const currentBackup = backupPath(controllerHome, current.active.releaseId, operationId);
|
|
@@ -6,6 +6,8 @@ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/
|
|
|
6
6
|
import type { ControlPlaneDatabaseInspection } from '../control-plane/persistence/sqlite-store';
|
|
7
7
|
import { inspectControlPlaneDatabase } from '../control-plane/persistence/sqlite-store';
|
|
8
8
|
import { activateExclusiveWorkAdmission } from '../control-plane/facade/work-admission-policy';
|
|
9
|
+
import { closeCodeGraphReadProviderSessions } from '../context/codegraph-read-provider';
|
|
10
|
+
import { cancelAllLightweightProcesses } from '../execution/process-runtime/lightweight-managed';
|
|
9
11
|
import {
|
|
10
12
|
collectRuntimeSourceIdentity,
|
|
11
13
|
rotateRuntimeGeneration,
|
|
@@ -40,6 +42,9 @@ export interface CanonicalRuntimeDependencies {
|
|
|
40
42
|
runMcpProbe(endpoint: string, authToken: string): Promise<void>;
|
|
41
43
|
collectRuntimeSourceIdentity: typeof collectRuntimeSourceIdentity;
|
|
42
44
|
rotateRuntimeGeneration: typeof rotateRuntimeGeneration;
|
|
45
|
+
stopLightweightProcesses(controllerHome: string): Promise<number>;
|
|
46
|
+
stopContextReadHelpers(): Promise<void>;
|
|
47
|
+
computeToolSurfaceFingerprint: typeof runtimeGatewayToolSurfaceFingerprint;
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
async function defaultMcpProbe(endpoint: string, authToken: string): Promise<void> {
|
|
@@ -77,6 +82,9 @@ const DEFAULT_DEPENDENCIES: CanonicalRuntimeDependencies = {
|
|
|
77
82
|
runMcpProbe: defaultMcpProbe,
|
|
78
83
|
collectRuntimeSourceIdentity,
|
|
79
84
|
rotateRuntimeGeneration,
|
|
85
|
+
stopLightweightProcesses: cancelAllLightweightProcesses,
|
|
86
|
+
stopContextReadHelpers: closeCodeGraphReadProviderSessions,
|
|
87
|
+
computeToolSurfaceFingerprint: runtimeGatewayToolSurfaceFingerprint,
|
|
80
88
|
};
|
|
81
89
|
|
|
82
90
|
export class CanonicalForgeRuntime {
|
|
@@ -143,6 +151,17 @@ export class CanonicalForgeRuntime {
|
|
|
143
151
|
}
|
|
144
152
|
}
|
|
145
153
|
|
|
154
|
+
private refreshToolSurfaceFingerprint(runtimeSourceRoot: string): void {
|
|
155
|
+
const next = this.dependencies.computeToolSurfaceFingerprint({
|
|
156
|
+
controllerHome: this.config.controllerHome,
|
|
157
|
+
runtimeInstanceId: this.runtimeInstanceId,
|
|
158
|
+
runtimeSourceRoot,
|
|
159
|
+
});
|
|
160
|
+
if (next === this.toolSurfaceFingerprint) return;
|
|
161
|
+
this.toolSurfaceFingerprint = next;
|
|
162
|
+
this.publishStatus();
|
|
163
|
+
}
|
|
164
|
+
|
|
146
165
|
endpoint(): string | undefined {
|
|
147
166
|
return this.transport?.endpoint;
|
|
148
167
|
}
|
|
@@ -218,11 +237,7 @@ export class CanonicalForgeRuntime {
|
|
|
218
237
|
});
|
|
219
238
|
|
|
220
239
|
stage = 'transport';
|
|
221
|
-
this.
|
|
222
|
-
controllerHome: this.config.controllerHome,
|
|
223
|
-
runtimeInstanceId: this.runtimeInstanceId,
|
|
224
|
-
runtimeSourceRoot,
|
|
225
|
-
});
|
|
240
|
+
this.refreshToolSurfaceFingerprint(runtimeSourceRoot);
|
|
226
241
|
this.transport = await this.dependencies.startTransport({
|
|
227
242
|
host: this.config.host,
|
|
228
243
|
port: this.config.port,
|
|
@@ -235,6 +250,7 @@ export class CanonicalForgeRuntime {
|
|
|
235
250
|
sessionId,
|
|
236
251
|
controllerType,
|
|
237
252
|
}),
|
|
253
|
+
onToolSurfaceObservation: () => this.refreshToolSurfaceFingerprint(runtimeSourceRoot),
|
|
238
254
|
onFatal: (error) => this.failCore('MCP_TRANSPORT_FAILED', error.message),
|
|
239
255
|
});
|
|
240
256
|
this.publishStatus();
|
|
@@ -298,6 +314,8 @@ export class CanonicalForgeRuntime {
|
|
|
298
314
|
// Stop accepting new MCP work before quiescing Scheduler activity, then
|
|
299
315
|
// release the Controller Home claim only after all in-process services stop.
|
|
300
316
|
await this.transport?.close().catch(() => undefined);
|
|
317
|
+
await this.dependencies.stopLightweightProcesses(this.config.controllerHome).catch(() => undefined);
|
|
318
|
+
await this.dependencies.stopContextReadHelpers().catch(() => undefined);
|
|
301
319
|
await this.localBridge?.close().catch(() => undefined);
|
|
302
320
|
await this.scheduler?.stop().catch(() => undefined);
|
|
303
321
|
const ownerPid = this.ownership?.record.pid;
|