@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
|
@@ -8,12 +8,12 @@ import { ensureRepositoryRuntimeStorage, type RepositoryRuntimeStorageReport } f
|
|
|
8
8
|
import { getRepository, selectRepositoryCheckout, setRepositoryCheckoutLifecycle } from '../../cli/repositories/registry';
|
|
9
9
|
import type { RepositoryRecord } from '../../cli/repositories/types';
|
|
10
10
|
import { rebuildRepositoryProjection } from '../projections/materialized-view';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { getWorkContract, readWorkContractStore, semanticWorkState, updateWorkContract } from '../../../packages/kernel/work/api/index';
|
|
12
|
+
import { assertOwnedResourceCleanupTarget, listOwnedResources, markOwnedResourceCleaned, type OwnedResource } from '../../../packages/kernel/identity/api/index';
|
|
13
13
|
import { listPlanContracts } from '../control-plane/facade/plan-contract-store';
|
|
14
14
|
import { readRequirement } from '../control-plane/persistence/requirement-store';
|
|
15
15
|
import { listControlPlaneRecords, type ControlPlaneRecord } from '../control-plane/persistence/sqlite-store';
|
|
16
|
-
import {
|
|
16
|
+
import type { WorkContract } from '../control-plane/facade/types';
|
|
17
17
|
import { listSchedules } from '../../../packages/kernel/scheduler/api/index';
|
|
18
18
|
import {
|
|
19
19
|
collectRuntimeProcesses,
|
|
@@ -29,6 +29,8 @@ import {
|
|
|
29
29
|
} from './local-jobs-repair';
|
|
30
30
|
import { gcTerminalProcesses, type ProcessGcResult } from '../execution/process-runtime/gc';
|
|
31
31
|
import { cleanupStaleWorkVerificationSnapshots, type WorkVerificationSnapshotRetentionReport } from '../control-plane/execution/work-verification-snapshot';
|
|
32
|
+
import { cleanupGeneratedRepositoryCheckoutCaches, type RepositoryGeneratedCacheRetentionReport } from '../control-plane/generated-cache-retention';
|
|
33
|
+
import { cleanupWorkPreservationArtifacts, type CleanupArtifactRetentionReport } from '../control-plane/cleanup-artifact-retention';
|
|
32
34
|
import {
|
|
33
35
|
cleanupRuntimeQuarantine,
|
|
34
36
|
quarantineRuntimePath,
|
|
@@ -38,6 +40,7 @@ import {
|
|
|
38
40
|
import { readWorkHandle, resolveWorkDeliveryTargetBranch } from '../control-plane/execution/work-handle-store';
|
|
39
41
|
import { listRecoverableProcessRecords } from '../execution/process-runtime/store';
|
|
40
42
|
import { isManagedProcessActive } from '../execution/process-runtime/types';
|
|
43
|
+
import { managedBranchOwnedResourceId, managedBranchOwnedResourceLocator, managedWorkspaceOwnedResourceId } from '../execution/managed-workspace';
|
|
41
44
|
|
|
42
45
|
export type RuntimeMaintenanceActionId =
|
|
43
46
|
| 'local_jobs_reconcile'
|
|
@@ -151,6 +154,8 @@ export interface RuntimeMaintenanceApplyResult extends Omit<RuntimeMaintenanceSt
|
|
|
151
154
|
processGc?: ProcessGcResult;
|
|
152
155
|
verificationSnapshotGc?: WorkVerificationSnapshotRetentionReport;
|
|
153
156
|
quarantineGc?: RuntimeQuarantineRetentionReport;
|
|
157
|
+
generatedCacheGc?: RepositoryGeneratedCacheRetentionReport;
|
|
158
|
+
cleanupArtifactGc?: CleanupArtifactRetentionReport;
|
|
154
159
|
projection?: unknown;
|
|
155
160
|
}
|
|
156
161
|
|
|
@@ -405,7 +410,11 @@ function scanRuntimeTempCandidates(
|
|
|
405
410
|
minAgeMinutes: RUNTIME_TEMP_RETENTION_MINUTES,
|
|
406
411
|
maxEntries: Math.max(maxCandidates * 3, 500),
|
|
407
412
|
});
|
|
408
|
-
|
|
413
|
+
// scanRuntimeTempEntries is the mechanical temp-ownership fence: it only
|
|
414
|
+
// returns direct Forge-prefixed children of the approved temp roots, and
|
|
415
|
+
// removeRuntimeTempEntry revalidates root/name/symlink/age/process occupancy
|
|
416
|
+
// immediately before mutation. Explicit roots narrow scope; they do not create
|
|
417
|
+
// a second ownership authority.
|
|
409
418
|
return scan.entries
|
|
410
419
|
.filter((entry) => entry.cleanupCandidate)
|
|
411
420
|
.slice(0, maxCandidates)
|
|
@@ -413,17 +422,15 @@ function scanRuntimeTempCandidates(
|
|
|
413
422
|
kind: 'stale_runtime_temp_entry',
|
|
414
423
|
id: `runtime-temp-${safeId(entry.path)}`,
|
|
415
424
|
path: entry.path,
|
|
416
|
-
safe: entry.cleanupCandidate
|
|
417
|
-
reason:
|
|
418
|
-
? '
|
|
419
|
-
: entry.
|
|
420
|
-
?
|
|
421
|
-
: entry.
|
|
422
|
-
? `Temp entry is referenced by live process ${entry.occupiedByPid}.`
|
|
423
|
-
: `Forge temp entry is unoccupied, not a symbolic link, and ${entry.ageMinutes} minute(s) old.`,
|
|
425
|
+
safe: entry.cleanupCandidate,
|
|
426
|
+
reason: entry.symbolicLink
|
|
427
|
+
? 'Symbolic links are never eligible for automatic cleanup.'
|
|
428
|
+
: entry.occupiedByPid
|
|
429
|
+
? `Temp entry is referenced by live process ${entry.occupiedByPid}.`
|
|
430
|
+
: `Forge temp entry is unoccupied, not a symbolic link, and ${entry.ageMinutes} minute(s) old.`,
|
|
424
431
|
ageMinutes: entry.ageMinutes,
|
|
425
432
|
suggestedAction: 'full_maintenance_pass',
|
|
426
|
-
ownershipStatus,
|
|
433
|
+
ownershipStatus: 'explicit' as const,
|
|
427
434
|
}));
|
|
428
435
|
}
|
|
429
436
|
|
|
@@ -464,7 +471,7 @@ function listRetainedMigratedWork(destinationHomeInput: string, repoId: string):
|
|
|
464
471
|
}
|
|
465
472
|
for (const source of sourceWork) {
|
|
466
473
|
const work = source.value;
|
|
467
|
-
if (work.repoId !== repoId ||
|
|
474
|
+
if (work.repoId !== repoId || semanticWorkState(work) === 'open') continue;
|
|
468
475
|
if (!work.worktreeRef?.trim() || !existsSync(work.worktreeRef)) continue;
|
|
469
476
|
if (destinationWorkIds.has(work.workId)) continue;
|
|
470
477
|
retained.push({ migrationId: migration.migrationId, sourceHome, work });
|
|
@@ -497,6 +504,121 @@ function looksLikeForgeManagedWorktree(path: string): boolean {
|
|
|
497
504
|
|
|
498
505
|
type StaleWorkSourceState = NonNullable<RuntimeMaintenanceCandidate['sourceState']>;
|
|
499
506
|
|
|
507
|
+
interface OwnedManagedWorktreeInspection {
|
|
508
|
+
safe: boolean;
|
|
509
|
+
path: string;
|
|
510
|
+
sourceState: StaleWorkSourceState;
|
|
511
|
+
detail: string;
|
|
512
|
+
workspaceResourceId?: string;
|
|
513
|
+
checkoutId?: string;
|
|
514
|
+
branch?: string;
|
|
515
|
+
canonicalBranch?: string;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function activeOwnedWorktreeResource(
|
|
519
|
+
controllerHome: string,
|
|
520
|
+
repoId: string,
|
|
521
|
+
path: string,
|
|
522
|
+
): OwnedResource | undefined {
|
|
523
|
+
const target = resolve(path);
|
|
524
|
+
return listOwnedResources(controllerHome, { kind: 'worktree', status: 'active', repoId })
|
|
525
|
+
.find((resource) => resource.cleanupCapable === true && resolve(resource.targetRef) === target);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function inspectOwnedManagedWorktree(
|
|
529
|
+
repository: RuntimeMaintenanceRepository,
|
|
530
|
+
controllerHome: string,
|
|
531
|
+
pathInput: string,
|
|
532
|
+
): OwnedManagedWorktreeInspection {
|
|
533
|
+
const path = resolve(pathInput);
|
|
534
|
+
if (!looksLikeForgeManagedWorktree(path)) {
|
|
535
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: 'Managed worktree is outside Forge-managed storage; automatic cleanup is forbidden.' };
|
|
536
|
+
}
|
|
537
|
+
if (!existsSync(path)) {
|
|
538
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: 'Owned managed worktree path is absent; registry/resource reconciliation is required before cleanup.' };
|
|
539
|
+
}
|
|
540
|
+
const workspaceResource = activeOwnedWorktreeResource(controllerHome, repository.repoId, path);
|
|
541
|
+
if (!workspaceResource) {
|
|
542
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: 'No active cleanup-capable OwnedResource matches this managed worktree path.' };
|
|
543
|
+
}
|
|
544
|
+
try {
|
|
545
|
+
assertOwnedResourceCleanupTarget(controllerHome, {
|
|
546
|
+
resourceId: workspaceResource.resourceId,
|
|
547
|
+
kind: 'worktree',
|
|
548
|
+
targetRef: path,
|
|
549
|
+
});
|
|
550
|
+
} catch (error) {
|
|
551
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: `Managed worktree OwnedResource failed exact identity validation: ${error instanceof Error ? error.message : String(error)}` };
|
|
552
|
+
}
|
|
553
|
+
const contractOwner = readWorkContractStore({ controllerHome, repoId: repository.repoId }).contracts.find((contract) =>
|
|
554
|
+
contract.worktreeRef && resolve(contract.worktreeRef) === path);
|
|
555
|
+
if (contractOwner) {
|
|
556
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: `Managed worktree still has WorkContract owner ${contractOwner.workId}; cleanup must remain with that Work lifecycle.` };
|
|
557
|
+
}
|
|
558
|
+
let registered;
|
|
559
|
+
try { registered = getRepository(repository.repoId, controllerHome, { includeRemoved: true }); } catch (error) {
|
|
560
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: `Repository registry could not be read for owned managed worktree: ${error instanceof Error ? error.message : String(error)}` };
|
|
561
|
+
}
|
|
562
|
+
const checkout = registered.checkouts.find((candidate) =>
|
|
563
|
+
candidate.worktree === true
|
|
564
|
+
&& (candidate.lifecycle ?? 'active') === 'active'
|
|
565
|
+
&& (resolve(candidate.canonicalRoot) === path || resolve(candidate.localRoot) === path));
|
|
566
|
+
if (!checkout) {
|
|
567
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: 'Owned managed worktree has no active matching Repository Registry checkout.' };
|
|
568
|
+
}
|
|
569
|
+
if (registered.activeCheckoutId === checkout.checkoutId) {
|
|
570
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: 'Owned managed worktree is unexpectedly the canonical active checkout; automatic cleanup is forbidden.' };
|
|
571
|
+
}
|
|
572
|
+
const status = runProcess('git', ['status', '--porcelain', '--untracked-files=all'], { cwd: path, timeoutMs: 10_000, maxOutputBytes: 500_000 });
|
|
573
|
+
if (!status.ok) {
|
|
574
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: 'Owned managed worktree status could not be read.' };
|
|
575
|
+
}
|
|
576
|
+
if (status.stdout.trim()) {
|
|
577
|
+
return { safe: false, path, sourceState: 'dirty_worktree', detail: 'Owned managed worktree is dirty; unique source must be preserved.' };
|
|
578
|
+
}
|
|
579
|
+
const head = runProcess('git', ['rev-parse', 'HEAD'], { cwd: path, timeoutMs: 10_000, maxOutputBytes: 100_000 });
|
|
580
|
+
const branch = runProcess('git', ['branch', '--show-current'], { cwd: path, timeoutMs: 10_000, maxOutputBytes: 100_000 });
|
|
581
|
+
if (!head.ok || !head.stdout.trim() || !branch.ok || !branch.stdout.trim()) {
|
|
582
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: 'Owned managed worktree HEAD/branch identity could not be resolved.' };
|
|
583
|
+
}
|
|
584
|
+
const branchName = branch.stdout.trim();
|
|
585
|
+
if (checkout.branch?.trim() && checkout.branch.trim() !== branchName) {
|
|
586
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: 'Owned managed worktree branch no longer matches its Repository Registry checkout identity.' };
|
|
587
|
+
}
|
|
588
|
+
let canonical;
|
|
589
|
+
try { canonical = selectRepositoryCheckout(registered, registered.activeCheckoutId); } catch (error) {
|
|
590
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: `Canonical repository checkout could not be resolved: ${error instanceof Error ? error.message : String(error)}` };
|
|
591
|
+
}
|
|
592
|
+
const canonicalBranch = runProcess('git', ['branch', '--show-current'], { cwd: canonical.canonicalRoot, timeoutMs: 10_000, maxOutputBytes: 100_000 });
|
|
593
|
+
if (!canonicalBranch.ok || !canonicalBranch.stdout.trim()) {
|
|
594
|
+
return { safe: false, path, sourceState: 'source_state_unknown', detail: 'Canonical integration branch could not be resolved for owned managed-worktree cleanup.' };
|
|
595
|
+
}
|
|
596
|
+
const canonicalBranchName = canonicalBranch.stdout.trim();
|
|
597
|
+
const contained = runProcess('git', ['merge-base', '--is-ancestor', head.stdout.trim(), `refs/heads/${canonicalBranchName}`], {
|
|
598
|
+
cwd: canonical.canonicalRoot,
|
|
599
|
+
timeoutMs: 10_000,
|
|
600
|
+
maxOutputBytes: 100_000,
|
|
601
|
+
});
|
|
602
|
+
if (!contained.ok) {
|
|
603
|
+
return {
|
|
604
|
+
safe: false,
|
|
605
|
+
path,
|
|
606
|
+
sourceState: 'unintegrated_commits',
|
|
607
|
+
detail: `Owned managed worktree HEAD ${head.stdout.trim()} is not contained in canonical branch ${canonicalBranchName}; source preservation remains required.`,
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
return {
|
|
611
|
+
safe: true,
|
|
612
|
+
path,
|
|
613
|
+
sourceState: 'clean_integrated',
|
|
614
|
+
workspaceResourceId: workspaceResource.resourceId,
|
|
615
|
+
checkoutId: checkout.checkoutId,
|
|
616
|
+
branch: branchName,
|
|
617
|
+
canonicalBranch: canonicalBranchName,
|
|
618
|
+
detail: `Canonical OwnedResource proves cleanup authority for a clean managed worktree whose HEAD ${head.stdout.trim()} is already contained in canonical branch ${canonicalBranchName}.`,
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
500
622
|
interface StaleWorkSourceInspection {
|
|
501
623
|
safeToCancel: boolean;
|
|
502
624
|
state: StaleWorkSourceState;
|
|
@@ -535,9 +657,8 @@ function resolveStaleWorkDeliveryTarget(
|
|
|
535
657
|
|
|
536
658
|
function isLegacyImplicitRemoteEffectPlacement(contract: WorkContract): boolean {
|
|
537
659
|
if (contract.workKind !== 'remote_effect' || contract.worktreePolicy.required !== true || !contract.worktreeRef || !contract.checkoutId) return false;
|
|
538
|
-
if (contract.routeDecision?.requiresIsolation === true) return false;
|
|
539
660
|
const reason = contract.worktreePolicy.reason?.trim() ?? '';
|
|
540
|
-
if (/Typed placement
|
|
661
|
+
if (/Typed placement/i.test(reason)) return false;
|
|
541
662
|
return true;
|
|
542
663
|
}
|
|
543
664
|
|
|
@@ -573,7 +694,7 @@ function inspectLegacyRemoteEffectPlacement(
|
|
|
573
694
|
if (registeredPath !== path && resolve(checkout.localRoot) !== path) return { safe: false, path, detail: 'Legacy remote_effect WorkContract path does not match its registered checkout identity.' };
|
|
574
695
|
const otherOwner = readWorkContractStore({ controllerHome, repoId: repository.repoId }).contracts.find((candidate) =>
|
|
575
696
|
candidate.workId !== contract.workId
|
|
576
|
-
&&
|
|
697
|
+
&& semanticWorkState(candidate) === 'open'
|
|
577
698
|
&& candidate.worktreeRef
|
|
578
699
|
&& resolve(candidate.worktreeRef) === path);
|
|
579
700
|
if (otherOwner) return { safe: false, path, detail: `Managed worktree is also owned by active Work ${otherOwner.workId}; resource detachment is fenced.` };
|
|
@@ -771,20 +892,11 @@ function inspectStaleWorkRepositorySource(
|
|
|
771
892
|
};
|
|
772
893
|
}
|
|
773
894
|
|
|
774
|
-
function
|
|
775
|
-
if (contract.phase !== 'cleanup') return false;
|
|
776
|
-
return (['implementation', 'verification', 'delivery'] as const).every((phase) =>
|
|
777
|
-
['satisfied', 'skipped'].includes(contract.phaseEvidence[phase].state));
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
function staleWorkCandidateReason(source: StaleWorkSourceInspection, semanticReady: boolean): string {
|
|
895
|
+
function staleWorkCandidateReason(source: StaleWorkSourceInspection): string {
|
|
781
896
|
if (!source.safeToCancel) {
|
|
782
|
-
return `Protected stale Work:
|
|
897
|
+
return `Protected stale Work: repository source preservation is required. ${source.detail} Maintenance may reconcile only concrete owned resources; semantic Work remains model/user-owned.`;
|
|
783
898
|
}
|
|
784
|
-
|
|
785
|
-
return `Protected stale Work: repository source has no unique live changes, but the Work semantic lifecycle has not reached cleanup with implementation, verification, and delivery explicitly satisfied or skipped. ${source.detail} Maintenance may clean source debt, but it cannot infer that the objective or acceptance criteria are complete.`;
|
|
786
|
-
}
|
|
787
|
-
return `Cleanup-ready WorkContract exceeded the explicit maintenance age threshold and has no active Plan, Requirement, Schedule, or Controller authority. ${source.detail} Explicit full maintenance may finish cleanup while retaining durable evidence.`;
|
|
899
|
+
return `Observed stale Work: repository source has no unique live changes, but liveness/legacy phase facts do not authorize semantic cancellation or completion. ${source.detail} Use explicit Work semantic CAS to close the Work.`;
|
|
788
900
|
}
|
|
789
901
|
|
|
790
902
|
function scanRetainedWorktreeCandidates(
|
|
@@ -811,12 +923,12 @@ function scanRetainedWorktreeCandidates(
|
|
|
811
923
|
if (normalized === resolve(repository.canonicalRoot) || currentOwnedPaths.has(normalized)) continue;
|
|
812
924
|
const migrated = retainedByPath.get(normalized);
|
|
813
925
|
if (migrated) {
|
|
814
|
-
const completed = migrated.work
|
|
926
|
+
const completed = semanticWorkState(migrated.work) === 'completed';
|
|
815
927
|
candidates.push({
|
|
816
928
|
kind: 'retained_migrated_work',
|
|
817
929
|
id: migrated.work.workId,
|
|
818
930
|
path: normalized,
|
|
819
|
-
status: migrated.work.
|
|
931
|
+
status: migrated.work.semanticState,
|
|
820
932
|
safe: false,
|
|
821
933
|
reason: completed
|
|
822
934
|
? 'A terminal Work from a retired Controller Home still owns a Git worktree and requires completion/cleanup reconciliation under the current Controller before lifecycle health can be reported.'
|
|
@@ -831,12 +943,28 @@ function scanRetainedWorktreeCandidates(
|
|
|
831
943
|
continue;
|
|
832
944
|
}
|
|
833
945
|
if (!looksLikeForgeManagedWorktree(normalized)) continue;
|
|
946
|
+
const ownedResource = activeOwnedWorktreeResource(controllerHome, repository.repoId, normalized);
|
|
947
|
+
if (ownedResource) {
|
|
948
|
+
const inspection = inspectOwnedManagedWorktree(repository, controllerHome, normalized);
|
|
949
|
+
candidates.push({
|
|
950
|
+
kind: 'unowned_managed_worktree',
|
|
951
|
+
id: `managed-worktree:${basename(normalized)}`,
|
|
952
|
+
path: normalized,
|
|
953
|
+
safe: inspection.safe,
|
|
954
|
+
reason: inspection.detail,
|
|
955
|
+
suggestedAction: 'full_maintenance_pass',
|
|
956
|
+
ownershipStatus: 'explicit',
|
|
957
|
+
sourceState: inspection.sourceState,
|
|
958
|
+
disposition: inspection.safe ? undefined : 'source_preservation_required',
|
|
959
|
+
});
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
834
962
|
candidates.push({
|
|
835
963
|
kind: 'unowned_managed_worktree',
|
|
836
964
|
id: `managed-worktree:${basename(normalized)}`,
|
|
837
965
|
path: normalized,
|
|
838
966
|
safe: false,
|
|
839
|
-
reason: 'Git reports a Forge-managed worktree for this repository, but the current
|
|
967
|
+
reason: 'Git reports a Forge-managed worktree for this repository, but neither the current Work store, retained migration state, nor canonical OwnedResource authority owns it. Ownership must be reconciled before lifecycle health can be reported.',
|
|
840
968
|
suggestedAction: 'full_maintenance_pass',
|
|
841
969
|
ownershipStatus: 'unknown',
|
|
842
970
|
disposition: 'ownership_reconciliation',
|
|
@@ -860,12 +988,12 @@ function scanRetainedWorktreeCandidates(
|
|
|
860
988
|
// path outside current Git inventory only remains lifecycle debt when its
|
|
861
989
|
// worktree .git marker still exists for manual reconciliation.
|
|
862
990
|
if (!existsSync(join(normalized, '.git'))) continue;
|
|
863
|
-
const completed = migrated.work
|
|
991
|
+
const completed = semanticWorkState(migrated.work) === 'completed';
|
|
864
992
|
candidates.push({
|
|
865
993
|
kind: 'retained_migrated_work',
|
|
866
994
|
id: migrated.work.workId,
|
|
867
995
|
path: normalized,
|
|
868
|
-
status: migrated.work.
|
|
996
|
+
status: migrated.work.semanticState,
|
|
869
997
|
safe: false,
|
|
870
998
|
reason: 'A terminal Work retained by a migrated Controller Home still has preserved filesystem state, but Git no longer reports it as a registered worktree. Manual lifecycle reconciliation is required; automatic cleanup is forbidden.',
|
|
871
999
|
suggestedAction: 'full_maintenance_pass',
|
|
@@ -891,7 +1019,6 @@ function normalizedOptions(options: RuntimeMaintenanceOptions = {}): Required<Ru
|
|
|
891
1019
|
interface RuntimeMaintenanceAuthoritySnapshot {
|
|
892
1020
|
contracts: WorkContract[];
|
|
893
1021
|
workById: Map<string, WorkContract>;
|
|
894
|
-
controllerWorkIds: Set<string>;
|
|
895
1022
|
planByWorkId: Map<string, string>;
|
|
896
1023
|
activeRequirementStateById: Map<string, string>;
|
|
897
1024
|
scheduleByWorkId: Map<string, string>;
|
|
@@ -911,7 +1038,6 @@ function buildRuntimeMaintenanceAuthoritySnapshot(
|
|
|
911
1038
|
): RuntimeMaintenanceAuthoritySnapshot {
|
|
912
1039
|
const contracts = readWorkContractStore({ controllerHome, repoId: repository.repoId }).contracts;
|
|
913
1040
|
const workById = new Map(contracts.map((contract) => [contract.workId, contract]));
|
|
914
|
-
const controllerWorkIds = new Set(listControllerSessions({ controllerHome, repoId: repository.repoId }).map((session) => session.workId));
|
|
915
1041
|
const planByWorkId = new Map<string, string>();
|
|
916
1042
|
for (const plan of listPlanContracts({ controllerHome, repoId: repository.repoId, status: 'active', limit: 100 })) {
|
|
917
1043
|
for (const step of plan.steps) if (step.workId) planByWorkId.set(step.workId, plan.planId);
|
|
@@ -934,12 +1060,11 @@ function buildRuntimeMaintenanceAuthoritySnapshot(
|
|
|
934
1060
|
for (const process of listRecoverableProcessRecords(controllerHome, repository.repoId)) {
|
|
935
1061
|
if (process.workId && isManagedProcessActive(process) && !processByWorkId.has(process.workId)) processByWorkId.set(process.workId, process.processId);
|
|
936
1062
|
}
|
|
937
|
-
return { contracts, workById,
|
|
1063
|
+
return { contracts, workById, planByWorkId, activeRequirementStateById, scheduleByWorkId, processByWorkId };
|
|
938
1064
|
}
|
|
939
1065
|
|
|
940
1066
|
function activeWorkAuthorityRefs(contract: WorkContract, snapshot: RuntimeMaintenanceAuthoritySnapshot): string[] {
|
|
941
1067
|
const refs: string[] = [];
|
|
942
|
-
if (snapshot.controllerWorkIds.has(contract.workId)) refs.push('controller_session');
|
|
943
1068
|
const planId = snapshot.planByWorkId.get(contract.workId);
|
|
944
1069
|
if (planId) refs.push(`plan:${planId}`);
|
|
945
1070
|
if (contract.requirementId) {
|
|
@@ -961,7 +1086,7 @@ function scanStaleWorkContractCandidates(
|
|
|
961
1086
|
): RuntimeMaintenanceCandidate[] {
|
|
962
1087
|
const nowMs = Date.now();
|
|
963
1088
|
return snapshot.contracts
|
|
964
|
-
.filter((contract) =>
|
|
1089
|
+
.filter((contract) => semanticWorkState(contract) === 'open')
|
|
965
1090
|
.map((contract) => {
|
|
966
1091
|
const updatedMs = Date.parse(contract.updatedAt);
|
|
967
1092
|
const ageMinutes = Number.isFinite(updatedMs) ? Math.max(0, Math.floor((nowMs - updatedMs) / 60_000)) : 0;
|
|
@@ -969,7 +1094,7 @@ function scanStaleWorkContractCandidates(
|
|
|
969
1094
|
})
|
|
970
1095
|
.filter(({ ageMinutes }) => ageMinutes >= options.minAgeMinutes)
|
|
971
1096
|
.filter(({ contract }) => {
|
|
972
|
-
// A live Plan/Requirement/Schedule/
|
|
1097
|
+
// A live Plan/Requirement/Schedule/Process reference is retained migration authority,
|
|
973
1098
|
// not maintenance debt. The authority inventory was read once for this status pass.
|
|
974
1099
|
return activeWorkAuthorityRefs(contract, snapshot).length === 0;
|
|
975
1100
|
})
|
|
@@ -981,21 +1106,20 @@ function scanStaleWorkContractCandidates(
|
|
|
981
1106
|
}))
|
|
982
1107
|
.map(({ contract, ageMinutes, source }) => {
|
|
983
1108
|
const legacyRemotePlacement = isLegacyImplicitRemoteEffectPlacement(contract);
|
|
984
|
-
const semanticReady = staleWorkSemanticTerminalizationReady(contract);
|
|
985
1109
|
return {
|
|
986
1110
|
kind: 'stale_work_contract' as const,
|
|
987
1111
|
id: contract.workId,
|
|
988
1112
|
path: source.path,
|
|
989
|
-
status: contract.
|
|
990
|
-
safe: legacyRemotePlacement ? source.safeToCancel :
|
|
991
|
-
reason: legacyRemotePlacement ? source.detail : staleWorkCandidateReason(source
|
|
1113
|
+
status: contract.semanticState,
|
|
1114
|
+
safe: legacyRemotePlacement ? source.safeToCancel : false,
|
|
1115
|
+
reason: legacyRemotePlacement ? source.detail : staleWorkCandidateReason(source),
|
|
992
1116
|
ageMinutes,
|
|
993
1117
|
suggestedAction: 'full_maintenance_pass' as const,
|
|
994
1118
|
ownershipStatus: 'explicit' as const,
|
|
995
1119
|
sourceState: source.state,
|
|
996
1120
|
disposition: !source.safeToCancel
|
|
997
1121
|
? ('source_preservation_required' as const)
|
|
998
|
-
: !legacyRemotePlacement
|
|
1122
|
+
: !legacyRemotePlacement
|
|
999
1123
|
? ('semantic_completion_required' as const)
|
|
1000
1124
|
: undefined,
|
|
1001
1125
|
};
|
|
@@ -1013,24 +1137,52 @@ function detachLegacyRemoteEffectPlacement(
|
|
|
1013
1137
|
return { ...candidate, safe: false, reason: inspection?.detail ?? 'Legacy remote_effect placement is no longer eligible for resource detachment.', sourceState: 'source_state_unknown', disposition: 'source_preservation_required', applied: false, result: 'legacy_remote_effect_placement_preserved' };
|
|
1014
1138
|
}
|
|
1015
1139
|
const store = { controllerHome, repoId: repository.repoId };
|
|
1016
|
-
|
|
1140
|
+
try {
|
|
1141
|
+
assertOwnedResourceCleanupTarget(controllerHome, {
|
|
1142
|
+
resourceId: managedWorkspaceOwnedResourceId(repository.repoId, inspection.checkoutId),
|
|
1143
|
+
kind: 'worktree',
|
|
1144
|
+
targetRef: inspection.path,
|
|
1145
|
+
});
|
|
1146
|
+
} catch (error) {
|
|
1147
|
+
return {
|
|
1148
|
+
...candidate,
|
|
1149
|
+
safe: false,
|
|
1150
|
+
reason: `Canonical OwnedResource authority is required before legacy worktree detachment: ${error instanceof Error ? error.message : String(error)}`,
|
|
1151
|
+
sourceState: 'source_state_unknown',
|
|
1152
|
+
disposition: 'source_preservation_required',
|
|
1153
|
+
applied: false,
|
|
1154
|
+
result: 'legacy_remote_effect_owned_resource_required',
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
const previous = { checkoutId: current.checkoutId, worktreeRef: current.worktreeRef, constraints: current.constraints, worktreePolicy: current.worktreePolicy };
|
|
1017
1158
|
updateWorkContract(store, current.workId, {
|
|
1018
1159
|
checkoutId: inspection.canonicalCheckoutId,
|
|
1019
1160
|
worktreeRef: undefined,
|
|
1020
|
-
constraints: { ...current.constraints, workspaceMode: '
|
|
1021
|
-
driver: { ...current.driver, preferred: 'direct_edit', allowDirectEdit: true },
|
|
1161
|
+
constraints: { ...current.constraints, workspaceMode: 'current' },
|
|
1022
1162
|
worktreePolicy: { required: false, reason: 'Legacy pure remote_effect repository placement detached by explicit runtime maintenance; external-effect execution has no repository source authority.' },
|
|
1023
1163
|
});
|
|
1024
1164
|
try {
|
|
1025
1165
|
setRepositoryCheckoutLifecycle({ controllerHome, repoId: repository.repoId, checkoutId: inspection.checkoutId, lifecycle: 'removed', reason: `Legacy remote_effect placement detached for ${current.workId}.` });
|
|
1026
1166
|
const removed = runProcess('git', ['worktree', 'remove', '--force', inspection.path], { cwd: repository.canonicalRoot, timeoutMs: 60_000, maxOutputBytes: 500_000 });
|
|
1027
1167
|
if (!removed.ok && existsSync(inspection.path)) throw new Error(`LEGACY_REMOTE_EFFECT_WORKTREE_REMOVE_FAILED: ${removed.stderr || removed.stdout}`);
|
|
1168
|
+
markOwnedResourceCleaned(controllerHome, managedWorkspaceOwnedResourceId(repository.repoId, inspection.checkoutId), 'forge:legacy-remote-effect-detach');
|
|
1028
1169
|
if (inspection.branch !== inspection.canonicalBranch) {
|
|
1170
|
+
try {
|
|
1171
|
+
assertOwnedResourceCleanupTarget(controllerHome, {
|
|
1172
|
+
resourceId: managedBranchOwnedResourceId(repository.repoId, inspection.checkoutId),
|
|
1173
|
+
kind: 'git_branch',
|
|
1174
|
+
targetRef: inspection.branch,
|
|
1175
|
+
locator: managedBranchOwnedResourceLocator(repository.canonicalRoot, inspection.checkoutId, inspection.branch),
|
|
1176
|
+
});
|
|
1177
|
+
} catch {
|
|
1178
|
+
return { ...candidate, safe: true, reason: inspection.detail, sourceState: 'clean_integrated', disposition: undefined, applied: true, result: `legacy_remote_effect_placement_detached_branch_retained:${inspection.branch}` };
|
|
1179
|
+
}
|
|
1029
1180
|
const deleted = runProcess('git', ['branch', '--delete', inspection.branch], { cwd: repository.canonicalRoot, timeoutMs: 10_000, maxOutputBytes: 100_000 });
|
|
1030
1181
|
if (!deleted.ok) {
|
|
1031
1182
|
const forced = runProcess('git', ['branch', '--delete', '--force', inspection.branch], { cwd: repository.canonicalRoot, timeoutMs: 10_000, maxOutputBytes: 100_000 });
|
|
1032
1183
|
if (!forced.ok) return { ...candidate, safe: true, reason: inspection.detail, sourceState: 'clean_integrated', disposition: undefined, applied: true, result: `legacy_remote_effect_placement_detached_branch_retained:${inspection.branch}` };
|
|
1033
1184
|
}
|
|
1185
|
+
markOwnedResourceCleaned(controllerHome, managedBranchOwnedResourceId(repository.repoId, inspection.checkoutId), 'forge:legacy-remote-effect-detach');
|
|
1034
1186
|
}
|
|
1035
1187
|
return { ...candidate, safe: true, reason: inspection.detail, sourceState: 'clean_integrated', disposition: undefined, applied: true, result: 'legacy_remote_effect_placement_detached' };
|
|
1036
1188
|
} catch (error) {
|
|
@@ -1042,99 +1194,169 @@ function detachLegacyRemoteEffectPlacement(
|
|
|
1042
1194
|
}
|
|
1043
1195
|
}
|
|
1044
1196
|
|
|
1045
|
-
|
|
1197
|
+
function detachOwnedManagedWorktree(
|
|
1046
1198
|
repository: RuntimeMaintenanceRepository,
|
|
1047
1199
|
controllerHome: string,
|
|
1048
1200
|
candidate: RuntimeMaintenanceCandidate,
|
|
1049
1201
|
): RuntimeMaintenanceCandidate & { applied: boolean; result: string } {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1202
|
+
if (!candidate.path) return { ...candidate, applied: false, result: 'owned_managed_worktree_path_missing' };
|
|
1203
|
+
const inspection = inspectOwnedManagedWorktree(repository, controllerHome, candidate.path);
|
|
1204
|
+
if (!inspection.safe || !inspection.workspaceResourceId || !inspection.checkoutId || !inspection.branch || !inspection.canonicalBranch) {
|
|
1205
|
+
return {
|
|
1206
|
+
...candidate,
|
|
1207
|
+
safe: false,
|
|
1208
|
+
reason: inspection.detail,
|
|
1209
|
+
sourceState: inspection.sourceState,
|
|
1210
|
+
disposition: 'source_preservation_required',
|
|
1211
|
+
applied: false,
|
|
1212
|
+
result: 'owned_managed_worktree_preserved',
|
|
1213
|
+
};
|
|
1053
1214
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1215
|
+
try {
|
|
1216
|
+
setRepositoryCheckoutLifecycle({
|
|
1217
|
+
controllerHome,
|
|
1218
|
+
repoId: repository.repoId,
|
|
1219
|
+
checkoutId: inspection.checkoutId,
|
|
1220
|
+
lifecycle: 'removed',
|
|
1221
|
+
reason: 'Canonical OwnedResource cleanup reconciled a WorkContract-less managed worktree whose source is already integrated.',
|
|
1222
|
+
});
|
|
1223
|
+
const removed = runProcess('git', ['worktree', 'remove', '--force', inspection.path], {
|
|
1224
|
+
cwd: repository.canonicalRoot,
|
|
1225
|
+
timeoutMs: 60_000,
|
|
1226
|
+
maxOutputBytes: 500_000,
|
|
1227
|
+
});
|
|
1228
|
+
if (!removed.ok && existsSync(inspection.path)) {
|
|
1229
|
+
throw new Error(`OWNED_MANAGED_WORKTREE_REMOVE_FAILED: ${removed.stderr || removed.stdout}`);
|
|
1230
|
+
}
|
|
1231
|
+
markOwnedResourceCleaned(controllerHome, inspection.workspaceResourceId, 'forge:runtime-maintenance-owned-worktree');
|
|
1232
|
+
if (inspection.branch !== inspection.canonicalBranch) {
|
|
1233
|
+
try {
|
|
1234
|
+
assertOwnedResourceCleanupTarget(controllerHome, {
|
|
1235
|
+
resourceId: managedBranchOwnedResourceId(repository.repoId, inspection.checkoutId),
|
|
1236
|
+
kind: 'git_branch',
|
|
1237
|
+
targetRef: inspection.branch,
|
|
1238
|
+
locator: managedBranchOwnedResourceLocator(repository.canonicalRoot, inspection.checkoutId, inspection.branch),
|
|
1239
|
+
});
|
|
1240
|
+
} catch {
|
|
1070
1241
|
return {
|
|
1071
1242
|
...candidate,
|
|
1072
|
-
|
|
1073
|
-
|
|
1243
|
+
safe: true,
|
|
1244
|
+
reason: inspection.detail,
|
|
1245
|
+
sourceState: 'clean_integrated',
|
|
1246
|
+
disposition: undefined,
|
|
1247
|
+
applied: true,
|
|
1248
|
+
result: `owned_managed_worktree_detached_branch_retained:${inspection.branch}`,
|
|
1074
1249
|
};
|
|
1075
1250
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
if (!
|
|
1251
|
+
const deleted = runProcess('git', ['branch', '--delete', inspection.branch], {
|
|
1252
|
+
cwd: repository.canonicalRoot,
|
|
1253
|
+
timeoutMs: 10_000,
|
|
1254
|
+
maxOutputBytes: 100_000,
|
|
1255
|
+
});
|
|
1256
|
+
if (!deleted.ok) {
|
|
1257
|
+
const forced = runProcess('git', ['branch', '--delete', '--force', inspection.branch], {
|
|
1258
|
+
cwd: repository.canonicalRoot,
|
|
1259
|
+
timeoutMs: 10_000,
|
|
1260
|
+
maxOutputBytes: 100_000,
|
|
1261
|
+
});
|
|
1262
|
+
if (!forced.ok) {
|
|
1263
|
+
return {
|
|
1264
|
+
...candidate,
|
|
1265
|
+
safe: true,
|
|
1266
|
+
reason: inspection.detail,
|
|
1267
|
+
sourceState: 'clean_integrated',
|
|
1268
|
+
disposition: undefined,
|
|
1269
|
+
applied: true,
|
|
1270
|
+
result: `owned_managed_worktree_detached_branch_retained:${inspection.branch}`,
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
markOwnedResourceCleaned(
|
|
1275
|
+
controllerHome,
|
|
1276
|
+
managedBranchOwnedResourceId(repository.repoId, inspection.checkoutId),
|
|
1277
|
+
'forge:runtime-maintenance-owned-worktree',
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
return {
|
|
1281
|
+
...candidate,
|
|
1282
|
+
safe: true,
|
|
1283
|
+
reason: inspection.detail,
|
|
1284
|
+
sourceState: 'clean_integrated',
|
|
1285
|
+
disposition: undefined,
|
|
1286
|
+
applied: true,
|
|
1287
|
+
result: 'owned_managed_worktree_detached',
|
|
1288
|
+
};
|
|
1289
|
+
} catch (error) {
|
|
1290
|
+
if (existsSync(inspection.path)) {
|
|
1291
|
+
try {
|
|
1292
|
+
setRepositoryCheckoutLifecycle({
|
|
1293
|
+
controllerHome,
|
|
1294
|
+
repoId: repository.repoId,
|
|
1295
|
+
checkoutId: inspection.checkoutId,
|
|
1296
|
+
lifecycle: 'active',
|
|
1297
|
+
reason: 'Rollback failed OwnedResource managed-worktree cleanup.',
|
|
1298
|
+
});
|
|
1299
|
+
} catch { /* preserve primary failure */ }
|
|
1300
|
+
}
|
|
1301
|
+
throw error;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
export function applyStaleWorkContractMaintenanceCandidate(
|
|
1306
|
+
repository: RuntimeMaintenanceRepository,
|
|
1307
|
+
controllerHome: string,
|
|
1308
|
+
candidate: RuntimeMaintenanceCandidate,
|
|
1309
|
+
): RuntimeMaintenanceCandidate & { applied: boolean; result: string } {
|
|
1310
|
+
const work = getWorkContract({ controllerHome, repoId: repository.repoId }, candidate.id);
|
|
1311
|
+
if (!work || semanticWorkState(work) !== 'open') {
|
|
1312
|
+
return { ...candidate, applied: false, result: 'already_terminal' };
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// The stale scan is discovery only. Re-read the exact Work and every
|
|
1316
|
+
// non-Controller authority immediately before mutation. WorkContract writes are
|
|
1317
|
+
// serialized by the canonical Work store writer; ControllerSession ownership is
|
|
1318
|
+
// continuation state and cannot fence maintenance of semantic Work.
|
|
1319
|
+
const current = getWorkContract({ controllerHome, repoId: repository.repoId }, work.workId);
|
|
1320
|
+
if (!current || semanticWorkState(current) !== 'open') {
|
|
1321
|
+
return { ...candidate, applied: false, result: 'already_terminal' };
|
|
1322
|
+
}
|
|
1323
|
+
const authorityRefs = activeWorkAuthorityRefs(current, buildRuntimeMaintenanceAuthoritySnapshot(repository, controllerHome));
|
|
1324
|
+
if (authorityRefs.length > 0) {
|
|
1325
|
+
return {
|
|
1326
|
+
...candidate,
|
|
1327
|
+
applied: false,
|
|
1328
|
+
result: `work_authority_became_active:${authorityRefs.join(',')}`,
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
// Discovery and mutation are separated by an arbitrary Runtime delay.
|
|
1332
|
+
// Re-probe the live worktree immediately before mutation; concrete Git/worktree
|
|
1333
|
+
// state is the relevant safety authority, not a Controller claim.
|
|
1334
|
+
const source = inspectStaleWorkRepositorySource(repository, controllerHome, current);
|
|
1335
|
+
if (!source.safeToCancel) {
|
|
1082
1336
|
return {
|
|
1083
1337
|
...candidate,
|
|
1084
1338
|
path: source.path ?? candidate.path,
|
|
1085
1339
|
safe: false,
|
|
1086
|
-
reason: isLegacyImplicitRemoteEffectPlacement(current) ? source.detail : staleWorkCandidateReason(source
|
|
1340
|
+
reason: isLegacyImplicitRemoteEffectPlacement(current) ? source.detail : staleWorkCandidateReason(source),
|
|
1087
1341
|
sourceState: source.state,
|
|
1088
1342
|
disposition: 'source_preservation_required' as const,
|
|
1089
1343
|
applied: false,
|
|
1090
1344
|
result: `work_source_preserved:${source.state}`,
|
|
1091
1345
|
};
|
|
1092
1346
|
}
|
|
1093
|
-
|
|
1347
|
+
if (isLegacyImplicitRemoteEffectPlacement(current)) {
|
|
1094
1348
|
return detachLegacyRemoteEffectPlacement(repository, controllerHome, current, candidate);
|
|
1095
1349
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
result: 'work_semantic_completion_required',
|
|
1107
|
-
};
|
|
1108
|
-
}
|
|
1109
|
-
cancelWorkContract(
|
|
1110
|
-
{ controllerHome, repoId: repository.repoId },
|
|
1111
|
-
current.workId,
|
|
1112
|
-
{
|
|
1113
|
-
summary: 'Cancelled by explicit full maintenance after the Work had already reached cleanup with prior semantic phases satisfied and no unique live repository source remained; durable evidence retained.',
|
|
1114
|
-
evidenceRefs: current.evidenceRefs,
|
|
1115
|
-
},
|
|
1116
|
-
);
|
|
1117
|
-
return {
|
|
1118
|
-
...candidate,
|
|
1119
|
-
path: source.path ?? candidate.path,
|
|
1120
|
-
safe: true,
|
|
1121
|
-
reason: staleWorkCandidateReason(source, true),
|
|
1122
|
-
sourceState: source.state,
|
|
1123
|
-
disposition: undefined,
|
|
1124
|
-
applied: true,
|
|
1125
|
-
result: 'work_contract_cancelled_evidence_retained',
|
|
1126
|
-
};
|
|
1127
|
-
},
|
|
1128
|
-
);
|
|
1129
|
-
if (!fenced.allowed) {
|
|
1130
|
-
const generation = fenced.owner?.claimGeneration;
|
|
1131
|
-
return {
|
|
1132
|
-
...candidate,
|
|
1133
|
-
applied: false,
|
|
1134
|
-
result: `work_terminalization_fenced:${fenced.reason}${typeof generation === 'number' ? `:claim_generation=${generation}` : ''}`,
|
|
1135
|
-
};
|
|
1136
|
-
}
|
|
1137
|
-
return fenced.value;
|
|
1350
|
+
return {
|
|
1351
|
+
...candidate,
|
|
1352
|
+
path: source.path ?? candidate.path,
|
|
1353
|
+
safe: false,
|
|
1354
|
+
reason: staleWorkCandidateReason(source),
|
|
1355
|
+
sourceState: source.state,
|
|
1356
|
+
disposition: 'semantic_completion_required' as const,
|
|
1357
|
+
applied: false,
|
|
1358
|
+
result: 'work_semantic_completion_required',
|
|
1359
|
+
};
|
|
1138
1360
|
}
|
|
1139
1361
|
|
|
1140
1362
|
function scanStaleEditSessionCandidates(
|
|
@@ -1157,7 +1379,7 @@ function scanStaleEditSessionCandidates(
|
|
|
1157
1379
|
.slice(0, options.maxCandidates)
|
|
1158
1380
|
.flatMap(({ session, ageMinutes }) => {
|
|
1159
1381
|
const work = session.workId ? snapshot.workById.get(session.workId) : undefined;
|
|
1160
|
-
const terminalWork = Boolean(work &&
|
|
1382
|
+
const terminalWork = Boolean(work && semanticWorkState(work) !== 'open');
|
|
1161
1383
|
if (work && !terminalWork && activeWorkAuthorityRefs(work, snapshot).length > 0) {
|
|
1162
1384
|
// The Edit Session inherits the live Work lifecycle authority. Reporting it
|
|
1163
1385
|
// as stale maintenance debt while that authority is active would duplicate
|
|
@@ -1269,7 +1491,7 @@ export function buildRuntimeMaintenanceStatus(
|
|
|
1269
1491
|
'Pending approvals are not cancelled unless cancel_pending_approvals is explicitly enabled.',
|
|
1270
1492
|
'System temp cleanup only removes direct forge-prefixed children of approved temp roots after a 24-hour retention period and a fresh process-occupancy check.',
|
|
1271
1493
|
'Runtime lifecycle changes and source repair are outside the runtime maintenance executor.',
|
|
1272
|
-
'Retained or
|
|
1494
|
+
'Retained or unknown-ownership managed worktrees remain review-only lifecycle blockers. A WorkContract-less managed worktree is cleanup-eligible only when canonical OwnedResource identity is exact, the worktree is clean, and its HEAD is already contained in the canonical branch.',
|
|
1273
1495
|
],
|
|
1274
1496
|
};
|
|
1275
1497
|
}
|
|
@@ -1482,6 +1704,9 @@ export function applyRuntimeMaintenance(
|
|
|
1482
1704
|
if (candidate.kind === 'stale_work_contract') {
|
|
1483
1705
|
return applyStaleWorkContractMaintenanceCandidate(repository, controllerHome, candidate);
|
|
1484
1706
|
}
|
|
1707
|
+
if (candidate.kind === 'unowned_managed_worktree') {
|
|
1708
|
+
return detachOwnedManagedWorktree(repository, controllerHome, candidate);
|
|
1709
|
+
}
|
|
1485
1710
|
if (candidate.kind === 'stale_edit_session') {
|
|
1486
1711
|
const cleaned = cleanupEditSession(repository.canonicalRoot, candidate.id, {
|
|
1487
1712
|
reviewer: 'runtime-maintenance',
|
|
@@ -1506,7 +1731,7 @@ export function applyRuntimeMaintenance(
|
|
|
1506
1731
|
: undefined;
|
|
1507
1732
|
const currentWork = readWorkContractStore({ controllerHome, repoId: repository.repoId }).contracts;
|
|
1508
1733
|
const protectedWorkIds = currentWork
|
|
1509
|
-
.filter((contract) =>
|
|
1734
|
+
.filter((contract) => semanticWorkState(contract) === 'open')
|
|
1510
1735
|
.map((contract) => contract.workId);
|
|
1511
1736
|
const verificationSnapshotGc = options.actionId === 'full_maintenance_pass'
|
|
1512
1737
|
? cleanupStaleWorkVerificationSnapshots(controllerHome, repository.repoId, {
|
|
@@ -1522,6 +1747,30 @@ export function applyRuntimeMaintenance(
|
|
|
1522
1747
|
additionalRoots: [runtimeLegacyCheckQuarantineRoot(controllerHome, repository.repoId)],
|
|
1523
1748
|
})
|
|
1524
1749
|
: undefined;
|
|
1750
|
+
let generatedCacheGc: RepositoryGeneratedCacheRetentionReport | undefined;
|
|
1751
|
+
let cleanupArtifactGc: CleanupArtifactRetentionReport | undefined;
|
|
1752
|
+
if (options.actionId === 'full_maintenance_pass') {
|
|
1753
|
+
let cacheRepository: Parameters<typeof cleanupGeneratedRepositoryCheckoutCaches>[0] = {
|
|
1754
|
+
canonicalRoot: repository.canonicalRoot,
|
|
1755
|
+
checkouts: [],
|
|
1756
|
+
};
|
|
1757
|
+
try {
|
|
1758
|
+
cacheRepository = getRepository(repository.repoId, controllerHome, { includeRemoved: true });
|
|
1759
|
+
} catch {
|
|
1760
|
+
// Embedded/test repositories may not be present in the Controller registry.
|
|
1761
|
+
// The explicit maintenance action still safely covers their canonical root.
|
|
1762
|
+
}
|
|
1763
|
+
generatedCacheGc = cleanupGeneratedRepositoryCheckoutCaches(cacheRepository, {
|
|
1764
|
+
graceMs: 60_000,
|
|
1765
|
+
maxEntries: Math.max(1_000, (options.maxCandidates ?? 50) * 20),
|
|
1766
|
+
maxRemovals: Math.max(1, options.maxCandidates ?? 50),
|
|
1767
|
+
});
|
|
1768
|
+
cleanupArtifactGc = cleanupWorkPreservationArtifacts(controllerHome, {
|
|
1769
|
+
maxEntries: Math.max(1_000, (options.maxCandidates ?? 50) * 20),
|
|
1770
|
+
maxRemovals: Math.max(1, options.maxCandidates ?? 50),
|
|
1771
|
+
repositoryIds: [repository.repoId],
|
|
1772
|
+
});
|
|
1773
|
+
}
|
|
1525
1774
|
|
|
1526
1775
|
if (options.actionId === 'runtime_storage_finalize_relocation' || options.actionId === 'full_maintenance_pass' || applied.some((candidate) => candidate.applied) || runtimeStorageRepairApply) {
|
|
1527
1776
|
rebuildActiveIndex(repository.canonicalRoot);
|
|
@@ -1541,6 +1790,8 @@ export function applyRuntimeMaintenance(
|
|
|
1541
1790
|
processGc,
|
|
1542
1791
|
verificationSnapshotGc,
|
|
1543
1792
|
quarantineGc,
|
|
1793
|
+
generatedCacheGc,
|
|
1794
|
+
cleanupArtifactGc,
|
|
1544
1795
|
projection,
|
|
1545
1796
|
};
|
|
1546
1797
|
}
|