@moretea-labs/forge 1.5.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -0
- package/CHANGELOG.md +46 -0
- package/CLAUDE.md +2 -0
- package/DESIGN.md +7 -2
- package/README.md +4 -4
- package/README.zh-CN.md +2 -2
- package/SKILL.md +2 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/hooks/hook-input.sh +11 -8
- package/assets/hooks/lib/session-state.sh +10 -7
- package/assets/hooks/lib/workflow-state.sh +13 -177
- package/assets/hooks/post-tool-observer.sh +8 -2
- package/assets/hooks/pre-edit-guard.sh +8 -39
- package/assets/hooks/prompt-guard.sh +7 -83
- package/assets/hooks/session-start-context.sh +56 -1
- package/assets/partials/05-workflow.partial.md +1 -1
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +54 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.md +1 -1
- package/assets/reference-configs/hook-operations.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/contract.template.md +2 -7
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-task-workflow.sh +4 -4
- package/assets/templates/helpers/contract-worktree.sh +1 -21
- package/assets/templates/helpers/ensure-task-workflow.sh +13 -38
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- package/assets/templates/helpers/new-plan.sh +1 -1
- package/assets/templates/helpers/plan-to-todo.sh +12 -37
- package/assets/templates/helpers/ship-worktrees.sh +2 -29
- package/assets/templates/helpers/sprint-backlog.sh +6 -6
- package/assets/templates/helpers/verify-contract.sh +1 -111
- package/assets/templates/helpers/verify-sprint.sh +3 -180
- package/assets/templates/plan.template.md +1 -1
- package/assets/templates/review.template.md +9 -34
- package/assets/workflow-contract.v1.json +10 -19
- package/docs/README.md +10 -10
- package/docs/architecture/CURRENT.md +170 -0
- package/docs/architecture/EVOLUTION.md +42 -0
- package/docs/architecture/current/README.md +4 -156
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
- package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
- package/docs/architecture/history/README.md +7 -0
- package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
- package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
- package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
- package/docs/architecture/history.md +3 -34
- package/docs/architecture/index.md +15 -98
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
- package/docs/architecture/versions/1.6.md +38 -0
- package/docs/architecture/versions/1.7.md +41 -0
- package/docs/forge-chatgpt-browser-engine.md +2 -2
- package/docs/forge-chatgpt-mcp-setup.md +4 -28
- package/docs/forge-chatgpt-supervised-automation.md +3 -3
- package/docs/forge-github-issue-launcher.md +1 -1
- package/docs/forge-runtime-self-healing-loop.md +1 -1
- package/docs/operations/controller-browser-plugin.md +38 -22
- package/docs/operations/controller-performance-and-502.md +124 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +3 -3
- package/docs/operations/github-repository.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +5 -3
- package/docs/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Installation.md +1 -1
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Quick-Start.md +1 -1
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/package.json +29 -10
- package/scripts/activate-source-baseline.ts +17 -13
- package/scripts/benchmark-background-check-overlap.ts +228 -0
- package/scripts/benchmark-mcp-host.sh +117 -0
- package/scripts/benchmark-mcp-transport.ts +170 -0
- package/scripts/benchmark-quality-harness.ts +146 -0
- package/scripts/benchmark-route-session-concurrency.ts +207 -6
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
- package/scripts/benchmark-typescript-navigation.ts +186 -0
- package/scripts/benchmark-work-efficiency.ts +334 -0
- package/scripts/capture-plan.sh +3 -3
- package/scripts/check-agent-tooling.sh +8 -35
- package/scripts/check-architecture-sync.sh +17 -86
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-public-docs.sh +14 -1
- package/scripts/check-runtime-architecture.mjs +107 -64
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-workflow.sh +4 -4
- package/scripts/contract-worktree.sh +1 -21
- package/scripts/ensure-task-workflow.sh +22 -55
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +15 -44
- package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
- package/scripts/migrate-project-template.sh +23 -1179
- package/scripts/new-plan.sh +1 -1
- package/scripts/plan-to-todo.sh +11 -36
- package/scripts/run-governed-gate.ts +2 -1
- package/scripts/ship-worktrees.sh +2 -29
- package/scripts/smoke-ios-physical-device.ts +4 -2
- package/scripts/smoke-runtime-recovery.ts +1 -35
- package/scripts/smoke-schedule-engine.ts +1 -20
- package/scripts/sprint-backlog.sh +1 -1
- package/scripts/verify-contract.sh +1 -111
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +3 -180
- package/scripts/workflow-contract.ts +1 -5
- package/src/cli/commands/chatgpt.ts +31 -2
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +37 -10
- package/src/cli/commands/recovery.ts +25 -3
- package/src/cli/commands/runtime.ts +55 -3
- package/src/cli/commands/security.ts +12 -1
- package/src/cli/commands/setup-profile.ts +31 -21
- package/src/cli/controller/check-runner.ts +106 -3
- package/src/cli/controller/composite-result.ts +1 -1
- package/src/cli/controller/context/focus.ts +51 -0
- package/src/cli/controller/context/instruction-context.ts +114 -0
- package/src/cli/controller/context/known-paths.ts +76 -0
- package/src/cli/controller/context/query-planning.ts +110 -0
- package/src/cli/controller/context/rule-resolution.ts +532 -0
- package/src/cli/controller/context/source-materializer.ts +278 -0
- package/src/cli/controller/context/structural.ts +16 -0
- package/src/cli/controller/context/types.ts +286 -0
- package/src/cli/controller/context-pack.ts +898 -430
- package/src/cli/controller/launch-agents.ts +77 -2
- package/src/cli/controller/operational-plan.ts +2 -2
- package/src/cli/controller/work-mode.ts +6 -4
- package/src/cli/editing/edit-session.ts +60 -7
- package/src/cli/github/github.ts +133 -0
- package/src/cli/hook/prompt-guard-decision.ts +17 -18
- package/src/cli/hook/prompt-intents.ts +1 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +225 -67
- package/src/cli/local-bridge/console-view-models.ts +3 -35
- package/src/cli/local-bridge/facade-api.ts +2 -217
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/styles.css +27 -11
- package/src/cli/local-bridge/frontend/src/types.ts +8 -7
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +29 -532
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
- package/src/cli/mcp/auth.ts +5 -5
- package/src/cli/mcp/instructions.ts +3 -2
- package/src/cli/mcp/legacy-tool-service.ts +0 -189
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/paths.ts +8 -2
- package/src/cli/mcp/repository-tools.ts +356 -101
- package/src/cli/mcp/server.ts +625 -54
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +42 -5
- package/src/cli/mcp/transports/http.ts +125 -15
- package/src/cli/mcp/transports/session-registry.ts +67 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +209 -14
- package/src/cli/repositories/command-executor.ts +55 -521
- package/src/cli/repositories/command-process.ts +108 -0
- package/src/cli/repositories/command-scope.ts +99 -41
- package/src/cli/repositories/controller-home.ts +7 -8
- package/src/cli/repositories/git-command-executor.ts +2 -0
- package/src/cli/repositories/locks.ts +53 -16
- package/src/cli/repositories/repository-snapshot.ts +121 -0
- package/src/cli/repositories/safe-patch.ts +6 -4
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +110 -10
- package/src/cli/repository/inspector.ts +565 -62
- package/src/cli/repository/session-cache.ts +58 -17
- package/src/cli/v81-entry.ts +1 -4
- package/src/effects/fs-transaction.ts +85 -17
- package/src/runtime/context/codegraph-read-provider.ts +233 -2
- package/src/runtime/context/codegraph-sidecar.cjs +74 -40
- package/src/runtime/context/generic-lsp-provider.ts +355 -0
- package/src/runtime/context/lsp-client.ts +283 -0
- package/src/runtime/context/semantic-navigation.ts +275 -0
- package/src/runtime/context/swift-navigation.ts +565 -0
- package/src/runtime/context/typescript-navigation.ts +226 -0
- package/src/runtime/control-plane/dispatch-priority.ts +28 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +196 -2
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/validation.ts +15 -2
- package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
- package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +175 -8
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +144 -14
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
- package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
- package/src/runtime/control-plane/facade/index.ts +1 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
- package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
- package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
- package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
- package/src/runtime/control-plane/facade/types.ts +55 -11
- package/src/runtime/control-plane/facade/work-contract-store.ts +204 -73
- package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
- package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
- package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
- package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
- package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
- package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
- package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
- package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
- package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +642 -51
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
- package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
- package/src/runtime/control-plane/release-retention.ts +62 -2
- package/src/runtime/control-plane/routing/route-policy.ts +7 -16
- package/src/runtime/control-plane/runtime-status-client.ts +0 -2
- package/src/runtime/diagnostics/mcp-timing.ts +19 -0
- package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
- package/src/runtime/diagnostics/performance.ts +24 -1
- package/src/runtime/evidence/event-ledger.ts +1 -1
- package/src/runtime/execution/jobs/store.ts +58 -4
- package/src/runtime/execution/jobs/types.ts +1 -1
- package/src/runtime/execution/managed-workspace.ts +203 -1
- package/src/runtime/execution/process-runtime/check-facade.ts +52 -14
- package/src/runtime/execution/process-runtime/check-result.ts +63 -2
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
- package/src/runtime/execution/process-runtime/gc.ts +98 -12
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
- package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
- package/src/runtime/execution/process-runtime/runtime.ts +59 -4
- package/src/runtime/execution/process-runtime/store.ts +7 -0
- package/src/runtime/execution/process-runtime/types.ts +2 -0
- package/src/runtime/execution/thin-harness/async-process.ts +12 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
- package/src/runtime/execution/workers/executor.ts +0 -48
- package/src/runtime/gateway/mcp/execution-tools.ts +1219 -126
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +185 -83
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
- package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
- package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
- package/src/runtime/plugins/browser-adapter.ts +2925 -318
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +6 -31
- package/src/runtime/plugins/browser-handoff.ts +92 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
- package/src/runtime/plugins/browser-node-bridge.ts +6 -34
- package/src/runtime/plugins/browser-provider-registry.ts +109 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
- package/src/runtime/plugins/browser-runtime.ts +183 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +15 -12
- package/src/runtime/plugins/external-adapter.ts +324 -3
- package/src/runtime/plugins/external-registration.ts +84 -5
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +4 -2
- package/src/runtime/plugins/github-adapter.ts +125 -0
- package/src/runtime/plugins/gmail-adapter.ts +28 -2
- package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
- package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
- package/src/runtime/plugins/ios-adapter.ts +106 -16
- package/src/runtime/plugins/ios-agent-device.ts +234 -64
- package/src/runtime/plugins/ios-physical-device.ts +1143 -392
- package/src/runtime/plugins/lightweight-action.ts +153 -0
- package/src/runtime/plugins/local-system-adapter.ts +125 -8
- package/src/runtime/plugins/macos-capability-broker.ts +55 -9
- package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
- package/src/runtime/plugins/plugin-management-adapter.ts +181 -0
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +366 -24
- package/src/runtime/plugins/types.ts +39 -2
- package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
- package/src/runtime/projections/git-status-sampler.ts +16 -16
- package/src/runtime/projections/materialized-view.ts +28 -10
- package/src/runtime/recovery/actions.ts +0 -10
- package/src/runtime/recovery/classifier.ts +0 -9
- package/src/runtime/recovery/maintenance-executor.ts +415 -18
- package/src/runtime/recovery/probe.ts +0 -1
- package/src/runtime/recovery/types.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +186 -8
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +430 -22
- package/src/runtime/root/release-manifest.ts +7 -2
- package/src/runtime/root/release-materialize.ts +162 -19
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -27
- package/src/runtime/root/types.ts +2 -0
- package/src/runtime/safe-tooling/index.ts +0 -1
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- package/src/runtime/safe-tooling/types.ts +0 -30
- package/src/runtime/shared/trusted-executable.ts +62 -0
- package/src/runtime/shared/trusted-node-executable.ts +48 -0
- package/src/runtime/standalone-recovery/core.ts +702 -94
- package/src/runtime/standalone-recovery/entry.ts +99 -23
- package/src/runtime/standalone-recovery/installer.ts +19 -3
- package/src/runtime/standalone-recovery/service-labels.ts +2 -0
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
- package/src/runtime/workflow/schedules/browser-probe.ts +258 -0
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
- package/src/runtime/workflow/schedules/engine.ts +509 -80
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +48 -4
- package/src/runtime/workflow/schedules/store.ts +131 -10
- package/src/runtime/workflow/schedules/types.ts +6 -3
- package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
- package/src/testing/test-governance.ts +8 -40
- package/assets/reference-configs/heartbeat-triage.md +0 -57
- package/assets/templates/helpers/harness-trace-grade.sh +0 -150
- package/assets/templates/helpers/heartbeat-triage.sh +0 -361
- package/assets/templates/helpers/maintenance-triage.sh +0 -167
- package/bin/forge-desktop-helper.mjs +0 -204
- package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
- package/docs/architecture/current/architecture-invariants.md +0 -331
- package/docs/architecture/current/automation-and-schedule-engine.md +0 -453
- package/docs/architecture/current/codegraph-context-provider.md +0 -226
- package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
- package/docs/architecture/current/controller-repository-decoupling.md +0 -148
- package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -354
- package/docs/architecture/current/entity-model.md +0 -592
- package/docs/architecture/current/external-plugin-governance.md +0 -396
- package/docs/architecture/current/failure-recovery.md +0 -447
- package/docs/architecture/current/governance.md +0 -213
- package/docs/architecture/current/human-interaction-plane.md +0 -87
- package/docs/architecture/current/implementation-status.md +0 -128
- package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
- package/docs/architecture/current/legacy-governance.md +0 -58
- package/docs/architecture/current/local-workspace-target-grants.md +0 -70
- package/docs/architecture/current/migration-roadmap.md +0 -105
- package/docs/architecture/current/multi-repository-execution.md +0 -371
- package/docs/architecture/current/operations-runbook.md +0 -45
- package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
- package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
- package/docs/architecture/current/repository-access-modes.md +0 -102
- package/docs/architecture/current/route-policy.md +0 -15
- package/docs/architecture/current/route-session-concurrency.md +0 -85
- package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
- package/docs/architecture/current/runtime-directory-map.md +0 -49
- package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
- package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
- package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
- package/docs/architecture/current/system-overview.md +0 -144
- package/docs/architecture/current/target-requirements-traceability.md +0 -202
- package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
- package/docs/architecture/current/thin-harness-v1.md +0 -311
- package/docs/architecture/current/verification-and-release-gates.md +0 -391
- package/docs/forge-autonomous-goal-loop.md +0 -9
- package/docs/forge-provider-configuration.md +0 -7
- package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -83
- package/docs/operations/controller-desktop-plugin.md +0 -112
- package/docs/operations/gmail-assistant-routines.md +0 -186
- package/docs/operations/personal-assistant-operator-guide.md +0 -61
- package/docs/operations/provider-configuration.md +0 -31
- package/scripts/harness-trace-grade.sh +0 -150
- package/scripts/heartbeat-triage.sh +0 -361
- package/scripts/maintenance-triage.sh +0 -167
- package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
- package/src/cli/repositories/goal-registry.ts +0 -239
- package/src/runtime/assistant/action-proposals.ts +0 -279
- package/src/runtime/assistant/intent.ts +0 -395
- package/src/runtime/assistant/model-provider.ts +0 -460
- package/src/runtime/assistant/openapi.ts +0 -223
- package/src/runtime/assistant/policy.ts +0 -89
- package/src/runtime/assistant/readiness.ts +0 -258
- package/src/runtime/assistant/routine-runtime.ts +0 -477
- package/src/runtime/assistant/schedule-binding.ts +0 -171
- package/src/runtime/assistant/standing-grants.ts +0 -375
- package/src/runtime/assistant/store.ts +0 -243
- package/src/runtime/assistant/types.ts +0 -135
- package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
- package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
- package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
- package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
- package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
- package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
- package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
- package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
- package/src/runtime/control-plane/goal-loop/index.ts +0 -13
- package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
- package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
- package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
- package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
- package/src/runtime/control-plane/goal-loop/types.ts +0 -378
- package/src/runtime/control-plane/startup-recovery.ts +0 -198
- package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
- package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
- package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
- package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
- package/src/runtime/plugins/desktop-adapter.ts +0 -374
- package/src/runtime/safe-tooling/browser-safe.ts +0 -133
- package/src/runtime/workflow/findings/store.ts +0 -204
- package/src/runtime/workflow/findings/types.ts +0 -58
- package/src/runtime/workflow/portfolio/engine.ts +0 -20
- package/src/runtime/workflow/portfolio/store.ts +0 -185
- package/src/runtime/workflow/portfolio/types.ts +0 -29
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { statSync } from 'fs';
|
|
2
|
+
import { dirname, relative, resolve } from 'path';
|
|
3
|
+
import * as ts from 'typescript';
|
|
4
|
+
|
|
5
|
+
export type TypeScriptNavigationKind = 'definition' | 'references' | 'implementations';
|
|
6
|
+
|
|
7
|
+
export interface TypeScriptNavigationRequest {
|
|
8
|
+
navigation: TypeScriptNavigationKind;
|
|
9
|
+
path: string;
|
|
10
|
+
line: number;
|
|
11
|
+
column: number;
|
|
12
|
+
tsconfigPath?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface TypeScriptNavigationLocation {
|
|
16
|
+
path: string;
|
|
17
|
+
line: number;
|
|
18
|
+
column: number;
|
|
19
|
+
name?: string;
|
|
20
|
+
kind?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TypeScriptNavigationResult {
|
|
24
|
+
navigation: TypeScriptNavigationKind;
|
|
25
|
+
target: { path: string; line: number; column: number };
|
|
26
|
+
locations: TypeScriptNavigationLocation[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface TypeScriptNavigationAccess {
|
|
30
|
+
/** Stable identity for one read-policy scope. Restricted and unrestricted projects must never share a Language Service. */
|
|
31
|
+
cacheScope: string;
|
|
32
|
+
/** Source identity observed by the caller. A different identity must not reuse project membership. */
|
|
33
|
+
sourceIdentity?: string;
|
|
34
|
+
/** Return true only for repository-relative paths that this navigation call may read. */
|
|
35
|
+
allowRepositoryPath(relativePath: string): boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface CachedProject {
|
|
39
|
+
repoRoot: string;
|
|
40
|
+
configPath: string;
|
|
41
|
+
service: ts.LanguageService;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const projects = new Map<string, CachedProject>();
|
|
45
|
+
const MAX_CACHED_TYPESCRIPT_PROJECTS = 32;
|
|
46
|
+
|
|
47
|
+
function normalizePath(path: string): string {
|
|
48
|
+
return path.replace(/\\/g, '/');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function scriptVersion(path: string): string {
|
|
52
|
+
try {
|
|
53
|
+
const stat = statSync(path);
|
|
54
|
+
return `${stat.mtimeMs}:${stat.size}`;
|
|
55
|
+
} catch {
|
|
56
|
+
return 'missing';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function repositoryRelativePath(repoRoot: string, fileName: string): string | undefined {
|
|
61
|
+
const normalized = normalizePath(relative(repoRoot, resolve(fileName)));
|
|
62
|
+
if (!normalized || normalized === '.' || normalized === '..' || normalized.startsWith('../')) return undefined;
|
|
63
|
+
return normalized;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function loadProject(repoRoot: string, tsconfigPath = 'tsconfig.json', access?: TypeScriptNavigationAccess): CachedProject {
|
|
67
|
+
const root = resolve(repoRoot);
|
|
68
|
+
const configPath = resolve(root, tsconfigPath);
|
|
69
|
+
const configRelative = repositoryRelativePath(root, configPath);
|
|
70
|
+
if (!configRelative) throw new Error('TypeScript navigation tsconfig must be inside the repository.');
|
|
71
|
+
if (access && !access.allowRepositoryPath(configRelative)) {
|
|
72
|
+
throw new Error(`TypeScript navigation tsconfig is denied by read policy: ${configRelative}.`);
|
|
73
|
+
}
|
|
74
|
+
const cacheKey = `${root}\0${configPath}\0${scriptVersion(configPath)}\0${access?.cacheScope ?? 'unrestricted'}\0${access?.sourceIdentity ?? 'unbound-source'}`;
|
|
75
|
+
const cached = projects.get(cacheKey);
|
|
76
|
+
if (cached) {
|
|
77
|
+
projects.delete(cacheKey);
|
|
78
|
+
projects.set(cacheKey, cached);
|
|
79
|
+
return cached;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const canReadAbsolute = (fileName: string): boolean => {
|
|
83
|
+
if (!access) return true;
|
|
84
|
+
const repoRelative = repositoryRelativePath(root, fileName);
|
|
85
|
+
return repoRelative === undefined || access.allowRepositoryPath(repoRelative);
|
|
86
|
+
};
|
|
87
|
+
const readAllowedFile = (fileName: string): string | undefined => canReadAbsolute(fileName) ? ts.sys.readFile(fileName) : undefined;
|
|
88
|
+
const fileExistsAllowed = (fileName: string): boolean => canReadAbsolute(fileName) && ts.sys.fileExists(fileName);
|
|
89
|
+
const readDirectoryAllowed: typeof ts.sys.readDirectory = (path, extensions, exclude, include, depth) =>
|
|
90
|
+
ts.sys.readDirectory(path, extensions, exclude, include, depth).filter(canReadAbsolute);
|
|
91
|
+
|
|
92
|
+
const config = ts.readConfigFile(configPath, readAllowedFile);
|
|
93
|
+
if (config.error) {
|
|
94
|
+
throw new Error(ts.flattenDiagnosticMessageText(config.error.messageText, '\n'));
|
|
95
|
+
}
|
|
96
|
+
const parseHost: ts.ParseConfigHost = {
|
|
97
|
+
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
|
|
98
|
+
readDirectory: readDirectoryAllowed,
|
|
99
|
+
fileExists: fileExistsAllowed,
|
|
100
|
+
readFile: readAllowedFile,
|
|
101
|
+
};
|
|
102
|
+
const parsed = ts.parseJsonConfigFileContent(config.config, parseHost, dirname(configPath), undefined, configPath);
|
|
103
|
+
if (parsed.errors.length > 0) {
|
|
104
|
+
throw new Error(parsed.errors.map((entry) => ts.flattenDiagnosticMessageText(entry.messageText, '\n')).join('\n'));
|
|
105
|
+
}
|
|
106
|
+
const scriptFileNames = parsed.fileNames.filter(canReadAbsolute);
|
|
107
|
+
|
|
108
|
+
const host: ts.LanguageServiceHost = {
|
|
109
|
+
getCompilationSettings: () => parsed.options,
|
|
110
|
+
getScriptFileNames: () => scriptFileNames,
|
|
111
|
+
getScriptVersion: scriptVersion,
|
|
112
|
+
getScriptSnapshot: (fileName) => {
|
|
113
|
+
if (!fileExistsAllowed(fileName)) return undefined;
|
|
114
|
+
const content = readAllowedFile(fileName);
|
|
115
|
+
return content === undefined ? undefined : ts.ScriptSnapshot.fromString(content);
|
|
116
|
+
},
|
|
117
|
+
getCurrentDirectory: () => root,
|
|
118
|
+
getDefaultLibFileName: (options) => ts.getDefaultLibFilePath(options),
|
|
119
|
+
fileExists: fileExistsAllowed,
|
|
120
|
+
readFile: readAllowedFile,
|
|
121
|
+
readDirectory: readDirectoryAllowed,
|
|
122
|
+
directoryExists: ts.sys.directoryExists,
|
|
123
|
+
getDirectories: ts.sys.getDirectories,
|
|
124
|
+
realpath: ts.sys.realpath,
|
|
125
|
+
useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
|
|
126
|
+
getNewLine: () => ts.sys.newLine,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const project = {
|
|
130
|
+
repoRoot: root,
|
|
131
|
+
configPath,
|
|
132
|
+
service: ts.createLanguageService(host, ts.createDocumentRegistry()),
|
|
133
|
+
};
|
|
134
|
+
projects.set(cacheKey, project);
|
|
135
|
+
while (projects.size > MAX_CACHED_TYPESCRIPT_PROJECTS) {
|
|
136
|
+
const oldestKey = projects.keys().next().value as string | undefined;
|
|
137
|
+
if (!oldestKey) break;
|
|
138
|
+
const oldest = projects.get(oldestKey);
|
|
139
|
+
projects.delete(oldestKey);
|
|
140
|
+
oldest?.service.dispose();
|
|
141
|
+
}
|
|
142
|
+
return project;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function sourcePosition(project: CachedProject, program: ts.Program, fileName: string, line: number, column: number): number {
|
|
146
|
+
if (!Number.isInteger(line) || line < 1 || !Number.isInteger(column) || column < 1) {
|
|
147
|
+
throw new Error('TypeScript navigation line and column must be positive 1-based integers.');
|
|
148
|
+
}
|
|
149
|
+
const source = program.getSourceFile(fileName);
|
|
150
|
+
if (!source) throw new Error(`TypeScript project does not include ${normalizePath(relative(project.repoRoot, fileName))}.`);
|
|
151
|
+
if (line > source.getLineAndCharacterOfPosition(source.getEnd()).line + 1) {
|
|
152
|
+
throw new Error(`TypeScript navigation line ${line} is outside ${normalizePath(relative(project.repoRoot, fileName))}.`);
|
|
153
|
+
}
|
|
154
|
+
return source.getPositionOfLineAndCharacter(line - 1, column - 1);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function location(
|
|
158
|
+
project: CachedProject,
|
|
159
|
+
program: ts.Program,
|
|
160
|
+
fileName: string,
|
|
161
|
+
textSpan: ts.TextSpan,
|
|
162
|
+
name?: string,
|
|
163
|
+
kind?: ts.ScriptElementKind,
|
|
164
|
+
): TypeScriptNavigationLocation {
|
|
165
|
+
const source = program.getSourceFile(fileName);
|
|
166
|
+
if (!source) {
|
|
167
|
+
return { path: normalizePath(relative(project.repoRoot, fileName)), line: 1, column: 1, ...(name ? { name } : {}), ...(kind ? { kind } : {}) };
|
|
168
|
+
}
|
|
169
|
+
const point = source.getLineAndCharacterOfPosition(textSpan.start);
|
|
170
|
+
return {
|
|
171
|
+
path: normalizePath(relative(project.repoRoot, fileName)),
|
|
172
|
+
line: point.line + 1,
|
|
173
|
+
column: point.character + 1,
|
|
174
|
+
...(name ? { name } : {}),
|
|
175
|
+
...(kind ? { kind } : {}),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function dedupe(locations: TypeScriptNavigationLocation[]): TypeScriptNavigationLocation[] {
|
|
180
|
+
const seen = new Set<string>();
|
|
181
|
+
return locations.filter((entry) => {
|
|
182
|
+
const key = `${entry.path}:${entry.line}:${entry.column}:${entry.name ?? ''}:${entry.kind ?? ''}`;
|
|
183
|
+
if (seen.has(key)) return false;
|
|
184
|
+
seen.add(key);
|
|
185
|
+
return true;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function navigateTypeScriptSymbol(
|
|
190
|
+
repoRoot: string,
|
|
191
|
+
request: TypeScriptNavigationRequest,
|
|
192
|
+
access?: TypeScriptNavigationAccess,
|
|
193
|
+
): TypeScriptNavigationResult {
|
|
194
|
+
const project = loadProject(repoRoot, request.tsconfigPath, access);
|
|
195
|
+
const fileName = resolve(project.repoRoot, request.path);
|
|
196
|
+
// A references response may materialize hundreds of locations. Acquire the
|
|
197
|
+
// Language Service Program once per navigation so that location formatting
|
|
198
|
+
// does not repeatedly re-enter the service while the result is built.
|
|
199
|
+
const program = project.service.getProgram();
|
|
200
|
+
if (!program) throw new Error('TypeScript Language Service did not produce a Program.');
|
|
201
|
+
const position = sourcePosition(project, program, fileName, request.line, request.column);
|
|
202
|
+
let locations: TypeScriptNavigationLocation[] = [];
|
|
203
|
+
|
|
204
|
+
if (request.navigation === 'definition') {
|
|
205
|
+
locations = (project.service.getDefinitionAtPosition(fileName, position) ?? [])
|
|
206
|
+
.map((entry) => location(project, program, entry.fileName, entry.textSpan, entry.name, entry.kind));
|
|
207
|
+
} else if (request.navigation === 'implementations') {
|
|
208
|
+
locations = (project.service.getImplementationAtPosition(fileName, position) ?? [])
|
|
209
|
+
.map((entry) => location(project, program, entry.fileName, entry.textSpan, undefined, entry.kind));
|
|
210
|
+
} else {
|
|
211
|
+
locations = (project.service.findReferences(fileName, position) ?? []).flatMap((group) =>
|
|
212
|
+
group.references.map((entry) => location(project, program, entry.fileName, entry.textSpan, group.definition.name, group.definition.kind)),
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
navigation: request.navigation,
|
|
218
|
+
target: { path: normalizePath(request.path), line: request.line, column: request.column },
|
|
219
|
+
locations: dedupe(locations),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function clearTypeScriptNavigationCache(): void {
|
|
224
|
+
for (const project of projects.values()) project.service.dispose();
|
|
225
|
+
projects.clear();
|
|
226
|
+
}
|
|
@@ -65,3 +65,31 @@ export function compareExecutionJobDispatchRanks(
|
|
|
65
65
|
|| left.queuedAtMs - right.queuedAtMs
|
|
66
66
|
|| left.jobId.localeCompare(right.jobId);
|
|
67
67
|
}
|
|
68
|
+
|
|
69
|
+
export function selectExecutionJobDispatchRepositories(
|
|
70
|
+
activeJobs: readonly ExecutionJob[],
|
|
71
|
+
scheduleNow: number,
|
|
72
|
+
lastRepoDispatch: ReadonlyMap<string, number>,
|
|
73
|
+
): string[] {
|
|
74
|
+
const waiting = activeJobs.filter(isExecutionJobDispatchCandidate);
|
|
75
|
+
const rankByJobId = new Map(
|
|
76
|
+
waiting.map((job) => [job.jobId, rankExecutionJobForDispatch(job, scheduleNow)] as const),
|
|
77
|
+
);
|
|
78
|
+
const compareWaiting = (left: ExecutionJob, right: ExecutionJob): number =>
|
|
79
|
+
compareExecutionJobDispatchRanks(rankByJobId.get(left.jobId)!, rankByJobId.get(right.jobId)!);
|
|
80
|
+
const topByRepo = new Map<string, ExecutionJob>();
|
|
81
|
+
for (const job of waiting.slice().sort(compareWaiting)) {
|
|
82
|
+
if (!topByRepo.has(job.repoId)) topByRepo.set(job.repoId, job);
|
|
83
|
+
}
|
|
84
|
+
return [...topByRepo.keys()].sort((left, right) => {
|
|
85
|
+
const leftRank = rankByJobId.get(topByRepo.get(left)!.jobId)!;
|
|
86
|
+
const rightRank = rankByJobId.get(topByRepo.get(right)!.jobId)!;
|
|
87
|
+
const priority = leftRank.effectivePriority - rightRank.effectivePriority;
|
|
88
|
+
if (priority !== 0) return priority;
|
|
89
|
+
const fairness = (lastRepoDispatch.get(left) ?? 0) - (lastRepoDispatch.get(right) ?? 0);
|
|
90
|
+
return fairness
|
|
91
|
+
|| leftRank.queuedAtMs - rightRank.queuedAtMs
|
|
92
|
+
|| leftRank.jobId.localeCompare(rightRank.jobId)
|
|
93
|
+
|| left.localeCompare(right);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { createHash } from 'crypto';
|
|
2
2
|
import { getEditSession, listEditSessions, type EditSession } from '../../../cli/editing/edit-session';
|
|
3
|
+
import { globMatches } from '../../../cli/mcp/paths';
|
|
3
4
|
import { runProcess } from '../../../effects/process-runner';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { completeRequirementFromWork } from '../persistence/requirement-store';
|
|
6
|
+
import { appendWorkEvidence, getWorkContract, recordWorkCompletionReceipt, updateWorkContract } from '../facade/work-contract-store';
|
|
7
|
+
import { isDirectEditWorkCompletionReceipt, isTerminalWorkContractStatus, type DirectEditWorkCompletionReceipt, type WorkReconciliationRecord } from '../facade/types';
|
|
8
|
+
import { historicalVerificationEvidenceAtRevision } from './verification-evidence';
|
|
9
|
+
import { readWorkHandle } from './work-handle-store';
|
|
6
10
|
|
|
7
11
|
export interface DirectEditWorkCompletionReconciliation {
|
|
8
12
|
completedWorkIds: string[];
|
|
@@ -149,3 +153,193 @@ export function reconcileFinalizedDirectEditWorksAfterCommit(input: {
|
|
|
149
153
|
|
|
150
154
|
return { completedWorkIds, examinedSessionIds, skipped, targetBranch, targetRevision };
|
|
151
155
|
}
|
|
156
|
+
|
|
157
|
+
export interface ReviewedDirectEditWorkReconciliationInput {
|
|
158
|
+
controllerHome: string;
|
|
159
|
+
repoId: string;
|
|
160
|
+
checkoutId: string;
|
|
161
|
+
repoRoot: string;
|
|
162
|
+
workId: string;
|
|
163
|
+
targetBranch: string;
|
|
164
|
+
targetRevision: string;
|
|
165
|
+
comparedPaths: string[];
|
|
166
|
+
reviewer: string;
|
|
167
|
+
rationale: string;
|
|
168
|
+
cleanupOwnershipProof: string;
|
|
169
|
+
reviewedAt?: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function exactCommit(repoRoot: string, revision: string, label: string): string {
|
|
173
|
+
const result = git(repoRoot, ['rev-parse', '--verify', `${revision}^{commit}`]);
|
|
174
|
+
if (!result.ok || !result.stdout.trim()) throw new Error(`DIRECT_EDIT_WORK_RECONCILIATION_${label}_INVALID`);
|
|
175
|
+
return result.stdout.trim();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function comparedRevisionPaths(repoRoot: string, baseRevision: string, targetRevision: string): string[] {
|
|
179
|
+
const result = git(repoRoot, ['diff', '--name-only', '-z', baseRevision, targetRevision]);
|
|
180
|
+
if (!result.ok) throw new Error('DIRECT_EDIT_WORK_RECONCILIATION_CHANGED_PATHS_UNAVAILABLE');
|
|
181
|
+
return [...new Set(result.stdout.split('\0').filter(Boolean))].sort((left, right) => left.localeCompare(right));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function normalizedComparedPaths(paths: string[]): string[] {
|
|
185
|
+
const normalized = [...new Set(paths.map((path) => path.trim()))].sort((left, right) => left.localeCompare(right));
|
|
186
|
+
if (normalized.length === 0 || normalized.length > 100 || normalized.some((path) => !path || path.startsWith('/') || path.includes('\0') || path.split('/').some((part) => part === '' || part === '.' || part === '..'))) {
|
|
187
|
+
throw new Error('DIRECT_EDIT_WORK_RECONCILIATION_PATHS_INVALID');
|
|
188
|
+
}
|
|
189
|
+
return normalized;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Explicitly close a historically delivered Direct Edit Work whose original
|
|
194
|
+
* edit-session binding was missed. This is never inferred: the caller must
|
|
195
|
+
* supply the exact accepted revision and the complete reviewed path set.
|
|
196
|
+
*/
|
|
197
|
+
export function acceptReviewedDirectEditWorkReconciliation(input: ReviewedDirectEditWorkReconciliationInput): {
|
|
198
|
+
workId: string;
|
|
199
|
+
reconciliation: WorkReconciliationRecord;
|
|
200
|
+
receipt: DirectEditWorkCompletionReceipt;
|
|
201
|
+
} {
|
|
202
|
+
const work = getWorkContract({ controllerHome: input.controllerHome, repoId: input.repoId }, input.workId);
|
|
203
|
+
if (!work || work.repoId !== input.repoId) throw new Error(`DIRECT_EDIT_WORK_RECONCILIATION_WORK_NOT_FOUND: ${input.workId}`);
|
|
204
|
+
if (work.checkoutId && work.checkoutId !== input.checkoutId) throw new Error(`DIRECT_EDIT_WORK_RECONCILIATION_CHECKOUT_MISMATCH: ${input.workId}`);
|
|
205
|
+
if (work.completionReceipt) {
|
|
206
|
+
const completionReceipt = work.completionReceipt;
|
|
207
|
+
if (isDirectEditWorkCompletionReceipt(completionReceipt) && completionReceipt.reconciliationId) {
|
|
208
|
+
const existing = work.reconciliations.find((entry) => entry.reconciliationId === completionReceipt.reconciliationId);
|
|
209
|
+
if (existing) return { workId: work.workId, reconciliation: existing, receipt: completionReceipt };
|
|
210
|
+
}
|
|
211
|
+
throw new Error(`DIRECT_EDIT_WORK_RECONCILIATION_WORK_TERMINAL: ${input.workId}`);
|
|
212
|
+
}
|
|
213
|
+
const failedHandle = work.status === 'failed'
|
|
214
|
+
? readWorkHandle(input.controllerHome, input.repoId, input.workId)
|
|
215
|
+
: undefined;
|
|
216
|
+
const failedReviewedRecovery = work.workKind === 'repository_change'
|
|
217
|
+
&& work.status === 'failed'
|
|
218
|
+
&& failedHandle?.managedWorktree === false
|
|
219
|
+
&& failedHandle.state === 'failed'
|
|
220
|
+
&& failedHandle.finalization.validation === 'failed'
|
|
221
|
+
&& String(failedHandle.finalization.lastError ?? failedHandle.failureReason ?? '').includes('WORK_HANDLE_HEAD_CHANGED');
|
|
222
|
+
if ((isTerminalWorkContractStatus(work.status) && !failedReviewedRecovery) || work.workKind !== 'repository_change') {
|
|
223
|
+
throw new Error(`DIRECT_EDIT_WORK_RECONCILIATION_WORK_NOT_ELIGIBLE: ${input.workId}`);
|
|
224
|
+
}
|
|
225
|
+
if (!work.baseRevision?.trim()) throw new Error('DIRECT_EDIT_WORK_RECONCILIATION_BASE_REVISION_MISSING');
|
|
226
|
+
|
|
227
|
+
const baseRevision = exactCommit(input.repoRoot, work.baseRevision, 'BASE_REVISION');
|
|
228
|
+
const targetRevision = exactCommit(input.repoRoot, input.targetRevision.trim(), 'TARGET_REVISION');
|
|
229
|
+
const targetBranch = input.targetBranch.trim();
|
|
230
|
+
if (!targetBranch) throw new Error('DIRECT_EDIT_WORK_RECONCILIATION_TARGET_BRANCH_REQUIRED');
|
|
231
|
+
if (!git(input.repoRoot, ['merge-base', '--is-ancestor', baseRevision, targetRevision]).ok) {
|
|
232
|
+
throw new Error('DIRECT_EDIT_WORK_RECONCILIATION_TARGET_NOT_DESCENDANT');
|
|
233
|
+
}
|
|
234
|
+
if (!git(input.repoRoot, ['merge-base', '--is-ancestor', targetRevision, targetBranch]).ok) {
|
|
235
|
+
throw new Error('DIRECT_EDIT_WORK_RECONCILIATION_TARGET_UNREACHABLE');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const comparedPaths = normalizedComparedPaths(input.comparedPaths);
|
|
239
|
+
let comparisonBaseRevision = baseRevision;
|
|
240
|
+
if (failedReviewedRecovery) {
|
|
241
|
+
const targetParent = exactCommit(input.repoRoot, `${targetRevision}^`, 'TARGET_PARENT_REVISION');
|
|
242
|
+
if (!git(input.repoRoot, ['merge-base', '--is-ancestor', baseRevision, targetParent]).ok) {
|
|
243
|
+
throw new Error('DIRECT_EDIT_WORK_RECONCILIATION_TARGET_PARENT_NOT_DESCENDANT');
|
|
244
|
+
}
|
|
245
|
+
comparisonBaseRevision = targetParent;
|
|
246
|
+
}
|
|
247
|
+
const actualPaths = comparedRevisionPaths(input.repoRoot, comparisonBaseRevision, targetRevision);
|
|
248
|
+
if (comparedPaths.length !== actualPaths.length || comparedPaths.some((path, index) => path !== actualPaths[index])) {
|
|
249
|
+
throw new Error('DIRECT_EDIT_WORK_RECONCILIATION_PATH_COMPARISON_MISMATCH');
|
|
250
|
+
}
|
|
251
|
+
for (const path of comparedPaths) {
|
|
252
|
+
if (work.forbiddenPaths.some((pattern) => globMatches(pattern, path))) throw new Error(`DIRECT_EDIT_WORK_RECONCILIATION_FORBIDDEN_PATH: ${path}`);
|
|
253
|
+
if (work.allowedPaths.length > 0 && !work.allowedPaths.some((pattern) => globMatches(pattern, path))) throw new Error(`DIRECT_EDIT_WORK_RECONCILIATION_PATH_OUT_OF_SCOPE: ${path}`);
|
|
254
|
+
}
|
|
255
|
+
const dirty = git(input.repoRoot, ['status', '--porcelain=v1', '--', ...comparedPaths]);
|
|
256
|
+
if (!dirty.ok || dirty.stdout.trim()) throw new Error('DIRECT_EDIT_WORK_RECONCILIATION_OWNED_PATHS_DIRTY');
|
|
257
|
+
|
|
258
|
+
let verifiedAt = new Date().toISOString();
|
|
259
|
+
for (const checkId of work.checks) {
|
|
260
|
+
const candidates = historicalVerificationEvidenceAtRevision(work.checkRefs, {
|
|
261
|
+
sourceRevision: targetRevision,
|
|
262
|
+
repoId: input.repoId,
|
|
263
|
+
workId: work.workId,
|
|
264
|
+
checkoutId: work.checkoutId,
|
|
265
|
+
checkId,
|
|
266
|
+
requestedChecks: work.checks,
|
|
267
|
+
}).filter((entry) => entry.current && entry.record.outcome === 'valid_pass');
|
|
268
|
+
const distinctReceipts = new Map(candidates.map((entry) => [entry.record.receipt!.receiptId, entry]));
|
|
269
|
+
if (distinctReceipts.size === 0) throw new Error(`DIRECT_EDIT_WORK_RECONCILIATION_CHECK_EVIDENCE_STALE: ${checkId}`);
|
|
270
|
+
if (distinctReceipts.size > 1) throw new Error(`DIRECT_EDIT_WORK_RECONCILIATION_CHECK_EVIDENCE_AMBIGUOUS: ${checkId}`);
|
|
271
|
+
const current = [...distinctReceipts.values()][0]!;
|
|
272
|
+
verifiedAt = current.record.completedAt ?? current.record.recordedAt ?? verifiedAt;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const reviewer = input.reviewer.trim();
|
|
276
|
+
const rationale = input.rationale.trim();
|
|
277
|
+
const cleanupOwnershipProof = input.cleanupOwnershipProof.trim();
|
|
278
|
+
const reviewedAt = input.reviewedAt ?? new Date().toISOString();
|
|
279
|
+
if (!reviewer || !rationale || !cleanupOwnershipProof || Number.isNaN(Date.parse(reviewedAt))) {
|
|
280
|
+
throw new Error('DIRECT_EDIT_WORK_RECONCILIATION_REVIEW_METADATA_INVALID');
|
|
281
|
+
}
|
|
282
|
+
const reconciliationId = `RECNC-${createHash('sha256').update([input.repoId, input.workId, baseRevision, targetRevision, comparedPaths.join('\0'), reviewer, reviewedAt].join('\0')).digest('hex').slice(0, 16)}`;
|
|
283
|
+
const reconciliation: WorkReconciliationRecord = {
|
|
284
|
+
schemaVersion: 1,
|
|
285
|
+
reconciliationId,
|
|
286
|
+
originalExpectedRevision: targetRevision,
|
|
287
|
+
observedTargetRevision: targetRevision,
|
|
288
|
+
baseRevision,
|
|
289
|
+
targetBranch,
|
|
290
|
+
reachable: true,
|
|
291
|
+
method: 'owned_path_tree',
|
|
292
|
+
comparedPaths,
|
|
293
|
+
reviewer: reviewer.slice(0, 200),
|
|
294
|
+
reviewedAt,
|
|
295
|
+
unrecoverableStages: ['receipt'],
|
|
296
|
+
cleanupOwnershipProof: cleanupOwnershipProof.slice(0, 2_000),
|
|
297
|
+
rationale: rationale.slice(0, 2_000),
|
|
298
|
+
outcome: 'accepted_equivalence',
|
|
299
|
+
};
|
|
300
|
+
updateWorkContract({ controllerHome: input.controllerHome, repoId: input.repoId }, input.workId, {
|
|
301
|
+
reconciliations: [reconciliation, ...work.reconciliations.filter((entry) => entry.reconciliationId !== reconciliationId)],
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
const recordedAt = new Date().toISOString();
|
|
305
|
+
const receipt: DirectEditWorkCompletionReceipt = {
|
|
306
|
+
schemaVersion: 1,
|
|
307
|
+
receiptId: `REC-direct-edit-reconciled-${createHash('sha256').update(`${input.repoId}\0${input.workId}\0${reconciliationId}\0${targetRevision}`).digest('hex').slice(0, 20)}`,
|
|
308
|
+
source: 'direct_edit_work',
|
|
309
|
+
workId: input.workId,
|
|
310
|
+
reconciliationId,
|
|
311
|
+
targetBranch,
|
|
312
|
+
targetRevision,
|
|
313
|
+
sourceRevision: targetRevision,
|
|
314
|
+
baseRevision,
|
|
315
|
+
changedPaths: comparedPaths,
|
|
316
|
+
delivery: { kind: 'commit', status: 'integrated', strategy: 'already_integrated', reachable: true, recordedAt },
|
|
317
|
+
cleanup: { status: 'complete', warnings: [], blockers: [], recordedAt },
|
|
318
|
+
verifiedAt,
|
|
319
|
+
recordedAt,
|
|
320
|
+
};
|
|
321
|
+
const recorded = recordWorkCompletionReceipt(
|
|
322
|
+
{ controllerHome: input.controllerHome, repoId: input.repoId },
|
|
323
|
+
input.workId,
|
|
324
|
+
receipt,
|
|
325
|
+
'completed_changed',
|
|
326
|
+
'repository_change',
|
|
327
|
+
);
|
|
328
|
+
if (recorded.requirementId) {
|
|
329
|
+
try {
|
|
330
|
+
completeRequirementFromWork({ controllerHome: input.controllerHome }, { requirementId: recorded.requirementId, work: recorded });
|
|
331
|
+
} catch (error) {
|
|
332
|
+
try {
|
|
333
|
+
appendWorkEvidence({ controllerHome: input.controllerHome, repoId: input.repoId }, input.workId, {
|
|
334
|
+
title: 'requirement completion projection pending',
|
|
335
|
+
summary: `Work completion remains authoritative; Requirement projection could not be applied: ${error instanceof Error ? error.message : String(error)}`.slice(0, 2_000),
|
|
336
|
+
detailLevel: 'summary',
|
|
337
|
+
});
|
|
338
|
+
} catch {
|
|
339
|
+
// Reconciliation already recorded the terminal receipt. A diagnostic
|
|
340
|
+
// write failure cannot make that completed Work non-terminal again.
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return { workId: input.workId, reconciliation, receipt };
|
|
345
|
+
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
listControllerChecks,
|
|
10
10
|
} from '../../../cli/controller/check-runner';
|
|
11
11
|
import type { RepositoryRecord } from '../../../cli/repositories/types';
|
|
12
|
+
import { selectRepositoryCheckout } from '../../../cli/repositories/registry';
|
|
12
13
|
import { executionIdentityForRepository } from './execution-identity';
|
|
13
14
|
import {
|
|
14
15
|
claimsForCheck,
|
|
@@ -266,6 +267,57 @@ function failedRun(
|
|
|
266
267
|
return coordinatorResult(controllerHome, failed);
|
|
267
268
|
}
|
|
268
269
|
|
|
270
|
+
export function resolveEditValidationRepository(
|
|
271
|
+
repository: RepositoryRecord,
|
|
272
|
+
editSessionId: string,
|
|
273
|
+
): { repository: RepositoryRecord; session: EditSession } {
|
|
274
|
+
const checkoutIds = [...new Set([
|
|
275
|
+
repository.activeCheckoutId,
|
|
276
|
+
...repository.checkouts.map((checkout) => checkout.checkoutId),
|
|
277
|
+
].filter(Boolean))];
|
|
278
|
+
for (const checkoutId of checkoutIds) {
|
|
279
|
+
let candidate: RepositoryRecord;
|
|
280
|
+
try {
|
|
281
|
+
candidate = selectRepositoryCheckout(repository, checkoutId);
|
|
282
|
+
} catch {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
let session: EditSession;
|
|
286
|
+
try {
|
|
287
|
+
session = getEditSession(candidate.canonicalRoot, editSessionId);
|
|
288
|
+
} catch (error) {
|
|
289
|
+
if (error instanceof Error && error.message === `edit session not found: ${editSessionId}`) continue;
|
|
290
|
+
throw error;
|
|
291
|
+
}
|
|
292
|
+
if (session.repoId && session.repoId !== candidate.repoId) {
|
|
293
|
+
throw new Error(`EDIT_VALIDATION_SESSION_IDENTITY_MISMATCH: repoId ${session.repoId} != ${candidate.repoId}`);
|
|
294
|
+
}
|
|
295
|
+
if (session.checkoutId && session.checkoutId !== candidate.activeCheckoutId) {
|
|
296
|
+
throw new Error(`EDIT_VALIDATION_SESSION_IDENTITY_MISMATCH: checkoutId ${session.checkoutId} != ${candidate.activeCheckoutId}`);
|
|
297
|
+
}
|
|
298
|
+
return { repository: candidate, session };
|
|
299
|
+
}
|
|
300
|
+
throw new Error(`edit session not found: ${editSessionId}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function validationRunRepository(
|
|
304
|
+
repository: RepositoryRecord,
|
|
305
|
+
run: EditValidationRunState,
|
|
306
|
+
): RepositoryRecord {
|
|
307
|
+
if (run.repositoryId !== repository.repoId) {
|
|
308
|
+
throw new Error(`EDIT_VALIDATION_REPOSITORY_MISMATCH: ${run.repositoryId} != ${repository.repoId}`);
|
|
309
|
+
}
|
|
310
|
+
const candidate = selectRepositoryCheckout(repository, run.checkoutId);
|
|
311
|
+
const session = getEditSession(candidate.canonicalRoot, run.editSessionId);
|
|
312
|
+
if (session.repoId && session.repoId !== run.repositoryId) {
|
|
313
|
+
throw new Error(`EDIT_VALIDATION_SESSION_IDENTITY_MISMATCH: repoId ${session.repoId} != ${run.repositoryId}`);
|
|
314
|
+
}
|
|
315
|
+
if (session.checkoutId && session.checkoutId !== run.checkoutId) {
|
|
316
|
+
throw new Error(`EDIT_VALIDATION_SESSION_IDENTITY_MISMATCH: checkoutId ${session.checkoutId} != ${run.checkoutId}`);
|
|
317
|
+
}
|
|
318
|
+
return candidate;
|
|
319
|
+
}
|
|
320
|
+
|
|
269
321
|
function receiptFor(
|
|
270
322
|
controllerHome: string,
|
|
271
323
|
repository: RepositoryRecord,
|
|
@@ -312,10 +364,18 @@ export async function reconcileEditValidationRun(
|
|
|
312
364
|
): Promise<EditValidationCoordinatorResult> {
|
|
313
365
|
let run = readRun(controllerHome, repository.repoId, runInput.validationId) ?? runInput;
|
|
314
366
|
if (run.status !== 'running') return coordinatorResult(controllerHome, run);
|
|
315
|
-
|
|
316
|
-
|
|
367
|
+
let validationRepository: RepositoryRecord;
|
|
368
|
+
try {
|
|
369
|
+
validationRepository = validationRunRepository(repository, run);
|
|
370
|
+
} catch (error) {
|
|
371
|
+
return failedRun(
|
|
372
|
+
controllerHome,
|
|
373
|
+
run,
|
|
374
|
+
'EDIT_VALIDATION_CHECKOUT_UNAVAILABLE',
|
|
375
|
+
error instanceof Error ? error.message : String(error),
|
|
376
|
+
);
|
|
317
377
|
}
|
|
318
|
-
const session = getEditSession(
|
|
378
|
+
const session = getEditSession(validationRepository.canonicalRoot, run.editSessionId);
|
|
319
379
|
if (session.currentRevision !== run.editRevision) {
|
|
320
380
|
return failedRun(controllerHome, run, 'EDIT_VALIDATION_STALE_REVISION', `Validation targets revision ${run.editRevision}, current edit revision is ${session.currentRevision}.`);
|
|
321
381
|
}
|
|
@@ -334,10 +394,10 @@ export async function reconcileEditValidationRun(
|
|
|
334
394
|
const checkRequestId = `${run.requestId}:check:${index + 1}:${createHash('sha256').update(checkId).digest('hex').slice(0, 12)}`;
|
|
335
395
|
const facade = await runPersistedCheckViaProcessRuntime({
|
|
336
396
|
controllerHome,
|
|
337
|
-
repoId:
|
|
338
|
-
checkoutId:
|
|
339
|
-
repoRoot:
|
|
340
|
-
executionIdentity: executionIdentityForRepository(
|
|
397
|
+
repoId: validationRepository.repoId,
|
|
398
|
+
checkoutId: validationRepository.activeCheckoutId,
|
|
399
|
+
repoRoot: validationRepository.canonicalRoot,
|
|
400
|
+
executionIdentity: executionIdentityForRepository(validationRepository),
|
|
341
401
|
checkId,
|
|
342
402
|
timeoutMs: run.timeoutMs,
|
|
343
403
|
interactiveWaitMs: 0,
|
|
@@ -384,10 +444,10 @@ export async function reconcileEditValidationRun(
|
|
|
384
444
|
}
|
|
385
445
|
|
|
386
446
|
try {
|
|
387
|
-
const receipts = run.checkIds.map((checkId) => receiptFor(controllerHome,
|
|
388
|
-
const checked = recordEditSessionProcessCheckReceipts(
|
|
389
|
-
repoId:
|
|
390
|
-
checkoutId:
|
|
447
|
+
const receipts = run.checkIds.map((checkId) => receiptFor(controllerHome, validationRepository, run, checkId));
|
|
448
|
+
const checked = recordEditSessionProcessCheckReceipts(validationRepository.canonicalRoot, run.editSessionId, {
|
|
449
|
+
repoId: validationRepository.repoId,
|
|
450
|
+
checkoutId: validationRepository.activeCheckoutId,
|
|
391
451
|
receipts,
|
|
392
452
|
reviewer: run.reviewer,
|
|
393
453
|
note: run.note,
|
|
@@ -415,7 +475,9 @@ export async function startOrJoinEditValidation(
|
|
|
415
475
|
repository: RepositoryRecord,
|
|
416
476
|
input: EditValidationStartInput,
|
|
417
477
|
): Promise<EditValidationCoordinatorResult> {
|
|
418
|
-
const
|
|
478
|
+
const resolved = resolveEditValidationRepository(repository, input.editSessionId);
|
|
479
|
+
const validationRepository = resolved.repository;
|
|
480
|
+
const session = resolved.session;
|
|
419
481
|
const checkIds = normalized(input.checkIds ?? session.requestedChecks);
|
|
420
482
|
const requestId = input.validationRequestId?.trim()
|
|
421
483
|
|| input.requestId?.trim()
|
|
@@ -426,14 +488,14 @@ export async function startOrJoinEditValidation(
|
|
|
426
488
|
if (existing.checkIds.join('\n') !== checkIds.join('\n')) {
|
|
427
489
|
return failedRun(controllerHome, existing, 'EDIT_VALIDATION_REQUEST_CONFLICT', 'The validation request id is already bound to a different check set.');
|
|
428
490
|
}
|
|
429
|
-
return reconcileEditValidationRun(controllerHome,
|
|
491
|
+
return reconcileEditValidationRun(controllerHome, validationRepository, existing);
|
|
430
492
|
}
|
|
431
493
|
|
|
432
494
|
if (checkIds.length === 0) {
|
|
433
495
|
try {
|
|
434
|
-
const checked = recordEditSessionProcessCheckReceipts(
|
|
435
|
-
repoId:
|
|
436
|
-
checkoutId:
|
|
496
|
+
const checked = recordEditSessionProcessCheckReceipts(validationRepository.canonicalRoot, session.sessionId, {
|
|
497
|
+
repoId: validationRepository.repoId,
|
|
498
|
+
checkoutId: validationRepository.activeCheckoutId,
|
|
437
499
|
receipts: [],
|
|
438
500
|
reviewer: input.reviewer,
|
|
439
501
|
note: input.note,
|
|
@@ -441,8 +503,8 @@ export async function startOrJoinEditValidation(
|
|
|
441
503
|
const completed = saveRun(controllerHome, {
|
|
442
504
|
schemaVersion: 1,
|
|
443
505
|
validationId: id,
|
|
444
|
-
repositoryId:
|
|
445
|
-
checkoutId:
|
|
506
|
+
repositoryId: validationRepository.repoId,
|
|
507
|
+
checkoutId: validationRepository.activeCheckoutId,
|
|
446
508
|
editSessionId: session.sessionId,
|
|
447
509
|
editRevision: session.currentRevision,
|
|
448
510
|
requestId,
|
|
@@ -464,8 +526,8 @@ export async function startOrJoinEditValidation(
|
|
|
464
526
|
const run: EditValidationRunState = {
|
|
465
527
|
schemaVersion: 1,
|
|
466
528
|
validationId: id,
|
|
467
|
-
repositoryId:
|
|
468
|
-
checkoutId:
|
|
529
|
+
repositoryId: validationRepository.repoId,
|
|
530
|
+
checkoutId: validationRepository.activeCheckoutId,
|
|
469
531
|
editSessionId: session.sessionId,
|
|
470
532
|
editRevision: session.currentRevision,
|
|
471
533
|
requestId,
|
|
@@ -487,13 +549,13 @@ export async function startOrJoinEditValidation(
|
|
|
487
549
|
const run = saveRun(controllerHome, {
|
|
488
550
|
schemaVersion: 1,
|
|
489
551
|
validationId: id,
|
|
490
|
-
repositoryId:
|
|
491
|
-
checkoutId:
|
|
552
|
+
repositoryId: validationRepository.repoId,
|
|
553
|
+
checkoutId: validationRepository.activeCheckoutId,
|
|
492
554
|
editSessionId: session.sessionId,
|
|
493
555
|
editRevision: session.currentRevision,
|
|
494
556
|
requestId,
|
|
495
557
|
checkIds,
|
|
496
|
-
lanes: checkLanes(
|
|
558
|
+
lanes: checkLanes(validationRepository, checkIds),
|
|
497
559
|
processes: {},
|
|
498
560
|
reviewer: input.reviewer,
|
|
499
561
|
note: input.note,
|
|
@@ -505,7 +567,7 @@ export async function startOrJoinEditValidation(
|
|
|
505
567
|
createdAt: now(),
|
|
506
568
|
updatedAt: now(),
|
|
507
569
|
});
|
|
508
|
-
return reconcileEditValidationRun(controllerHome,
|
|
570
|
+
return reconcileEditValidationRun(controllerHome, validationRepository, run);
|
|
509
571
|
}
|
|
510
572
|
|
|
511
573
|
export interface PendingEditValidationSummary {
|