@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'crypto';
|
|
2
|
-
import { existsSync, mkdirSync, realpathSync } from 'fs';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, symlinkSync } from 'fs';
|
|
3
3
|
import { dirname, join, resolve } from 'path';
|
|
4
4
|
import { repositoryControllerRoot } from '../../cli/repositories/controller-home';
|
|
5
5
|
import type { RepositoryRecord } from '../../cli/repositories/types';
|
|
@@ -14,6 +14,7 @@ import { branchSlugSegment, validateBranchName } from '../../cli/repositories/br
|
|
|
14
14
|
import { withControllerLock } from '../../cli/repositories/locks';
|
|
15
15
|
import { resolveGitExecutable } from '../../effects/git-executable';
|
|
16
16
|
import { runProcess } from '../../effects/process-runner';
|
|
17
|
+
import { repositoryChildProcessEnvironment, resolveBunExecutable } from '../shared/process-environment';
|
|
17
18
|
import { readJsonFile, writeJsonAtomic } from '../shared/json-files';
|
|
18
19
|
|
|
19
20
|
export interface EnsureManagedWorkspaceInput {
|
|
@@ -21,6 +22,24 @@ export interface EnsureManagedWorkspaceInput {
|
|
|
21
22
|
title: string;
|
|
22
23
|
baseRef?: string;
|
|
23
24
|
branchName?: string;
|
|
25
|
+
/** Explicitly materialize lockfile-backed Node dependencies in this isolated worktree. */
|
|
26
|
+
prepareDependencies?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ManagedWorkspaceDependencyBootstrap {
|
|
30
|
+
packageManager: 'bun' | 'pnpm' | 'npm' | 'yarn';
|
|
31
|
+
lockfile: string;
|
|
32
|
+
command: string[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ManagedWorkspaceDependencyPreparation {
|
|
36
|
+
mode: 'already_ready' | 'canonical_reuse' | 'installed';
|
|
37
|
+
nodeModulesRoot: string;
|
|
38
|
+
canonicalRoot?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ManagedWorkspaceDependencies {
|
|
42
|
+
materializeDependencies?: (workspaceRoot: string) => void;
|
|
24
43
|
}
|
|
25
44
|
|
|
26
45
|
export interface ManagedWorkspace {
|
|
@@ -73,6 +92,180 @@ function assertBranch(root: string, branch: string): string {
|
|
|
73
92
|
return normalized;
|
|
74
93
|
}
|
|
75
94
|
|
|
95
|
+
export function managedWorkspaceDependencyBootstrap(repoRoot: string): ManagedWorkspaceDependencyBootstrap | undefined {
|
|
96
|
+
if (!existsSync(join(repoRoot, 'package.json')) || existsSync(join(repoRoot, 'node_modules'))) return undefined;
|
|
97
|
+
const lockCandidates = [
|
|
98
|
+
['bun', 'bun.lock', ['bun', 'install', '--frozen-lockfile']],
|
|
99
|
+
['bun', 'bun.lockb', ['bun', 'install', '--frozen-lockfile']],
|
|
100
|
+
['pnpm', 'pnpm-lock.yaml', ['pnpm', 'install', '--frozen-lockfile']],
|
|
101
|
+
['npm', 'package-lock.json', ['npm', 'ci']],
|
|
102
|
+
['yarn', 'yarn.lock', ['yarn', 'install', '--frozen-lockfile']],
|
|
103
|
+
] as const;
|
|
104
|
+
const detected = lockCandidates.find(([, lockfile]) => existsSync(join(repoRoot, lockfile)));
|
|
105
|
+
if (!detected) return undefined;
|
|
106
|
+
return { packageManager: detected[0], lockfile: detected[1], command: [...detected[2]] };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const DEPENDENCY_REUSE_CONFIG_PATHS = [
|
|
110
|
+
'.npmrc',
|
|
111
|
+
'bunfig.toml',
|
|
112
|
+
'pnpm-workspace.yaml',
|
|
113
|
+
'.yarnrc.yml',
|
|
114
|
+
] as const;
|
|
115
|
+
|
|
116
|
+
function dependencyInputMatches(leftRoot: string, rightRoot: string, path: string): boolean {
|
|
117
|
+
const left = join(leftRoot, path);
|
|
118
|
+
const right = join(rightRoot, path);
|
|
119
|
+
const leftExists = existsSync(left);
|
|
120
|
+
const rightExists = existsSync(right);
|
|
121
|
+
if (leftExists !== rightExists) return false;
|
|
122
|
+
return !leftExists || readFileSync(left).equals(readFileSync(right));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function linkedWorkspaceCanonicalRoot(repoRoot: string): string | undefined {
|
|
126
|
+
const common = runProcess(resolveGitExecutable(), ['-C', repoRoot, 'rev-parse', '--path-format=absolute', '--git-common-dir'], {
|
|
127
|
+
timeoutMs: 15_000,
|
|
128
|
+
maxOutputBytes: 8 * 1024,
|
|
129
|
+
});
|
|
130
|
+
if (!common.ok || !common.stdout.trim()) return undefined;
|
|
131
|
+
const canonicalRoot = dirname(resolve(common.stdout.trim()));
|
|
132
|
+
if (!existsSync(canonicalRoot)) return undefined;
|
|
133
|
+
try {
|
|
134
|
+
if (realpathSync(canonicalRoot) === realpathSync(repoRoot)) return undefined;
|
|
135
|
+
} catch {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
const topLevel = runProcess(resolveGitExecutable(), ['-C', canonicalRoot, 'rev-parse', '--show-toplevel'], {
|
|
139
|
+
timeoutMs: 15_000,
|
|
140
|
+
maxOutputBytes: 8 * 1024,
|
|
141
|
+
});
|
|
142
|
+
if (!topLevel.ok || !topLevel.stdout.trim()) return undefined;
|
|
143
|
+
try {
|
|
144
|
+
return realpathSync(topLevel.stdout.trim()) === realpathSync(canonicalRoot) ? canonicalRoot : undefined;
|
|
145
|
+
} catch {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function resolveManagedWorkspaceCanonicalDependencies(repoRoot: string): {
|
|
151
|
+
canonicalRoot: string;
|
|
152
|
+
nodeModulesRoot: string;
|
|
153
|
+
} | undefined {
|
|
154
|
+
const bootstrap = managedWorkspaceDependencyBootstrap(repoRoot);
|
|
155
|
+
if (!bootstrap) return undefined;
|
|
156
|
+
const canonicalRoot = linkedWorkspaceCanonicalRoot(repoRoot);
|
|
157
|
+
if (!canonicalRoot) return undefined;
|
|
158
|
+
const nodeModulesRoot = join(canonicalRoot, 'node_modules');
|
|
159
|
+
if (!existsSync(nodeModulesRoot)) return undefined;
|
|
160
|
+
const dependencyInputs = ['package.json', bootstrap.lockfile, ...DEPENDENCY_REUSE_CONFIG_PATHS];
|
|
161
|
+
if (!dependencyInputs.every((path) => dependencyInputMatches(repoRoot, canonicalRoot, path))) return undefined;
|
|
162
|
+
return { canonicalRoot, nodeModulesRoot: realpathSync(nodeModulesRoot) };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function packageManifestRequiresDependencyMaterialization(repoRoot: string): boolean {
|
|
166
|
+
const packagePath = join(repoRoot, 'package.json');
|
|
167
|
+
if (!existsSync(packagePath)) return false;
|
|
168
|
+
let manifest: Record<string, unknown>;
|
|
169
|
+
try {
|
|
170
|
+
const parsed = JSON.parse(readFileSync(packagePath, 'utf8')) as unknown;
|
|
171
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return true;
|
|
172
|
+
manifest = parsed as Record<string, unknown>;
|
|
173
|
+
} catch {
|
|
174
|
+
// Preserve fail-closed dependency preparation for malformed manifests. The
|
|
175
|
+
// package manager remains the authority for the concrete parse error once a
|
|
176
|
+
// supported frozen lockfile is present.
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const dependencyFields = [
|
|
181
|
+
'dependencies',
|
|
182
|
+
'devDependencies',
|
|
183
|
+
'optionalDependencies',
|
|
184
|
+
'peerDependencies',
|
|
185
|
+
'bundleDependencies',
|
|
186
|
+
'bundledDependencies',
|
|
187
|
+
] as const;
|
|
188
|
+
if (dependencyFields.some((field) => {
|
|
189
|
+
const value = manifest[field];
|
|
190
|
+
return Array.isArray(value)
|
|
191
|
+
? value.length > 0
|
|
192
|
+
: Boolean(value && typeof value === 'object' && Object.keys(value as Record<string, unknown>).length > 0);
|
|
193
|
+
})) return true;
|
|
194
|
+
|
|
195
|
+
const workspaces = manifest.workspaces;
|
|
196
|
+
if (Array.isArray(workspaces)) return workspaces.length > 0;
|
|
197
|
+
if (workspaces && typeof workspaces === 'object') {
|
|
198
|
+
const packages = (workspaces as Record<string, unknown>).packages;
|
|
199
|
+
if (Array.isArray(packages)) return packages.length > 0;
|
|
200
|
+
return Object.keys(workspaces as Record<string, unknown>).length > 0;
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function reuseManagedWorkspaceCanonicalDependencies(repoRoot: string): ManagedWorkspaceDependencyPreparation | undefined {
|
|
206
|
+
const nodeModulesRoot = join(repoRoot, 'node_modules');
|
|
207
|
+
const reusable = resolveManagedWorkspaceCanonicalDependencies(repoRoot);
|
|
208
|
+
if (!reusable) return undefined;
|
|
209
|
+
try {
|
|
210
|
+
symlinkSync(reusable.nodeModulesRoot, nodeModulesRoot, process.platform === 'win32' ? 'junction' : 'dir');
|
|
211
|
+
} catch (error) {
|
|
212
|
+
if (!existsSync(nodeModulesRoot)) {
|
|
213
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
214
|
+
throw new Error(`MANAGED_WORKSPACE_DEPENDENCY_REUSE_FAILED: ${detail}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
mode: 'canonical_reuse',
|
|
219
|
+
nodeModulesRoot: realpathSync(nodeModulesRoot),
|
|
220
|
+
canonicalRoot: reusable.canonicalRoot,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function materializeManagedWorkspaceDependencies(repoRoot: string): ManagedWorkspaceDependencyPreparation | undefined {
|
|
225
|
+
if (!existsSync(join(repoRoot, 'package.json'))) return undefined;
|
|
226
|
+
const nodeModulesRoot = join(repoRoot, 'node_modules');
|
|
227
|
+
if (existsSync(nodeModulesRoot)) {
|
|
228
|
+
return { mode: 'already_ready', nodeModulesRoot: realpathSync(nodeModulesRoot) };
|
|
229
|
+
}
|
|
230
|
+
// A linked worktree may safely reuse canonical dependencies even when the
|
|
231
|
+
// package manifest itself declares no dependencies. The supported lockfile
|
|
232
|
+
// and dependency-reuse inputs remain the authority for proving equivalence.
|
|
233
|
+
const reused = reuseManagedWorkspaceCanonicalDependencies(repoRoot);
|
|
234
|
+
if (reused) return reused;
|
|
235
|
+
// A package manifest can define dependency-free scripts (for example a
|
|
236
|
+
// built-in `node -e` check). Such checks do not need node_modules and must not
|
|
237
|
+
// be rejected merely because the repository intentionally has no lockfile.
|
|
238
|
+
if (!packageManifestRequiresDependencyMaterialization(repoRoot)) return undefined;
|
|
239
|
+
const bootstrap = managedWorkspaceDependencyBootstrap(repoRoot);
|
|
240
|
+
if (!bootstrap) {
|
|
241
|
+
throw new Error('MANAGED_WORKSPACE_DEPENDENCY_LOCK_REQUIRED: package.json declares dependencies but no supported lockfile was found');
|
|
242
|
+
}
|
|
243
|
+
const childEnv = repositoryChildProcessEnvironment();
|
|
244
|
+
const executable = bootstrap.packageManager === 'bun'
|
|
245
|
+
? resolveBunExecutable(process.execPath, childEnv)
|
|
246
|
+
: bootstrap.command[0]!;
|
|
247
|
+
const result = runProcess(executable, bootstrap.command.slice(1), {
|
|
248
|
+
cwd: repoRoot,
|
|
249
|
+
env: childEnv,
|
|
250
|
+
timeoutMs: 10 * 60_000,
|
|
251
|
+
maxOutputBytes: 4 * 1024 * 1024,
|
|
252
|
+
});
|
|
253
|
+
if (!result.ok) {
|
|
254
|
+
const detail = result.stderr || result.error || `exit ${result.status}`;
|
|
255
|
+
throw new Error(`MANAGED_WORKSPACE_DEPENDENCY_INSTALL_FAILED: ${bootstrap.command.join(' ')}: ${detail}`);
|
|
256
|
+
}
|
|
257
|
+
if (!existsSync(nodeModulesRoot)) {
|
|
258
|
+
throw new Error(`MANAGED_WORKSPACE_DEPENDENCY_INSTALL_INCOMPLETE: ${bootstrap.command.join(' ')} completed without node_modules`);
|
|
259
|
+
}
|
|
260
|
+
return { mode: 'installed', nodeModulesRoot: realpathSync(nodeModulesRoot) };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function materializeManagedWorkspaceCheckDependencies(repoRoot: string): ManagedWorkspaceDependencyPreparation | undefined {
|
|
264
|
+
if (!existsSync(join(repoRoot, 'package.json')) || existsSync(join(repoRoot, 'node_modules'))) return undefined;
|
|
265
|
+
if (!linkedWorkspaceCanonicalRoot(repoRoot)) return undefined;
|
|
266
|
+
return materializeManagedWorkspaceDependencies(repoRoot);
|
|
267
|
+
}
|
|
268
|
+
|
|
76
269
|
function existingWorkspace(path: string, branch: string): boolean {
|
|
77
270
|
if (!existsSync(path)) return false;
|
|
78
271
|
const root = runProcess(resolveGitExecutable(), ['-C', path, 'rev-parse', '--show-toplevel'], {
|
|
@@ -109,6 +302,7 @@ export function ensureManagedWorkspace(
|
|
|
109
302
|
controllerHome: string,
|
|
110
303
|
repository: RepositoryRecord,
|
|
111
304
|
input: EnsureManagedWorkspaceInput,
|
|
305
|
+
dependencies: ManagedWorkspaceDependencies = {},
|
|
112
306
|
): ManagedWorkspace {
|
|
113
307
|
const requestId = input.requestId.trim();
|
|
114
308
|
if (!requestId) throw new Error('MANAGED_WORKSPACE_REQUEST_ID_REQUIRED');
|
|
@@ -159,6 +353,14 @@ export function ensureManagedWorkspace(
|
|
|
159
353
|
if (!repositoryCheckoutRootMatches(repository, path)) {
|
|
160
354
|
throw new Error(`MANAGED_WORKSPACE_REPOSITORY_MISMATCH: ${path}`);
|
|
161
355
|
}
|
|
356
|
+
if (input.prepareDependencies === true) {
|
|
357
|
+
(dependencies.materializeDependencies ?? materializeManagedWorkspaceDependencies)(path);
|
|
358
|
+
} else {
|
|
359
|
+
// Reusing a byte-equivalent canonical dependency tree is cheap and
|
|
360
|
+
// deterministic, so isolated Work checkouts should get it even when a
|
|
361
|
+
// full package-manager install was not explicitly requested.
|
|
362
|
+
reuseManagedWorkspaceCanonicalDependencies(path);
|
|
363
|
+
}
|
|
162
364
|
|
|
163
365
|
const record = addRepositoryCheckout({
|
|
164
366
|
repoId: repository.repoId,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Lightweight run_check facade.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Ordinary checks execute through an in-memory lightweight handle and return
|
|
5
|
+
* within the interactive budget without creating Process/Lease state. Checks
|
|
6
|
+
* with real Work/Edit/verification consumers keep persisted Process receipts.
|
|
6
7
|
* Multi-phase and release checks require explicit external Controller handling.
|
|
7
8
|
*/
|
|
8
9
|
|
|
@@ -15,6 +16,12 @@ import {
|
|
|
15
16
|
} from '../../../cli/controller/check-runner';
|
|
16
17
|
import { claimsForCheck, scopeResourceClaims, toProcessClaims } from './resource-claims';
|
|
17
18
|
import { spawnManagedProcess, waitForProcess, getProcessHandle } from './runtime';
|
|
19
|
+
import {
|
|
20
|
+
getLightweightProcessHandle,
|
|
21
|
+
isLightweightProcessId,
|
|
22
|
+
startLightweightControllerCheck,
|
|
23
|
+
waitForLightweightProcess,
|
|
24
|
+
} from './lightweight-managed';
|
|
18
25
|
import type { ProcessHandle } from './types';
|
|
19
26
|
import { DEFAULT_INTERACTIVE_WAIT_MS } from './types';
|
|
20
27
|
import { durationAwareInteractiveWaitMs } from './interactive-admission';
|
|
@@ -37,10 +44,14 @@ export interface RunCheckFacadeInput {
|
|
|
37
44
|
*/
|
|
38
45
|
leaseWaitMs?: number;
|
|
39
46
|
requestId?: string;
|
|
47
|
+
/** Stable caller-owned semantic identity for safely reattaching the same request before rebuilding ephemeral execution inputs. */
|
|
48
|
+
requestSemanticFingerprint?: string;
|
|
40
49
|
workId?: string;
|
|
41
50
|
commandId?: string;
|
|
42
51
|
/** Force durable workflow (release / multi-phase). */
|
|
43
52
|
forceDurable?: boolean;
|
|
53
|
+
/** Internal-only: allow an already-authorized external Work Controller to execute a durable-class check through persisted Process Runtime. */
|
|
54
|
+
allowDurableCheckExecution?: boolean;
|
|
44
55
|
signal?: AbortSignal;
|
|
45
56
|
/** Immutable resolved identity — required; never inferred from main/active/cwd. */
|
|
46
57
|
executionIdentity: ResolvedExecutionIdentity;
|
|
@@ -64,16 +75,7 @@ export function processCheckSemanticScopeKey(
|
|
|
64
75
|
input: Pick<RunCheckFacadeInput, 'workId' | 'verificationBinding' | 'checkoutId'>,
|
|
65
76
|
reuseScope: 'repository' | 'checkout',
|
|
66
77
|
): string {
|
|
67
|
-
|
|
68
|
-
const binding = input.verificationBinding;
|
|
69
|
-
const owner = [
|
|
70
|
-
input.workId ? `work:${input.workId}` : undefined,
|
|
71
|
-
binding?.executionSessionId ? `execution:${binding.executionSessionId}` : undefined,
|
|
72
|
-
binding?.editSessionId ? `edit:${binding.editSessionId}:r${binding.editRevision ?? 'unknown'}` : undefined,
|
|
73
|
-
binding?.issueId ? `issue:${binding.issueId}` : undefined,
|
|
74
|
-
binding?.taskId ? `task:${binding.taskId}` : undefined,
|
|
75
|
-
].filter(Boolean).join('|') || 'unbound';
|
|
76
|
-
return `${base}|owner:${owner}`;
|
|
78
|
+
return reuseScope === 'repository' ? 'repository' : `checkout:${input.checkoutId ?? 'unknown'}`;
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
export interface RunCheckFacadeResult {
|
|
@@ -152,8 +154,9 @@ export async function runCheckViaProcessRuntime(
|
|
|
152
154
|
};
|
|
153
155
|
}
|
|
154
156
|
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
+
// The wait budget is an interaction preference, not a persistence reason.
|
|
158
|
+
// Ordinary checks stay in memory; only a real durable evidence consumer may
|
|
159
|
+
// allocate Process/Lease state.
|
|
157
160
|
const interactiveWaitMs = durationAwareInteractiveWaitMs(
|
|
158
161
|
check.command,
|
|
159
162
|
input.interactiveWaitMs,
|
|
@@ -165,6 +168,14 @@ export async function runCheckViaProcessRuntime(
|
|
|
165
168
|
? Math.max(1_000, Math.trunc(input.timeoutMs))
|
|
166
169
|
: check.timeoutMs,
|
|
167
170
|
);
|
|
171
|
+
const durableVerificationBinding = Boolean(
|
|
172
|
+
input.workId
|
|
173
|
+
|| input.verificationSnapshot
|
|
174
|
+
|| input.verificationBinding?.executionSessionId
|
|
175
|
+
|| input.verificationBinding?.editSessionId
|
|
176
|
+
|| input.verificationBinding?.issueId
|
|
177
|
+
|| input.verificationBinding?.taskId,
|
|
178
|
+
);
|
|
168
179
|
if (!input.executionIdentity) {
|
|
169
180
|
throw new Error('EXECUTION_IDENTITY_REQUIRED: run_check requires an immutable executionIdentity');
|
|
170
181
|
}
|
|
@@ -179,6 +190,27 @@ export async function runCheckViaProcessRuntime(
|
|
|
179
190
|
`CHECKOUT_ROUTE_MISMATCH: check checkout ${input.checkoutId} differs from identity ${executionIdentity.checkoutId}`,
|
|
180
191
|
);
|
|
181
192
|
}
|
|
193
|
+
if (!durableVerificationBinding) {
|
|
194
|
+
const lightweight = await startLightweightControllerCheck({
|
|
195
|
+
controllerHome: input.controllerHome,
|
|
196
|
+
repoId: input.repoId,
|
|
197
|
+
repoRoot: input.repoRoot,
|
|
198
|
+
checkId: input.checkId,
|
|
199
|
+
interactiveWaitMs,
|
|
200
|
+
timeoutMs,
|
|
201
|
+
workId: input.workId,
|
|
202
|
+
commandId: input.commandId ?? input.requestId,
|
|
203
|
+
});
|
|
204
|
+
const handle = lightweight.handle;
|
|
205
|
+
return {
|
|
206
|
+
mode: handle.completed ? 'direct' : 'managed',
|
|
207
|
+
checkId: input.checkId,
|
|
208
|
+
check,
|
|
209
|
+
process: handle,
|
|
210
|
+
ok: handle.completed ? handle.ok : undefined,
|
|
211
|
+
durableSideEffects: emptyEffects,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
182
214
|
const claims = scopeResourceClaims(
|
|
183
215
|
claimsForCheck(
|
|
184
216
|
input.checkId,
|
|
@@ -261,6 +293,9 @@ export async function waitForCheckProcess(
|
|
|
261
293
|
processId: string,
|
|
262
294
|
timeoutMs?: number,
|
|
263
295
|
): Promise<ProcessHandle> {
|
|
296
|
+
if (isLightweightProcessId(processId)) {
|
|
297
|
+
return waitForLightweightProcess(controllerHome, repoId, processId, { timeoutMs });
|
|
298
|
+
}
|
|
264
299
|
return waitForProcess(controllerHome, repoId, processId, { timeoutMs });
|
|
265
300
|
}
|
|
266
301
|
|
|
@@ -269,6 +304,9 @@ export function getCheckProcessHandle(
|
|
|
269
304
|
repoId: string,
|
|
270
305
|
processId: string,
|
|
271
306
|
): ProcessHandle | undefined {
|
|
307
|
+
if (isLightweightProcessId(processId)) {
|
|
308
|
+
return getLightweightProcessHandle(controllerHome, repoId, processId);
|
|
309
|
+
}
|
|
272
310
|
return getProcessHandle(controllerHome, repoId, processId);
|
|
273
311
|
}
|
|
274
312
|
|
|
@@ -2,6 +2,7 @@ import { createHash, randomUUID } from 'crypto';
|
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'fs';
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
4
|
import { processLogDir } from './store';
|
|
5
|
+
import type { ManagedProcessRecord } from './types';
|
|
5
6
|
|
|
6
7
|
export interface PersistedCheckResultReceipt {
|
|
7
8
|
schemaVersion: 1;
|
|
@@ -18,10 +19,18 @@ export interface PersistedCheckResultReceipt {
|
|
|
18
19
|
cacheHit?: boolean;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
export function allocatePersistedCheckResultReceiptPath(
|
|
22
|
+
export function allocatePersistedCheckResultReceiptPath(
|
|
23
|
+
controllerHome: string,
|
|
24
|
+
repoId: string,
|
|
25
|
+
requestId?: string,
|
|
26
|
+
): string {
|
|
22
27
|
const root = join(processLogDir(controllerHome, repoId), 'check-results');
|
|
23
28
|
mkdirSync(root, { recursive: true });
|
|
24
|
-
|
|
29
|
+
const stableRequestId = requestId?.trim();
|
|
30
|
+
const receiptId = stableRequestId
|
|
31
|
+
? `request-${createHash('sha256').update(stableRequestId).digest('hex').slice(0, 32)}`
|
|
32
|
+
: randomUUID();
|
|
33
|
+
return join(root, `${receiptId}.json`);
|
|
25
34
|
}
|
|
26
35
|
|
|
27
36
|
export function writePersistedCheckResultReceipt(path: string, input: Omit<PersistedCheckResultReceipt, 'schemaVersion' | 'receiptId'>): PersistedCheckResultReceipt {
|
|
@@ -43,3 +52,55 @@ export function readPersistedCheckResultReceipt(path: string | undefined): Persi
|
|
|
43
52
|
return undefined;
|
|
44
53
|
}
|
|
45
54
|
}
|
|
55
|
+
|
|
56
|
+
export type PersistedCheckTerminalEvidenceState =
|
|
57
|
+
| 'matched'
|
|
58
|
+
| 'process_runtime_failed_before_result'
|
|
59
|
+
| 'missing'
|
|
60
|
+
| 'mismatch';
|
|
61
|
+
|
|
62
|
+
export interface PersistedCheckTerminalEvidence {
|
|
63
|
+
state: PersistedCheckTerminalEvidenceState;
|
|
64
|
+
failureClass?: PersistedCheckResultReceipt['failureClass'];
|
|
65
|
+
warning?: string;
|
|
66
|
+
infrastructureReason?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Classify one terminal Check Process using the structured result emitted by
|
|
71
|
+
* the check-runner sidecar. A Process Runtime/admission failure can terminate
|
|
72
|
+
* before that result exists (for example PROCESS_LEASE_CONFLICT); such a
|
|
73
|
+
* Process is infrastructure failure, never evidence that repository checks
|
|
74
|
+
* rejected the candidate. Missing/mismatched result identity also fails closed
|
|
75
|
+
* as infrastructure rather than manufacturing acceptance evidence.
|
|
76
|
+
*/
|
|
77
|
+
export function classifyPersistedCheckTerminalEvidence(
|
|
78
|
+
record: ManagedProcessRecord,
|
|
79
|
+
expectedCheckId: string,
|
|
80
|
+
): PersistedCheckTerminalEvidence {
|
|
81
|
+
const structured = readPersistedCheckResultReceipt(record.origin?.checkResultReceiptPath);
|
|
82
|
+
const structuredMatches = Boolean(
|
|
83
|
+
structured
|
|
84
|
+
&& record.checkExecution
|
|
85
|
+
&& structured.checkId === expectedCheckId
|
|
86
|
+
&& structured.cacheKey === record.checkExecution.cacheKey,
|
|
87
|
+
);
|
|
88
|
+
if (structuredMatches) {
|
|
89
|
+
return { state: 'matched', failureClass: structured?.failureClass };
|
|
90
|
+
}
|
|
91
|
+
if (!structured && record.error?.message?.trim()) {
|
|
92
|
+
const reason = record.error.message.trim().slice(0, 512);
|
|
93
|
+
return {
|
|
94
|
+
state: 'process_runtime_failed_before_result',
|
|
95
|
+
warning: `check process failed before structured result receipt: ${reason}`,
|
|
96
|
+
infrastructureReason: reason,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (structured) {
|
|
100
|
+
return {
|
|
101
|
+
state: 'mismatch',
|
|
102
|
+
warning: 'check result receipt did not match the terminal Process semantic identity',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return { state: 'missing', warning: 'check result receipt is missing for the terminal Check Process' };
|
|
106
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { ControllerCheck } from '../../../cli/controller/check-runner';
|
|
2
|
+
import type { ResourceClaimSpec } from '../jobs/types';
|
|
3
|
+
import { resourceClaimsConflict } from '../../resources/claims/conflicts';
|
|
4
|
+
import { claimsForCheck } from './resource-claims';
|
|
5
|
+
|
|
6
|
+
export interface CheckExecutionWave {
|
|
7
|
+
wave: number;
|
|
8
|
+
checkIds: string[];
|
|
9
|
+
parallelSafe: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CheckExecutionConflict {
|
|
13
|
+
leftCheckId: string;
|
|
14
|
+
rightCheckId: string;
|
|
15
|
+
resources: Array<{
|
|
16
|
+
left: Pick<ResourceClaimSpec, 'resourceKey' | 'mode'>;
|
|
17
|
+
right: Pick<ResourceClaimSpec, 'resourceKey' | 'mode'>;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface ScheduledCheck {
|
|
22
|
+
check: ControllerCheck;
|
|
23
|
+
claims: ResourceClaimSpec[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function conflictingResources(left: ScheduledCheck, right: ScheduledCheck): CheckExecutionConflict['resources'] {
|
|
27
|
+
const conflicts: CheckExecutionConflict['resources'] = [];
|
|
28
|
+
for (const leftClaim of left.claims) {
|
|
29
|
+
for (const rightClaim of right.claims) {
|
|
30
|
+
if (!resourceClaimsConflict(leftClaim, rightClaim)) continue;
|
|
31
|
+
conflicts.push({
|
|
32
|
+
left: { resourceKey: leftClaim.resourceKey, mode: leftClaim.mode },
|
|
33
|
+
right: { resourceKey: rightClaim.resourceKey, mode: rightClaim.mode },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return conflicts;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Produce deterministic execution waves from the exact same resource-claim model
|
|
42
|
+
* used by Process Runtime. Checks in one wave may overlap; waves run in order.
|
|
43
|
+
* This is advisory scheduling metadata, not a second lease authority.
|
|
44
|
+
*/
|
|
45
|
+
export function buildCheckExecutionSchedule(input: {
|
|
46
|
+
checks: ControllerCheck[];
|
|
47
|
+
requestedCheckIds: string[];
|
|
48
|
+
repoId: string;
|
|
49
|
+
checkoutId?: string;
|
|
50
|
+
}): {
|
|
51
|
+
waves: CheckExecutionWave[];
|
|
52
|
+
conflicts: CheckExecutionConflict[];
|
|
53
|
+
invalidCheckIds: string[];
|
|
54
|
+
maxParallel: number;
|
|
55
|
+
guidance: string[];
|
|
56
|
+
claimsByCheck: Array<{ checkId: string; claims: Array<Pick<ResourceClaimSpec, 'resourceKey' | 'mode'>> }>;
|
|
57
|
+
} {
|
|
58
|
+
const byId = new Map(input.checks.map((check) => [check.id, check]));
|
|
59
|
+
const requested = [...new Set(input.requestedCheckIds.filter(Boolean))];
|
|
60
|
+
const invalidCheckIds = requested.filter((checkId) => !byId.has(checkId));
|
|
61
|
+
const scheduled: ScheduledCheck[] = requested.flatMap((checkId) => {
|
|
62
|
+
const check = byId.get(checkId);
|
|
63
|
+
if (!check) return [];
|
|
64
|
+
return [{
|
|
65
|
+
check,
|
|
66
|
+
claims: claimsForCheck(check.id, check.command, input.repoId, input.checkoutId, check.effects),
|
|
67
|
+
}];
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const conflicts: CheckExecutionConflict[] = [];
|
|
71
|
+
for (let leftIndex = 0; leftIndex < scheduled.length; leftIndex += 1) {
|
|
72
|
+
for (let rightIndex = leftIndex + 1; rightIndex < scheduled.length; rightIndex += 1) {
|
|
73
|
+
const left = scheduled[leftIndex]!;
|
|
74
|
+
const right = scheduled[rightIndex]!;
|
|
75
|
+
const resources = conflictingResources(left, right);
|
|
76
|
+
if (resources.length === 0) continue;
|
|
77
|
+
conflicts.push({ leftCheckId: left.check.id, rightCheckId: right.check.id, resources });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const waves: ScheduledCheck[][] = [];
|
|
82
|
+
for (const entry of scheduled) {
|
|
83
|
+
const compatible = waves.find((wave) => wave.every((other) => conflictingResources(entry, other).length === 0));
|
|
84
|
+
if (compatible) compatible.push(entry);
|
|
85
|
+
else waves.push([entry]);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const projectedWaves = waves.map((wave, index) => ({
|
|
89
|
+
wave: index + 1,
|
|
90
|
+
checkIds: wave.map((entry) => entry.check.id),
|
|
91
|
+
parallelSafe: wave.length > 1,
|
|
92
|
+
}));
|
|
93
|
+
const maxParallel = projectedWaves.reduce((max, wave) => Math.max(max, wave.checkIds.length), 0);
|
|
94
|
+
const guidance: string[] = [];
|
|
95
|
+
if (projectedWaves.length > 1) {
|
|
96
|
+
guidance.push('Run check waves in order; only checks within the same wave are resource-compatible for overlap.');
|
|
97
|
+
} else if (maxParallel > 1) {
|
|
98
|
+
guidance.push('Requested checks are resource-compatible and may run concurrently for this checkout.');
|
|
99
|
+
} else if (maxParallel === 1) {
|
|
100
|
+
guidance.push('Run the requested check as one focused verification unit.');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
waves: projectedWaves,
|
|
105
|
+
conflicts,
|
|
106
|
+
invalidCheckIds,
|
|
107
|
+
maxParallel,
|
|
108
|
+
guidance,
|
|
109
|
+
claimsByCheck: scheduled.map((entry) => ({
|
|
110
|
+
checkId: entry.check.id,
|
|
111
|
+
claims: entry.claims.map((claim) => ({ resourceKey: claim.resourceKey, mode: claim.mode })),
|
|
112
|
+
})),
|
|
113
|
+
};
|
|
114
|
+
}
|