@moretea-labs/forge 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +70 -7
- package/CHANGELOG.md +14 -0
- package/CLAUDE.md +17 -2
- package/CONTRIBUTING.md +3 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/adapters/chatgpt/browser-delivery-host.ts +7 -1
- package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
- package/adapters/chatgpt/controller-binding-store.ts +101 -22
- package/adapters/chatgpt/controller-round-host.ts +15 -25
- package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
- package/adapters/chatgpt/provider-delivery.ts +228 -1
- package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
- package/adapters/computer/chatgpt-extension-target.ts +463 -0
- package/adapters/computer/chatgpt-target-router.ts +103 -0
- package/adapters/computer/chrome-extension/background.js +385 -0
- package/adapters/computer/chrome-extension/content.js +378 -0
- package/adapters/computer/chrome-extension/core.js +24 -0
- package/adapters/computer/chrome-extension/manifest.json +30 -0
- package/adapters/computer/desktop-operator-discovery.ts +11 -31
- package/adapters/computer/interaction-target-authority.ts +142 -18
- package/adapters/mcp/auth.ts +0 -1
- package/adapters/mcp/instructions.ts +5 -4
- package/adapters/mcp/multi-repository.ts +3 -19
- package/adapters/mcp/oauth.ts +73 -0
- package/adapters/mcp/paths.ts +4 -1
- package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
- package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
- package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
- package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
- package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
- package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
- package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
- package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
- package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
- package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
- package/adapters/mcp/runtime-gateway/router.ts +18 -504
- package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
- package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
- package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
- package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
- package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
- package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
- package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
- package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
- package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
- package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
- package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
- package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
- package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
- package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
- package/adapters/mcp/server.ts +67 -23
- package/adapters/mcp/setup.ts +1 -3
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
- package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
- package/adapters/mcp/toolset-names.ts +5 -0
- package/adapters/mcp/toolset.ts +6 -5
- package/adapters/mcp/transports/http-observation.ts +365 -0
- package/adapters/mcp/transports/http.ts +154 -677
- package/adapters/mcp/transports/oauth-http.ts +322 -0
- package/adapters/mcp/transports/session-registry.ts +6 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
- package/assets/plugin-registry.v1.json +6 -4
- package/assets/reference-configs/agentic-development-flow.md +25 -0
- package/assets/reference-configs/global-working-rules.md +19 -0
- package/assets/skill-version.json +2 -2
- package/docs/architecture/CURRENT.md +111 -41
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
- package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
- package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
- package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
- package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
- package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
- package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
- package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
- package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
- package/docs/architecture/domains/verification.md +1 -0
- package/docs/architecture/domains/workflow-engine.md +6 -0
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/forge-plugin-management.md +2 -2
- package/docs/operations/controller-performance-and-502.md +17 -0
- package/docs/operations/controller-reliability-runbook.md +2 -2
- package/docs/operations/features.md +1 -1
- package/docs/operations/features.zh-CN.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +2 -0
- package/docs/operations/releasing.md +2 -0
- package/docs/operations/standalone-disaster-recovery.md +14 -6
- package/docs/wiki/Implementation.md +1 -1
- package/package.json +25 -14
- package/packages/kernel/cognition/api/index.ts +6 -0
- package/packages/kernel/cognition/application/activation-service.ts +451 -0
- package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
- package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
- package/packages/kernel/cognition/application/memory-service.ts +64 -0
- package/packages/kernel/cognition/domain/learning.ts +106 -0
- package/packages/kernel/cognition/domain/memory.ts +254 -0
- package/packages/kernel/controller/api/index.ts +1 -0
- package/packages/kernel/controller/application/continuation-service.ts +281 -0
- package/packages/kernel/controller/application/controller-round-service.ts +12 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
- package/packages/kernel/controller/domain/controller-round.ts +4 -1
- package/packages/kernel/controller/domain/execution-quality.ts +3 -1
- package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
- package/packages/kernel/controller/ports/controller-host.ts +2 -0
- package/packages/kernel/identity/api/index.ts +10 -0
- package/packages/kernel/identity/domain/activity-projection.ts +43 -0
- package/packages/kernel/identity/domain/capability-broker.ts +60 -0
- package/packages/kernel/identity/domain/grant.ts +72 -0
- package/packages/kernel/identity/domain/owned-resource.ts +116 -0
- package/packages/kernel/identity/domain/user-request.ts +93 -0
- package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
- package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
- package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
- package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
- package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
- package/packages/kernel/scheduler/api/index.ts +0 -2
- package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
- package/packages/kernel/scheduler/application/settlement.ts +0 -15
- package/packages/kernel/scheduler/domain/schedule.ts +87 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
- package/packages/kernel/work/api/index.ts +3 -2
- package/packages/kernel/work/application/work-service.ts +17 -42
- package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
- package/packages/kernel/work/domain/engineering-design.ts +10 -5
- package/packages/kernel/work/domain/engineering-profile.ts +8 -12
- package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
- package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
- package/packages/kernel/work/domain/implementation-review.ts +14 -331
- package/packages/kernel/work/domain/objective-graph.ts +119 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
- package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
- package/packages/kernel/work/domain/state-machine.ts +25 -63
- package/packages/kernel/work/domain/types.ts +57 -51
- package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
- package/packages/kernel/work/ports/work-contract-store.ts +5 -2
- package/packages/plugin-runtime/browser/session-authority.ts +2 -1
- package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
- package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
- package/packages/plugin-runtime/computer/index.ts +2 -0
- package/packages/plugin-runtime/computer/target-authority.ts +26 -1
- package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
- package/packages/protocols/computer/contract.ts +27 -1
- package/scripts/activate-source-baseline.ts +7 -9
- package/scripts/canary-controller-semantic-wait.ts +12 -24
- package/scripts/check-mcp-compatibility.ts +48 -136
- package/scripts/check-runtime-architecture.mjs +622 -217
- package/scripts/forge-local-recovery-helper.mjs +93 -15
- package/scripts/lib/project-init-lib.sh +3 -0
- package/scripts/open-source-audit-allowlist.txt +1 -2
- package/scripts/run-bounded-command.mjs +5 -0
- package/scripts/run-governed-gate.ts +0 -1
- package/scripts/run-mobile-monitor-bridge.ts +0 -1
- package/scripts/smoke-control-plane-failure-domain.ts +94 -0
- package/scripts/smoke-mcp-http-runtime.ts +5 -0
- package/scripts/smoke-runtime-recovery.ts +12 -43
- package/scripts/smoke-schedule-engine.ts +23 -15
- package/scripts/smoke-unattended-transport-recovery.ts +223 -0
- package/scripts/smoke-user-request-continuation-restart.ts +232 -0
- package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
- package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
- package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
- package/scripts/smoke-workflow-supervisor.ts +103 -0
- package/scripts/verify-forge-runtime.sh +2 -1
- package/src/cli/agent-jobs/executor-health.ts +11 -34
- package/src/cli/agent-jobs/integration.ts +18 -49
- package/src/cli/agent-jobs/job-manager.ts +7 -3
- package/src/cli/commands/brain-assistant.ts +27 -13
- package/src/cli/commands/brain.ts +13 -15
- package/src/cli/commands/chatgpt.ts +1 -163
- package/src/cli/commands/recovery.ts +135 -121
- package/src/cli/commands/runtime.ts +3 -3
- package/src/cli/commands/setup-profile.ts +8 -0
- package/src/cli/controller/check-runner.ts +13 -2
- package/src/cli/controller/completion-backlog.ts +3 -3
- package/src/cli/controller/completion-orchestrator.ts +4 -43
- package/src/cli/controller/completion-target.ts +3 -72
- package/src/cli/controller/context/source-materializer.ts +81 -100
- package/src/cli/controller/context-pack.ts +10 -8
- package/src/cli/controller/execution-completion.ts +4 -7
- package/src/cli/controller/execution-policy.ts +36 -153
- package/src/cli/controller/governance.ts +2 -3
- package/src/cli/controller/issue-store.ts +4 -99
- package/src/cli/controller/launch-agents.ts +59 -18
- package/src/cli/controller/operational-plan.ts +24 -51
- package/src/cli/controller/runtime-config.ts +5 -1
- package/src/cli/controller/stuck-state-migration.ts +2 -3
- package/src/cli/controller/systemd-user.ts +39 -1
- package/src/cli/editing/edit-session.ts +1 -7
- package/src/cli/local-bridge/console-automations.ts +18 -13
- package/src/cli/local-bridge/console-view-models.ts +3 -12
- package/src/cli/local-bridge/facade-api.ts +64 -191
- package/src/cli/local-bridge/server.ts +24 -147
- package/src/cli/local-bridge/types.ts +0 -1
- package/src/cli/mcp/oauth-client-retirement.ts +74 -0
- package/src/cli/repositories/command-executor.ts +29 -23
- package/src/cli/repositories/command-scope.ts +35 -16
- package/src/cli/repositories/controller-home.ts +48 -0
- package/src/cli/repositories/ephemeral-workspace.ts +20 -30
- package/src/cli/repositories/git-command-executor.ts +2 -2
- package/src/cli/repositories/registry.ts +77 -11
- package/src/cli/repositories/structured-git.ts +62 -2
- package/src/cli/repository/session-cache.ts +92 -6
- package/src/runtime/context/assistant-context.ts +20 -7
- package/src/runtime/context/assistant-work-context.ts +89 -27
- package/src/runtime/context/automatic-learning.ts +565 -0
- package/src/runtime/context/cognitive-attention.ts +173 -0
- package/src/runtime/context/cognitive-skill-canary.ts +158 -0
- package/src/runtime/context/context-closure.ts +46 -9
- package/src/runtime/context/context-pack-process.ts +103 -0
- package/src/runtime/context/context-plane.ts +1 -9
- package/src/runtime/context/direct-controller-learning.ts +298 -0
- package/src/runtime/context/semantic-navigation-contract.ts +9 -0
- package/src/runtime/context/semantic-navigation.ts +6 -34
- package/src/runtime/context/typescript-navigation-process.ts +145 -0
- package/src/runtime/context/typescript-navigation.ts +89 -3
- package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
- package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
- package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
- package/src/runtime/control-plane/execution/session-store.ts +31 -1
- package/src/runtime/control-plane/execution/validation.ts +6 -8
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
- package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
- package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
- package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
- package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
- package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
- package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
- package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
- package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
- package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
- package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
- package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
- package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
- package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
- package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
- package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
- package/src/runtime/control-plane/facade/index.ts +0 -1
- package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
- package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
- package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
- package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
- package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
- package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
- package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
- package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
- package/src/runtime/control-plane/facade/types.ts +49 -108
- package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
- package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
- package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
- package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
- package/src/runtime/control-plane/governance/access-policy.ts +19 -2
- package/src/runtime/control-plane/governance/authorization.ts +20 -3
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
- package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
- package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
- package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
- package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
- package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
- package/src/runtime/control-plane/release-retention.ts +135 -47
- package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
- package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
- package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
- package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
- package/src/runtime/diagnostics/incident-repair.ts +313 -146
- package/src/runtime/diagnostics/mcp-timing.ts +114 -0
- package/src/runtime/evidence/artifact-store.ts +158 -40
- package/src/runtime/evidence/evidence-store.ts +112 -8
- package/src/runtime/evidence/output-handle-index.ts +225 -0
- package/src/runtime/evidence/result-store.ts +158 -44
- package/src/runtime/execution/jobs/store.ts +3 -4
- package/src/runtime/execution/managed-workspace.ts +57 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
- package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
- package/src/runtime/execution/process-runtime/check-result.ts +105 -1
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
- package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
- package/src/runtime/execution/process-runtime/gc.ts +15 -2
- package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
- package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
- package/src/runtime/execution/process-runtime/index.ts +3 -0
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
- package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
- package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
- package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
- package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
- package/src/runtime/execution/process-runtime/runtime.ts +35 -2
- package/src/runtime/execution/process-runtime/store.ts +30 -2
- package/src/runtime/execution/process-runtime/types.ts +6 -1
- package/src/runtime/execution/workers/executor.ts +2 -6
- package/src/runtime/platform/service-inventory.ts +130 -0
- package/src/runtime/platform/service-manager.ts +8 -0
- package/src/runtime/plugins/action-application.ts +85 -28
- package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
- package/src/runtime/plugins/browser-adapter.ts +757 -34
- package/src/runtime/plugins/browser-automation-service.ts +23 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
- package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
- package/src/runtime/plugins/browser-native-session-service.ts +63 -13
- package/src/runtime/plugins/browser-registration.ts +16 -0
- package/src/runtime/plugins/browser-runtime.ts +14 -1
- package/src/runtime/plugins/browser-session-authority.ts +2 -2
- package/src/runtime/plugins/browser-session-store.ts +46 -76
- package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
- package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
- package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
- package/src/runtime/plugins/computer-registration.ts +222 -11
- package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
- package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
- package/src/runtime/plugins/external-adapter.ts +42 -6
- package/src/runtime/plugins/external-registration.ts +21 -1
- package/src/runtime/plugins/gmail-adapter.ts +23 -2
- package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
- package/src/runtime/plugins/google-shared.ts +14 -7
- package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
- package/src/runtime/plugins/ios-adapter.ts +1 -1
- package/src/runtime/plugins/lightweight-action.ts +208 -2
- package/src/runtime/plugins/local-system-adapter.ts +12 -2
- package/src/runtime/plugins/managed-process-adapter.ts +12 -5
- package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
- package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +602 -428
- package/src/runtime/plugins/types.ts +20 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
- package/src/runtime/projections/invalidation.ts +7 -3
- package/src/runtime/projections/materialized-view.ts +80 -36
- package/src/runtime/recovery/actions.ts +3 -3
- package/src/runtime/recovery/capability-action-application.ts +46 -45
- package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
- package/src/runtime/recovery/maintenance-executor.ts +374 -123
- package/src/runtime/recovery/store.ts +29 -11
- package/src/runtime/release/release-coordinator.ts +296 -0
- package/src/runtime/release/release-session.ts +716 -0
- package/src/runtime/release/release-state-migration.ts +25 -0
- package/src/runtime/resources/leases/store.ts +56 -25
- package/src/runtime/root/computer-composition.ts +191 -6
- package/src/runtime/root/controller-progression-composition.ts +192 -0
- package/src/runtime/root/controller-round-composition.ts +20 -1
- package/src/runtime/root/deployment-topology.ts +106 -0
- package/src/runtime/root/entry.ts +4 -3
- package/src/runtime/root/known-good-recovery.ts +184 -0
- package/src/runtime/root/local-bridge.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +111 -18
- package/src/runtime/root/ownership.ts +261 -9
- package/src/runtime/root/package-connector-service.ts +105 -19
- package/src/runtime/root/package-runtime-release.ts +117 -18
- package/src/runtime/root/package-runtime-service.ts +17 -11
- package/src/runtime/root/release-execution-canary.ts +44 -12
- package/src/runtime/root/release-loader.ts +90 -8
- package/src/runtime/root/release-manifest.ts +80 -6
- package/src/runtime/root/release-materialize.ts +372 -28
- package/src/runtime/root/release-store.ts +395 -36
- package/src/runtime/root/runtime-lane.ts +191 -0
- package/src/runtime/root/runtime.ts +159 -27
- package/src/runtime/root/scheduled-controller-composition.ts +28 -3
- package/src/runtime/root/service-runner.ts +2 -2
- package/src/runtime/root/service.ts +36 -33
- package/src/runtime/root/status.ts +48 -0
- package/src/runtime/root/types.ts +32 -3
- package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
- package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
- package/src/runtime/root/write-fence.ts +50 -2
- package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
- package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
- package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
- package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
- package/src/runtime/shared/process-environment.ts +20 -9
- package/src/runtime/shared/response-budget.ts +1 -3
- package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
- package/src/runtime/standalone-recovery/core.ts +3702 -342
- package/src/runtime/standalone-recovery/entry.ts +469 -39
- package/src/runtime/standalone-recovery/installer.ts +262 -148
- package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
- package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
- package/src/runtime/standalone-recovery/performance.ts +54 -16
- package/src/runtime/standalone-recovery/release.ts +53 -5
- package/src/runtime/standalone-recovery/service-labels.ts +5 -2
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
- package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
- package/src/runtime/workflow/schedules/engine.ts +138 -172
- package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
- package/src/runtime/workflows/runtime.ts +15 -19
- package/src/testing/test-governance.ts +5 -1
- package/supervisor/chatgpt-conversation.ts +23 -0
- package/supervisor/client.ts +201 -0
- package/supervisor/control-plane.ts +868 -0
- package/supervisor/entry.ts +15 -0
- package/supervisor/forge-validators.ts +80 -0
- package/supervisor/index.ts +5 -0
- package/supervisor/native-browser-adapter.ts +786 -0
- package/supervisor/native-messaging/host.ts +39 -0
- package/supervisor/native-messaging/manifest.ts +26 -0
- package/supervisor/native-messaging/protocol.ts +27 -0
- package/supervisor/paths.ts +18 -0
- package/supervisor/protocol.ts +202 -0
- package/supervisor/server.ts +404 -0
- package/supervisor/store.ts +1451 -0
- package/supervisor/tsconfig.json +8 -0
- package/supervisor/types.ts +255 -0
- package/adapters/chatgpt/controller-host.ts +0 -119
- package/adapters/mcp/controller-round-compatibility.ts +0 -184
- package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
- package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
- package/packages/kernel/progression/api/index.ts +0 -2
- package/packages/kernel/progression/application/projector.ts +0 -211
- package/packages/kernel/progression/domain/types.ts +0 -116
- package/packages/kernel/progression/index.ts +0 -1
- package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
- package/packages/kernel/scheduler/domain/continuation.ts +0 -38
- package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
- package/packages/kernel/work/domain/admission-policy.ts +0 -34
- package/scripts/benchmark-background-check-overlap.ts +0 -228
- package/scripts/benchmark-computer-hotpath.ts +0 -255
- package/scripts/benchmark-controller-hotpath.ts +0 -212
- package/scripts/benchmark-controller-round2.ts +0 -191
- package/scripts/benchmark-ios-agent-device.ts +0 -511
- package/scripts/benchmark-mcp-host.sh +0 -117
- package/scripts/benchmark-mcp-transport.ts +0 -169
- package/scripts/benchmark-operational-memory-activation.ts +0 -235
- package/scripts/benchmark-operational-shadow.ts +0 -28
- package/scripts/benchmark-quality-harness.ts +0 -146
- package/scripts/benchmark-route-session-concurrency.ts +0 -915
- package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
- package/scripts/benchmark-thin-harness.ts +0 -251
- package/scripts/benchmark-typescript-navigation.ts +0 -186
- package/scripts/benchmark-work-efficiency.ts +0 -334
- package/scripts/build-controller-ui.ts +0 -28
- package/scripts/check-npm-release.sh +0 -32
- package/scripts/check-public-release-surface.sh +0 -19
- package/scripts/check-release-published.sh +0 -57
- package/scripts/check-release-readiness.sh +0 -37
- package/scripts/check-release-version.mjs +0 -74
- package/scripts/check-tarball-install-smoke.sh +0 -150
- package/scripts/package-source-archive.sh +0 -147
- package/scripts/public-release-files.txt +0 -39
- package/scripts/public-release.ts +0 -174
- package/scripts/publish-release-tarball.sh +0 -27
- package/scripts/route-nl-vs-ts-eval.ts +0 -679
- package/scripts/stage-runtime-release.ts +0 -44
- package/src/cli/controller/progress.ts +0 -656
- package/src/cli/controller/work-mode.ts +0 -181
- package/src/cli/local-bridge/console-assets.ts +0 -17
- package/src/cli/local-bridge/dashboard.ts +0 -17
- package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
- package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
- package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
- package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
- package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/styles.css +0 -28
- package/src/cli/local-bridge/frontend/src/types.ts +0 -15
- package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
- package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
- package/src/cli/local-bridge/ui-dist/app.css +0 -1
- package/src/cli/local-bridge/ui-dist/app.js +0 -11228
- package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
- package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
- package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
- package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
- package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
- package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
- package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
- package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
- package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
- package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
- package/src/runtime/control-plane/routing/index.ts +0 -1
- package/src/runtime/control-plane/routing/route-policy.ts +0 -401
- package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { createHash } from 'crypto';
|
|
2
2
|
import { spawnSync } from 'child_process';
|
|
3
3
|
import {
|
|
4
|
-
cpSync,
|
|
5
4
|
existsSync,
|
|
6
5
|
mkdirSync,
|
|
7
6
|
readFileSync,
|
|
8
|
-
writeFileSync,
|
|
9
7
|
} from 'fs';
|
|
10
8
|
import { dirname, join, resolve } from 'path';
|
|
11
9
|
import { repoLocalNoIndexControllerHome, repositoryControllerRoot } from '../../../cli/repositories/controller-home';
|
|
@@ -19,15 +17,10 @@ import {
|
|
|
19
17
|
import { managedPathInside, managedWorktreeStorageRoot } from '../../../cli/repositories/worktree-storage';
|
|
20
18
|
import { markRepositoryProjectionDirty } from '../../projections/invalidation';
|
|
21
19
|
import { listControlPlaneRecords } from '../persistence/sqlite-store';
|
|
22
|
-
import { getWorkContract } from '../../../../packages/kernel/work/api/index';
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
releaseControllerSessionWithAuthority,
|
|
27
|
-
releaseObservedControllerSession,
|
|
28
|
-
type ControllerTerminalizationAuthority,
|
|
29
|
-
} from '../../../../packages/kernel/controller/api/index';
|
|
30
|
-
import { isRepositoryCompletionReceipt, isTerminalWorkContractStatus, type WorkContract } from '../facade/types';
|
|
20
|
+
import { getWorkContract, recordCancelledWorkCleanupCompleted, semanticWorkState } from '../../../../packages/kernel/work/api/index';
|
|
21
|
+
import { assertOwnedResourceCleanupTarget, markOwnedResourceCleaned, markOwnedResourceRetained } from '../../../../packages/kernel/identity/api/index';
|
|
22
|
+
import { managedBranchOwnedResourceId, managedBranchOwnedResourceLocator, managedWorkspaceOwnedResourceId } from '../../execution/managed-workspace';
|
|
23
|
+
import { isRepositoryCompletionReceipt, type WorkContract } from '../facade/types';
|
|
31
24
|
import {
|
|
32
25
|
cancelProcess,
|
|
33
26
|
getProcessHandle,
|
|
@@ -49,8 +42,6 @@ import {
|
|
|
49
42
|
} from './work-handle-store';
|
|
50
43
|
import { proveWorkPreservationContained } from '../cleanup-artifact-retention';
|
|
51
44
|
|
|
52
|
-
const CHECKPOINT_MESSAGE = 'chore(checkpoint): preserve terminal work before cleanup';
|
|
53
|
-
|
|
54
45
|
export interface TerminalWorkCleanupInput {
|
|
55
46
|
controllerHome: string;
|
|
56
47
|
handle: WorkHandleState;
|
|
@@ -118,7 +109,7 @@ function newReceipt(handle: WorkHandleState, targetBranch: string, terminalOutco
|
|
|
118
109
|
updatedAt: timestamp,
|
|
119
110
|
verification: { mode: 'cleanup_only', checksRun: [] },
|
|
120
111
|
processes: { examined: [], terminated: [], blocking: [], allTerminal: false },
|
|
121
|
-
ownership: { controllerLease: '
|
|
112
|
+
ownership: { controllerLease: 'already_released', processLeases: 'pending' },
|
|
122
113
|
preservation: { status: 'not_needed' },
|
|
123
114
|
worktree: { path: handle.worktreePath, status: 'pending' },
|
|
124
115
|
branchCleanup: { branch: handle.branch, status: 'pending' },
|
|
@@ -168,62 +159,6 @@ function branchUsedByAnotherWorktree(root: string, branch: string, currentPath:
|
|
|
168
159
|
return false;
|
|
169
160
|
}
|
|
170
161
|
|
|
171
|
-
function copyUntrackedFiles(worktreePath: string, archiveRoot: string): Array<{ path: string; sha256: string }> {
|
|
172
|
-
const listed = git(worktreePath, ['ls-files', '--others', '--exclude-standard', '-z']);
|
|
173
|
-
if (!listed.ok || !listed.stdout) return [];
|
|
174
|
-
const manifest: Array<{ path: string; sha256: string }> = [];
|
|
175
|
-
for (const relativePath of listed.stdout.split('\0').filter(Boolean)) {
|
|
176
|
-
const source = join(worktreePath, relativePath);
|
|
177
|
-
const destination = join(archiveRoot, 'untracked', relativePath);
|
|
178
|
-
mkdirSync(dirname(destination), { recursive: true });
|
|
179
|
-
if (!existsSync(destination)) {
|
|
180
|
-
cpSync(source, destination, { recursive: true, force: false, errorOnExist: true });
|
|
181
|
-
}
|
|
182
|
-
if (existsSync(source)) {
|
|
183
|
-
try {
|
|
184
|
-
manifest.push({ path: relativePath, sha256: hashText(readFileSync(source)) });
|
|
185
|
-
} catch {
|
|
186
|
-
manifest.push({ path: relativePath, sha256: 'directory-or-unreadable' });
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return manifest;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function createPatchArchive(controllerHome: string, handle: WorkHandleState): {
|
|
194
|
-
path: string;
|
|
195
|
-
sha256: string;
|
|
196
|
-
recoveryInstructions: string;
|
|
197
|
-
} {
|
|
198
|
-
const root = artifactRoot(controllerHome, handle);
|
|
199
|
-
const path = join(root, 'worktree.patch.json');
|
|
200
|
-
if (!existsSync(path)) {
|
|
201
|
-
const unstaged = git(handle.worktreePath, ['diff', '--binary', 'HEAD']);
|
|
202
|
-
const staged = git(handle.worktreePath, ['diff', '--binary', '--cached', 'HEAD']);
|
|
203
|
-
const untracked = copyUntrackedFiles(handle.worktreePath, root);
|
|
204
|
-
const archive = {
|
|
205
|
-
schemaVersion: 1,
|
|
206
|
-
repoId: handle.repositoryId,
|
|
207
|
-
checkoutId: handle.checkoutId,
|
|
208
|
-
workId: handle.workId,
|
|
209
|
-
branch: handle.branch,
|
|
210
|
-
baseCommit: handle.baseCommit,
|
|
211
|
-
expectedHead: handle.expectedHead,
|
|
212
|
-
createdAt: nowIso(),
|
|
213
|
-
unstagedPatch: unstaged.stdout,
|
|
214
|
-
stagedPatch: staged.stdout,
|
|
215
|
-
untracked,
|
|
216
|
-
};
|
|
217
|
-
writeFileSync(path, `${JSON.stringify(archive, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
218
|
-
}
|
|
219
|
-
const sha256 = hashText(readFileSync(path));
|
|
220
|
-
return {
|
|
221
|
-
path,
|
|
222
|
-
sha256,
|
|
223
|
-
recoveryInstructions: `Apply tracked changes from ${path}; restore copied untracked files from ${join(root, 'untracked')}. Verify SHA-256 ${sha256}.`,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
|
|
227
162
|
function createVerifiedBundle(controllerHome: string, handle: WorkHandleState, targetRoot: string): {
|
|
228
163
|
path: string;
|
|
229
164
|
sha256: string;
|
|
@@ -305,7 +240,7 @@ function workHandleOwnsCheckout(controllerHome: string, handle: WorkHandleState)
|
|
|
305
240
|
// WorkContract completion is the authoritative ownership boundary. Older
|
|
306
241
|
// runtimes could persist a completed contract while leaving the handle in a
|
|
307
242
|
// non-terminal state; that historical handle must not remain a live owner.
|
|
308
|
-
return contract === undefined ||
|
|
243
|
+
return contract === undefined || semanticWorkState(contract) === 'open';
|
|
309
244
|
}
|
|
310
245
|
|
|
311
246
|
function assertNoOtherLiveWork(input: TerminalWorkCleanupInput, receipt: WorkCleanupReceipt): void {
|
|
@@ -330,59 +265,22 @@ function preserveDirtyWorktree(
|
|
|
330
265
|
return persist(input.controllerHome, current, receipt);
|
|
331
266
|
}
|
|
332
267
|
if (!status.stdout) {
|
|
333
|
-
receipt.preservation.status =
|
|
334
|
-
? receipt.preservation.status
|
|
335
|
-
: 'not_needed';
|
|
268
|
+
receipt.preservation.status = 'not_needed';
|
|
336
269
|
return persist(input.controllerHome, current, receipt);
|
|
337
270
|
}
|
|
338
271
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
receipt.preservation.status = 'failed';
|
|
352
|
-
addBlocker(receipt, 'CHECKPOINT_HEAD_UNAVAILABLE');
|
|
353
|
-
} else {
|
|
354
|
-
receipt.preservation.status = 'checkpointed';
|
|
355
|
-
receipt.preservation.checkpointCommit = head.stdout;
|
|
356
|
-
current = writeWorkHandle(input.controllerHome, {
|
|
357
|
-
...current,
|
|
358
|
-
expectedHead: head.stdout,
|
|
359
|
-
cleanupReceipt: receipt,
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
} else {
|
|
363
|
-
try {
|
|
364
|
-
const archive = createPatchArchive(input.controllerHome, current);
|
|
365
|
-
receipt.preservation.status = 'patch_archived';
|
|
366
|
-
receipt.preservation.patchArchivePath = archive.path;
|
|
367
|
-
receipt.preservation.patchArchiveSha256 = archive.sha256;
|
|
368
|
-
receipt.preservation.recoveryInstructions = archive.recoveryInstructions;
|
|
369
|
-
} catch (error) {
|
|
370
|
-
receipt.preservation.status = 'failed';
|
|
371
|
-
addBlocker(receipt, `PRESERVATION_FAILED: ${error instanceof Error ? error.message : String(error)}`);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
} else if (receipt.preservation.checkpointCommit && status.stdout) {
|
|
375
|
-
try {
|
|
376
|
-
const archive = createPatchArchive(input.controllerHome, current);
|
|
377
|
-
receipt.preservation.status = 'patch_archived';
|
|
378
|
-
receipt.preservation.patchArchivePath = archive.path;
|
|
379
|
-
receipt.preservation.patchArchiveSha256 = archive.sha256;
|
|
380
|
-
receipt.preservation.recoveryInstructions = archive.recoveryInstructions;
|
|
381
|
-
} catch (error) {
|
|
382
|
-
receipt.preservation.status = 'failed';
|
|
383
|
-
addBlocker(receipt, `POST_CHECKPOINT_PRESERVATION_FAILED: ${error instanceof Error ? error.message : String(error)}`);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
272
|
+
// Semantic Work terminal state is not authority to mutate, commit, archive,
|
|
273
|
+
// or delete uncommitted workspace content. Dirty bytes stay exactly where the
|
|
274
|
+
// model/user left them until an explicit delivery/discard action resolves them.
|
|
275
|
+
receipt.preservation.status = 'not_needed';
|
|
276
|
+
receipt.preservation.recoveryInstructions = `Dirty managed worktree retained in place at ${current.worktreePath}; commit, deliver, or explicitly discard the pending changes before cleanup.`;
|
|
277
|
+
receipt.worktree.status = 'retained';
|
|
278
|
+
receipt.worktree.reason = 'Dirty managed worktree retained; terminal semantic state does not authorize destructive cleanup.';
|
|
279
|
+
receipt.branchCleanup.status = 'retained';
|
|
280
|
+
receipt.branchCleanup.reason = 'Branch retained with dirty managed worktree.';
|
|
281
|
+
addBlocker(receipt, 'DIRTY_WORKTREE_RETAINED');
|
|
282
|
+
markOwnedResourceRetained(input.controllerHome, managedWorkspaceOwnedResourceId(current.repositoryId, current.checkoutId));
|
|
283
|
+
markOwnedResourceRetained(input.controllerHome, managedBranchOwnedResourceId(current.repositoryId, current.checkoutId));
|
|
386
284
|
return persist(input.controllerHome, current, receipt);
|
|
387
285
|
}
|
|
388
286
|
|
|
@@ -460,9 +358,15 @@ export interface TerminalWorkCleanupReconcileReport {
|
|
|
460
358
|
truncated: boolean;
|
|
461
359
|
}
|
|
462
360
|
|
|
361
|
+
function contractCompletedNoChange(contract: WorkContract): boolean {
|
|
362
|
+
if (contract.workKind === 'completed_no_change' || contract.completionOutcome === 'completed_no_change') return true;
|
|
363
|
+
const receipt = contract.completionReceipt;
|
|
364
|
+
return Boolean(receipt && isRepositoryCompletionReceipt(receipt) && receipt.delivery.kind === 'no_change');
|
|
365
|
+
}
|
|
366
|
+
|
|
463
367
|
function terminalOutcomeForContract(contract: WorkContract): WorkTerminalOutcome {
|
|
464
|
-
if (contract
|
|
465
|
-
if (contract
|
|
368
|
+
if (semanticWorkState(contract) === 'cancelled') return 'cancelled';
|
|
369
|
+
if (semanticWorkState(contract) === 'completed') return 'completed_cleanup';
|
|
466
370
|
return 'failed';
|
|
467
371
|
}
|
|
468
372
|
|
|
@@ -474,7 +378,7 @@ export function recoverTerminalWorkHandle(
|
|
|
474
378
|
const existing = readWorkHandle(controllerHome, repositoryId, workId);
|
|
475
379
|
if (existing) return existing;
|
|
476
380
|
const contract = getWorkContract({ controllerHome, repoId: repositoryId }, workId);
|
|
477
|
-
if (!contract ||
|
|
381
|
+
if (!contract || semanticWorkState(contract) === 'open') return undefined;
|
|
478
382
|
const worktreePath = contract.worktreeRef?.trim();
|
|
479
383
|
const checkoutId = contract.checkoutId?.trim();
|
|
480
384
|
if (!worktreePath || !checkoutId || !existsSync(worktreePath)) return undefined;
|
|
@@ -500,15 +404,15 @@ export function recoverTerminalWorkHandle(
|
|
|
500
404
|
const contained = targetExists
|
|
501
405
|
? git(repository.canonicalRoot, ['merge-base', '--is-ancestor', head.stdout, `refs/heads/${targetBranch}`]).ok
|
|
502
406
|
: false;
|
|
503
|
-
const
|
|
504
|
-
const
|
|
407
|
+
const completedNoChange = contractCompletedNoChange(contract);
|
|
408
|
+
const delivered = semanticWorkState(contract) === 'completed' && contained && !completedNoChange;
|
|
505
409
|
const recordedAt = nowIso();
|
|
506
410
|
return writeWorkHandle(controllerHome, {
|
|
507
411
|
schemaVersion: 1,
|
|
508
412
|
workId,
|
|
509
413
|
workContractId: workId,
|
|
510
|
-
sessionId:
|
|
511
|
-
principalId: contract.principalId?.trim() ||
|
|
414
|
+
sessionId: `terminal-recovery:${workId}`,
|
|
415
|
+
principalId: contract.principalId?.trim() || 'terminal-recovery',
|
|
512
416
|
repositoryId,
|
|
513
417
|
checkoutId,
|
|
514
418
|
sourceCheckoutId: repository.activeCheckoutId,
|
|
@@ -520,17 +424,18 @@ export function recoverTerminalWorkHandle(
|
|
|
520
424
|
expectedHead: head.stdout,
|
|
521
425
|
permissionSnapshotVersion: 1,
|
|
522
426
|
state: delivered ? 'merged' : 'failed_terminal_cleanup',
|
|
523
|
-
failureReason: delivered
|
|
427
|
+
failureReason: delivered || completedNoChange
|
|
428
|
+
? undefined
|
|
429
|
+
: 'Recovered terminal Work ownership for cleanup; target-branch containment was not proven.',
|
|
524
430
|
createdAt: contract.createdAt || recordedAt,
|
|
525
431
|
updatedAt: recordedAt,
|
|
526
432
|
cleanupResponsibility: { owner: 'work_finalizer', registeredAt: recordedAt },
|
|
527
433
|
finalization: {
|
|
528
|
-
validation:
|
|
434
|
+
validation: 'done',
|
|
529
435
|
commit: 'skipped',
|
|
530
436
|
merge: delivered ? 'done' : 'skipped',
|
|
531
437
|
branchCleanup: 'pending',
|
|
532
438
|
worktreeCleanup: 'pending',
|
|
533
|
-
...(contract.status === 'failed' ? { lastError: 'Recovered failed terminal Work for cleanup.' } : {}),
|
|
534
439
|
},
|
|
535
440
|
});
|
|
536
441
|
}
|
|
@@ -646,6 +551,7 @@ function prepareManagedBranchPreservation(
|
|
|
646
551
|
}
|
|
647
552
|
|
|
648
553
|
function applyManagedBranchCleanup(
|
|
554
|
+
controllerHome: string,
|
|
649
555
|
target: ReturnType<typeof getRepository>,
|
|
650
556
|
current: WorkHandleState,
|
|
651
557
|
targetBranch: string,
|
|
@@ -673,6 +579,21 @@ function applyManagedBranchCleanup(
|
|
|
673
579
|
receipt.branchCleanup.reason = 'Unique commits are not archived.';
|
|
674
580
|
addBlocker(receipt, `BRANCH_UNPRESERVED: ${current.branch}`);
|
|
675
581
|
} else {
|
|
582
|
+
// Branch deletion requires the canonical OwnedResource witness in addition
|
|
583
|
+
// to Git relation checks. Repository/ref shape alone is not cleanup authority.
|
|
584
|
+
try {
|
|
585
|
+
assertOwnedResourceCleanupTarget(controllerHome, {
|
|
586
|
+
resourceId: managedBranchOwnedResourceId(current.repositoryId, current.checkoutId),
|
|
587
|
+
kind: 'git_branch',
|
|
588
|
+
targetRef: current.branch,
|
|
589
|
+
locator: managedBranchOwnedResourceLocator(target.canonicalRoot, current.checkoutId, current.branch),
|
|
590
|
+
});
|
|
591
|
+
} catch (error) {
|
|
592
|
+
receipt.branchCleanup.status = 'retained';
|
|
593
|
+
receipt.branchCleanup.reason = error instanceof Error ? error.message : String(error);
|
|
594
|
+
addBlocker(receipt, `OWNED_BRANCH_CLEANUP_FENCED: ${receipt.branchCleanup.reason}`);
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
676
597
|
// We already proved the exact branch relation against targetBranch above.
|
|
677
598
|
// `git branch -d` instead consults the checkout's current HEAD, which may be
|
|
678
599
|
// an older/stale source checkout and can falsely reject a branch that is
|
|
@@ -699,6 +620,24 @@ function cleanupReceiptComplete(receipt: WorkCleanupReceipt, deleteBranch: boole
|
|
|
699
620
|
: receipt.branchCleanup.status === 'retained');
|
|
700
621
|
}
|
|
701
622
|
|
|
623
|
+
function projectOwnedResourceCleanup(
|
|
624
|
+
controllerHome: string,
|
|
625
|
+
handle: WorkHandleState,
|
|
626
|
+
receipt: WorkCleanupReceipt,
|
|
627
|
+
): void {
|
|
628
|
+
const worktreeResourceId = managedWorkspaceOwnedResourceId(handle.repositoryId, handle.checkoutId);
|
|
629
|
+
if (['removed', 'already_removed'].includes(receipt.worktree.status)) {
|
|
630
|
+
markOwnedResourceCleaned(controllerHome, worktreeResourceId, 'forge:work-terminal-cleanup', receipt.receiptId);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const branchResourceId = managedBranchOwnedResourceId(handle.repositoryId, handle.checkoutId);
|
|
634
|
+
if (['deleted', 'already_deleted', 'archived'].includes(receipt.branchCleanup.status)) {
|
|
635
|
+
markOwnedResourceCleaned(controllerHome, branchResourceId, 'forge:work-terminal-cleanup', receipt.receiptId);
|
|
636
|
+
} else if (receipt.branchCleanup.status === 'retained') {
|
|
637
|
+
markOwnedResourceRetained(controllerHome, branchResourceId);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
702
641
|
function reconcileCleanedManagedBranchRetirement(
|
|
703
642
|
input: TerminalWorkCleanupInput,
|
|
704
643
|
repository: ReturnType<typeof getRepository>,
|
|
@@ -709,7 +648,7 @@ function reconcileCleanedManagedBranchRetirement(
|
|
|
709
648
|
): TerminalWorkCleanupResult | undefined {
|
|
710
649
|
const workId = current.workContractId ?? current.workId;
|
|
711
650
|
const contract = getWorkContract({ controllerHome: input.controllerHome, repoId: current.repositoryId }, workId);
|
|
712
|
-
if (!contract ||
|
|
651
|
+
if (!contract || semanticWorkState(contract) === 'open'
|
|
713
652
|
|| !cleanedManagedBranchRetirementCandidate(repository, contract, current, targetBranch, deleteBranch)) return undefined;
|
|
714
653
|
|
|
715
654
|
const target = selectTerminalCleanupTarget(repository, current);
|
|
@@ -724,6 +663,7 @@ function reconcileCleanedManagedBranchRetirement(
|
|
|
724
663
|
current = persist(input.controllerHome, current, receipt);
|
|
725
664
|
if (receipt.blockers.length === 0) {
|
|
726
665
|
applyManagedBranchCleanup(
|
|
666
|
+
input.controllerHome,
|
|
727
667
|
target,
|
|
728
668
|
current,
|
|
729
669
|
targetBranch,
|
|
@@ -818,8 +758,19 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
818
758
|
const targetBranch = resolveWorkDeliveryTargetBranch(input.handle, repository.defaultBranch, input.targetBranch);
|
|
819
759
|
const deleteBranch = input.deleteBranch !== false;
|
|
820
760
|
let current = input.handle;
|
|
821
|
-
const
|
|
822
|
-
|
|
761
|
+
const contract = getWorkContract(
|
|
762
|
+
{ controllerHome: input.controllerHome, repoId: current.repositoryId },
|
|
763
|
+
current.workContractId ?? current.workId,
|
|
764
|
+
);
|
|
765
|
+
const completedNoChange = Boolean(contract && contractCompletedNoChange(contract));
|
|
766
|
+
// `merged` is delivery truth, not a generic terminal-cleanup waypoint. Historical
|
|
767
|
+
// no-change handles may carry merge=done/state=merged from the retired finalizer;
|
|
768
|
+
// normalize that stale projection before any destructive cleanup attempt.
|
|
769
|
+
const landed = !completedNoChange && (current.state === 'merged' || current.finalization.merge === 'done');
|
|
770
|
+
const successfulCompletion = completedNoChange || input.terminalOutcome === 'completed_cleanup';
|
|
771
|
+
const preservedFailure = successfulCompletion
|
|
772
|
+
? undefined
|
|
773
|
+
: (input.failureReason ?? current.failureReason ?? current.finalization.lastError ?? 'terminal work cleanup').slice(0, 1_000);
|
|
823
774
|
const receipt = current.cleanupReceipt ?? newReceipt(current, targetBranch, input.terminalOutcome);
|
|
824
775
|
|
|
825
776
|
if (
|
|
@@ -827,6 +778,12 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
827
778
|
|| receipt.checkoutId !== current.checkoutId
|
|
828
779
|
|| receipt.workId !== current.workId
|
|
829
780
|
) throw new Error('WORK_CLEANUP_RECEIPT_IDENTITY_MISMATCH');
|
|
781
|
+
// Legacy receipts may retain the former Controller lease stage. ControllerSession
|
|
782
|
+
// is no longer a cleanup resource; normalize this projection without touching
|
|
783
|
+
// any explicit continuation state.
|
|
784
|
+
if (receipt.ownership.controllerLease === 'pending') {
|
|
785
|
+
receipt.ownership.controllerLease = 'already_released';
|
|
786
|
+
}
|
|
830
787
|
|
|
831
788
|
if (current.state === 'cleaned') {
|
|
832
789
|
const branchRetirement = reconcileCleanedManagedBranchRetirement(
|
|
@@ -844,7 +801,6 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
844
801
|
receipt.completedAt = receipt.completedAt ?? current.updatedAt ?? nowIso();
|
|
845
802
|
receipt.blockers = [];
|
|
846
803
|
receipt.processes.allTerminal = true;
|
|
847
|
-
if (receipt.ownership.controllerLease === 'pending') receipt.ownership.controllerLease = 'already_released';
|
|
848
804
|
if (receipt.ownership.processLeases === 'pending') receipt.ownership.processLeases = 'released';
|
|
849
805
|
if (receipt.worktree.status === 'pending' || receipt.worktree.status === 'failed') {
|
|
850
806
|
receipt.worktree.status = 'already_removed';
|
|
@@ -890,7 +846,11 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
890
846
|
? 'failed' as const
|
|
891
847
|
: current.finalization.validation,
|
|
892
848
|
commit: current.finalization.commit === 'pending' ? 'skipped' as const : current.finalization.commit,
|
|
893
|
-
merge:
|
|
849
|
+
merge: completedNoChange
|
|
850
|
+
? 'skipped' as const
|
|
851
|
+
: landed
|
|
852
|
+
? 'done' as const
|
|
853
|
+
: current.finalization.merge === 'pending' ? 'skipped' as const : current.finalization.merge,
|
|
894
854
|
lastError: preservedFailure,
|
|
895
855
|
};
|
|
896
856
|
if (landed) {
|
|
@@ -987,7 +947,19 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
987
947
|
current = persist(input.controllerHome, current, receipt);
|
|
988
948
|
return { handle: current, receipt };
|
|
989
949
|
}
|
|
990
|
-
|
|
950
|
+
const rootIdentityValid = root.ok && resolve(root.stdout) === resolve(current.worktreePath);
|
|
951
|
+
const branchIdentityValid = branch.ok && branch.stdout === current.branch;
|
|
952
|
+
let detachedContainedIdentity = false;
|
|
953
|
+
if (rootIdentityValid && branch.ok && !branch.stdout) {
|
|
954
|
+
const status = git(current.worktreePath, ['status', '--porcelain=v1', '--untracked-files=all']);
|
|
955
|
+
const head = git(current.worktreePath, ['rev-parse', 'HEAD']);
|
|
956
|
+
detachedContainedIdentity = status.ok
|
|
957
|
+
&& !status.stdout
|
|
958
|
+
&& head.ok
|
|
959
|
+
&& Boolean(head.stdout)
|
|
960
|
+
&& git(target.canonicalRoot, ['merge-base', '--is-ancestor', head.stdout, `refs/heads/${targetBranch}`]).ok;
|
|
961
|
+
}
|
|
962
|
+
if (!rootIdentityValid || (!branchIdentityValid && !detachedContainedIdentity)) {
|
|
991
963
|
addBlocker(receipt, 'WORKTREE_IDENTITY_INVALID');
|
|
992
964
|
current = persist(input.controllerHome, current, receipt);
|
|
993
965
|
return { handle: current, receipt };
|
|
@@ -1020,6 +992,19 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
1020
992
|
}
|
|
1021
993
|
|
|
1022
994
|
if (existsSync(current.worktreePath)) {
|
|
995
|
+
try {
|
|
996
|
+
assertOwnedResourceCleanupTarget(input.controllerHome, {
|
|
997
|
+
resourceId: managedWorkspaceOwnedResourceId(current.repositoryId, current.checkoutId),
|
|
998
|
+
kind: 'worktree',
|
|
999
|
+
targetRef: current.worktreePath,
|
|
1000
|
+
});
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
receipt.worktree.status = 'retained';
|
|
1003
|
+
receipt.worktree.reason = error instanceof Error ? error.message : String(error);
|
|
1004
|
+
addBlocker(receipt, `OWNED_WORKTREE_CLEANUP_FENCED: ${receipt.worktree.reason}`);
|
|
1005
|
+
current = persist(input.controllerHome, current, receipt);
|
|
1006
|
+
return { handle: current, receipt };
|
|
1007
|
+
}
|
|
1023
1008
|
const removed = git(target.canonicalRoot, ['worktree', 'remove', '--force', current.worktreePath], 60_000);
|
|
1024
1009
|
if (!removed.ok && existsSync(current.worktreePath)) {
|
|
1025
1010
|
receipt.worktree.status = 'failed';
|
|
@@ -1056,6 +1041,7 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
1056
1041
|
}
|
|
1057
1042
|
|
|
1058
1043
|
applyManagedBranchCleanup(
|
|
1044
|
+
input.controllerHome,
|
|
1059
1045
|
target,
|
|
1060
1046
|
current,
|
|
1061
1047
|
targetBranch,
|
|
@@ -1075,6 +1061,7 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
1075
1061
|
receipt.complete = cleanupReceiptComplete(receipt, deleteBranch);
|
|
1076
1062
|
receipt.partial = !receipt.complete;
|
|
1077
1063
|
if (receipt.complete) receipt.completedAt = receipt.completedAt ?? nowIso();
|
|
1064
|
+
projectOwnedResourceCleanup(input.controllerHome, current, receipt);
|
|
1078
1065
|
|
|
1079
1066
|
const finalization = {
|
|
1080
1067
|
...current.finalization,
|
|
@@ -1120,6 +1107,30 @@ export interface SingleTerminalWorkCleanupResult {
|
|
|
1120
1107
|
* Controller ownership or unsafe branch drift. A caller proving the exact
|
|
1121
1108
|
* leftover owner epoch may release it before physical cleanup.
|
|
1122
1109
|
*/
|
|
1110
|
+
function reconcileCancelledCleanupProjection(
|
|
1111
|
+
controllerHome: string,
|
|
1112
|
+
repoId: string,
|
|
1113
|
+
contract: WorkContract,
|
|
1114
|
+
receipt: WorkCleanupReceipt,
|
|
1115
|
+
): void {
|
|
1116
|
+
if (contract.semanticState !== 'cancelled' || receipt.complete !== true) return;
|
|
1117
|
+
if (contract.phase === 'cleanup' && contract.phaseEvidence.cleanup.state === 'satisfied'
|
|
1118
|
+
&& contract.phaseEvidence.cleanup.receiptId === receipt.receiptId) return;
|
|
1119
|
+
recordCancelledWorkCleanupCompleted(
|
|
1120
|
+
{ controllerHome, repoId },
|
|
1121
|
+
contract.workId,
|
|
1122
|
+
{
|
|
1123
|
+
summary: `Verified terminal resource cleanup completed with receipt ${receipt.receiptId}.`,
|
|
1124
|
+
receiptId: receipt.receiptId,
|
|
1125
|
+
evidenceRefs: [{
|
|
1126
|
+
title: 'cancelled Work terminal cleanup completed',
|
|
1127
|
+
summary: `Physical worktree/branch cleanup completed under receipt ${receipt.receiptId}; unexecuted semantic phases remain skipped rather than satisfied.`,
|
|
1128
|
+
detailLevel: 'summary',
|
|
1129
|
+
}, ...contract.evidenceRefs],
|
|
1130
|
+
},
|
|
1131
|
+
);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1123
1134
|
export async function reconcileSingleTerminalWorkCleanup(
|
|
1124
1135
|
controllerHome: string,
|
|
1125
1136
|
repositoryId: string,
|
|
@@ -1127,38 +1138,13 @@ export async function reconcileSingleTerminalWorkCleanup(
|
|
|
1127
1138
|
options: {
|
|
1128
1139
|
targetBranch?: string;
|
|
1129
1140
|
deleteBranch?: boolean;
|
|
1130
|
-
/** Recovery authority for the narrow crash window after semantic terminalization but before owner release. */
|
|
1131
|
-
controllerAuthority?: ControllerTerminalizationAuthority;
|
|
1132
1141
|
} = {},
|
|
1133
1142
|
): Promise<SingleTerminalWorkCleanupResult> {
|
|
1134
1143
|
const repository = getRepository(repositoryId, controllerHome, { includeRemoved: true });
|
|
1135
1144
|
const contract = getWorkContract({ controllerHome, repoId: repositoryId }, workId);
|
|
1136
|
-
if (!contract ||
|
|
1145
|
+
if (!contract || semanticWorkState(contract) === 'open') {
|
|
1137
1146
|
return { status: 'not_terminal', workId, reason: 'Work is not terminal.' };
|
|
1138
1147
|
}
|
|
1139
|
-
let controllerLease: WorkCleanupReceipt['ownership']['controllerLease'] = 'already_released';
|
|
1140
|
-
const owner = getControllerSession({ controllerHome, repoId: repositoryId }, workId);
|
|
1141
|
-
if (owner) {
|
|
1142
|
-
const authority = options.controllerAuthority;
|
|
1143
|
-
if (!authority) return { status: 'blocked', workId, reason: 'Active Controller ownership still exists.' };
|
|
1144
|
-
const ownerAuthority = controllerTerminalizationAuthorityFromSession(owner);
|
|
1145
|
-
if (!ownerAuthority
|
|
1146
|
-
|| ownerAuthority.controllerId !== authority.controllerId
|
|
1147
|
-
|| ownerAuthority.controllerType !== authority.controllerType
|
|
1148
|
-
|| ownerAuthority.principalId !== authority.principalId
|
|
1149
|
-
|| ownerAuthority.controllerInstanceId !== authority.controllerInstanceId
|
|
1150
|
-
|| ownerAuthority.claimGeneration !== authority.claimGeneration) {
|
|
1151
|
-
return { status: 'blocked', workId, reason: 'Active Controller ownership does not match the cleanup authority.' };
|
|
1152
|
-
}
|
|
1153
|
-
const released = releaseControllerSessionWithAuthority(
|
|
1154
|
-
{ controllerHome, repoId: repositoryId },
|
|
1155
|
-
{ workId, actor: `terminal-cleanup:${workId}`, authority },
|
|
1156
|
-
);
|
|
1157
|
-
if (!released.allowed) {
|
|
1158
|
-
return { status: 'blocked', workId, reason: `Active Controller ownership release fenced: ${released.reason}.` };
|
|
1159
|
-
}
|
|
1160
|
-
controllerLease = 'released';
|
|
1161
|
-
}
|
|
1162
1148
|
const originalHandle = readWorkHandle(controllerHome, repositoryId, workId)
|
|
1163
1149
|
?? recoverTerminalWorkHandle(controllerHome, repositoryId, workId);
|
|
1164
1150
|
if (!originalHandle) return { status: 'no_handle', workId };
|
|
@@ -1176,8 +1162,10 @@ export async function reconcileSingleTerminalWorkCleanup(
|
|
|
1176
1162
|
terminalOutcome: terminalOutcomeForContract(contract),
|
|
1177
1163
|
failureReason: drift.handle.failureReason ?? drift.handle.finalization.lastError,
|
|
1178
1164
|
});
|
|
1179
|
-
cleaned.receipt.ownership.controllerLease = controllerLease;
|
|
1180
1165
|
const persisted = writeWorkHandle(controllerHome, { ...cleaned.handle, cleanupReceipt: cleaned.receipt });
|
|
1166
|
+
if (cleaned.receipt.complete) {
|
|
1167
|
+
reconcileCancelledCleanupProjection(controllerHome, repositoryId, contract, cleaned.receipt);
|
|
1168
|
+
}
|
|
1181
1169
|
if (!cleaned.receipt.complete) {
|
|
1182
1170
|
return {
|
|
1183
1171
|
status: 'blocked',
|
|
@@ -1211,7 +1199,14 @@ export async function reconcileTerminalWorkCleanups(
|
|
|
1211
1199
|
truncated: false,
|
|
1212
1200
|
};
|
|
1213
1201
|
|
|
1214
|
-
const
|
|
1202
|
+
const maintenanceEpoch = Math.floor(nowMs / 60_000);
|
|
1203
|
+
const repositories = listRepositories(controllerHome)
|
|
1204
|
+
.filter((repository) => repository.enabled && !repository.removedAt)
|
|
1205
|
+
.sort((left, right) => {
|
|
1206
|
+
const leftOrder = hashText(`${maintenanceEpoch}\0${left.repoId}`);
|
|
1207
|
+
const rightOrder = hashText(`${maintenanceEpoch}\0${right.repoId}`);
|
|
1208
|
+
return leftOrder.localeCompare(rightOrder) || left.repoId.localeCompare(right.repoId);
|
|
1209
|
+
});
|
|
1215
1210
|
outer: for (const repository of repositories) {
|
|
1216
1211
|
const handles = listWorkHandles(controllerHome, repository.repoId, 10_000)
|
|
1217
1212
|
.filter((handle) => handle.managedWorktree);
|
|
@@ -1223,7 +1218,7 @@ export async function reconcileTerminalWorkCleanups(
|
|
|
1223
1218
|
limit: 10_000,
|
|
1224
1219
|
})) {
|
|
1225
1220
|
const contract = record.value;
|
|
1226
|
-
if (knownWorkIds.has(contract.workId) ||
|
|
1221
|
+
if (knownWorkIds.has(contract.workId) || semanticWorkState(contract) === 'open') continue;
|
|
1227
1222
|
if (!contract.worktreeRef?.trim() || !existsSync(contract.worktreeRef)) continue;
|
|
1228
1223
|
let recovered: WorkHandleState | undefined;
|
|
1229
1224
|
try {
|
|
@@ -1247,15 +1242,22 @@ export async function reconcileTerminalWorkCleanups(
|
|
|
1247
1242
|
report.errors.push({ workId: originalHandle.workId, error: error instanceof Error ? error.message : String(error) });
|
|
1248
1243
|
continue;
|
|
1249
1244
|
}
|
|
1250
|
-
if (!contract ||
|
|
1245
|
+
if (!contract || semanticWorkState(contract) === 'open') {
|
|
1251
1246
|
report.skippedNonTerminal.push(originalHandle.workId);
|
|
1252
1247
|
continue;
|
|
1253
1248
|
}
|
|
1249
|
+
// Semantic terminality is the lifecycle authority that starts mechanical
|
|
1250
|
+
// cleanup reconciliation. It is not deletion authority: work_finalizer must
|
|
1251
|
+
// still prove exact Forge ownership, preserve dirty bytes/unique commits,
|
|
1252
|
+
// settle live processes, and honor explicit retention before removing any
|
|
1253
|
+
// physical resource. Completion/cleanup receipts are delivery/progress
|
|
1254
|
+
// evidence, not a second permission gate that can strand terminal Work.
|
|
1254
1255
|
if (cleanupRetainedByRequest(contract, originalHandle)) {
|
|
1255
1256
|
report.skippedRetained.push(originalHandle.workId);
|
|
1256
1257
|
continue;
|
|
1257
1258
|
}
|
|
1258
1259
|
if (originalHandle.state === 'cleaned' && originalHandle.cleanupReceipt?.complete === true) {
|
|
1260
|
+
reconcileCancelledCleanupProjection(controllerHome, repository.repoId, contract, originalHandle.cleanupReceipt);
|
|
1259
1261
|
const targetBranch = resolveWorkDeliveryTargetBranch(originalHandle, repository.defaultBranch);
|
|
1260
1262
|
if (!cleanedManagedBranchRetirementCandidate(
|
|
1261
1263
|
repository,
|
|
@@ -1296,26 +1298,11 @@ export async function reconcileTerminalWorkCleanups(
|
|
|
1296
1298
|
terminalOutcome: terminalOutcomeForContract(contract),
|
|
1297
1299
|
failureReason: drift.handle.failureReason ?? drift.handle.finalization.lastError,
|
|
1298
1300
|
});
|
|
1299
|
-
const workId = cleaned.handle.workContractId ?? cleaned.handle.workId;
|
|
1300
|
-
const controllerSession = getControllerSession({ controllerHome, repoId: repository.repoId }, workId);
|
|
1301
|
-
if (controllerSession) {
|
|
1302
|
-
const released = releaseObservedControllerSession(
|
|
1303
|
-
{ controllerHome, repoId: repository.repoId },
|
|
1304
|
-
{ workId, actor: `terminal-cleanup:${originalHandle.workId}`, owner: controllerSession },
|
|
1305
|
-
);
|
|
1306
|
-
if (released.allowed) {
|
|
1307
|
-
cleaned.receipt.ownership.controllerLease = 'released';
|
|
1308
|
-
} else {
|
|
1309
|
-
cleaned.receipt.complete = false;
|
|
1310
|
-
cleaned.receipt.partial = true;
|
|
1311
|
-
cleaned.receipt.completedAt = undefined;
|
|
1312
|
-
cleaned.receipt.blockers = appendUnique(cleaned.receipt.blockers, `controller lease release fenced: ${released.reason}`);
|
|
1313
|
-
}
|
|
1314
|
-
} else {
|
|
1315
|
-
cleaned.receipt.ownership.controllerLease = 'already_released';
|
|
1316
|
-
}
|
|
1317
1301
|
writeWorkHandle(controllerHome, { ...cleaned.handle, cleanupReceipt: cleaned.receipt });
|
|
1318
|
-
if (cleaned.receipt.complete)
|
|
1302
|
+
if (cleaned.receipt.complete) {
|
|
1303
|
+
reconcileCancelledCleanupProjection(controllerHome, repository.repoId, contract, cleaned.receipt);
|
|
1304
|
+
report.cleaned.push(originalHandle.workId);
|
|
1305
|
+
}
|
|
1319
1306
|
else report.blocked.push({
|
|
1320
1307
|
workId: originalHandle.workId,
|
|
1321
1308
|
reason: cleaned.receipt.blockers.join('; ') || cleaned.receipt.worktree.reason || cleaned.receipt.branchCleanup.reason || 'terminal cleanup incomplete',
|