@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,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'crypto';
|
|
2
2
|
|
|
3
|
-
export const ROUTE_POLICY_VERSION = 'route-policy-
|
|
3
|
+
export const ROUTE_POLICY_VERSION = 'route-policy-v5' as const;
|
|
4
4
|
|
|
5
5
|
export type RouteExecutionMode = 'direct_control' | 'goal_workloop' | 'handoff_only';
|
|
6
6
|
export type RouteWorkMode = 'direct_edit' | 'bounded_work' | 'quick_agent' | 'issue_task';
|
|
@@ -50,6 +50,10 @@ export interface RoutePolicyInput {
|
|
|
50
50
|
dirty?: boolean;
|
|
51
51
|
checkoutId?: string;
|
|
52
52
|
fingerprint?: string;
|
|
53
|
+
/** Canonical typed placement constraint resolved before routing. */
|
|
54
|
+
placement?: 'current' | 'isolated' | 'auto';
|
|
55
|
+
/** Admission fence: Direct Control/current-main mutation is not permitted. */
|
|
56
|
+
directMainProhibited?: boolean;
|
|
53
57
|
};
|
|
54
58
|
policy: {
|
|
55
59
|
risk?: string;
|
|
@@ -234,12 +238,12 @@ export function decideRoute(input: RoutePolicyInput): RouteDecision {
|
|
|
234
238
|
const protectedPath = paths.some((path) => PROTECTED_PATH.test(path));
|
|
235
239
|
const explicitMode = input.intent.explicitMode;
|
|
236
240
|
const explicitParallelMode = explicitMode === 'scale';
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
241
|
+
const placementIsolationRequired = input.workspace.placement === 'isolated'
|
|
242
|
+
|| input.workspace.directMainProhibited === true;
|
|
243
|
+
const requiresIsolation = placementIsolationRequired
|
|
244
|
+
|| input.recovery.isolationRequired === true
|
|
245
|
+
|| explicitParallelMode;
|
|
240
246
|
const requiresRecovery = input.recovery.required === true
|
|
241
|
-
|| input.intent.requiresLongRunningChecks === true
|
|
242
|
-
|| explicitMode === 'debug'
|
|
243
247
|
|| explicitMode === 'release'
|
|
244
248
|
|| explicitMode === 'scale';
|
|
245
249
|
const coordinationRequired = explicitParallelMode || input.intent.requiresIndependentDeliverables === true
|
|
@@ -289,28 +293,29 @@ export function decideRoute(input: RoutePolicyInput): RouteDecision {
|
|
|
289
293
|
}
|
|
290
294
|
|
|
291
295
|
if (input.workspace.dirty && mutation) {
|
|
292
|
-
reasons.push({
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
requiresIsolation: true, requiresRecovery: true, createHandoff: true, waitForUser: false,
|
|
297
|
-
approvalState: 'approval_not_required', alternatives: [], ...decisionBase(input, reasons),
|
|
298
|
-
};
|
|
296
|
+
reasons.push({
|
|
297
|
+
code: 'dirty_workspace_preserve_existing_changes',
|
|
298
|
+
message: 'The checkout is already dirty; preserve unrelated changes and treat inspected/actual scope as evidence instead of creating Work solely for adoption.',
|
|
299
|
+
});
|
|
299
300
|
}
|
|
300
301
|
if (explicitMode) reasons.push({ code: `explicit_${explicitMode}`, message: `Explicit -${explicitMode} mode overrides automatic work topology while policy gates remain authoritative.` });
|
|
301
302
|
if (protectedPath) reasons.push({ code: 'protected_path', message: 'The predicted scope includes a protected or release-sensitive path.' });
|
|
302
303
|
if (requiresRecovery) reasons.push({ code: 'recovery_required', message: 'The operation needs resumable Work and bounded recovery.' });
|
|
304
|
+
if (input.workspace.placement === 'isolated') reasons.push({ code: 'placement_isolated', message: 'Typed Work admission requires an isolated workspace.' });
|
|
305
|
+
if (input.workspace.directMainProhibited === true) reasons.push({ code: 'direct_main_prohibited', message: 'Typed Work admission forbids the Direct Control/current-main mutation lane.' });
|
|
303
306
|
if (requiresIsolation) reasons.push({ code: 'isolation_required', message: 'The operation requires an isolated checkout or serialized lane.' });
|
|
304
|
-
if (input.intent.requiresLongRunningChecks) reasons.push({ code: 'long_checks', message: 'Long-running checks require durable
|
|
307
|
+
if (input.intent.requiresLongRunningChecks) reasons.push({ code: 'long_checks', message: 'Long-running checks may use a lightweight handle; duration alone does not require durable Work.' });
|
|
305
308
|
if (input.intent.requiresInvestigation) reasons.push({ code: 'investigation', message: 'Investigation is required before or during implementation.' });
|
|
306
309
|
if (input.intent.needsDependencies) reasons.push({ code: 'dependencies', message: 'Dependency ordering requires durable Work.' });
|
|
307
310
|
if (coordinationRequired) reasons.push({ code: 'independent_deliverables', message: 'Multiple independent deliverables require durable PlanContract/Work coordination.' });
|
|
308
311
|
|
|
309
312
|
const explicitBoundedMode = explicitMode === 'plan'
|
|
310
|
-
|| explicitMode === 'debug'
|
|
311
|
-
|| explicitMode === 'review'
|
|
312
313
|
|| explicitMode === 'release';
|
|
313
|
-
const
|
|
314
|
+
const directModeCanRemainFast = explicitMode === 'direct'
|
|
315
|
+
&& !requiresIsolation
|
|
316
|
+
&& !requiresRecovery
|
|
317
|
+
&& !coordinationRequired;
|
|
318
|
+
const complex = directModeCanRemainFast
|
|
314
319
|
? false
|
|
315
320
|
: coordinationRequired
|
|
316
321
|
|| explicitBoundedMode
|
|
@@ -320,16 +325,14 @@ export function decideRoute(input: RoutePolicyInput): RouteDecision {
|
|
|
320
325
|
|| input.capabilities.requiresWorker === true
|
|
321
326
|
|| input.capabilities.requiresExternalEffect === true
|
|
322
327
|
|| input.intent.needsDependencies === true
|
|
323
|
-
|| protectedPath
|
|
324
328
|
|| destructive
|
|
325
329
|
|| remoteWrite
|
|
326
|
-
|| secretAccess
|
|
327
|
-
|| (mutation && (expectedFiles > 4 || expectedChangedLines > 200));
|
|
330
|
+
|| secretAccess;
|
|
328
331
|
const executionMode: RouteExecutionMode = complex ? 'goal_workloop' : 'direct_control';
|
|
329
332
|
// Work topology is independent from executor/provider choice. Independent or
|
|
330
333
|
// parallel deliverables stay in the durable Goal Workloop and are decomposed by
|
|
331
334
|
// PlanContract/Work rather than introducing another project-level lifecycle.
|
|
332
|
-
const workMode: RouteWorkMode =
|
|
335
|
+
const workMode: RouteWorkMode = directModeCanRemainFast
|
|
333
336
|
? 'direct_edit'
|
|
334
337
|
: coordinationRequired
|
|
335
338
|
? 'bounded_work'
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export type WorkspacePlacementMode = 'current' | 'isolated' | 'auto';
|
|
2
|
+
|
|
3
|
+
export interface WorkspaceAdmissionConstraintInput {
|
|
4
|
+
workspaceMode?: WorkspacePlacementMode;
|
|
5
|
+
requireWorktree?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Forbid repository mutation through the current/direct-main lane. This is
|
|
8
|
+
* an admission constraint, not a routing hint: callers must never silently
|
|
9
|
+
* downgrade it to Direct Control.
|
|
10
|
+
*/
|
|
11
|
+
directMainProhibited?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface WorkspaceAdmissionConstraint {
|
|
15
|
+
workspaceMode: WorkspacePlacementMode;
|
|
16
|
+
requireWorktree: boolean;
|
|
17
|
+
directMainProhibited: boolean;
|
|
18
|
+
requiresIsolation: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type WorkspaceAdmissionResolution =
|
|
22
|
+
| { ok: true; constraint: WorkspaceAdmissionConstraint }
|
|
23
|
+
| { ok: false; code: 'WORKSPACE_PLACEMENT_CONSTRAINT_CONFLICT'; message: string };
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Canonicalize Work placement before Route Policy runs. Placement is a policy
|
|
27
|
+
* fence: explicit isolation / direct-main prohibition has precedence over an
|
|
28
|
+
* operator request for the fast Direct Control topology.
|
|
29
|
+
*/
|
|
30
|
+
export function resolveWorkspaceAdmissionConstraint(
|
|
31
|
+
input: WorkspaceAdmissionConstraintInput = {},
|
|
32
|
+
): WorkspaceAdmissionResolution {
|
|
33
|
+
const workspaceMode = input.workspaceMode ?? 'auto';
|
|
34
|
+
const directMainProhibited = input.directMainProhibited === true;
|
|
35
|
+
|
|
36
|
+
if (workspaceMode === 'current' && input.requireWorktree === true) {
|
|
37
|
+
return {
|
|
38
|
+
ok: false,
|
|
39
|
+
code: 'WORKSPACE_PLACEMENT_CONSTRAINT_CONFLICT',
|
|
40
|
+
message: 'workspaceMode=current conflicts with requireWorktree=true.',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (workspaceMode === 'isolated' && input.requireWorktree === false) {
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
code: 'WORKSPACE_PLACEMENT_CONSTRAINT_CONFLICT',
|
|
47
|
+
message: 'workspaceMode=isolated conflicts with requireWorktree=false.',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (workspaceMode === 'current' && directMainProhibited) {
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
code: 'WORKSPACE_PLACEMENT_CONSTRAINT_CONFLICT',
|
|
54
|
+
message: 'workspaceMode=current conflicts with directMainProhibited=true because the current lane cannot prove a non-main placement at admission time.',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const requiresIsolation = workspaceMode === 'isolated'
|
|
59
|
+
|| input.requireWorktree === true
|
|
60
|
+
|| directMainProhibited;
|
|
61
|
+
return {
|
|
62
|
+
ok: true,
|
|
63
|
+
constraint: {
|
|
64
|
+
workspaceMode: requiresIsolation ? 'isolated' : workspaceMode,
|
|
65
|
+
requireWorktree: requiresIsolation,
|
|
66
|
+
directMainProhibited,
|
|
67
|
+
requiresIsolation,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { resolveControllerHome } from '../../cli/repositories/controller-home';
|
|
2
2
|
import { readSchedulerHealthSnapshot } from './global-scheduler/scheduler';
|
|
3
|
-
import type { ControllerStartupRecoveryResult } from './startup-recovery';
|
|
4
3
|
import type { RuntimeSourceIdentity } from './runtime-generation';
|
|
5
4
|
import { readRuntimeOwner } from '../root/ownership';
|
|
6
5
|
import { observeRuntimeStatus } from '../root/status';
|
|
@@ -26,7 +25,6 @@ export interface ForgeRuntimeStatus {
|
|
|
26
25
|
gatewaySeparated?: boolean;
|
|
27
26
|
workerIsolation?: boolean;
|
|
28
27
|
degraded?: boolean;
|
|
29
|
-
recovery?: ControllerStartupRecoveryResult;
|
|
30
28
|
generation?: string;
|
|
31
29
|
source?: RuntimeSourceIdentity;
|
|
32
30
|
restartRequired?: boolean;
|
|
@@ -21,6 +21,19 @@ export interface McpTimingTrace {
|
|
|
21
21
|
commandExecutionMs?: number;
|
|
22
22
|
resultSerializationMs?: number;
|
|
23
23
|
resultPersistenceMs?: number;
|
|
24
|
+
/** Public Gateway only: resolve current Canonical Runtime identity/token/endpoint. */
|
|
25
|
+
gatewayProxyResolveMs?: number;
|
|
26
|
+
/** Public Gateway only: establish or await a Canonical Runtime MCP client connection. */
|
|
27
|
+
gatewayProxyConnectMs?: number;
|
|
28
|
+
/** Public Gateway only: MCP call duration after a client is acquired, including Canonical Runtime work. */
|
|
29
|
+
gatewayProxyCallMs?: number;
|
|
30
|
+
/** Public Gateway only: time from forwarding the tool call until the Canonical Runtime handler starts. */
|
|
31
|
+
gatewayProxyCanonicalDispatchLagMs?: number;
|
|
32
|
+
/** Canonical Runtime server duration projected back through the proxy response. */
|
|
33
|
+
gatewayProxyCanonicalDurationMs?: number;
|
|
34
|
+
/** Public Gateway only: response/transport tail after canonical handler completion. */
|
|
35
|
+
gatewayProxyReturnMs?: number;
|
|
36
|
+
gatewayProxyConnectionState?: 'reused' | 'cold_connect' | 'coalesced_connect' | 'identity_reconnect';
|
|
24
37
|
totalToolDurationMs: number;
|
|
25
38
|
sessionId?: string;
|
|
26
39
|
repoId?: string;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
export type McpTransportTimingScope = 'tool_call' | 'connect_and_tool_call';
|
|
2
|
+
|
|
3
|
+
export interface McpTransportLatencySample {
|
|
4
|
+
label: string;
|
|
5
|
+
tool: string;
|
|
6
|
+
timingScope?: McpTransportTimingScope;
|
|
7
|
+
clientTotalMs: number;
|
|
8
|
+
serverDurationMs: number;
|
|
9
|
+
traceId?: string;
|
|
10
|
+
requestId?: string;
|
|
11
|
+
observedAt?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface McpTransportLatencyStats {
|
|
15
|
+
p50: number;
|
|
16
|
+
p95: number;
|
|
17
|
+
max: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface McpTransportLatencyGroup {
|
|
21
|
+
label: string;
|
|
22
|
+
tool: string;
|
|
23
|
+
timingScope: McpTransportTimingScope;
|
|
24
|
+
sampleCount: number;
|
|
25
|
+
clientTotalMs: McpTransportLatencyStats;
|
|
26
|
+
serverDurationMs: McpTransportLatencyStats;
|
|
27
|
+
externalResidualMs: McpTransportLatencyStats;
|
|
28
|
+
externalSharePct: McpTransportLatencyStats;
|
|
29
|
+
serverExceedsClientCount: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface McpTransportLatencyReport {
|
|
33
|
+
schemaVersion: 1;
|
|
34
|
+
sampleCount: number;
|
|
35
|
+
groups: McpTransportLatencyGroup[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function round(value: number): number {
|
|
39
|
+
return Math.round(value * 100) / 100;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function percentile(values: number[], fraction: number): number {
|
|
43
|
+
if (values.length === 0) return 0;
|
|
44
|
+
const sorted = [...values].sort((left, right) => left - right);
|
|
45
|
+
const index = Math.max(0, Math.min(sorted.length - 1, Math.ceil(sorted.length * fraction) - 1));
|
|
46
|
+
return round(sorted[index]!);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function stats(values: number[]): McpTransportLatencyStats {
|
|
50
|
+
return {
|
|
51
|
+
p50: percentile(values, 0.5),
|
|
52
|
+
p95: percentile(values, 0.95),
|
|
53
|
+
max: round(Math.max(...values, 0)),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function validDuration(value: unknown): value is number {
|
|
58
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function normalizeMcpTransportLatencySample(value: unknown): McpTransportLatencySample {
|
|
62
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
63
|
+
throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: sample must be an object');
|
|
64
|
+
}
|
|
65
|
+
const record = value as Record<string, unknown>;
|
|
66
|
+
const label = typeof record.label === 'string' ? record.label.trim() : '';
|
|
67
|
+
const tool = typeof record.tool === 'string' ? record.tool.trim() : '';
|
|
68
|
+
const timingScope = record.timingScope === undefined || record.timingScope === 'tool_call'
|
|
69
|
+
? 'tool_call'
|
|
70
|
+
: record.timingScope === 'connect_and_tool_call'
|
|
71
|
+
? 'connect_and_tool_call'
|
|
72
|
+
: undefined;
|
|
73
|
+
if (!label) throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: label is required');
|
|
74
|
+
if (!tool) throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: tool is required');
|
|
75
|
+
if (!timingScope) throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: timingScope must be tool_call or connect_and_tool_call');
|
|
76
|
+
if (!validDuration(record.clientTotalMs)) throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: clientTotalMs must be a non-negative finite number');
|
|
77
|
+
if (!validDuration(record.serverDurationMs)) throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: serverDurationMs must be a non-negative finite number');
|
|
78
|
+
return {
|
|
79
|
+
label,
|
|
80
|
+
tool,
|
|
81
|
+
timingScope,
|
|
82
|
+
clientTotalMs: record.clientTotalMs,
|
|
83
|
+
serverDurationMs: record.serverDurationMs,
|
|
84
|
+
...(typeof record.traceId === 'string' && record.traceId.trim() ? { traceId: record.traceId.trim() } : {}),
|
|
85
|
+
...(typeof record.requestId === 'string' && record.requestId.trim() ? { requestId: record.requestId.trim() } : {}),
|
|
86
|
+
...(typeof record.observedAt === 'string' && record.observedAt.trim() ? { observedAt: record.observedAt.trim() } : {}),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function extractForgeServerDuration(result: unknown): number | undefined {
|
|
91
|
+
if (!result || typeof result !== 'object' || Array.isArray(result)) return undefined;
|
|
92
|
+
const structured = (result as Record<string, unknown>).structuredContent;
|
|
93
|
+
if (!structured || typeof structured !== 'object' || Array.isArray(structured)) return undefined;
|
|
94
|
+
const responseMeta = (structured as Record<string, unknown>).responseMeta;
|
|
95
|
+
if (!responseMeta || typeof responseMeta !== 'object' || Array.isArray(responseMeta)) return undefined;
|
|
96
|
+
const duration = (responseMeta as Record<string, unknown>).serverDurationMs;
|
|
97
|
+
return validDuration(duration) ? duration : undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function aggregateMcpTransportLatencySamples(values: unknown[]): McpTransportLatencyReport {
|
|
101
|
+
const samples = values.map(normalizeMcpTransportLatencySample);
|
|
102
|
+
const grouped = new Map<string, McpTransportLatencySample[]>();
|
|
103
|
+
for (const sample of samples) {
|
|
104
|
+
const key = `${sample.label}\u0000${sample.tool}\u0000${sample.timingScope ?? 'tool_call'}`;
|
|
105
|
+
const entries = grouped.get(key) ?? [];
|
|
106
|
+
entries.push(sample);
|
|
107
|
+
grouped.set(key, entries);
|
|
108
|
+
}
|
|
109
|
+
const groups = [...grouped.values()].map((entries): McpTransportLatencyGroup => {
|
|
110
|
+
const client = entries.map((sample) => sample.clientTotalMs);
|
|
111
|
+
const server = entries.map((sample) => sample.serverDurationMs);
|
|
112
|
+
const residual = entries.map((sample) => Math.max(0, sample.clientTotalMs - sample.serverDurationMs));
|
|
113
|
+
const share = entries.map((sample, index) => client[index]! > 0 ? residual[index]! / client[index]! * 100 : 0);
|
|
114
|
+
return {
|
|
115
|
+
label: entries[0]!.label,
|
|
116
|
+
tool: entries[0]!.tool,
|
|
117
|
+
timingScope: entries[0]!.timingScope ?? 'tool_call',
|
|
118
|
+
sampleCount: entries.length,
|
|
119
|
+
clientTotalMs: stats(client),
|
|
120
|
+
serverDurationMs: stats(server),
|
|
121
|
+
externalResidualMs: stats(residual),
|
|
122
|
+
externalSharePct: stats(share),
|
|
123
|
+
serverExceedsClientCount: entries.filter((sample) => sample.serverDurationMs > sample.clientTotalMs).length,
|
|
124
|
+
};
|
|
125
|
+
}).sort((left, right) => left.label.localeCompare(right.label)
|
|
126
|
+
|| left.tool.localeCompare(right.tool)
|
|
127
|
+
|| left.timingScope.localeCompare(right.timingScope));
|
|
128
|
+
return { schemaVersion: 1, sampleCount: samples.length, groups };
|
|
129
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFileSync } from 'child_process';
|
|
2
|
-
import { existsSync, lstatSync, readdirSync, rmSync } from 'fs';
|
|
2
|
+
import { existsSync, lstatSync, readdirSync, rmSync, statfsSync } from 'fs';
|
|
3
3
|
import { tmpdir } from 'os';
|
|
4
4
|
import { basename, dirname, join, resolve } from 'path';
|
|
5
5
|
|
|
@@ -46,6 +46,7 @@ export interface RuntimePerformanceDiagnostics {
|
|
|
46
46
|
};
|
|
47
47
|
processes: RuntimeProcessSample[];
|
|
48
48
|
temp: { scannedRoots: string[]; totalEntries: number; cleanupCandidates: number; entries: RuntimeTempEntry[] };
|
|
49
|
+
storage: { availableBytes?: number; availableGiB?: number; pressure: 'normal' | 'warning' | 'critical' | 'unknown'; managedCacheRoots: string[] };
|
|
49
50
|
cleanupPreview?: { safeToTerminate: RuntimeProcessSample[]; safeToRemoveTempEntries: RuntimeTempEntry[]; requiresConfirmation: true };
|
|
50
51
|
truncated: {
|
|
51
52
|
summary: boolean;
|
|
@@ -322,7 +323,27 @@ export function collectRuntimePerformanceDiagnostics(input: DiagnosticsInput): R
|
|
|
322
323
|
const temp = input.includeTempDirs === false
|
|
323
324
|
? { roots: [] as string[], entries: [] as RuntimeTempEntry[] }
|
|
324
325
|
: scanRuntimeTempEntries(processes);
|
|
326
|
+
let availableBytes: number | undefined;
|
|
327
|
+
try {
|
|
328
|
+
const fs = statfsSync(input.repoRoot);
|
|
329
|
+
availableBytes = Number(fs.bavail) * Number(fs.bsize);
|
|
330
|
+
} catch {}
|
|
331
|
+
const availableGiB = availableBytes === undefined ? undefined : Math.round((availableBytes / (1024 ** 3)) * 10) / 10;
|
|
332
|
+
const storagePressure: RuntimePerformanceDiagnostics['storage']['pressure'] = availableGiB === undefined
|
|
333
|
+
? 'unknown'
|
|
334
|
+
: availableGiB < 30
|
|
335
|
+
? 'critical'
|
|
336
|
+
: availableGiB < 50
|
|
337
|
+
? 'warning'
|
|
338
|
+
: 'normal';
|
|
339
|
+
const managedCacheRoots = [
|
|
340
|
+
join(input.repoRoot, '.forge', 'ios', 'DerivedData'),
|
|
341
|
+
join(input.repoRoot, '.ai', 'harness'),
|
|
342
|
+
join(input.repoRoot, '.repo-harness'),
|
|
343
|
+
].filter((path) => existsSync(path));
|
|
325
344
|
const findings: RuntimePerformanceDiagnostics['findings'] = [];
|
|
345
|
+
if (storagePressure === 'critical') findings.push({ severity: 'critical', code: 'LOW_DISK_SPACE', message: `Only ${availableGiB} GiB of repository volume space is available.` });
|
|
346
|
+
else if (storagePressure === 'warning') findings.push({ severity: 'warning', code: 'LOW_DISK_SPACE', message: `Repository volume free space is ${availableGiB} GiB.` });
|
|
326
347
|
if (orphanWorkers.length > 0) findings.push({ severity: orphanWorkers.length >= 3 ? 'critical' : 'warning', code: 'ORPHAN_WORKERS', message: 'Detected ' + orphanWorkers.length + ' orphan worker process(es).' });
|
|
327
348
|
const totalCpu = Math.round(repoProcesses.reduce((sum, process) => sum + process.cpu, 0) * 10) / 10;
|
|
328
349
|
if (totalCpu >= 100 || highCpu.length >= 3) findings.push({ severity: 'warning', code: 'HIGH_FORGE_CPU', message: 'Forge-related CPU is ' + totalCpu + '%.' });
|
|
@@ -341,6 +362,7 @@ export function collectRuntimePerformanceDiagnostics(input: DiagnosticsInput): R
|
|
|
341
362
|
...(orphanWorkers.length ? ['Terminate orphan workers only after reviewing cleanupPreview.safeToTerminate.'] : []),
|
|
342
363
|
...(tempCleanupCandidates.length ? ['Remove stale temp entries through runtime_maintenance_apply after reviewing cleanupPreview.safeToRemoveTempEntries.'] : []),
|
|
343
364
|
...(highCpu.length ? ['Inspect highCpuProcesses before restarting the controller stack.'] : []),
|
|
365
|
+
...(storagePressure === 'critical' ? ['Allow Forge generated-cache retention to reclaim stale DerivedData before starting another heavy iOS verification.'] : []),
|
|
344
366
|
];
|
|
345
367
|
return {
|
|
346
368
|
schemaVersion: 1,
|
|
@@ -358,6 +380,7 @@ export function collectRuntimePerformanceDiagnostics(input: DiagnosticsInput): R
|
|
|
358
380
|
cleanupCandidates: tempCleanupCandidates.length,
|
|
359
381
|
entries: temp.entries.slice(0, MAX_DIAGNOSTIC_TEMP_ENTRIES),
|
|
360
382
|
},
|
|
383
|
+
storage: { availableBytes, availableGiB, pressure: storagePressure, managedCacheRoots },
|
|
361
384
|
cleanupPreview: input.cleanupPreview === true
|
|
362
385
|
? {
|
|
363
386
|
safeToTerminate: rawCleanupProcesses,
|
|
@@ -18,7 +18,7 @@ export interface RuntimeEntityEvent {
|
|
|
18
18
|
eventId: string;
|
|
19
19
|
eventType: string;
|
|
20
20
|
repoId: string;
|
|
21
|
-
entityType: 'job' | 'plugin' | 'schedule' | 'occurrence' | 'portfolio' | '
|
|
21
|
+
entityType: 'job' | 'plugin' | 'schedule' | 'occurrence' | 'portfolio' | 'release' | 'lease' | 'schedule-decision';
|
|
22
22
|
entityId: string;
|
|
23
23
|
correlationId?: string;
|
|
24
24
|
causationId?: string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content-bound Check identity shared by Process Runtime and Work validation.
|
|
3
|
+
*
|
|
4
|
+
* This is durable evidence metadata, not Process lifecycle state. Keeping the
|
|
5
|
+
* contract outside Process Runtime prevents WorkHandle persistence from
|
|
6
|
+
* depending on the Process implementation layer.
|
|
7
|
+
*/
|
|
8
|
+
export interface ProcessCheckExecutionIdentity {
|
|
9
|
+
schemaVersion: 1;
|
|
10
|
+
checkId: string;
|
|
11
|
+
cacheKey: string;
|
|
12
|
+
revision: string;
|
|
13
|
+
definitionDigest: string;
|
|
14
|
+
environmentFingerprint: string;
|
|
15
|
+
timeoutMs: number;
|
|
16
|
+
reuseScope: 'repository' | 'checkout';
|
|
17
|
+
scopeKey: string;
|
|
18
|
+
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { ExecutionJob } from './types';
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
export interface ChildReferenceReceiptLike {
|
|
4
|
+
childReference?: unknown;
|
|
5
|
+
result?: Record<string, unknown>;
|
|
6
|
+
}
|
|
3
7
|
|
|
4
8
|
/** Durable pointer from a short-lived parent Execution Job to its child Agent Run. */
|
|
5
9
|
export interface ExecutionChildReference {
|
|
@@ -72,7 +76,7 @@ export function childReferenceFromUnknown(value: unknown): ExecutionChildReferen
|
|
|
72
76
|
return pickChildReference(value as Record<string, unknown>);
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
export function childReferenceFromReceipt(receipt:
|
|
79
|
+
export function childReferenceFromReceipt(receipt: ChildReferenceReceiptLike | undefined): ExecutionChildReference | undefined {
|
|
76
80
|
if (!receipt) return undefined;
|
|
77
81
|
return childReferenceFromUnknown(receipt.childReference)
|
|
78
82
|
?? childReferenceFromUnknown(receipt.result);
|
|
@@ -2,7 +2,7 @@ import { createHash, randomUUID } from 'crypto';
|
|
|
2
2
|
import { existsSync, readdirSync } from 'fs';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { ensureControllerHome, ensureRepositoryControllerLayout, repositoryControllerRoot } from '../../../cli/repositories/controller-home';
|
|
5
|
-
import { withControllerLock } from '../../../cli/repositories/locks';
|
|
5
|
+
import { releaseControllerLock, tryAcquireControllerLock, withControllerLock } from '../../../cli/repositories/locks';
|
|
6
6
|
import { appendJobEvent } from '../../evidence/event-ledger';
|
|
7
7
|
import { writeExecutionArtifact } from '../../evidence/artifact-store';
|
|
8
8
|
import { markRepositoryProjectionDirty } from '../../projections/invalidation';
|
|
@@ -206,7 +206,9 @@ function writeActiveIndex(controllerHome: string, index: ActiveJobIndex): void {
|
|
|
206
206
|
writeJsonAtomic(activeIndexPath(controllerHome), {
|
|
207
207
|
schemaVersion: 1,
|
|
208
208
|
updatedAt: now(),
|
|
209
|
-
|
|
209
|
+
// Active work is correctness state, not a presentation window. Dropping an
|
|
210
|
+
// entry here makes Scheduler/recovery reads forget a durable non-terminal Job.
|
|
211
|
+
jobs: [...deduped.values()].sort((a, b) => a.queuedAt.localeCompare(b.queuedAt)),
|
|
210
212
|
} satisfies ActiveJobIndex);
|
|
211
213
|
}
|
|
212
214
|
|
|
@@ -258,7 +260,9 @@ export function rebuildExecutionJobIndexes(controllerHome: string, repoIds: stri
|
|
|
258
260
|
for (const repoId of targetRepos) {
|
|
259
261
|
const records = join(executionJobRoot(controllerHome, repoId), 'records');
|
|
260
262
|
let names: string[] = [];
|
|
261
|
-
|
|
263
|
+
// Startup repair must rebuild every active and request authority. Only the
|
|
264
|
+
// recent-history projection below is intentionally bounded.
|
|
265
|
+
try { names = readdirSync(records).filter((name) => name.endsWith('.json')); } catch { continue; }
|
|
262
266
|
for (const name of names) {
|
|
263
267
|
try {
|
|
264
268
|
const job = readJsonFile<ExecutionJob>(join(records, name));
|
|
@@ -648,11 +652,61 @@ export function listActiveExecutionJobs(controllerHome: string, repoId?: string)
|
|
|
648
652
|
try {
|
|
649
653
|
const job = getExecutionJob(controllerHome, entry.repoId, entry.jobId);
|
|
650
654
|
if (ACTIVE_JOB_STATUSES.has(job.status)) output.push(job);
|
|
651
|
-
} catch { /* stale
|
|
655
|
+
} catch { /* maintenance reconciliation owns stale-index repair */ }
|
|
652
656
|
}
|
|
653
657
|
return output;
|
|
654
658
|
}
|
|
655
659
|
|
|
660
|
+
/**
|
|
661
|
+
* Maintenance-only active-index convergence. The active index itself is the
|
|
662
|
+
* bounded candidate set; this never scans historical Job directories. Ordinary
|
|
663
|
+
* read APIs remain side-effect free, while the Scheduler can remove terminal or
|
|
664
|
+
* missing entries once and make subsequent idle reads genuinely cheap.
|
|
665
|
+
*/
|
|
666
|
+
export function reconcileActiveExecutionJobIndex(
|
|
667
|
+
controllerHome: string,
|
|
668
|
+
repoId?: string,
|
|
669
|
+
): ExecutionJob[] {
|
|
670
|
+
const key = { scope: 'global' as const, resource: 'execution-index' };
|
|
671
|
+
const owner = `execution-index-active-reconcile:${repoId ?? 'all'}`;
|
|
672
|
+
const acquired = tryAcquireControllerLock(controllerHome, key, owner);
|
|
673
|
+
if (!acquired.acquired) return listActiveExecutionJobs(controllerHome, repoId);
|
|
674
|
+
try {
|
|
675
|
+
const index = readActiveIndex(controllerHome);
|
|
676
|
+
const jobs: ExecutionJob[] = [];
|
|
677
|
+
const retained: ActiveJobIndex['jobs'] = [];
|
|
678
|
+
let removed = 0;
|
|
679
|
+
for (const entry of index.jobs) {
|
|
680
|
+
if (repoId && entry.repoId !== repoId) {
|
|
681
|
+
retained.push(entry);
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
try {
|
|
685
|
+
const job = getExecutionJob(controllerHome, entry.repoId, entry.jobId);
|
|
686
|
+
if (!ACTIVE_JOB_STATUSES.has(job.status)) {
|
|
687
|
+
removed += 1;
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
jobs.push(job);
|
|
691
|
+
retained.push({
|
|
692
|
+
jobId: job.jobId,
|
|
693
|
+
repoId: job.repoId,
|
|
694
|
+
status: job.status,
|
|
695
|
+
priority: job.priority,
|
|
696
|
+
queuedAt: job.queuedAt,
|
|
697
|
+
updatedAt: job.updatedAt,
|
|
698
|
+
});
|
|
699
|
+
} catch {
|
|
700
|
+
removed += 1;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (removed > 0) writeActiveIndex(controllerHome, { ...index, jobs: retained });
|
|
704
|
+
return jobs;
|
|
705
|
+
} finally {
|
|
706
|
+
releaseControllerLock(controllerHome, key, acquired.lock.lockId);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
656
710
|
function executionJobApprovalRequestId(job: ExecutionJob): string | undefined {
|
|
657
711
|
if (typeof job.result?.approvalRequestId === 'string') return job.result.approvalRequestId;
|
|
658
712
|
const authorization = job.result?.authorization;
|
|
@@ -45,7 +45,7 @@ export interface ResourceClaimSpec {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export interface ExecutionJobOrigin {
|
|
48
|
-
surface: 'mcp' | 'local-ui' | 'mobile-intent' | 'chatgpt-action' | '
|
|
48
|
+
surface: 'mcp' | 'local-ui' | 'mobile-intent' | 'chatgpt-action' | 'cli' | 'schedule' | 'reconciliation' | 'system';
|
|
49
49
|
actor?: string;
|
|
50
50
|
correlationId?: string;
|
|
51
51
|
causationId?: string;
|