@moretea-labs/forge 1.5.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -0
- package/CHANGELOG.md +46 -0
- package/CLAUDE.md +2 -0
- package/DESIGN.md +7 -2
- package/README.md +4 -4
- package/README.zh-CN.md +2 -2
- package/SKILL.md +2 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/hooks/hook-input.sh +11 -8
- package/assets/hooks/lib/session-state.sh +10 -7
- package/assets/hooks/lib/workflow-state.sh +13 -177
- package/assets/hooks/post-tool-observer.sh +8 -2
- package/assets/hooks/pre-edit-guard.sh +8 -39
- package/assets/hooks/prompt-guard.sh +7 -83
- package/assets/hooks/session-start-context.sh +56 -1
- package/assets/partials/05-workflow.partial.md +1 -1
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +54 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.md +1 -1
- package/assets/reference-configs/hook-operations.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/contract.template.md +2 -7
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-task-workflow.sh +4 -4
- package/assets/templates/helpers/contract-worktree.sh +1 -21
- package/assets/templates/helpers/ensure-task-workflow.sh +13 -38
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- package/assets/templates/helpers/new-plan.sh +1 -1
- package/assets/templates/helpers/plan-to-todo.sh +12 -37
- package/assets/templates/helpers/ship-worktrees.sh +2 -29
- package/assets/templates/helpers/sprint-backlog.sh +6 -6
- package/assets/templates/helpers/verify-contract.sh +1 -111
- package/assets/templates/helpers/verify-sprint.sh +3 -180
- package/assets/templates/plan.template.md +1 -1
- package/assets/templates/review.template.md +9 -34
- package/assets/workflow-contract.v1.json +10 -19
- package/docs/README.md +10 -10
- package/docs/architecture/CURRENT.md +170 -0
- package/docs/architecture/EVOLUTION.md +42 -0
- package/docs/architecture/current/README.md +4 -156
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
- package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
- package/docs/architecture/history/README.md +7 -0
- package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
- package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
- package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
- package/docs/architecture/history.md +3 -34
- package/docs/architecture/index.md +15 -98
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
- package/docs/architecture/versions/1.6.md +38 -0
- package/docs/architecture/versions/1.7.md +41 -0
- package/docs/forge-chatgpt-browser-engine.md +2 -2
- package/docs/forge-chatgpt-mcp-setup.md +4 -28
- package/docs/forge-chatgpt-supervised-automation.md +3 -3
- package/docs/forge-github-issue-launcher.md +1 -1
- package/docs/forge-runtime-self-healing-loop.md +1 -1
- package/docs/operations/controller-browser-plugin.md +38 -22
- package/docs/operations/controller-performance-and-502.md +124 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +3 -3
- package/docs/operations/github-repository.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +5 -3
- package/docs/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Installation.md +1 -1
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Quick-Start.md +1 -1
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/package.json +29 -10
- package/scripts/activate-source-baseline.ts +17 -13
- package/scripts/benchmark-background-check-overlap.ts +228 -0
- package/scripts/benchmark-mcp-host.sh +117 -0
- package/scripts/benchmark-mcp-transport.ts +170 -0
- package/scripts/benchmark-quality-harness.ts +146 -0
- package/scripts/benchmark-route-session-concurrency.ts +207 -6
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
- package/scripts/benchmark-typescript-navigation.ts +186 -0
- package/scripts/benchmark-work-efficiency.ts +334 -0
- package/scripts/capture-plan.sh +3 -3
- package/scripts/check-agent-tooling.sh +8 -35
- package/scripts/check-architecture-sync.sh +17 -86
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-public-docs.sh +14 -1
- package/scripts/check-runtime-architecture.mjs +107 -64
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-workflow.sh +4 -4
- package/scripts/contract-worktree.sh +1 -21
- package/scripts/ensure-task-workflow.sh +22 -55
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +15 -44
- package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
- package/scripts/migrate-project-template.sh +23 -1179
- package/scripts/new-plan.sh +1 -1
- package/scripts/plan-to-todo.sh +11 -36
- package/scripts/run-governed-gate.ts +2 -1
- package/scripts/ship-worktrees.sh +2 -29
- package/scripts/smoke-ios-physical-device.ts +4 -2
- package/scripts/smoke-runtime-recovery.ts +1 -35
- package/scripts/smoke-schedule-engine.ts +1 -20
- package/scripts/sprint-backlog.sh +1 -1
- package/scripts/verify-contract.sh +1 -111
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +3 -180
- package/scripts/workflow-contract.ts +1 -5
- package/src/cli/commands/chatgpt.ts +31 -2
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +37 -10
- package/src/cli/commands/recovery.ts +25 -3
- package/src/cli/commands/runtime.ts +55 -3
- package/src/cli/commands/security.ts +12 -1
- package/src/cli/commands/setup-profile.ts +31 -21
- package/src/cli/controller/check-runner.ts +106 -3
- package/src/cli/controller/composite-result.ts +1 -1
- package/src/cli/controller/context/focus.ts +51 -0
- package/src/cli/controller/context/instruction-context.ts +114 -0
- package/src/cli/controller/context/known-paths.ts +76 -0
- package/src/cli/controller/context/query-planning.ts +110 -0
- package/src/cli/controller/context/rule-resolution.ts +532 -0
- package/src/cli/controller/context/source-materializer.ts +278 -0
- package/src/cli/controller/context/structural.ts +16 -0
- package/src/cli/controller/context/types.ts +286 -0
- package/src/cli/controller/context-pack.ts +898 -430
- package/src/cli/controller/launch-agents.ts +77 -2
- package/src/cli/controller/operational-plan.ts +2 -2
- package/src/cli/controller/work-mode.ts +6 -4
- package/src/cli/editing/edit-session.ts +60 -7
- package/src/cli/github/github.ts +133 -0
- package/src/cli/hook/prompt-guard-decision.ts +17 -18
- package/src/cli/hook/prompt-intents.ts +1 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +225 -67
- package/src/cli/local-bridge/console-view-models.ts +3 -35
- package/src/cli/local-bridge/facade-api.ts +2 -217
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/styles.css +27 -11
- package/src/cli/local-bridge/frontend/src/types.ts +8 -7
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +29 -532
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
- package/src/cli/mcp/auth.ts +5 -5
- package/src/cli/mcp/instructions.ts +3 -2
- package/src/cli/mcp/legacy-tool-service.ts +0 -189
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/paths.ts +8 -2
- package/src/cli/mcp/repository-tools.ts +356 -101
- package/src/cli/mcp/server.ts +625 -54
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +42 -5
- package/src/cli/mcp/transports/http.ts +125 -15
- package/src/cli/mcp/transports/session-registry.ts +67 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +209 -14
- package/src/cli/repositories/command-executor.ts +55 -521
- package/src/cli/repositories/command-process.ts +108 -0
- package/src/cli/repositories/command-scope.ts +99 -41
- package/src/cli/repositories/controller-home.ts +7 -8
- package/src/cli/repositories/git-command-executor.ts +2 -0
- package/src/cli/repositories/locks.ts +53 -16
- package/src/cli/repositories/repository-snapshot.ts +121 -0
- package/src/cli/repositories/safe-patch.ts +6 -4
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +110 -10
- package/src/cli/repository/inspector.ts +565 -62
- package/src/cli/repository/session-cache.ts +58 -17
- package/src/cli/v81-entry.ts +1 -4
- package/src/effects/fs-transaction.ts +85 -17
- package/src/runtime/context/codegraph-read-provider.ts +233 -2
- package/src/runtime/context/codegraph-sidecar.cjs +74 -40
- package/src/runtime/context/generic-lsp-provider.ts +355 -0
- package/src/runtime/context/lsp-client.ts +283 -0
- package/src/runtime/context/semantic-navigation.ts +275 -0
- package/src/runtime/context/swift-navigation.ts +565 -0
- package/src/runtime/context/typescript-navigation.ts +226 -0
- package/src/runtime/control-plane/dispatch-priority.ts +28 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +196 -2
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/validation.ts +15 -2
- package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
- package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +175 -8
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +144 -14
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
- package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
- package/src/runtime/control-plane/facade/index.ts +1 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
- package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
- package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
- package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
- package/src/runtime/control-plane/facade/types.ts +55 -11
- package/src/runtime/control-plane/facade/work-contract-store.ts +204 -73
- package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
- package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
- package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
- package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
- package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
- package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
- package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
- package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
- package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +642 -51
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
- package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
- package/src/runtime/control-plane/release-retention.ts +62 -2
- package/src/runtime/control-plane/routing/route-policy.ts +7 -16
- package/src/runtime/control-plane/runtime-status-client.ts +0 -2
- package/src/runtime/diagnostics/mcp-timing.ts +19 -0
- package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
- package/src/runtime/diagnostics/performance.ts +24 -1
- package/src/runtime/evidence/event-ledger.ts +1 -1
- package/src/runtime/execution/jobs/store.ts +58 -4
- package/src/runtime/execution/jobs/types.ts +1 -1
- package/src/runtime/execution/managed-workspace.ts +203 -1
- package/src/runtime/execution/process-runtime/check-facade.ts +52 -14
- package/src/runtime/execution/process-runtime/check-result.ts +63 -2
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
- package/src/runtime/execution/process-runtime/gc.ts +98 -12
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
- package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
- package/src/runtime/execution/process-runtime/runtime.ts +59 -4
- package/src/runtime/execution/process-runtime/store.ts +7 -0
- package/src/runtime/execution/process-runtime/types.ts +2 -0
- package/src/runtime/execution/thin-harness/async-process.ts +12 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
- package/src/runtime/execution/workers/executor.ts +0 -48
- package/src/runtime/gateway/mcp/execution-tools.ts +1219 -126
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +185 -83
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
- package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
- package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
- package/src/runtime/plugins/browser-adapter.ts +2925 -318
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +6 -31
- package/src/runtime/plugins/browser-handoff.ts +92 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
- package/src/runtime/plugins/browser-node-bridge.ts +6 -34
- package/src/runtime/plugins/browser-provider-registry.ts +109 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
- package/src/runtime/plugins/browser-runtime.ts +183 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +15 -12
- package/src/runtime/plugins/external-adapter.ts +324 -3
- package/src/runtime/plugins/external-registration.ts +84 -5
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +4 -2
- package/src/runtime/plugins/github-adapter.ts +125 -0
- package/src/runtime/plugins/gmail-adapter.ts +28 -2
- package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
- package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
- package/src/runtime/plugins/ios-adapter.ts +106 -16
- package/src/runtime/plugins/ios-agent-device.ts +234 -64
- package/src/runtime/plugins/ios-physical-device.ts +1143 -392
- package/src/runtime/plugins/lightweight-action.ts +153 -0
- package/src/runtime/plugins/local-system-adapter.ts +125 -8
- package/src/runtime/plugins/macos-capability-broker.ts +55 -9
- package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
- package/src/runtime/plugins/plugin-management-adapter.ts +181 -0
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +366 -24
- package/src/runtime/plugins/types.ts +39 -2
- package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
- package/src/runtime/projections/git-status-sampler.ts +16 -16
- package/src/runtime/projections/materialized-view.ts +28 -10
- package/src/runtime/recovery/actions.ts +0 -10
- package/src/runtime/recovery/classifier.ts +0 -9
- package/src/runtime/recovery/maintenance-executor.ts +415 -18
- package/src/runtime/recovery/probe.ts +0 -1
- package/src/runtime/recovery/types.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +186 -8
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +430 -22
- package/src/runtime/root/release-manifest.ts +7 -2
- package/src/runtime/root/release-materialize.ts +162 -19
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -27
- package/src/runtime/root/types.ts +2 -0
- package/src/runtime/safe-tooling/index.ts +0 -1
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- package/src/runtime/safe-tooling/types.ts +0 -30
- package/src/runtime/shared/trusted-executable.ts +62 -0
- package/src/runtime/shared/trusted-node-executable.ts +48 -0
- package/src/runtime/standalone-recovery/core.ts +702 -94
- package/src/runtime/standalone-recovery/entry.ts +99 -23
- package/src/runtime/standalone-recovery/installer.ts +19 -3
- package/src/runtime/standalone-recovery/service-labels.ts +2 -0
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
- package/src/runtime/workflow/schedules/browser-probe.ts +258 -0
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
- package/src/runtime/workflow/schedules/engine.ts +509 -80
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +48 -4
- package/src/runtime/workflow/schedules/store.ts +131 -10
- package/src/runtime/workflow/schedules/types.ts +6 -3
- package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
- package/src/testing/test-governance.ts +8 -40
- package/assets/reference-configs/heartbeat-triage.md +0 -57
- package/assets/templates/helpers/harness-trace-grade.sh +0 -150
- package/assets/templates/helpers/heartbeat-triage.sh +0 -361
- package/assets/templates/helpers/maintenance-triage.sh +0 -167
- package/bin/forge-desktop-helper.mjs +0 -204
- package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
- package/docs/architecture/current/architecture-invariants.md +0 -331
- package/docs/architecture/current/automation-and-schedule-engine.md +0 -453
- package/docs/architecture/current/codegraph-context-provider.md +0 -226
- package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
- package/docs/architecture/current/controller-repository-decoupling.md +0 -148
- package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -354
- package/docs/architecture/current/entity-model.md +0 -592
- package/docs/architecture/current/external-plugin-governance.md +0 -396
- package/docs/architecture/current/failure-recovery.md +0 -447
- package/docs/architecture/current/governance.md +0 -213
- package/docs/architecture/current/human-interaction-plane.md +0 -87
- package/docs/architecture/current/implementation-status.md +0 -128
- package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
- package/docs/architecture/current/legacy-governance.md +0 -58
- package/docs/architecture/current/local-workspace-target-grants.md +0 -70
- package/docs/architecture/current/migration-roadmap.md +0 -105
- package/docs/architecture/current/multi-repository-execution.md +0 -371
- package/docs/architecture/current/operations-runbook.md +0 -45
- package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
- package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
- package/docs/architecture/current/repository-access-modes.md +0 -102
- package/docs/architecture/current/route-policy.md +0 -15
- package/docs/architecture/current/route-session-concurrency.md +0 -85
- package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
- package/docs/architecture/current/runtime-directory-map.md +0 -49
- package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
- package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
- package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
- package/docs/architecture/current/system-overview.md +0 -144
- package/docs/architecture/current/target-requirements-traceability.md +0 -202
- package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
- package/docs/architecture/current/thin-harness-v1.md +0 -311
- package/docs/architecture/current/verification-and-release-gates.md +0 -391
- package/docs/forge-autonomous-goal-loop.md +0 -9
- package/docs/forge-provider-configuration.md +0 -7
- package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -83
- package/docs/operations/controller-desktop-plugin.md +0 -112
- package/docs/operations/gmail-assistant-routines.md +0 -186
- package/docs/operations/personal-assistant-operator-guide.md +0 -61
- package/docs/operations/provider-configuration.md +0 -31
- package/scripts/harness-trace-grade.sh +0 -150
- package/scripts/heartbeat-triage.sh +0 -361
- package/scripts/maintenance-triage.sh +0 -167
- package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
- package/src/cli/repositories/goal-registry.ts +0 -239
- package/src/runtime/assistant/action-proposals.ts +0 -279
- package/src/runtime/assistant/intent.ts +0 -395
- package/src/runtime/assistant/model-provider.ts +0 -460
- package/src/runtime/assistant/openapi.ts +0 -223
- package/src/runtime/assistant/policy.ts +0 -89
- package/src/runtime/assistant/readiness.ts +0 -258
- package/src/runtime/assistant/routine-runtime.ts +0 -477
- package/src/runtime/assistant/schedule-binding.ts +0 -171
- package/src/runtime/assistant/standing-grants.ts +0 -375
- package/src/runtime/assistant/store.ts +0 -243
- package/src/runtime/assistant/types.ts +0 -135
- package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
- package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
- package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
- package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
- package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
- package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
- package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
- package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
- package/src/runtime/control-plane/goal-loop/index.ts +0 -13
- package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
- package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
- package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
- package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
- package/src/runtime/control-plane/goal-loop/types.ts +0 -378
- package/src/runtime/control-plane/startup-recovery.ts +0 -198
- package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
- package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
- package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
- package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
- package/src/runtime/plugins/desktop-adapter.ts +0 -374
- package/src/runtime/safe-tooling/browser-safe.ts +0 -133
- package/src/runtime/workflow/findings/store.ts +0 -204
- package/src/runtime/workflow/findings/types.ts +0 -58
- package/src/runtime/workflow/portfolio/engine.ts +0 -20
- package/src/runtime/workflow/portfolio/store.ts +0 -185
- package/src/runtime/workflow/portfolio/types.ts +0 -29
|
@@ -106,6 +106,60 @@ function releasePathFromAuthorityRecord(
|
|
|
106
106
|
return canonical(releasePath);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
function loadPackageConnectorReleaseProtection(controllerHome: string, releasesRoot: string): string | undefined {
|
|
110
|
+
const connectorRoot = join(controllerHome, 'runtime', 'connector-service');
|
|
111
|
+
if (!existsSync(connectorRoot)) return undefined;
|
|
112
|
+
const authorityPath = join(connectorRoot, 'authority.json');
|
|
113
|
+
if (!existsSync(authorityPath)) throw new Error('package connector release authority is missing');
|
|
114
|
+
|
|
115
|
+
const parsed = JSON.parse(readFileSync(authorityPath, 'utf8')) as Record<string, unknown>;
|
|
116
|
+
const releaseId = typeof parsed.releaseId === 'string' ? parsed.releaseId.trim() : '';
|
|
117
|
+
const releaseRootValue = typeof parsed.releaseRoot === 'string' ? parsed.releaseRoot.trim() : '';
|
|
118
|
+
const packageRoot = typeof parsed.packageRoot === 'string' ? parsed.packageRoot.trim() : '';
|
|
119
|
+
const endpoint = typeof parsed.endpoint === 'string' ? parsed.endpoint.trim() : '';
|
|
120
|
+
if (parsed.schemaVersion !== 1 || !releaseId || !releaseRootValue || !packageRoot || !endpoint) {
|
|
121
|
+
throw new Error('package connector release authority is invalid');
|
|
122
|
+
}
|
|
123
|
+
const releaseRoot = resolve(releaseRootValue);
|
|
124
|
+
if (basename(releaseRoot) !== releaseId || !directChild(releasesRoot, releaseRoot) || !existsSync(releaseRoot)) {
|
|
125
|
+
throw new Error('package connector release is outside runtime release authority or missing');
|
|
126
|
+
}
|
|
127
|
+
return canonical(releaseRoot);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function loadRecoveryKnownGoodReleaseProtection(controllerHome: string, releasesRoot: string): Set<string> {
|
|
131
|
+
const knownGoodPath = join(controllerHome, 'recovery', 'state', 'known-good.json');
|
|
132
|
+
const protectedPaths = new Set<string>();
|
|
133
|
+
if (!existsSync(knownGoodPath)) return protectedPaths;
|
|
134
|
+
const parsed = JSON.parse(readFileSync(knownGoodPath, 'utf8')) as Record<string, unknown>;
|
|
135
|
+
if (parsed.schemaVersion !== 1 || !Array.isArray(parsed.releases)) {
|
|
136
|
+
throw new Error('standalone recovery known-good authority is invalid');
|
|
137
|
+
}
|
|
138
|
+
for (const raw of parsed.releases) {
|
|
139
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('standalone recovery known-good release record is invalid');
|
|
140
|
+
const record = raw as Record<string, unknown>;
|
|
141
|
+
const releaseId = typeof record.revision === 'string' ? record.revision.trim() : '';
|
|
142
|
+
const manifestPathValue = typeof record.path === 'string' ? record.path.trim() : '';
|
|
143
|
+
if (!releaseId || !manifestPathValue) throw new Error('standalone recovery known-good release identity is incomplete');
|
|
144
|
+
const manifestPath = resolve(manifestPathValue);
|
|
145
|
+
const releaseRoot = dirname(manifestPath);
|
|
146
|
+
if (
|
|
147
|
+
basename(manifestPath) !== 'manifest.json'
|
|
148
|
+
|| basename(releaseRoot) !== releaseId
|
|
149
|
+
|| !directChild(releasesRoot, releaseRoot)
|
|
150
|
+
) {
|
|
151
|
+
throw new Error('standalone recovery known-good release is outside runtime releases');
|
|
152
|
+
}
|
|
153
|
+
// Known-good history is append-only recovery evidence. A historical record
|
|
154
|
+
// may legitimately outlive the retained release directory after a bounded
|
|
155
|
+
// cleanup pass. Missing historical artifacts therefore protect nothing and
|
|
156
|
+
// must not disable retention for the remaining authoritative releases.
|
|
157
|
+
if (!existsSync(manifestPath) || !existsSync(releaseRoot)) continue;
|
|
158
|
+
protectedPaths.add(canonical(releaseRoot));
|
|
159
|
+
}
|
|
160
|
+
return protectedPaths;
|
|
161
|
+
}
|
|
162
|
+
|
|
109
163
|
function loadRuntimeProtection(controllerHome: string): RuntimeProtection | undefined {
|
|
110
164
|
const releasesRoot = join(controllerHome, 'runtime', 'releases');
|
|
111
165
|
if (!existsSync(releasesRoot)) return undefined;
|
|
@@ -124,6 +178,11 @@ function loadRuntimeProtection(controllerHome: string): RuntimeProtection | unde
|
|
|
124
178
|
if (previous !== undefined) {
|
|
125
179
|
releasePaths.add(releasePathFromAuthorityRecord(releasesRoot, previous, 'previous'));
|
|
126
180
|
}
|
|
181
|
+
const connectorRelease = loadPackageConnectorReleaseProtection(controllerHome, releasesRoot);
|
|
182
|
+
if (connectorRelease) releasePaths.add(connectorRelease);
|
|
183
|
+
for (const knownGoodRelease of loadRecoveryKnownGoodReleaseProtection(controllerHome, releasesRoot)) {
|
|
184
|
+
releasePaths.add(knownGoodRelease);
|
|
185
|
+
}
|
|
127
186
|
|
|
128
187
|
const backupPaths = new Set<string>();
|
|
129
188
|
let backupAuthoritySafe = true;
|
|
@@ -409,8 +468,9 @@ function scanLinkedReleaseFamily(
|
|
|
409
468
|
/**
|
|
410
469
|
* Reclaim immutable Controller release history while preserving the exact
|
|
411
470
|
* rollback authorities. Runtime keeps active + previous + the previous DB
|
|
412
|
-
* backup
|
|
413
|
-
*
|
|
471
|
+
* backup plus the immutable release backing the persistent public MCP Gateway;
|
|
472
|
+
* Recovery/Supervisor keep current + previous. Missing or malformed authority
|
|
473
|
+
* always fails closed.
|
|
414
474
|
*/
|
|
415
475
|
export function cleanupControllerReleaseHistory(
|
|
416
476
|
controllerHome: string,
|
|
@@ -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-v4' 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';
|
|
@@ -238,8 +238,6 @@ export function decideRoute(input: RoutePolicyInput): RouteDecision {
|
|
|
238
238
|
? false
|
|
239
239
|
: input.recovery.isolationRequired === true || explicitParallelMode;
|
|
240
240
|
const requiresRecovery = input.recovery.required === true
|
|
241
|
-
|| input.intent.requiresLongRunningChecks === true
|
|
242
|
-
|| explicitMode === 'debug'
|
|
243
241
|
|| explicitMode === 'release'
|
|
244
242
|
|| explicitMode === 'scale';
|
|
245
243
|
const coordinationRequired = explicitParallelMode || input.intent.requiresIndependentDeliverables === true
|
|
@@ -289,26 +287,21 @@ export function decideRoute(input: RoutePolicyInput): RouteDecision {
|
|
|
289
287
|
}
|
|
290
288
|
|
|
291
289
|
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
|
-
};
|
|
290
|
+
reasons.push({
|
|
291
|
+
code: 'dirty_workspace_preserve_existing_changes',
|
|
292
|
+
message: 'The checkout is already dirty; preserve unrelated changes and treat inspected/actual scope as evidence instead of creating Work solely for adoption.',
|
|
293
|
+
});
|
|
299
294
|
}
|
|
300
295
|
if (explicitMode) reasons.push({ code: `explicit_${explicitMode}`, message: `Explicit -${explicitMode} mode overrides automatic work topology while policy gates remain authoritative.` });
|
|
301
296
|
if (protectedPath) reasons.push({ code: 'protected_path', message: 'The predicted scope includes a protected or release-sensitive path.' });
|
|
302
297
|
if (requiresRecovery) reasons.push({ code: 'recovery_required', message: 'The operation needs resumable Work and bounded recovery.' });
|
|
303
298
|
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
|
|
299
|
+
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
300
|
if (input.intent.requiresInvestigation) reasons.push({ code: 'investigation', message: 'Investigation is required before or during implementation.' });
|
|
306
301
|
if (input.intent.needsDependencies) reasons.push({ code: 'dependencies', message: 'Dependency ordering requires durable Work.' });
|
|
307
302
|
if (coordinationRequired) reasons.push({ code: 'independent_deliverables', message: 'Multiple independent deliverables require durable PlanContract/Work coordination.' });
|
|
308
303
|
|
|
309
304
|
const explicitBoundedMode = explicitMode === 'plan'
|
|
310
|
-
|| explicitMode === 'debug'
|
|
311
|
-
|| explicitMode === 'review'
|
|
312
305
|
|| explicitMode === 'release';
|
|
313
306
|
const complex = explicitMode === 'direct'
|
|
314
307
|
? false
|
|
@@ -320,11 +313,9 @@ export function decideRoute(input: RoutePolicyInput): RouteDecision {
|
|
|
320
313
|
|| input.capabilities.requiresWorker === true
|
|
321
314
|
|| input.capabilities.requiresExternalEffect === true
|
|
322
315
|
|| input.intent.needsDependencies === true
|
|
323
|
-
|| protectedPath
|
|
324
316
|
|| destructive
|
|
325
317
|
|| remoteWrite
|
|
326
|
-
|| secretAccess
|
|
327
|
-
|| (mutation && (expectedFiles > 4 || expectedChangedLines > 200));
|
|
318
|
+
|| secretAccess;
|
|
328
319
|
const executionMode: RouteExecutionMode = complex ? 'goal_workloop' : 'direct_control';
|
|
329
320
|
// Work topology is independent from executor/provider choice. Independent or
|
|
330
321
|
// parallel deliverables stay in the durable Goal Workloop and are decomposed by
|
|
@@ -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;
|
|
@@ -7,6 +7,10 @@ export interface McpTimingTrace {
|
|
|
7
7
|
traceId?: string;
|
|
8
8
|
requestId?: string;
|
|
9
9
|
rpcId?: string | number;
|
|
10
|
+
/** Public Connector ingress versus the authoritative loopback Runtime span. */
|
|
11
|
+
layer?: 'public_gateway' | 'canonical_runtime';
|
|
12
|
+
/** Wall-clock start for joining nested spans and later client-side timing when available. */
|
|
13
|
+
startedAt?: string;
|
|
10
14
|
outcome?: 'ok' | 'error' | 'exception';
|
|
11
15
|
errorCode?: string;
|
|
12
16
|
sessionResolutionMs?: number;
|
|
@@ -17,10 +21,25 @@ export interface McpTimingTrace {
|
|
|
17
21
|
commandExecutionMs?: number;
|
|
18
22
|
resultSerializationMs?: number;
|
|
19
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';
|
|
20
37
|
totalToolDurationMs: number;
|
|
21
38
|
sessionId?: string;
|
|
22
39
|
repoId?: string;
|
|
23
40
|
workId?: string;
|
|
41
|
+
processId?: string;
|
|
42
|
+
route?: string;
|
|
24
43
|
}
|
|
25
44
|
|
|
26
45
|
export interface McpIncident {
|
|
@@ -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;
|
|
@@ -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;
|