@moretea-labs/forge 1.8.0 → 1.8.2
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 +73 -7
- package/CHANGELOG.md +34 -0
- package/CLAUDE.md +17 -2
- package/CONTRIBUTING.md +3 -2
- package/README.en.md +24 -3
- package/README.md +10 -6
- package/README.zh-CN.md +5 -3
- package/THIRD_PARTY_NOTICES.md +1 -2
- package/adapters/chatgpt/browser-delivery-host.ts +7 -1
- package/adapters/chatgpt/browser-delivery-runtime.ts +531 -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 +229 -2
- package/adapters/chatgpt/work-conversation-binding-store.ts +99 -54
- package/adapters/computer/chatgpt-extension-target.ts +708 -0
- package/adapters/computer/chrome-extension/background.js +541 -0
- package/adapters/computer/chrome-extension/content.js +402 -0
- package/adapters/computer/chrome-extension/core.js +24 -0
- package/adapters/computer/chrome-extension/manifest.json +32 -0
- package/adapters/computer/desktop-operator-discovery.ts +11 -31
- package/adapters/computer/desktop-operator-provider.ts +18 -6
- package/adapters/computer/interaction-target-authority.ts +178 -24
- package/adapters/mcp/access-mode.ts +18 -39
- package/adapters/mcp/auth.ts +2 -7
- package/adapters/mcp/instructions.ts +6 -5
- package/adapters/mcp/multi-repository.ts +10 -47
- package/adapters/mcp/oauth.ts +73 -0
- package/adapters/mcp/paths.ts +4 -1
- 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 +490 -113
- package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +83 -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 +14 -54
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +132 -47
- package/adapters/mcp/runtime-gateway/process-tools.ts +173 -23
- 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 +19 -507
- package/adapters/mcp/runtime-gateway/routing-policy.ts +506 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +15 -66
- package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +123 -178
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +11 -5
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +37 -1
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +416 -270
- package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +140 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +262 -3123
- 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 +229 -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 +320 -0
- package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
- package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +180 -0
- package/adapters/mcp/server.ts +91 -26
- package/adapters/mcp/setup.ts +5 -13
- package/adapters/mcp/tool-mapping/access-tools.ts +0 -6
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +703 -3092
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +5 -10
- package/adapters/mcp/tool-mapping/repository-tools.ts +170 -213
- package/adapters/mcp/toolset-names.ts +11 -37
- package/adapters/mcp/toolset.ts +19 -92
- package/{src/cli → adapters}/mcp/transports/AGENTS.md +5 -5
- package/{src/cli → adapters}/mcp/transports/CLAUDE.md +5 -5
- package/adapters/mcp/transports/http-observation.ts +377 -0
- package/adapters/mcp/transports/http-post-lifecycle.ts +19 -0
- package/adapters/mcp/transports/http.ts +200 -683
- 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/adapters/mcp/types.ts +0 -6
- package/assets/hooks/lib/session-state.sh +0 -38
- package/assets/hooks/post-bash.sh +1 -1
- package/assets/hooks/post-tool-observer.sh +0 -5
- package/assets/hooks/prompt-guard.sh +0 -55
- package/assets/partials/04-project-structure.partial.md +1 -1
- package/assets/partials/07-footer.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +1 -1
- package/assets/partials-agents/08-deep-docs.partial.md +1 -1
- package/assets/plugin-registry.v1.json +6 -4
- package/assets/reference-configs/agentic-development-flow.md +26 -1
- package/assets/reference-configs/external-tooling.md +0 -76
- package/assets/reference-configs/global-working-rules.md +19 -0
- package/assets/reference-configs/release-deploy.md +1 -1
- package/assets/templates/helpers/architecture-queue.sh +1 -1
- package/assets/templates/helpers/check-agent-tooling.sh +1 -327
- package/assets/templates/helpers/check-task-workflow.sh +1 -1
- package/assets/templates/helpers/ensure-task-workflow.sh +0 -14
- package/assets/templates/helpers/migrate-project-template.sh +2 -2
- package/assets/workflow-contract.v1.json +0 -2
- package/docs/README.md +5 -2
- package/docs/architecture/CURRENT.md +205 -51
- 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/20260904-ios-device-migration-baseline.md +42 -0
- 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 +234 -0
- package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
- package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +74 -0
- package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +342 -0
- package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
- package/docs/architecture/decisions/20261009-exact-code-context-discovery.md +19 -0
- package/docs/architecture/decisions/20261009-generated-xcode-cache-retention.md +37 -0
- package/docs/architecture/decisions/20261011-autonomous-continuation-convergence.md +597 -0
- package/docs/architecture/decisions/20261017-edit-session-finalization-reconciliation.md +17 -0
- package/docs/architecture/decisions/20261019-retire-host-skills.md +16 -0
- package/docs/architecture/diagrams/agentic-dev-plugin-architecture.html +1 -1
- package/docs/architecture/domains/public-surface.md +3 -5
- package/docs/architecture/domains/verification.md +6 -5
- package/docs/architecture/domains/workflow-engine.md +6 -0
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +3 -3
- package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +4 -4
- package/docs/architecture/reviews/20261015-code-search-runtime-acceptance.md +75 -0
- package/docs/forge-plugin-management.md +16 -4
- package/docs/operations/controller-browser-plugin.md +23 -0
- package/docs/operations/controller-performance-and-502.md +17 -0
- package/docs/operations/controller-reliability-runbook.md +2 -2
- package/docs/operations/features.md +6 -7
- package/docs/operations/features.zh-CN.md +1 -1
- package/docs/operations/github-repository.md +4 -4
- package/docs/operations/github-semantic-release-projection.md +20 -0
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +13 -52
- package/docs/operations/releasing.md +2 -0
- package/docs/operations/runtime-performance-diagnostics.md +8 -0
- package/docs/operations/standalone-disaster-recovery.md +15 -7
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/tutorials/03-first-repository-task.md +2 -0
- package/docs/wiki/Computer-and-Plugins.md +78 -0
- package/docs/wiki/Computer-and-Plugins.zh-CN.md +88 -0
- package/docs/wiki/Home.md +16 -2
- package/docs/wiki/Implementation.md +25 -13
- package/docs/wiki/Installation.md +28 -32
- package/docs/wiki/Integrations.md +4 -0
- package/docs/wiki/Quick-Start.md +35 -22
- package/docs/wiki/Releases-and-Upgrades.md +15 -25
- package/docs/wiki/_Sidebar.md +5 -1
- package/package.json +25 -25
- 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 +348 -97
- 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 +87 -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/eligibility.ts +4 -1
- 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 +166 -143
- package/packages/kernel/work/api/index.ts +3 -2
- package/packages/kernel/work/application/work-service.ts +18 -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 +34 -65
- package/packages/kernel/work/domain/types.ts +57 -51
- package/packages/kernel/work/infrastructure/work-contract-store.ts +847 -729
- package/packages/kernel/work/ports/work-contract-store.ts +5 -2
- package/packages/plugin-runtime/browser/provider-registry.ts +12 -36
- 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 +153 -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/assemble-template.ts +11 -72
- package/scripts/canary-controller-semantic-wait.ts +12 -24
- package/scripts/check-mcp-compatibility.ts +94 -201
- package/scripts/check-package-identity.mjs +0 -5
- package/scripts/check-runtime-architecture.mjs +921 -239
- package/scripts/forge-local-recovery-helper.mjs +93 -15
- package/scripts/init-project.sh +0 -46
- package/scripts/install-ios-hid-toolchain.sh +60 -0
- package/scripts/install-standalone-recovery.ts +1 -1
- package/scripts/lib/project-init-lib.sh +6 -3
- package/scripts/migrate-windows-wsl-controller-home.ts +2 -0
- package/scripts/open-source-audit-allowlist.txt +1 -3
- package/scripts/run-bounded-command.mjs +5 -0
- package/scripts/run-governed-gate.ts +2 -1
- package/scripts/run-mobile-monitor-bridge.ts +0 -1
- package/scripts/smoke-control-plane-failure-domain.ts +94 -0
- package/scripts/smoke-ios-physical-device.ts +38 -10
- package/scripts/smoke-mcp-http-runtime.ts +12 -8
- package/scripts/smoke-mcp-tool-surface.ts +27 -41
- 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 +95 -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/sync-generated-authority.mjs +0 -1
- package/scripts/verify-forge-runtime.sh +2 -1
- package/src/cli/agent-jobs/executor-health.ts +12 -35
- package/src/cli/agent-jobs/integration.ts +20 -51
- package/src/cli/agent-jobs/job-manager.ts +7 -3
- package/src/cli/chatgpt-browser/file-policy.ts +2 -2
- 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/doctor.ts +1 -143
- package/src/cli/commands/global-runtime.ts +3 -196
- package/src/cli/commands/init-hook.ts +6 -23
- package/src/cli/commands/init.ts +3 -252
- package/src/cli/commands/mcp.ts +0 -5
- package/src/cli/commands/prompt-guard-decision.ts +0 -2
- package/src/cli/commands/recovery.ts +137 -135
- package/src/cli/commands/repository.ts +17 -1
- package/src/cli/commands/runtime.ts +3 -3
- package/src/cli/commands/setup-execution.ts +41 -0
- 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 +5 -44
- package/src/cli/controller/completion-target.ts +3 -72
- package/src/cli/controller/composite-operations.ts +1 -1
- package/src/cli/controller/context/instruction-context.ts +1 -1
- package/src/cli/controller/context/known-paths.ts +2 -2
- package/src/cli/controller/context/query-planning.ts +11 -4
- package/src/cli/controller/context/rule-resolution.ts +2 -2
- package/src/cli/controller/context/source-materializer.ts +83 -102
- package/src/cli/controller/context/structural-provider.ts +84 -0
- package/src/cli/controller/context/structural.ts +6 -6
- package/src/cli/controller/context/types.ts +8 -9
- package/src/cli/controller/context-pack.ts +107 -84
- 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 +25 -52
- 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 +42 -10
- package/src/cli/editing/edit-session.ts +18 -12
- package/src/cli/github/github.ts +4 -4
- package/src/cli/github/semantic-projection.ts +174 -0
- package/src/cli/hook/prompt-intents.ts +0 -9
- package/src/cli/index.ts +1 -43
- package/src/cli/local-bridge/connector-freshness.ts +1 -12
- package/src/cli/local-bridge/console-automations.ts +19 -14
- package/src/cli/local-bridge/console-view-models.ts +4 -13
- package/src/cli/local-bridge/facade-api.ts +64 -193
- 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-classifier.ts +0 -9
- package/src/cli/repositories/command-executor.ts +29 -23
- package/src/cli/repositories/command-scope.ts +37 -18
- 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/locks.ts +20 -0
- package/src/cli/repositories/registry.ts +79 -12
- package/src/cli/repositories/safe-patch.ts +2 -12
- package/src/cli/repositories/structured-git.ts +101 -5
- package/src/cli/repository/inspector.ts +185 -343
- package/src/cli/repository/session-cache.ts +92 -6
- package/src/effects/process-runner.ts +17 -1
- 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/generic-lsp-provider.ts +1 -1
- package/src/runtime/context/semantic-navigation-contract.ts +16 -0
- package/src/runtime/context/semantic-navigation.ts +7 -35
- 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 +215 -12
- 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 +616 -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 +197 -110
- package/src/runtime/control-plane/execution/work-handle-store.ts +72 -44
- 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 +60 -34
- package/src/runtime/control-plane/execution/work-preparation-service.ts +231 -267
- package/src/runtime/control-plane/execution/work-process-evidence.ts +2 -2
- 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 +201 -199
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +33 -85
- package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +6 -2
- package/src/runtime/control-plane/facade/capability-registry.ts +364 -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 +9 -9
- package/src/runtime/control-plane/generated-cache-retention.ts +206 -59
- 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 +256 -117
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -12
- 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/governance/external-effects.ts +1 -1
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +29 -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 +295 -107
- 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/evidence/sensitive-output.ts +22 -2
- package/src/runtime/execution/jobs/child-reference.ts +11 -0
- package/src/runtime/execution/jobs/receipt-recovery.ts +1 -11
- 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 +82 -30
- 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 +55 -18
- package/src/runtime/execution/process-runtime/store.ts +30 -2
- package/src/runtime/execution/process-runtime/types.ts +6 -1
- package/src/runtime/execution/thin-harness/execution-router.ts +16 -16
- package/src/runtime/execution/thin-harness/fast-executor.ts +2 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +2 -2
- package/src/runtime/execution/workers/executor.ts +3 -8
- package/src/runtime/maintenance/cleanup.ts +41 -5
- 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 +97 -29
- package/src/runtime/plugins/app-store-connect-adapter.ts +290 -18
- package/src/runtime/plugins/browser-adapter.ts +1124 -333
- package/src/runtime/plugins/browser-automation-service.ts +23 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +431 -137
- package/src/runtime/plugins/browser-manifest-surface.ts +47 -12
- package/src/runtime/plugins/browser-native-session-service.ts +63 -13
- package/src/runtime/plugins/browser-registration.ts +18 -0
- package/src/runtime/plugins/browser-runtime.ts +40 -36
- 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 +228 -0
- package/src/runtime/plugins/computer-registration.ts +298 -20
- 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/github-adapter.ts +30 -3
- package/src/runtime/plugins/gmail-adapter.ts +189 -3
- package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
- package/src/runtime/plugins/google-shared.ts +24 -12
- package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +70 -30
- package/src/runtime/plugins/ios-adapter.ts +46 -41
- package/src/runtime/plugins/ios-agent-device.ts +54 -4
- package/src/runtime/plugins/ios-device-ownership.ts +103 -0
- package/src/runtime/plugins/ios-physical-device.ts +497 -79
- package/src/runtime/plugins/lightweight-action.ts +208 -2
- package/src/runtime/plugins/local-system-adapter.ts +12 -100
- 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 +682 -435
- package/src/runtime/plugins/types.ts +24 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
- package/src/runtime/projections/git-status-sampler.ts +2 -19
- package/src/runtime/projections/invalidation.ts +7 -3
- package/src/runtime/projections/materialized-view.ts +80 -36
- package/src/runtime/recovery/actions.ts +4 -4
- package/src/runtime/recovery/capability-action-application.ts +46 -45
- package/src/runtime/recovery/lifecycle-inventory.ts +30 -40
- package/src/runtime/recovery/maintenance-executor.ts +374 -123
- package/src/runtime/recovery/probe.ts +2 -2
- package/src/runtime/recovery/store.ts +29 -11
- package/src/runtime/release/release-coordinator.ts +312 -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 +254 -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 +227 -29
- package/src/runtime/root/package-runtime-release.ts +117 -30
- package/src/runtime/root/package-runtime-service.ts +24 -24
- package/src/runtime/root/release-execution-canary.ts +57 -12
- package/src/runtime/root/release-loader.ts +90 -8
- package/src/runtime/root/release-manifest.ts +80 -40
- package/src/runtime/root/release-materialize.ts +372 -106
- package/src/runtime/root/release-store.ts +395 -36
- package/src/runtime/root/runtime-lane.ts +191 -0
- package/src/runtime/root/runtime.ts +160 -29
- package/src/runtime/root/scheduled-controller-composition.ts +29 -3
- package/src/runtime/root/service-runner.ts +2 -2
- package/src/runtime/root/service.ts +126 -44
- package/src/runtime/root/status.ts +48 -0
- package/src/runtime/root/types.ts +32 -9
- package/src/runtime/root/workflow-supervisor-composition.ts +681 -0
- package/src/runtime/root/workflow-supervisor-runtime.ts +564 -0
- package/src/runtime/root/write-fence.ts +50 -2
- package/src/runtime/safe-tooling/google-credential-store.ts +67 -22
- package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
- package/src/runtime/safe-tooling/ios-development.ts +22 -8
- package/src/runtime/safe-tooling/job-summary.ts +1 -1
- package/src/runtime/safe-tooling/workspace-auth.ts +5 -2
- package/src/runtime/shared/atomic-text-file.ts +21 -0
- package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
- package/src/runtime/shared/json-files.ts +8 -3
- 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 +3792 -417
- package/src/runtime/standalone-recovery/entry.ts +507 -45
- 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 +12 -2
- 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 +11 -3
- package/src/runtime/workflow/schedules/engine.ts +166 -178
- package/src/runtime/workflow/schedules/pending-activation.ts +11 -4
- package/src/runtime/workflow/schedules/work-continuation.ts +95 -11
- 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 +218 -0
- package/supervisor/control-plane.ts +963 -0
- package/supervisor/entry.ts +15 -0
- package/supervisor/forge-validators.ts +147 -0
- package/supervisor/index.ts +5 -0
- package/supervisor/native-browser-adapter.ts +1151 -0
- package/supervisor/native-messaging/host.ts +58 -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 +250 -0
- package/supervisor/server.ts +412 -0
- package/supervisor/store.ts +1870 -0
- package/supervisor/tsconfig.json +8 -0
- package/supervisor/types.ts +261 -0
- package/SKILL.md +0 -427
- 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/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +0 -1
- package/adapters/mcp/toolset-selection.ts +0 -41
- package/agents/openai.yaml +0 -4
- package/assets/skill-hooks.json +0 -41
- package/assets/skill-version.json +0 -189
- package/assets/skills/claude-review/SKILL.md +0 -231
- package/assets/skills/codex-review/SKILL.md +0 -103
- package/assets/templates/helpers/check-skill-version.ts +0 -193
- 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-skill-version.ts +0 -5
- package/scripts/check-tarball-install-smoke.sh +0 -150
- package/scripts/ensure-codegraph.sh +0 -16
- package/scripts/package-source-archive.sh +0 -147
- package/scripts/public-release-files.txt +0 -39
- package/scripts/public-release.ts +0 -174
- package/scripts/publish-release-tarball.sh +0 -27
- package/scripts/route-nl-vs-ts-eval.ts +0 -679
- package/scripts/run-skill-hook.ts +0 -244
- package/scripts/stage-runtime-release.ts +0 -44
- package/scripts/sync-codex-installed-copies.sh +0 -182
- package/src/cli/commands/tools.ts +0 -167
- 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/cli/mcp/access-mode.ts +0 -2
- package/src/cli/mcp/access-tools.ts +0 -2
- package/src/cli/mcp/audit.ts +0 -2
- package/src/cli/mcp/auth.ts +0 -2
- package/src/cli/mcp/instructions.ts +0 -2
- package/src/cli/mcp/legacy-context.ts +0 -2
- package/src/cli/mcp/legacy-tool-service.ts +0 -2
- package/src/cli/mcp/multi-repository.ts +0 -2
- package/src/cli/mcp/oauth.ts +0 -2
- package/src/cli/mcp/openai-secure-tunnel.ts +0 -2
- package/src/cli/mcp/paths.ts +0 -2
- package/src/cli/mcp/policy.ts +0 -2
- package/src/cli/mcp/post-finalize-work-attribution.ts +0 -2
- package/src/cli/mcp/proxy-env.ts +0 -2
- package/src/cli/mcp/readiness-projection.ts +0 -2
- package/src/cli/mcp/redaction.ts +0 -2
- package/src/cli/mcp/repo.ts +0 -2
- package/src/cli/mcp/repository-tools.ts +0 -2
- package/src/cli/mcp/server.ts +0 -2
- package/src/cli/mcp/setup.ts +0 -2
- package/src/cli/mcp/tool-capability-cache.ts +0 -2
- package/src/cli/mcp/tool-contract.ts +0 -2
- package/src/cli/mcp/tools.ts +0 -2
- package/src/cli/mcp/toolset-names.ts +0 -2
- package/src/cli/mcp/toolset-selection.ts +0 -2
- package/src/cli/mcp/toolset.ts +0 -2
- package/src/cli/mcp/transports/http.ts +0 -2
- package/src/cli/mcp/transports/session-registry.ts +0 -2
- package/src/cli/mcp/transports/stdio.ts +0 -2
- package/src/cli/mcp/types.ts +0 -2
- package/src/cli/mcp/umbrella-tools.ts +0 -2
- package/src/cli/tools/codegraph.ts +0 -695
- package/src/core/adoption/helper-wrapper-plan.ts +0 -159
- package/src/runtime/context/codegraph-cache-boundary.ts +0 -255
- package/src/runtime/context/codegraph-read-provider.ts +0 -611
- package/src/runtime/context/codegraph-sidecar.cjs +0 -248
- package/src/runtime/control-plane/codegraph-cache-retention.ts +0 -164
- 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
- package/src/runtime/gateway/mcp/execution-tools.ts +0 -2
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +0 -2
- package/src/runtime/gateway/mcp/persisted-check-process.ts +0 -2
- package/src/runtime/gateway/mcp/process-tools.ts +0 -2
- package/src/runtime/gateway/mcp/router.ts +0 -2
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +0 -2
- package/src/runtime/gateway/mcp/runtime-tools.ts +0 -2
- package/src/runtime/gateway/mcp/work-validation-reconciler.ts +0 -2
- package/src/runtime/plugins/browser-provider-registry.ts +0 -2
|
@@ -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;
|
|
@@ -235,6 +170,11 @@ function createVerifiedBundle(controllerHome: string, handle: WorkHandleState, t
|
|
|
235
170
|
}
|
|
236
171
|
const verified = git(targetRoot, ['bundle', 'verify', path], 60_000);
|
|
237
172
|
if (!verified.ok) throw new Error(verified.stderr || 'git bundle verify failed');
|
|
173
|
+
const branchHead = git(targetRoot, ['rev-parse', '--verify', `refs/heads/${handle.branch}^{commit}`]);
|
|
174
|
+
const bundleHead = git(targetRoot, ['bundle', 'list-heads', path, `refs/heads/${handle.branch}`]);
|
|
175
|
+
if (!branchHead.ok || !bundleHead.ok || bundleHead.stdout !== `${branchHead.stdout} refs/heads/${handle.branch}`) {
|
|
176
|
+
throw new Error('BRANCH_BUNDLE_HEAD_MISMATCH: verified bundle does not preserve the current branch tip');
|
|
177
|
+
}
|
|
238
178
|
return { path, sha256: hashText(readFileSync(path)) };
|
|
239
179
|
}
|
|
240
180
|
|
|
@@ -305,7 +245,7 @@ function workHandleOwnsCheckout(controllerHome: string, handle: WorkHandleState)
|
|
|
305
245
|
// WorkContract completion is the authoritative ownership boundary. Older
|
|
306
246
|
// runtimes could persist a completed contract while leaving the handle in a
|
|
307
247
|
// non-terminal state; that historical handle must not remain a live owner.
|
|
308
|
-
return contract === undefined ||
|
|
248
|
+
return contract === undefined || semanticWorkState(contract) === 'open';
|
|
309
249
|
}
|
|
310
250
|
|
|
311
251
|
function assertNoOtherLiveWork(input: TerminalWorkCleanupInput, receipt: WorkCleanupReceipt): void {
|
|
@@ -330,59 +270,22 @@ function preserveDirtyWorktree(
|
|
|
330
270
|
return persist(input.controllerHome, current, receipt);
|
|
331
271
|
}
|
|
332
272
|
if (!status.stdout) {
|
|
333
|
-
receipt.preservation.status =
|
|
334
|
-
? receipt.preservation.status
|
|
335
|
-
: 'not_needed';
|
|
273
|
+
receipt.preservation.status = 'not_needed';
|
|
336
274
|
return persist(input.controllerHome, current, receipt);
|
|
337
275
|
}
|
|
338
276
|
|
|
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
|
-
}
|
|
277
|
+
// Semantic Work terminal state is not authority to mutate, commit, archive,
|
|
278
|
+
// or delete uncommitted workspace content. Dirty bytes stay exactly where the
|
|
279
|
+
// model/user left them until an explicit delivery/discard action resolves them.
|
|
280
|
+
receipt.preservation.status = 'not_needed';
|
|
281
|
+
receipt.preservation.recoveryInstructions = `Dirty managed worktree retained in place at ${current.worktreePath}; commit, deliver, or explicitly discard the pending changes before cleanup.`;
|
|
282
|
+
receipt.worktree.status = 'retained';
|
|
283
|
+
receipt.worktree.reason = 'Dirty managed worktree retained; terminal semantic state does not authorize destructive cleanup.';
|
|
284
|
+
receipt.branchCleanup.status = 'retained';
|
|
285
|
+
receipt.branchCleanup.reason = 'Branch retained with dirty managed worktree.';
|
|
286
|
+
addBlocker(receipt, 'DIRTY_WORKTREE_RETAINED');
|
|
287
|
+
markOwnedResourceRetained(input.controllerHome, managedWorkspaceOwnedResourceId(current.repositoryId, current.checkoutId));
|
|
288
|
+
markOwnedResourceRetained(input.controllerHome, managedBranchOwnedResourceId(current.repositoryId, current.checkoutId));
|
|
386
289
|
return persist(input.controllerHome, current, receipt);
|
|
387
290
|
}
|
|
388
291
|
|
|
@@ -460,9 +363,15 @@ export interface TerminalWorkCleanupReconcileReport {
|
|
|
460
363
|
truncated: boolean;
|
|
461
364
|
}
|
|
462
365
|
|
|
366
|
+
function contractCompletedNoChange(contract: WorkContract): boolean {
|
|
367
|
+
if (contract.workKind === 'completed_no_change' || contract.completionOutcome === 'completed_no_change') return true;
|
|
368
|
+
const receipt = contract.completionReceipt;
|
|
369
|
+
return Boolean(receipt && isRepositoryCompletionReceipt(receipt) && receipt.delivery.kind === 'no_change');
|
|
370
|
+
}
|
|
371
|
+
|
|
463
372
|
function terminalOutcomeForContract(contract: WorkContract): WorkTerminalOutcome {
|
|
464
|
-
if (contract
|
|
465
|
-
if (contract
|
|
373
|
+
if (semanticWorkState(contract) === 'cancelled') return 'cancelled';
|
|
374
|
+
if (semanticWorkState(contract) === 'completed') return 'completed_cleanup';
|
|
466
375
|
return 'failed';
|
|
467
376
|
}
|
|
468
377
|
|
|
@@ -474,7 +383,7 @@ export function recoverTerminalWorkHandle(
|
|
|
474
383
|
const existing = readWorkHandle(controllerHome, repositoryId, workId);
|
|
475
384
|
if (existing) return existing;
|
|
476
385
|
const contract = getWorkContract({ controllerHome, repoId: repositoryId }, workId);
|
|
477
|
-
if (!contract ||
|
|
386
|
+
if (!contract || semanticWorkState(contract) === 'open') return undefined;
|
|
478
387
|
const worktreePath = contract.worktreeRef?.trim();
|
|
479
388
|
const checkoutId = contract.checkoutId?.trim();
|
|
480
389
|
if (!worktreePath || !checkoutId || !existsSync(worktreePath)) return undefined;
|
|
@@ -500,15 +409,15 @@ export function recoverTerminalWorkHandle(
|
|
|
500
409
|
const contained = targetExists
|
|
501
410
|
? git(repository.canonicalRoot, ['merge-base', '--is-ancestor', head.stdout, `refs/heads/${targetBranch}`]).ok
|
|
502
411
|
: false;
|
|
503
|
-
const
|
|
504
|
-
const
|
|
412
|
+
const completedNoChange = contractCompletedNoChange(contract);
|
|
413
|
+
const delivered = semanticWorkState(contract) === 'completed' && contained && !completedNoChange;
|
|
505
414
|
const recordedAt = nowIso();
|
|
506
415
|
return writeWorkHandle(controllerHome, {
|
|
507
416
|
schemaVersion: 1,
|
|
508
417
|
workId,
|
|
509
418
|
workContractId: workId,
|
|
510
|
-
sessionId:
|
|
511
|
-
principalId: contract.principalId?.trim() ||
|
|
419
|
+
sessionId: `terminal-recovery:${workId}`,
|
|
420
|
+
principalId: contract.principalId?.trim() || 'terminal-recovery',
|
|
512
421
|
repositoryId,
|
|
513
422
|
checkoutId,
|
|
514
423
|
sourceCheckoutId: repository.activeCheckoutId,
|
|
@@ -520,17 +429,18 @@ export function recoverTerminalWorkHandle(
|
|
|
520
429
|
expectedHead: head.stdout,
|
|
521
430
|
permissionSnapshotVersion: 1,
|
|
522
431
|
state: delivered ? 'merged' : 'failed_terminal_cleanup',
|
|
523
|
-
failureReason: delivered
|
|
432
|
+
failureReason: delivered || completedNoChange
|
|
433
|
+
? undefined
|
|
434
|
+
: 'Recovered terminal Work ownership for cleanup; target-branch containment was not proven.',
|
|
524
435
|
createdAt: contract.createdAt || recordedAt,
|
|
525
436
|
updatedAt: recordedAt,
|
|
526
437
|
cleanupResponsibility: { owner: 'work_finalizer', registeredAt: recordedAt },
|
|
527
438
|
finalization: {
|
|
528
|
-
validation:
|
|
439
|
+
validation: 'done',
|
|
529
440
|
commit: 'skipped',
|
|
530
441
|
merge: delivered ? 'done' : 'skipped',
|
|
531
442
|
branchCleanup: 'pending',
|
|
532
443
|
worktreeCleanup: 'pending',
|
|
533
|
-
...(contract.status === 'failed' ? { lastError: 'Recovered failed terminal Work for cleanup.' } : {}),
|
|
534
444
|
},
|
|
535
445
|
});
|
|
536
446
|
}
|
|
@@ -584,9 +494,13 @@ function prepareManagedBranchPreservation(
|
|
|
584
494
|
current: WorkHandleState,
|
|
585
495
|
target: ReturnType<typeof getRepository>,
|
|
586
496
|
targetBranch: string,
|
|
587
|
-
): { uniqueCommits: number; branchPreserved: boolean } {
|
|
497
|
+
): { uniqueCommits: number; branchPreserved: boolean; branchHead?: string } {
|
|
588
498
|
let uniqueCommits = 0;
|
|
499
|
+
let branchHead: string | undefined;
|
|
589
500
|
if (branchExists(target.canonicalRoot, current.branch)) {
|
|
501
|
+
const observed = git(target.canonicalRoot, ['rev-parse', '--verify', `refs/heads/${current.branch}^{commit}`]);
|
|
502
|
+
if (!observed.ok || !observed.stdout) addBlocker(receipt, 'BRANCH_REVISION_UNKNOWN');
|
|
503
|
+
else branchHead = observed.stdout;
|
|
590
504
|
if (!branchExists(target.canonicalRoot, targetBranch)) {
|
|
591
505
|
addBlocker(receipt, `TARGET_BRANCH_MISSING: ${targetBranch}`);
|
|
592
506
|
} else {
|
|
@@ -597,11 +511,12 @@ function prepareManagedBranchPreservation(
|
|
|
597
511
|
}
|
|
598
512
|
receipt.branchCleanup.uniqueCommits = uniqueCommits;
|
|
599
513
|
|
|
514
|
+
const retirement = receipt.preservation.bundleRetirement;
|
|
600
515
|
let branchPreserved = Boolean(
|
|
601
|
-
|
|
602
|
-
||
|
|
516
|
+
branchHead && retirement?.protectedRevision === branchHead
|
|
517
|
+
&& (retirement.status === 'not_needed' || retirement.status === 'removed'),
|
|
603
518
|
);
|
|
604
|
-
if (receipt.preservation.bundlePath && !branchPreserved) {
|
|
519
|
+
if (branchHead && receipt.preservation.bundlePath && !branchPreserved) {
|
|
605
520
|
try {
|
|
606
521
|
const bundle = createVerifiedBundle(input.controllerHome, current, target.canonicalRoot);
|
|
607
522
|
if (receipt.preservation.bundleSha256 && receipt.preservation.bundleSha256 !== bundle.sha256) {
|
|
@@ -614,7 +529,7 @@ function prepareManagedBranchPreservation(
|
|
|
614
529
|
}
|
|
615
530
|
}
|
|
616
531
|
if (uniqueCommits > 0 && !branchPreserved && receipt.blockers.length === 0) {
|
|
617
|
-
const proof = proveWorkPreservationContained(target.canonicalRoot,
|
|
532
|
+
const proof = proveWorkPreservationContained(target.canonicalRoot, current, targetBranch, branchHead);
|
|
618
533
|
if (proof.contained) {
|
|
619
534
|
receipt.preservation.bundleRetirement = {
|
|
620
535
|
status: 'not_needed',
|
|
@@ -642,10 +557,11 @@ function prepareManagedBranchPreservation(
|
|
|
642
557
|
}
|
|
643
558
|
}
|
|
644
559
|
}
|
|
645
|
-
return { uniqueCommits, branchPreserved };
|
|
560
|
+
return { uniqueCommits, branchPreserved, branchHead };
|
|
646
561
|
}
|
|
647
562
|
|
|
648
563
|
function applyManagedBranchCleanup(
|
|
564
|
+
controllerHome: string,
|
|
649
565
|
target: ReturnType<typeof getRepository>,
|
|
650
566
|
current: WorkHandleState,
|
|
651
567
|
targetBranch: string,
|
|
@@ -653,6 +569,7 @@ function applyManagedBranchCleanup(
|
|
|
653
569
|
receipt: WorkCleanupReceipt,
|
|
654
570
|
uniqueCommits: number,
|
|
655
571
|
branchPreserved: boolean,
|
|
572
|
+
expectedBranchHead: string | undefined,
|
|
656
573
|
): void {
|
|
657
574
|
if (!deleteBranch) {
|
|
658
575
|
receipt.branchCleanup.status = 'retained';
|
|
@@ -672,13 +589,30 @@ function applyManagedBranchCleanup(
|
|
|
672
589
|
receipt.branchCleanup.status = 'retained';
|
|
673
590
|
receipt.branchCleanup.reason = 'Unique commits are not archived.';
|
|
674
591
|
addBlocker(receipt, `BRANCH_UNPRESERVED: ${current.branch}`);
|
|
592
|
+
} else if (!expectedBranchHead) {
|
|
593
|
+
receipt.branchCleanup.status = 'retained';
|
|
594
|
+
receipt.branchCleanup.reason = 'Exact branch revision is unavailable.';
|
|
595
|
+
addBlocker(receipt, 'BRANCH_REVISION_UNKNOWN');
|
|
675
596
|
} else {
|
|
676
|
-
//
|
|
677
|
-
//
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
597
|
+
// Branch deletion requires the canonical OwnedResource witness in addition
|
|
598
|
+
// to Git relation checks. Repository/ref shape alone is not cleanup authority.
|
|
599
|
+
try {
|
|
600
|
+
assertOwnedResourceCleanupTarget(controllerHome, {
|
|
601
|
+
resourceId: managedBranchOwnedResourceId(current.repositoryId, current.checkoutId),
|
|
602
|
+
kind: 'git_branch',
|
|
603
|
+
targetRef: current.branch,
|
|
604
|
+
locator: managedBranchOwnedResourceLocator(target.canonicalRoot, current.checkoutId, current.branch),
|
|
605
|
+
});
|
|
606
|
+
} catch (error) {
|
|
607
|
+
receipt.branchCleanup.status = 'retained';
|
|
608
|
+
receipt.branchCleanup.reason = error instanceof Error ? error.message : String(error);
|
|
609
|
+
addBlocker(receipt, `OWNED_BRANCH_CLEANUP_FENCED: ${receipt.branchCleanup.reason}`);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
// Delete only the exact tip whose containment or bundle was proved above.
|
|
613
|
+
// A concurrent successor must retain its ref rather than inherit an older
|
|
614
|
+
// WorkHandle or preservation receipt's deletion authority.
|
|
615
|
+
const deleted = git(target.canonicalRoot, ['update-ref', '-d', `refs/heads/${current.branch}`, expectedBranchHead]);
|
|
682
616
|
if (!deleted.ok && branchExists(target.canonicalRoot, current.branch)) {
|
|
683
617
|
receipt.branchCleanup.status = 'failed';
|
|
684
618
|
receipt.branchCleanup.reason = deleted.stderr || 'branch delete failed';
|
|
@@ -699,6 +633,24 @@ function cleanupReceiptComplete(receipt: WorkCleanupReceipt, deleteBranch: boole
|
|
|
699
633
|
: receipt.branchCleanup.status === 'retained');
|
|
700
634
|
}
|
|
701
635
|
|
|
636
|
+
function projectOwnedResourceCleanup(
|
|
637
|
+
controllerHome: string,
|
|
638
|
+
handle: WorkHandleState,
|
|
639
|
+
receipt: WorkCleanupReceipt,
|
|
640
|
+
): void {
|
|
641
|
+
const worktreeResourceId = managedWorkspaceOwnedResourceId(handle.repositoryId, handle.checkoutId);
|
|
642
|
+
if (['removed', 'already_removed'].includes(receipt.worktree.status)) {
|
|
643
|
+
markOwnedResourceCleaned(controllerHome, worktreeResourceId, 'forge:work-terminal-cleanup', receipt.receiptId);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const branchResourceId = managedBranchOwnedResourceId(handle.repositoryId, handle.checkoutId);
|
|
647
|
+
if (['deleted', 'already_deleted', 'archived'].includes(receipt.branchCleanup.status)) {
|
|
648
|
+
markOwnedResourceCleaned(controllerHome, branchResourceId, 'forge:work-terminal-cleanup', receipt.receiptId);
|
|
649
|
+
} else if (receipt.branchCleanup.status === 'retained') {
|
|
650
|
+
markOwnedResourceRetained(controllerHome, branchResourceId);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
702
654
|
function reconcileCleanedManagedBranchRetirement(
|
|
703
655
|
input: TerminalWorkCleanupInput,
|
|
704
656
|
repository: ReturnType<typeof getRepository>,
|
|
@@ -709,7 +661,7 @@ function reconcileCleanedManagedBranchRetirement(
|
|
|
709
661
|
): TerminalWorkCleanupResult | undefined {
|
|
710
662
|
const workId = current.workContractId ?? current.workId;
|
|
711
663
|
const contract = getWorkContract({ controllerHome: input.controllerHome, repoId: current.repositoryId }, workId);
|
|
712
|
-
if (!contract ||
|
|
664
|
+
if (!contract || semanticWorkState(contract) === 'open'
|
|
713
665
|
|| !cleanedManagedBranchRetirementCandidate(repository, contract, current, targetBranch, deleteBranch)) return undefined;
|
|
714
666
|
|
|
715
667
|
const target = selectTerminalCleanupTarget(repository, current);
|
|
@@ -724,6 +676,7 @@ function reconcileCleanedManagedBranchRetirement(
|
|
|
724
676
|
current = persist(input.controllerHome, current, receipt);
|
|
725
677
|
if (receipt.blockers.length === 0) {
|
|
726
678
|
applyManagedBranchCleanup(
|
|
679
|
+
input.controllerHome,
|
|
727
680
|
target,
|
|
728
681
|
current,
|
|
729
682
|
targetBranch,
|
|
@@ -731,6 +684,7 @@ function reconcileCleanedManagedBranchRetirement(
|
|
|
731
684
|
receipt,
|
|
732
685
|
preservation.uniqueCommits,
|
|
733
686
|
preservation.branchPreserved,
|
|
687
|
+
preservation.branchHead,
|
|
734
688
|
);
|
|
735
689
|
} else if (receipt.branchCleanup.status === 'pending') {
|
|
736
690
|
receipt.branchCleanup.status = 'retained';
|
|
@@ -818,8 +772,19 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
818
772
|
const targetBranch = resolveWorkDeliveryTargetBranch(input.handle, repository.defaultBranch, input.targetBranch);
|
|
819
773
|
const deleteBranch = input.deleteBranch !== false;
|
|
820
774
|
let current = input.handle;
|
|
821
|
-
const
|
|
822
|
-
|
|
775
|
+
const contract = getWorkContract(
|
|
776
|
+
{ controllerHome: input.controllerHome, repoId: current.repositoryId },
|
|
777
|
+
current.workContractId ?? current.workId,
|
|
778
|
+
);
|
|
779
|
+
const completedNoChange = Boolean(contract && contractCompletedNoChange(contract));
|
|
780
|
+
// `merged` is delivery truth, not a generic terminal-cleanup waypoint. Historical
|
|
781
|
+
// no-change handles may carry merge=done/state=merged from the retired finalizer;
|
|
782
|
+
// normalize that stale projection before any destructive cleanup attempt.
|
|
783
|
+
const landed = !completedNoChange && (current.state === 'merged' || current.finalization.merge === 'done');
|
|
784
|
+
const successfulCompletion = completedNoChange || input.terminalOutcome === 'completed_cleanup';
|
|
785
|
+
const preservedFailure = successfulCompletion
|
|
786
|
+
? undefined
|
|
787
|
+
: (input.failureReason ?? current.failureReason ?? current.finalization.lastError ?? 'terminal work cleanup').slice(0, 1_000);
|
|
823
788
|
const receipt = current.cleanupReceipt ?? newReceipt(current, targetBranch, input.terminalOutcome);
|
|
824
789
|
|
|
825
790
|
if (
|
|
@@ -827,6 +792,12 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
827
792
|
|| receipt.checkoutId !== current.checkoutId
|
|
828
793
|
|| receipt.workId !== current.workId
|
|
829
794
|
) throw new Error('WORK_CLEANUP_RECEIPT_IDENTITY_MISMATCH');
|
|
795
|
+
// Legacy receipts may retain the former Controller lease stage. ControllerSession
|
|
796
|
+
// is no longer a cleanup resource; normalize this projection without touching
|
|
797
|
+
// any explicit continuation state.
|
|
798
|
+
if (receipt.ownership.controllerLease === 'pending') {
|
|
799
|
+
receipt.ownership.controllerLease = 'already_released';
|
|
800
|
+
}
|
|
830
801
|
|
|
831
802
|
if (current.state === 'cleaned') {
|
|
832
803
|
const branchRetirement = reconcileCleanedManagedBranchRetirement(
|
|
@@ -844,7 +815,6 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
844
815
|
receipt.completedAt = receipt.completedAt ?? current.updatedAt ?? nowIso();
|
|
845
816
|
receipt.blockers = [];
|
|
846
817
|
receipt.processes.allTerminal = true;
|
|
847
|
-
if (receipt.ownership.controllerLease === 'pending') receipt.ownership.controllerLease = 'already_released';
|
|
848
818
|
if (receipt.ownership.processLeases === 'pending') receipt.ownership.processLeases = 'released';
|
|
849
819
|
if (receipt.worktree.status === 'pending' || receipt.worktree.status === 'failed') {
|
|
850
820
|
receipt.worktree.status = 'already_removed';
|
|
@@ -890,7 +860,11 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
890
860
|
? 'failed' as const
|
|
891
861
|
: current.finalization.validation,
|
|
892
862
|
commit: current.finalization.commit === 'pending' ? 'skipped' as const : current.finalization.commit,
|
|
893
|
-
merge:
|
|
863
|
+
merge: completedNoChange
|
|
864
|
+
? 'skipped' as const
|
|
865
|
+
: landed
|
|
866
|
+
? 'done' as const
|
|
867
|
+
: current.finalization.merge === 'pending' ? 'skipped' as const : current.finalization.merge,
|
|
894
868
|
lastError: preservedFailure,
|
|
895
869
|
};
|
|
896
870
|
if (landed) {
|
|
@@ -987,7 +961,19 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
987
961
|
current = persist(input.controllerHome, current, receipt);
|
|
988
962
|
return { handle: current, receipt };
|
|
989
963
|
}
|
|
990
|
-
|
|
964
|
+
const rootIdentityValid = root.ok && resolve(root.stdout) === resolve(current.worktreePath);
|
|
965
|
+
const branchIdentityValid = branch.ok && branch.stdout === current.branch;
|
|
966
|
+
let detachedContainedIdentity = false;
|
|
967
|
+
if (rootIdentityValid && branch.ok && !branch.stdout) {
|
|
968
|
+
const status = git(current.worktreePath, ['status', '--porcelain=v1', '--untracked-files=all']);
|
|
969
|
+
const head = git(current.worktreePath, ['rev-parse', 'HEAD']);
|
|
970
|
+
detachedContainedIdentity = status.ok
|
|
971
|
+
&& !status.stdout
|
|
972
|
+
&& head.ok
|
|
973
|
+
&& Boolean(head.stdout)
|
|
974
|
+
&& git(target.canonicalRoot, ['merge-base', '--is-ancestor', head.stdout, `refs/heads/${targetBranch}`]).ok;
|
|
975
|
+
}
|
|
976
|
+
if (!rootIdentityValid || (!branchIdentityValid && !detachedContainedIdentity)) {
|
|
991
977
|
addBlocker(receipt, 'WORKTREE_IDENTITY_INVALID');
|
|
992
978
|
current = persist(input.controllerHome, current, receipt);
|
|
993
979
|
return { handle: current, receipt };
|
|
@@ -1003,7 +989,7 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
1003
989
|
receipt.worktree.status = 'already_removed';
|
|
1004
990
|
}
|
|
1005
991
|
|
|
1006
|
-
const { uniqueCommits, branchPreserved } = prepareManagedBranchPreservation(
|
|
992
|
+
const { uniqueCommits, branchPreserved, branchHead } = prepareManagedBranchPreservation(
|
|
1007
993
|
input,
|
|
1008
994
|
receipt,
|
|
1009
995
|
current,
|
|
@@ -1020,6 +1006,19 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
1020
1006
|
}
|
|
1021
1007
|
|
|
1022
1008
|
if (existsSync(current.worktreePath)) {
|
|
1009
|
+
try {
|
|
1010
|
+
assertOwnedResourceCleanupTarget(input.controllerHome, {
|
|
1011
|
+
resourceId: managedWorkspaceOwnedResourceId(current.repositoryId, current.checkoutId),
|
|
1012
|
+
kind: 'worktree',
|
|
1013
|
+
targetRef: current.worktreePath,
|
|
1014
|
+
});
|
|
1015
|
+
} catch (error) {
|
|
1016
|
+
receipt.worktree.status = 'retained';
|
|
1017
|
+
receipt.worktree.reason = error instanceof Error ? error.message : String(error);
|
|
1018
|
+
addBlocker(receipt, `OWNED_WORKTREE_CLEANUP_FENCED: ${receipt.worktree.reason}`);
|
|
1019
|
+
current = persist(input.controllerHome, current, receipt);
|
|
1020
|
+
return { handle: current, receipt };
|
|
1021
|
+
}
|
|
1023
1022
|
const removed = git(target.canonicalRoot, ['worktree', 'remove', '--force', current.worktreePath], 60_000);
|
|
1024
1023
|
if (!removed.ok && existsSync(current.worktreePath)) {
|
|
1025
1024
|
receipt.worktree.status = 'failed';
|
|
@@ -1056,6 +1055,7 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
1056
1055
|
}
|
|
1057
1056
|
|
|
1058
1057
|
applyManagedBranchCleanup(
|
|
1058
|
+
input.controllerHome,
|
|
1059
1059
|
target,
|
|
1060
1060
|
current,
|
|
1061
1061
|
targetBranch,
|
|
@@ -1063,6 +1063,7 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
1063
1063
|
receipt,
|
|
1064
1064
|
uniqueCommits,
|
|
1065
1065
|
branchPreserved,
|
|
1066
|
+
branchHead,
|
|
1066
1067
|
);
|
|
1067
1068
|
|
|
1068
1069
|
const pruned = git(target.canonicalRoot, ['worktree', 'prune']);
|
|
@@ -1075,6 +1076,7 @@ export async function cleanupTerminalWork(input: TerminalWorkCleanupInput): Prom
|
|
|
1075
1076
|
receipt.complete = cleanupReceiptComplete(receipt, deleteBranch);
|
|
1076
1077
|
receipt.partial = !receipt.complete;
|
|
1077
1078
|
if (receipt.complete) receipt.completedAt = receipt.completedAt ?? nowIso();
|
|
1079
|
+
projectOwnedResourceCleanup(input.controllerHome, current, receipt);
|
|
1078
1080
|
|
|
1079
1081
|
const finalization = {
|
|
1080
1082
|
...current.finalization,
|
|
@@ -1120,6 +1122,30 @@ export interface SingleTerminalWorkCleanupResult {
|
|
|
1120
1122
|
* Controller ownership or unsafe branch drift. A caller proving the exact
|
|
1121
1123
|
* leftover owner epoch may release it before physical cleanup.
|
|
1122
1124
|
*/
|
|
1125
|
+
function reconcileCancelledCleanupProjection(
|
|
1126
|
+
controllerHome: string,
|
|
1127
|
+
repoId: string,
|
|
1128
|
+
contract: WorkContract,
|
|
1129
|
+
receipt: WorkCleanupReceipt,
|
|
1130
|
+
): void {
|
|
1131
|
+
if (contract.semanticState !== 'cancelled' || receipt.complete !== true) return;
|
|
1132
|
+
if (contract.phase === 'cleanup' && contract.phaseEvidence.cleanup.state === 'satisfied'
|
|
1133
|
+
&& contract.phaseEvidence.cleanup.receiptId === receipt.receiptId) return;
|
|
1134
|
+
recordCancelledWorkCleanupCompleted(
|
|
1135
|
+
{ controllerHome, repoId },
|
|
1136
|
+
contract.workId,
|
|
1137
|
+
{
|
|
1138
|
+
summary: `Verified terminal resource cleanup completed with receipt ${receipt.receiptId}.`,
|
|
1139
|
+
receiptId: receipt.receiptId,
|
|
1140
|
+
evidenceRefs: [{
|
|
1141
|
+
title: 'cancelled Work terminal cleanup completed',
|
|
1142
|
+
summary: `Physical worktree/branch cleanup completed under receipt ${receipt.receiptId}; unexecuted semantic phases remain skipped rather than satisfied.`,
|
|
1143
|
+
detailLevel: 'summary',
|
|
1144
|
+
}, ...contract.evidenceRefs],
|
|
1145
|
+
},
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1123
1149
|
export async function reconcileSingleTerminalWorkCleanup(
|
|
1124
1150
|
controllerHome: string,
|
|
1125
1151
|
repositoryId: string,
|
|
@@ -1127,38 +1153,13 @@ export async function reconcileSingleTerminalWorkCleanup(
|
|
|
1127
1153
|
options: {
|
|
1128
1154
|
targetBranch?: string;
|
|
1129
1155
|
deleteBranch?: boolean;
|
|
1130
|
-
/** Recovery authority for the narrow crash window after semantic terminalization but before owner release. */
|
|
1131
|
-
controllerAuthority?: ControllerTerminalizationAuthority;
|
|
1132
1156
|
} = {},
|
|
1133
1157
|
): Promise<SingleTerminalWorkCleanupResult> {
|
|
1134
1158
|
const repository = getRepository(repositoryId, controllerHome, { includeRemoved: true });
|
|
1135
1159
|
const contract = getWorkContract({ controllerHome, repoId: repositoryId }, workId);
|
|
1136
|
-
if (!contract ||
|
|
1160
|
+
if (!contract || semanticWorkState(contract) === 'open') {
|
|
1137
1161
|
return { status: 'not_terminal', workId, reason: 'Work is not terminal.' };
|
|
1138
1162
|
}
|
|
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
1163
|
const originalHandle = readWorkHandle(controllerHome, repositoryId, workId)
|
|
1163
1164
|
?? recoverTerminalWorkHandle(controllerHome, repositoryId, workId);
|
|
1164
1165
|
if (!originalHandle) return { status: 'no_handle', workId };
|
|
@@ -1176,8 +1177,10 @@ export async function reconcileSingleTerminalWorkCleanup(
|
|
|
1176
1177
|
terminalOutcome: terminalOutcomeForContract(contract),
|
|
1177
1178
|
failureReason: drift.handle.failureReason ?? drift.handle.finalization.lastError,
|
|
1178
1179
|
});
|
|
1179
|
-
cleaned.receipt.ownership.controllerLease = controllerLease;
|
|
1180
1180
|
const persisted = writeWorkHandle(controllerHome, { ...cleaned.handle, cleanupReceipt: cleaned.receipt });
|
|
1181
|
+
if (cleaned.receipt.complete) {
|
|
1182
|
+
reconcileCancelledCleanupProjection(controllerHome, repositoryId, contract, cleaned.receipt);
|
|
1183
|
+
}
|
|
1181
1184
|
if (!cleaned.receipt.complete) {
|
|
1182
1185
|
return {
|
|
1183
1186
|
status: 'blocked',
|
|
@@ -1211,7 +1214,14 @@ export async function reconcileTerminalWorkCleanups(
|
|
|
1211
1214
|
truncated: false,
|
|
1212
1215
|
};
|
|
1213
1216
|
|
|
1214
|
-
const
|
|
1217
|
+
const maintenanceEpoch = Math.floor(nowMs / 60_000);
|
|
1218
|
+
const repositories = listRepositories(controllerHome)
|
|
1219
|
+
.filter((repository) => repository.enabled && !repository.removedAt)
|
|
1220
|
+
.sort((left, right) => {
|
|
1221
|
+
const leftOrder = hashText(`${maintenanceEpoch}\0${left.repoId}`);
|
|
1222
|
+
const rightOrder = hashText(`${maintenanceEpoch}\0${right.repoId}`);
|
|
1223
|
+
return leftOrder.localeCompare(rightOrder) || left.repoId.localeCompare(right.repoId);
|
|
1224
|
+
});
|
|
1215
1225
|
outer: for (const repository of repositories) {
|
|
1216
1226
|
const handles = listWorkHandles(controllerHome, repository.repoId, 10_000)
|
|
1217
1227
|
.filter((handle) => handle.managedWorktree);
|
|
@@ -1223,7 +1233,7 @@ export async function reconcileTerminalWorkCleanups(
|
|
|
1223
1233
|
limit: 10_000,
|
|
1224
1234
|
})) {
|
|
1225
1235
|
const contract = record.value;
|
|
1226
|
-
if (knownWorkIds.has(contract.workId) ||
|
|
1236
|
+
if (knownWorkIds.has(contract.workId) || semanticWorkState(contract) === 'open') continue;
|
|
1227
1237
|
if (!contract.worktreeRef?.trim() || !existsSync(contract.worktreeRef)) continue;
|
|
1228
1238
|
let recovered: WorkHandleState | undefined;
|
|
1229
1239
|
try {
|
|
@@ -1247,15 +1257,22 @@ export async function reconcileTerminalWorkCleanups(
|
|
|
1247
1257
|
report.errors.push({ workId: originalHandle.workId, error: error instanceof Error ? error.message : String(error) });
|
|
1248
1258
|
continue;
|
|
1249
1259
|
}
|
|
1250
|
-
if (!contract ||
|
|
1260
|
+
if (!contract || semanticWorkState(contract) === 'open') {
|
|
1251
1261
|
report.skippedNonTerminal.push(originalHandle.workId);
|
|
1252
1262
|
continue;
|
|
1253
1263
|
}
|
|
1264
|
+
// Semantic terminality is the lifecycle authority that starts mechanical
|
|
1265
|
+
// cleanup reconciliation. It is not deletion authority: work_finalizer must
|
|
1266
|
+
// still prove exact Forge ownership, preserve dirty bytes/unique commits,
|
|
1267
|
+
// settle live processes, and honor explicit retention before removing any
|
|
1268
|
+
// physical resource. Completion/cleanup receipts are delivery/progress
|
|
1269
|
+
// evidence, not a second permission gate that can strand terminal Work.
|
|
1254
1270
|
if (cleanupRetainedByRequest(contract, originalHandle)) {
|
|
1255
1271
|
report.skippedRetained.push(originalHandle.workId);
|
|
1256
1272
|
continue;
|
|
1257
1273
|
}
|
|
1258
1274
|
if (originalHandle.state === 'cleaned' && originalHandle.cleanupReceipt?.complete === true) {
|
|
1275
|
+
reconcileCancelledCleanupProjection(controllerHome, repository.repoId, contract, originalHandle.cleanupReceipt);
|
|
1259
1276
|
const targetBranch = resolveWorkDeliveryTargetBranch(originalHandle, repository.defaultBranch);
|
|
1260
1277
|
if (!cleanedManagedBranchRetirementCandidate(
|
|
1261
1278
|
repository,
|
|
@@ -1296,26 +1313,11 @@ export async function reconcileTerminalWorkCleanups(
|
|
|
1296
1313
|
terminalOutcome: terminalOutcomeForContract(contract),
|
|
1297
1314
|
failureReason: drift.handle.failureReason ?? drift.handle.finalization.lastError,
|
|
1298
1315
|
});
|
|
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
1316
|
writeWorkHandle(controllerHome, { ...cleaned.handle, cleanupReceipt: cleaned.receipt });
|
|
1318
|
-
if (cleaned.receipt.complete)
|
|
1317
|
+
if (cleaned.receipt.complete) {
|
|
1318
|
+
reconcileCancelledCleanupProjection(controllerHome, repository.repoId, contract, cleaned.receipt);
|
|
1319
|
+
report.cleaned.push(originalHandle.workId);
|
|
1320
|
+
}
|
|
1319
1321
|
else report.blocked.push({
|
|
1320
1322
|
workId: originalHandle.workId,
|
|
1321
1323
|
reason: cleaned.receipt.blockers.join('; ') || cleaned.receipt.worktree.reason || cleaned.receipt.branchCleanup.reason || 'terminal cleanup incomplete',
|