@moretea-labs/forge 1.6.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -0
- package/CHANGELOG.md +39 -0
- package/CLAUDE.md +4 -0
- package/README.md +2 -2
- package/README.zh-CN.md +1 -1
- 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/prompt-guard.sh +5 -81
- package/assets/hooks/session-start-context.sh +56 -1
- package/assets/partials/05-workflow.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +2 -0
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +3 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.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-architecture-sync.sh +17 -0
- 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 +11 -36
- package/assets/templates/helpers/inspect-project-state.ts +8 -6
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
- 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/verify-contract.sh +1 -111
- package/assets/templates/helpers/verify-sprint.sh +3 -180
- package/assets/templates/helpers/workflow-contract.ts +5 -1
- 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 +178 -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-plugin-management.md +1 -1
- package/docs/forge-runtime-self-healing-loop.md +1 -1
- package/docs/operations/controller-browser-plugin.md +26 -6
- package/docs/operations/controller-performance-and-502.md +143 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +2 -2
- 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/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/package.json +33 -11
- package/scripts/activate-source-baseline.ts +17 -13
- package/scripts/architecture-event.ts +2 -820
- package/scripts/architecture-queue.sh +2 -645
- package/scripts/archive-architecture-request.sh +2 -242
- package/scripts/archive-workflow.sh +1 -291
- 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/capability-config.ts +2 -392
- package/scripts/capability-resolver.ts +2 -503
- package/scripts/capture-plan.sh +1 -332
- package/scripts/check-agent-tooling.sh +2 -1558
- package/scripts/check-architecture-sync.sh +2 -371
- package/scripts/check-brain-manifest.sh +2 -253
- package/scripts/check-context-files.sh +2 -47
- package/scripts/check-deploy-sql-order.sh +2 -115
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-runtime-architecture.mjs +349 -79
- package/scripts/check-skill-version.ts +3 -191
- package/scripts/check-source-duplication.mjs +61 -0
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-sync.sh +2 -63
- package/scripts/check-task-workflow.sh +2 -1000
- package/scripts/codex-handoff-resume.sh +2 -267
- package/scripts/context-contract-sync.sh +2 -514
- package/scripts/contract-run.ts +2 -463
- package/scripts/contract-worktree.sh +1 -722
- package/scripts/ensure-task-workflow.sh +1 -1225
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/inspect-project-state.ts +4 -279
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +22 -46
- package/scripts/lib/run-forge-helper.sh +19 -0
- package/scripts/lib/run-forge-helper.ts +26 -0
- package/scripts/migrate-project-template.sh +1 -1189
- package/scripts/migrate-workflow-docs.ts +4 -412
- package/scripts/new-plan.sh +1 -180
- package/scripts/new-spec.sh +1 -47
- package/scripts/new-sprint.sh +1 -46
- package/scripts/plan-to-todo.sh +1 -796
- package/scripts/prepare-codex-handoff.sh +2 -201
- package/scripts/prepare-handoff.sh +1 -78
- package/scripts/refresh-current-status.sh +2 -467
- package/scripts/run-governed-gate.ts +5 -1
- package/scripts/select-agent-context-blocks.sh +2 -64
- package/scripts/ship-worktrees.sh +1 -558
- 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 -834
- package/scripts/stage-runtime-release.ts +2 -1
- package/scripts/summarize-failures.sh +2 -123
- package/scripts/switch-plan.sh +1 -150
- package/scripts/sync-brain-docs.sh +2 -379
- package/scripts/sync-generated-authority.mjs +175 -0
- package/scripts/verify-contract.sh +2 -703
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +1 -677
- package/scripts/workflow-contract.ts +4 -205
- package/scripts/workstream-sync.sh +2 -261
- package/src/cli/agent-jobs/executor-health.ts +1 -1
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +12 -3
- 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 +113 -5
- 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 +828 -487
- 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/contracts.ts +16 -0
- package/src/cli/github/github.ts +135 -16
- package/src/cli/github/session.ts +2 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +54 -78
- package/src/cli/local-bridge/console-view-models.ts +1 -35
- package/src/cli/local-bridge/facade-api.ts +37 -264
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
- package/src/cli/local-bridge/frontend/src/styles.css +1 -1
- package/src/cli/local-bridge/frontend/src/types.ts +5 -8
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +2 -515
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
- package/src/cli/mcp/auth.ts +5 -5
- package/src/cli/mcp/instructions.ts +3 -2
- package/src/cli/mcp/legacy-tool-service.ts +10 -222
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
- package/src/cli/mcp/repository-tools.ts +282 -146
- package/src/cli/mcp/server.ts +586 -116
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/tool-contract.ts +14 -0
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +44 -7
- package/src/cli/mcp/transports/http.ts +124 -14
- package/src/cli/mcp/transports/session-registry.ts +43 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +103 -21
- package/src/cli/repositories/command-executor.ts +78 -526
- 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 +124 -0
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +118 -6
- package/src/cli/repository/inspector.ts +563 -65
- 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-contract.ts +61 -0
- package/src/runtime/context/semantic-navigation.ts +223 -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 +48 -16
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
- package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
- package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
- package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
- package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
- 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-operation-service.ts +468 -0
- package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
- package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
- package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +22 -18
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +156 -11
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
- package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
- package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +90 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +1118 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +302 -12
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +17 -1
- package/src/runtime/control-plane/facade/goal-workloop.ts +928 -190
- package/src/runtime/control-plane/facade/index.ts +3 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +275 -42
- package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
- package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
- 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 +90 -10
- package/src/runtime/control-plane/facade/work-contract-store.ts +157 -261
- package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
- 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 +152 -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 +278 -543
- 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 +63 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +365 -117
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +89 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +244 -11
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
- 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/repo-actor/registry.ts +4 -2
- package/src/runtime/control-plane/routing/route-policy.ts +24 -21
- package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
- package/src/runtime/control-plane/runtime-status-client.ts +0 -2
- package/src/runtime/diagnostics/mcp-timing.ts +13 -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/evidence/process-check-execution.ts +18 -0
- package/src/runtime/execution/jobs/child-reference.ts +6 -2
- 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 +51 -4
- package/src/runtime/execution/process-runtime/check-result.ts +88 -0
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +367 -40
- package/src/runtime/execution/process-runtime/gc.ts +38 -6
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1201 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +51 -5
- package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
- package/src/runtime/execution/process-runtime/runtime.ts +53 -3
- package/src/runtime/execution/process-runtime/store.ts +1 -0
- package/src/runtime/execution/process-runtime/types.ts +4 -12
- 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/work-activity.ts +21 -0
- package/src/runtime/execution/workers/executor.ts +18 -61
- package/src/runtime/gateway/mcp/execution-tools.ts +35 -1852
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +186 -84
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +565 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2378 -1947
- package/src/runtime/plugins/app-store-connect-adapter.ts +216 -47
- package/src/runtime/plugins/browser-adapter.ts +2662 -829
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +2 -25
- package/src/runtime/plugins/browser-handoff.ts +110 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +701 -63
- package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
- package/src/runtime/plugins/browser-native-session-service.ts +222 -0
- 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 +154 -0
- package/src/runtime/plugins/browser-runtime.ts +193 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/browser-session-store.ts +121 -0
- package/src/runtime/plugins/browser-session-types.ts +98 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +10 -4
- package/src/runtime/plugins/external-adapter.ts +358 -3
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +2 -0
- package/src/runtime/plugins/github-adapter.ts +125 -0
- 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 +123 -6
- package/src/runtime/plugins/macos-capability-broker.ts +47 -9
- package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
- package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +330 -33
- package/src/runtime/plugins/types.ts +38 -3
- 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/maintenance-executor.ts +426 -25
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +230 -10
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +461 -22
- package/src/runtime/root/release-manifest.ts +144 -18
- package/src/runtime/root/release-materialize.ts +125 -32
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -29
- package/src/runtime/root/types.ts +12 -0
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- 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 +1079 -240
- package/src/runtime/standalone-recovery/entry.ts +100 -24
- package/src/runtime/standalone-recovery/installer.ts +20 -4
- 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 +81 -3
- package/src/runtime/workflow/schedules/engine.ts +364 -202
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +64 -17
- package/src/runtime/workflow/schedules/store.ts +209 -19
- package/src/runtime/workflow/schedules/types.ts +2 -4
- package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
- 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/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 -459
- package/docs/architecture/current/codegraph-context-provider.md +0 -238
- 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 -373
- package/docs/architecture/current/entity-model.md +0 -612
- 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 -169
- 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 -321
- 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 -93
- 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/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;
|
|
@@ -143,8 +154,9 @@ export async function runCheckViaProcessRuntime(
|
|
|
143
154
|
};
|
|
144
155
|
}
|
|
145
156
|
|
|
146
|
-
//
|
|
147
|
-
//
|
|
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.
|
|
148
160
|
const interactiveWaitMs = durationAwareInteractiveWaitMs(
|
|
149
161
|
check.command,
|
|
150
162
|
input.interactiveWaitMs,
|
|
@@ -156,6 +168,14 @@ export async function runCheckViaProcessRuntime(
|
|
|
156
168
|
? Math.max(1_000, Math.trunc(input.timeoutMs))
|
|
157
169
|
: check.timeoutMs,
|
|
158
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
|
+
);
|
|
159
179
|
if (!input.executionIdentity) {
|
|
160
180
|
throw new Error('EXECUTION_IDENTITY_REQUIRED: run_check requires an immutable executionIdentity');
|
|
161
181
|
}
|
|
@@ -170,6 +190,27 @@ export async function runCheckViaProcessRuntime(
|
|
|
170
190
|
`CHECKOUT_ROUTE_MISMATCH: check checkout ${input.checkoutId} differs from identity ${executionIdentity.checkoutId}`,
|
|
171
191
|
);
|
|
172
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
|
+
}
|
|
173
214
|
const claims = scopeResourceClaims(
|
|
174
215
|
claimsForCheck(
|
|
175
216
|
input.checkId,
|
|
@@ -252,6 +293,9 @@ export async function waitForCheckProcess(
|
|
|
252
293
|
processId: string,
|
|
253
294
|
timeoutMs?: number,
|
|
254
295
|
): Promise<ProcessHandle> {
|
|
296
|
+
if (isLightweightProcessId(processId)) {
|
|
297
|
+
return waitForLightweightProcess(controllerHome, repoId, processId, { timeoutMs });
|
|
298
|
+
}
|
|
255
299
|
return waitForProcess(controllerHome, repoId, processId, { timeoutMs });
|
|
256
300
|
}
|
|
257
301
|
|
|
@@ -260,6 +304,9 @@ export function getCheckProcessHandle(
|
|
|
260
304
|
repoId: string,
|
|
261
305
|
processId: string,
|
|
262
306
|
): ProcessHandle | undefined {
|
|
307
|
+
if (isLightweightProcessId(processId)) {
|
|
308
|
+
return getLightweightProcessHandle(controllerHome, repoId, processId);
|
|
309
|
+
}
|
|
263
310
|
return getProcessHandle(controllerHome, repoId, processId);
|
|
264
311
|
}
|
|
265
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;
|
|
@@ -51,3 +52,90 @@ export function readPersistedCheckResultReceipt(path: string | undefined): Persi
|
|
|
51
52
|
return undefined;
|
|
52
53
|
}
|
|
53
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
|
+
export interface TerminalCheckEvidenceClassificationInput {
|
|
70
|
+
processError?: { code: string; message: string };
|
|
71
|
+
structuredPresent: boolean;
|
|
72
|
+
structuredMatches: boolean;
|
|
73
|
+
legacyPresent: boolean;
|
|
74
|
+
legacyMatches: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Compatibility-level classifier for terminal Check evidence. Keep this pure so
|
|
79
|
+
* legacy/public callers and the Process Runtime record adapter share one semantic
|
|
80
|
+
* authority instead of carrying duplicate decision trees.
|
|
81
|
+
*/
|
|
82
|
+
export function classifyTerminalCheckEvidence(
|
|
83
|
+
input: TerminalCheckEvidenceClassificationInput,
|
|
84
|
+
): PersistedCheckTerminalEvidence {
|
|
85
|
+
if (input.structuredMatches || input.legacyMatches) return { state: 'matched' };
|
|
86
|
+
if (!input.structuredPresent && !input.legacyPresent && input.processError?.message?.trim()) {
|
|
87
|
+
const reason = input.processError.message.trim().slice(0, 512);
|
|
88
|
+
return {
|
|
89
|
+
state: 'process_runtime_failed_before_result',
|
|
90
|
+
warning: `check process failed before structured result receipt: ${reason}`,
|
|
91
|
+
infrastructureReason: reason,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (input.structuredPresent || input.legacyPresent) {
|
|
95
|
+
return { state: 'mismatch', warning: 'check result receipt did not match the terminal Process semantic identity' };
|
|
96
|
+
}
|
|
97
|
+
return { state: 'missing', warning: 'check result receipt is missing for the terminal Check Process' };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Classify one terminal Check Process using the structured result emitted by
|
|
102
|
+
* the check-runner sidecar. A Process Runtime/admission failure can terminate
|
|
103
|
+
* before that result exists (for example PROCESS_LEASE_CONFLICT); such a
|
|
104
|
+
* Process is infrastructure failure, never evidence that repository checks
|
|
105
|
+
* rejected the candidate. Missing/mismatched result identity also fails closed
|
|
106
|
+
* as infrastructure rather than manufacturing acceptance evidence.
|
|
107
|
+
*/
|
|
108
|
+
export interface LegacyCheckEvidenceLike {
|
|
109
|
+
cacheKey?: string;
|
|
110
|
+
failureClass?: PersistedCheckResultReceipt['failureClass'];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function classifyPersistedCheckTerminalEvidence(
|
|
114
|
+
record: ManagedProcessRecord,
|
|
115
|
+
expectedCheckId: string,
|
|
116
|
+
options: { legacyEvidence?: LegacyCheckEvidenceLike } = {},
|
|
117
|
+
): PersistedCheckTerminalEvidence {
|
|
118
|
+
const structured = readPersistedCheckResultReceipt(record.origin?.checkResultReceiptPath);
|
|
119
|
+
const structuredMatches = Boolean(
|
|
120
|
+
structured
|
|
121
|
+
&& record.checkExecution
|
|
122
|
+
&& structured.checkId === expectedCheckId
|
|
123
|
+
&& structured.cacheKey === record.checkExecution.cacheKey,
|
|
124
|
+
);
|
|
125
|
+
const legacy = options.legacyEvidence;
|
|
126
|
+
const legacyMatches = Boolean(
|
|
127
|
+
legacy?.cacheKey
|
|
128
|
+
&& record.checkExecution?.cacheKey
|
|
129
|
+
&& legacy.cacheKey === record.checkExecution.cacheKey,
|
|
130
|
+
);
|
|
131
|
+
const classified = classifyTerminalCheckEvidence({
|
|
132
|
+
processError: record.error,
|
|
133
|
+
structuredPresent: Boolean(structured),
|
|
134
|
+
structuredMatches,
|
|
135
|
+
legacyPresent: Boolean(legacy),
|
|
136
|
+
legacyMatches,
|
|
137
|
+
});
|
|
138
|
+
return classified.state === 'matched'
|
|
139
|
+
? { ...classified, failureClass: structuredMatches ? structured?.failureClass : legacy?.failureClass }
|
|
140
|
+
: classified;
|
|
141
|
+
}
|
|
@@ -16,6 +16,7 @@ interface ParsedArgs {
|
|
|
16
16
|
expectedCheckFingerprint: string;
|
|
17
17
|
resultReceiptPath?: string;
|
|
18
18
|
cleanupRoot?: string;
|
|
19
|
+
isolatedControllerHome?: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
function requiredValue(argv: string[], flag: string): string {
|
|
@@ -38,6 +39,7 @@ function parseArgs(argv: string[]): ParsedArgs {
|
|
|
38
39
|
expectedCheckFingerprint: requiredValue(argv, '--expected-check-fingerprint'),
|
|
39
40
|
resultReceiptPath: argv.includes('--result-receipt') ? requiredValue(argv, '--result-receipt') : undefined,
|
|
40
41
|
cleanupRoot: argv.includes('--cleanup-root') ? requiredValue(argv, '--cleanup-root') : undefined,
|
|
42
|
+
isolatedControllerHome: argv.includes('--isolated-controller-home') ? requiredValue(argv, '--isolated-controller-home') : undefined,
|
|
41
43
|
};
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -51,7 +53,11 @@ export async function runPersistedCheckSidecar(argv = process.argv.slice(2)): Pr
|
|
|
51
53
|
throw new Error('CHECK_SNAPSHOT_CHANGED: registered check changed before Process Runtime execution');
|
|
52
54
|
}
|
|
53
55
|
const identity = controllerCheckExecutionIdentity(root, args.checkId, args.timeoutMs, snapshot);
|
|
54
|
-
const result = await runControllerCheckAsync(root, args.checkId, {
|
|
56
|
+
const result = await runControllerCheckAsync(root, args.checkId, {
|
|
57
|
+
requestedTimeoutMs: args.timeoutMs,
|
|
58
|
+
snapshot,
|
|
59
|
+
isolatedControllerHome: args.isolatedControllerHome,
|
|
60
|
+
});
|
|
55
61
|
if (args.resultReceiptPath) {
|
|
56
62
|
writePersistedCheckResultReceipt(args.resultReceiptPath, {
|
|
57
63
|
checkId: args.checkId,
|
|
@@ -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
|
+
}
|