@moretea-labs/forge 1.6.0 → 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 +26 -0
- package/CLAUDE.md +2 -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/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +1 -1
- 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-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/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/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 +26 -6
- package/docs/operations/controller-performance-and-502.md +124 -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 +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-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-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/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/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +1 -1
- 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 +785 -469
- 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/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 +0 -217
- 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 +0 -513
- 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 +0 -189
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/repository-tools.ts +247 -107
- package/src/cli/mcp/server.ts +537 -111
- 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 +101 -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 +101 -19
- 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/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +61 -3
- package/src/cli/repository/inspector.ts +553 -63
- 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 +47 -8
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- 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-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 +143 -8
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +85 -8
- 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 +132 -1
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +2 -0
- package/src/runtime/control-plane/facade/goal-workloop.ts +686 -129
- package/src/runtime/control-plane/facade/index.ts +1 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +185 -20
- 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 +22 -5
- package/src/runtime/control-plane/facade/work-contract-store.ts +175 -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 +355 -116
- 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/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 +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/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 +53 -0
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +345 -40
- package/src/runtime/execution/process-runtime/gc.ts +38 -6
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +47 -4
- package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
- package/src/runtime/execution/process-runtime/runtime.ts +43 -3
- package/src/runtime/execution/process-runtime/store.ts +1 -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 +1192 -114
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +184 -82
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2224 -1589
- package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
- package/src/runtime/plugins/browser-adapter.ts +2901 -241
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff.ts +92 -2
- package/src/runtime/plugins/browser-macos-bridge.ts +582 -49
- 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 +8 -2
- package/src/runtime/plugins/external-adapter.ts +324 -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 +55 -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 +269 -29
- package/src/runtime/plugins/types.ts +35 -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/maintenance-executor.ts +393 -28
- 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 +19 -0
- 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 +2 -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 +700 -92
- 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 +81 -3
- package/src/runtime/workflow/schedules/engine.ts +287 -151
- 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 +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
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { execFileSync } from 'child_process';
|
|
4
|
+
import { readFileSync } from 'fs';
|
|
5
|
+
import { resolve } from 'path';
|
|
6
|
+
import { performance } from 'perf_hooks';
|
|
7
|
+
import {
|
|
8
|
+
clearTypeScriptNavigationCache,
|
|
9
|
+
navigateTypeScriptSymbol,
|
|
10
|
+
type TypeScriptNavigationKind,
|
|
11
|
+
} from '../src/runtime/context/typescript-navigation';
|
|
12
|
+
|
|
13
|
+
interface BenchmarkCase {
|
|
14
|
+
label: string;
|
|
15
|
+
path: string;
|
|
16
|
+
symbol: string;
|
|
17
|
+
marker: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const repoRoot = execFileSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf8' }).trim();
|
|
21
|
+
const cases: BenchmarkCase[] = [
|
|
22
|
+
{
|
|
23
|
+
label: 'repository command execution',
|
|
24
|
+
path: 'src/cli/repositories/command-executor.ts',
|
|
25
|
+
symbol: 'executeRepositoryCommand',
|
|
26
|
+
marker: 'export function executeRepositoryCommand(',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: 'MCP repository dispatch',
|
|
30
|
+
path: 'src/cli/mcp/repository-tools.ts',
|
|
31
|
+
symbol: 'callRepositoryTool',
|
|
32
|
+
marker: 'export async function callRepositoryTool(',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
label: 'canonical Runtime proxy',
|
|
36
|
+
path: 'src/cli/mcp/server.ts',
|
|
37
|
+
symbol: 'createCanonicalRuntimeProxy',
|
|
38
|
+
marker: 'export function createCanonicalRuntimeProxy(',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
label: 'Runtime MCP dispatch',
|
|
42
|
+
path: 'src/runtime/gateway/mcp/runtime-tools.ts',
|
|
43
|
+
symbol: 'callRuntimeTool',
|
|
44
|
+
marker: 'export async function callRuntimeTool(',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
label: 'Lightweight command execution',
|
|
48
|
+
path: 'src/runtime/execution/process-runtime/lightweight-managed.ts',
|
|
49
|
+
symbol: 'startLightweightRepositoryCommand',
|
|
50
|
+
marker: 'export async function startLightweightRepositoryCommand(',
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
const requestedSymbols = new Set(
|
|
54
|
+
String(process.env.FORGE_TSNAV_BENCHMARK_SYMBOLS ?? '')
|
|
55
|
+
.split(',')
|
|
56
|
+
.map((value) => value.trim())
|
|
57
|
+
.filter(Boolean),
|
|
58
|
+
);
|
|
59
|
+
const benchmarkCases = requestedSymbols.size === 0
|
|
60
|
+
? cases
|
|
61
|
+
: cases.filter((case_) => requestedSymbols.has(case_.symbol));
|
|
62
|
+
if (benchmarkCases.length === 0) {
|
|
63
|
+
throw new Error(`No benchmark cases match FORGE_TSNAV_BENCHMARK_SYMBOLS=${[...requestedSymbols].join(',')}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function target(case_: BenchmarkCase): { line: number; column: number } {
|
|
67
|
+
const text = readFileSync(resolve(repoRoot, case_.path), 'utf8');
|
|
68
|
+
const markerOffset = text.indexOf(case_.marker);
|
|
69
|
+
if (markerOffset < 0) throw new Error(`marker not found for ${case_.label}: ${case_.marker}`);
|
|
70
|
+
const symbolOffset = markerOffset + case_.marker.indexOf(case_.symbol);
|
|
71
|
+
const before = text.slice(0, symbolOffset);
|
|
72
|
+
const lines = before.split('\n');
|
|
73
|
+
return { line: lines.length, column: (lines.at(-1)?.length ?? 0) + 1 };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function navigate(case_: BenchmarkCase, navigation: TypeScriptNavigationKind) {
|
|
77
|
+
const point = target(case_);
|
|
78
|
+
return navigateTypeScriptSymbol(repoRoot, { navigation, path: case_.path, ...point });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function lexicalMatches(symbol: string): string[] {
|
|
82
|
+
try {
|
|
83
|
+
const output = execFileSync('git', ['grep', '-n', '-w', symbol, '--', 'src', 'scripts', 'tests'], {
|
|
84
|
+
cwd: repoRoot,
|
|
85
|
+
encoding: 'utf8',
|
|
86
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
87
|
+
}).trim();
|
|
88
|
+
return output ? output.split('\n') : [];
|
|
89
|
+
} catch {
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function percentile(values: number[], ratio: number): number {
|
|
95
|
+
if (values.length === 0) return 0;
|
|
96
|
+
const sorted = [...values].sort((left, right) => left - right);
|
|
97
|
+
const index = Math.min(sorted.length - 1, Math.floor(sorted.length * ratio));
|
|
98
|
+
return Math.round((sorted[index] ?? 0) * 100) / 100;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const results = [];
|
|
102
|
+
for (const case_ of benchmarkCases) {
|
|
103
|
+
clearTypeScriptNavigationCache();
|
|
104
|
+
// This first reference call represents the user-visible cold path.
|
|
105
|
+
const coldReferenceStartedAt = performance.now();
|
|
106
|
+
const coldReferences = navigate(case_, 'references');
|
|
107
|
+
const coldReferenceMs = performance.now() - coldReferenceStartedAt;
|
|
108
|
+
|
|
109
|
+
// Then separately initialize a fresh project through the cheap definition
|
|
110
|
+
// query and measure references on that already-built Language Service. This
|
|
111
|
+
// makes project construction and high-fanout reference cost visible instead
|
|
112
|
+
// of attributing both to one opaque cold number.
|
|
113
|
+
clearTypeScriptNavigationCache();
|
|
114
|
+
const projectSetupStartedAt = performance.now();
|
|
115
|
+
const coldDefinition = navigate(case_, 'definition');
|
|
116
|
+
const projectSetupMs = performance.now() - projectSetupStartedAt;
|
|
117
|
+
const firstReferenceStartedAt = performance.now();
|
|
118
|
+
const firstReferencesOnPreparedProject = navigate(case_, 'references');
|
|
119
|
+
const firstReferenceOnPreparedProjectMs = performance.now() - firstReferenceStartedAt;
|
|
120
|
+
|
|
121
|
+
const warmDurations: number[] = [];
|
|
122
|
+
let warmReferences = firstReferencesOnPreparedProject;
|
|
123
|
+
for (let index = 0; index < 3; index += 1) {
|
|
124
|
+
const startedAt = performance.now();
|
|
125
|
+
warmReferences = navigate(case_, 'references');
|
|
126
|
+
warmDurations.push(performance.now() - startedAt);
|
|
127
|
+
}
|
|
128
|
+
const definitions = navigate(case_, 'definition');
|
|
129
|
+
const implementations = navigate(case_, 'implementations');
|
|
130
|
+
const lexical = lexicalMatches(case_.symbol);
|
|
131
|
+
|
|
132
|
+
results.push({
|
|
133
|
+
label: case_.label,
|
|
134
|
+
symbol: case_.symbol,
|
|
135
|
+
target: { path: case_.path, ...target(case_) },
|
|
136
|
+
semantic: {
|
|
137
|
+
coldReferenceLocations: coldReferences.locations.length,
|
|
138
|
+
coldDefinitionLocations: coldDefinition.locations.length,
|
|
139
|
+
references: warmReferences.locations.length,
|
|
140
|
+
definitions: definitions.locations.length,
|
|
141
|
+
implementations: implementations.locations.length,
|
|
142
|
+
crossFileReferences: warmReferences.locations.filter((location) => location.path !== case_.path).length,
|
|
143
|
+
sampleReferences: warmReferences.locations.slice(0, 8),
|
|
144
|
+
},
|
|
145
|
+
lexical: {
|
|
146
|
+
exactMatches: lexical.length,
|
|
147
|
+
sampleMatches: lexical.slice(0, 8),
|
|
148
|
+
},
|
|
149
|
+
latencyMs: {
|
|
150
|
+
coldReferences: Math.round(coldReferenceMs * 100) / 100,
|
|
151
|
+
projectSetupViaDefinition: Math.round(projectSetupMs * 100) / 100,
|
|
152
|
+
firstReferencesOnPreparedProject: Math.round(firstReferenceOnPreparedProjectMs * 100) / 100,
|
|
153
|
+
warmReferences: warmDurations.map((value) => Math.round(value * 100) / 100),
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
clearTypeScriptNavigationCache();
|
|
158
|
+
|
|
159
|
+
const preparedReferenceDurations = results.map((entry) => entry.latencyMs.firstReferencesOnPreparedProject);
|
|
160
|
+
const warmReferenceDurations = results.flatMap((entry) => entry.latencyMs.warmReferences);
|
|
161
|
+
const thresholds = {
|
|
162
|
+
firstReferencesOnPreparedProjectP95MaxMs: 250,
|
|
163
|
+
warmReferencesP95MaxMs: 150,
|
|
164
|
+
};
|
|
165
|
+
const assertions = {
|
|
166
|
+
allDefinitionsResolved: results.every((entry) => entry.semantic.definitions >= 1),
|
|
167
|
+
allReferencesResolved: results.every((entry) => entry.semantic.references >= 1),
|
|
168
|
+
allImplementationsResolved: results.every((entry) => entry.semantic.implementations >= 1),
|
|
169
|
+
crossFileSemanticReferencesResolved: results.every((entry) => entry.semantic.crossFileReferences >= 1),
|
|
170
|
+
preparedReferenceLatencyBounded: percentile(preparedReferenceDurations, 0.95) <= thresholds.firstReferencesOnPreparedProjectP95MaxMs,
|
|
171
|
+
warmReferenceLatencyBounded: percentile(warmReferenceDurations, 0.95) <= thresholds.warmReferencesP95MaxMs,
|
|
172
|
+
};
|
|
173
|
+
const output = {
|
|
174
|
+
repoRoot,
|
|
175
|
+
requestedSymbols: [...requestedSymbols],
|
|
176
|
+
cases: results,
|
|
177
|
+
summary: {
|
|
178
|
+
firstReferencesOnPreparedProjectP95Ms: percentile(preparedReferenceDurations, 0.95),
|
|
179
|
+
warmReferencesP95Ms: percentile(warmReferenceDurations, 0.95),
|
|
180
|
+
},
|
|
181
|
+
thresholds,
|
|
182
|
+
assertions,
|
|
183
|
+
passed: Object.values(assertions).every(Boolean),
|
|
184
|
+
};
|
|
185
|
+
console.log(JSON.stringify(output, null, 2));
|
|
186
|
+
if (!output.passed) process.exitCode = 1;
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Forge Work efficiency benchmark.
|
|
5
|
+
*
|
|
6
|
+
* Measures end-to-end controller ceremony for a tiny, real repository change
|
|
7
|
+
* against isolated temporary repository/controller state. It compares the
|
|
8
|
+
* streamlined path (verify -> finalize) with the legacy-style ceremony
|
|
9
|
+
* (verify -> continue -> finalize) without mutating the Forge checkout.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'fs';
|
|
12
|
+
import { tmpdir } from 'os';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
import { spawnSync } from 'child_process';
|
|
15
|
+
import { createMcpToolContext } from '../src/cli/mcp/server';
|
|
16
|
+
import type { MultiRepositoryMcpToolContext } from '../src/cli/mcp/multi-repository';
|
|
17
|
+
import { ensureControllerHome } from '../src/cli/repositories/controller-home';
|
|
18
|
+
import { registerRepository } from '../src/cli/repositories/registry';
|
|
19
|
+
import { callRuntimeTool } from '../src/runtime/gateway/mcp/runtime-tools';
|
|
20
|
+
import { getWorkContract } from '../src/runtime/control-plane/facade/work-contract-store';
|
|
21
|
+
import { waitForProcess } from '../src/runtime/execution/process-runtime';
|
|
22
|
+
import { acquireRuntimeOwnership } from '../src/runtime/root/ownership';
|
|
23
|
+
import { forgeRuntimeServicePaths } from '../src/runtime/root/service';
|
|
24
|
+
import { writeRuntimeStatusSnapshot } from '../src/runtime/root/status';
|
|
25
|
+
import { ensureActiveRuntimeRelease } from '../src/runtime/root/release-store';
|
|
26
|
+
import { bindRuntimeWriteClaim, clearRuntimeWriteClaimForTests } from '../src/runtime/root/write-fence';
|
|
27
|
+
|
|
28
|
+
interface TimedCall {
|
|
29
|
+
elapsedMs: number;
|
|
30
|
+
value: Record<string, any>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface FlowSample {
|
|
34
|
+
mode: 'streamlined' | 'legacy_ceremony';
|
|
35
|
+
sample: number;
|
|
36
|
+
ok: boolean;
|
|
37
|
+
controllerCalls: number;
|
|
38
|
+
processWaits: number;
|
|
39
|
+
startMs: number;
|
|
40
|
+
verifySubmitMs: number;
|
|
41
|
+
verifyWaitMs: number;
|
|
42
|
+
verifyReattachMs: number;
|
|
43
|
+
continueMs: number;
|
|
44
|
+
finalizeMs: number;
|
|
45
|
+
totalMs: number;
|
|
46
|
+
verificationNextStep?: string;
|
|
47
|
+
finalStatus?: string;
|
|
48
|
+
cleanupComplete: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function argNumber(name: string, fallback: number): number {
|
|
52
|
+
const index = process.argv.indexOf(name);
|
|
53
|
+
if (index < 0) return fallback;
|
|
54
|
+
const parsed = Number(process.argv[index + 1]);
|
|
55
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function git(root: string, args: string[]): string {
|
|
59
|
+
const result = spawnSync('git', ['-C', root, ...args], { encoding: 'utf8' });
|
|
60
|
+
if (result.status !== 0) throw new Error(String(result.stderr || `git ${args.join(' ')} failed`));
|
|
61
|
+
return String(result.stdout ?? '').trim();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function runtimeManifest(controllerHome: string): string {
|
|
65
|
+
const path = join(controllerHome, 'benchmark-runtime.manifest.json');
|
|
66
|
+
writeFileSync(path, JSON.stringify({
|
|
67
|
+
schemaVersion: 1,
|
|
68
|
+
releaseId: 'release-work-efficiency-benchmark',
|
|
69
|
+
artifactIdentity: 'artifact-work-efficiency-benchmark',
|
|
70
|
+
entrypoint: 'forge-runtime',
|
|
71
|
+
arguments: [],
|
|
72
|
+
configurationSchemaVersion: 1,
|
|
73
|
+
controllerHome,
|
|
74
|
+
databaseSchemaCompatibility: { minimum: 1, maximum: 1 },
|
|
75
|
+
workerProtocolVersion: 1,
|
|
76
|
+
createdAt: new Date().toISOString(),
|
|
77
|
+
}));
|
|
78
|
+
return path;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function createFixture(label: string) {
|
|
82
|
+
const root = mkdtempSync(join(tmpdir(), `forge-work-efficiency-${label}-`));
|
|
83
|
+
const controllerHome = join(root, 'controller');
|
|
84
|
+
const repoRoot = join(root, 'repo');
|
|
85
|
+
ensureControllerHome(controllerHome);
|
|
86
|
+
mkdirSync(repoRoot, { recursive: true });
|
|
87
|
+
git(repoRoot, ['init', '-b', 'main']);
|
|
88
|
+
git(repoRoot, ['config', 'user.name', 'Work Efficiency Benchmark']);
|
|
89
|
+
git(repoRoot, ['config', 'user.email', 'benchmark@example.test']);
|
|
90
|
+
writeFileSync(join(repoRoot, 'README.md'), 'fixture\n');
|
|
91
|
+
writeFileSync(join(repoRoot, 'package.json'), JSON.stringify({
|
|
92
|
+
name: `work-efficiency-${label}`,
|
|
93
|
+
private: true,
|
|
94
|
+
scripts: { 'check:bench': 'node -e "process.exit(0)"' },
|
|
95
|
+
}, null, 2));
|
|
96
|
+
git(repoRoot, ['add', '.']);
|
|
97
|
+
git(repoRoot, ['commit', '-m', 'fixture']);
|
|
98
|
+
|
|
99
|
+
const repository = registerRepository({ path: repoRoot, controllerHome, displayName: `work-efficiency-${label}` });
|
|
100
|
+
const owner = acquireRuntimeOwnership(controllerHome, `runtime-work-efficiency-${label}`);
|
|
101
|
+
const authority = ensureActiveRuntimeRelease(controllerHome, runtimeManifest(controllerHome));
|
|
102
|
+
bindRuntimeWriteClaim({ controllerHome, owner: owner.record, authority });
|
|
103
|
+
|
|
104
|
+
const runtimeService = forgeRuntimeServicePaths(controllerHome);
|
|
105
|
+
mkdirSync(runtimeService.serviceRoot, { recursive: true });
|
|
106
|
+
mkdirSync(join(controllerHome, 'mcp'), { recursive: true });
|
|
107
|
+
const runtimeTokenPath = join(controllerHome, 'mcp', 'runtime-token');
|
|
108
|
+
writeFileSync(runtimeTokenPath, `fixture-token-${label}\n`, { mode: 0o600 });
|
|
109
|
+
writeFileSync(runtimeService.configPath, JSON.stringify({
|
|
110
|
+
schemaVersion: 1,
|
|
111
|
+
controllerHome,
|
|
112
|
+
repositoryRoot: repoRoot,
|
|
113
|
+
host: '127.0.0.1',
|
|
114
|
+
port: 9876,
|
|
115
|
+
authTokenFile: runtimeTokenPath,
|
|
116
|
+
}));
|
|
117
|
+
const observedAt = new Date().toISOString();
|
|
118
|
+
writeRuntimeStatusSnapshot(controllerHome, {
|
|
119
|
+
schemaVersion: 1,
|
|
120
|
+
runtimeInstanceId: owner.record.runtimeInstanceId,
|
|
121
|
+
pid: owner.record.pid,
|
|
122
|
+
releaseId: authority.active.releaseId,
|
|
123
|
+
artifactIdentity: authority.active.artifactIdentity,
|
|
124
|
+
endpoint: 'http://127.0.0.1:9876/mcp',
|
|
125
|
+
readiness: {
|
|
126
|
+
ready: true,
|
|
127
|
+
reasonCodes: [],
|
|
128
|
+
diagnostics: {
|
|
129
|
+
database: { outcome: 'pass' },
|
|
130
|
+
scheduler: { outcome: 'pass' },
|
|
131
|
+
releaseCoherence: { outcome: 'pass' },
|
|
132
|
+
mcpEndToEnd: { outcome: 'pass' },
|
|
133
|
+
},
|
|
134
|
+
observedAt,
|
|
135
|
+
},
|
|
136
|
+
startedAt: observedAt,
|
|
137
|
+
updatedAt: observedAt,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const ctx = createMcpToolContext({
|
|
141
|
+
controllerHome,
|
|
142
|
+
profile: 'controller',
|
|
143
|
+
repo: repoRoot,
|
|
144
|
+
sessionId: `mcp-work-efficiency-${label}`,
|
|
145
|
+
principalId: `principal-work-efficiency-${label}`,
|
|
146
|
+
controllerInstanceId: owner.record.runtimeInstanceId,
|
|
147
|
+
}) as MultiRepositoryMcpToolContext;
|
|
148
|
+
return { root, controllerHome, repoRoot, repository, ctx };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function timedCall(ctx: MultiRepositoryMcpToolContext, args: Record<string, unknown>): Promise<TimedCall> {
|
|
152
|
+
const startedAt = performance.now();
|
|
153
|
+
const result = await callRuntimeTool(ctx, 'rh_work', args);
|
|
154
|
+
const elapsedMs = Math.round((performance.now() - startedAt) * 100) / 100;
|
|
155
|
+
if (!result) throw new Error('rh_work returned no benchmark result');
|
|
156
|
+
const value = (result.structuredContent ?? JSON.parse(result.content?.[0]?.text ?? '{}')) as Record<string, any>;
|
|
157
|
+
return { elapsedMs, value };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function runFlow(mode: FlowSample['mode'], sample: number): Promise<FlowSample> {
|
|
161
|
+
const label = `${mode}-${sample}-${Date.now()}`;
|
|
162
|
+
const fx = createFixture(label);
|
|
163
|
+
const wallStartedAt = performance.now();
|
|
164
|
+
let controllerCalls = 0;
|
|
165
|
+
let processWaits = 0;
|
|
166
|
+
try {
|
|
167
|
+
const started = await timedCall(fx.ctx, {
|
|
168
|
+
repo_id: fx.repository.repoId,
|
|
169
|
+
operation: 'start',
|
|
170
|
+
objective: `Benchmark ${mode} work lifecycle`,
|
|
171
|
+
scope_clear: true,
|
|
172
|
+
expected_files: 1,
|
|
173
|
+
expected_changed_lines: 1,
|
|
174
|
+
requires_recovery: true,
|
|
175
|
+
allowed_paths: ['README.md'],
|
|
176
|
+
check_ids: ['package:check:bench'],
|
|
177
|
+
constraints: { workspaceMode: 'isolated' },
|
|
178
|
+
request_id: `work-efficiency-start-${label}`,
|
|
179
|
+
});
|
|
180
|
+
controllerCalls += 1;
|
|
181
|
+
const workId = String(started.value.data?.work?.workId ?? '');
|
|
182
|
+
if (!workId) throw new Error('benchmark Work was not created');
|
|
183
|
+
const store = { controllerHome: fx.controllerHome, repoId: fx.repository.repoId };
|
|
184
|
+
const contract = getWorkContract(store, workId);
|
|
185
|
+
if (!contract?.worktreeRef) throw new Error('benchmark Work has no managed worktree');
|
|
186
|
+
writeFileSync(join(contract.worktreeRef, 'README.md'), `fixture\n${mode}\n`);
|
|
187
|
+
|
|
188
|
+
const verifyArgs = {
|
|
189
|
+
repo_id: fx.repository.repoId,
|
|
190
|
+
operation: 'verify',
|
|
191
|
+
work_id: workId,
|
|
192
|
+
check_id: 'package:check:bench',
|
|
193
|
+
request_id: `work-efficiency-verify-${label}`,
|
|
194
|
+
};
|
|
195
|
+
const verifySubmit = await timedCall(fx.ctx, verifyArgs);
|
|
196
|
+
controllerCalls += 1;
|
|
197
|
+
const processId = String(verifySubmit.value.data?.verification?.processId ?? '');
|
|
198
|
+
if (!processId) throw new Error('benchmark verification did not return a Process id');
|
|
199
|
+
const waitStartedAt = performance.now();
|
|
200
|
+
await waitForProcess(fx.controllerHome, fx.repository.repoId, processId, { timeoutMs: 10_000 });
|
|
201
|
+
const verifyWaitMs = Math.round((performance.now() - waitStartedAt) * 100) / 100;
|
|
202
|
+
processWaits += 1;
|
|
203
|
+
|
|
204
|
+
const verifyReattach = await timedCall(fx.ctx, verifyArgs);
|
|
205
|
+
controllerCalls += 1;
|
|
206
|
+
const verificationOutcome = String(verifyReattach.value.data?.verification?.outcome ?? '');
|
|
207
|
+
const verificationNextStep = typeof verifyReattach.value.data?.nextStep === 'string'
|
|
208
|
+
? verifyReattach.value.data.nextStep
|
|
209
|
+
: undefined;
|
|
210
|
+
if (verificationOutcome !== 'valid_pass') throw new Error(`benchmark verification outcome: ${verificationOutcome}`);
|
|
211
|
+
|
|
212
|
+
let continueMs = 0;
|
|
213
|
+
if (mode === 'legacy_ceremony') {
|
|
214
|
+
const continued = await timedCall(fx.ctx, {
|
|
215
|
+
repo_id: fx.repository.repoId,
|
|
216
|
+
operation: 'continue',
|
|
217
|
+
work_id: workId,
|
|
218
|
+
});
|
|
219
|
+
controllerCalls += 1;
|
|
220
|
+
continueMs = continued.elapsedMs;
|
|
221
|
+
if (continued.value.data?.nextStep !== 'finalize') throw new Error('legacy ceremony did not reach finalize');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const finalized = await timedCall(fx.ctx, {
|
|
225
|
+
repo_id: fx.repository.repoId,
|
|
226
|
+
operation: 'finalize',
|
|
227
|
+
work_id: workId,
|
|
228
|
+
});
|
|
229
|
+
controllerCalls += 1;
|
|
230
|
+
const finalStatus = String(finalized.value.data?.finalStatus ?? '');
|
|
231
|
+
const cleanupComplete = !existsSync(contract.worktreeRef);
|
|
232
|
+
const totalMs = Math.round((performance.now() - wallStartedAt) * 100) / 100;
|
|
233
|
+
return {
|
|
234
|
+
mode,
|
|
235
|
+
sample,
|
|
236
|
+
ok: finalStatus === 'completed' && cleanupComplete,
|
|
237
|
+
controllerCalls,
|
|
238
|
+
processWaits,
|
|
239
|
+
startMs: started.elapsedMs,
|
|
240
|
+
verifySubmitMs: verifySubmit.elapsedMs,
|
|
241
|
+
verifyWaitMs,
|
|
242
|
+
verifyReattachMs: verifyReattach.elapsedMs,
|
|
243
|
+
continueMs,
|
|
244
|
+
finalizeMs: finalized.elapsedMs,
|
|
245
|
+
totalMs,
|
|
246
|
+
verificationNextStep,
|
|
247
|
+
finalStatus,
|
|
248
|
+
cleanupComplete,
|
|
249
|
+
};
|
|
250
|
+
} finally {
|
|
251
|
+
clearRuntimeWriteClaimForTests();
|
|
252
|
+
rmSync(fx.root, { recursive: true, force: true });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function percentile(values: number[], p: number): number {
|
|
257
|
+
if (values.length === 0) return 0;
|
|
258
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
259
|
+
const index = Math.min(sorted.length - 1, Math.ceil(sorted.length * p) - 1);
|
|
260
|
+
return Math.round((sorted[Math.max(0, index)] ?? 0) * 100) / 100;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function summarize(samples: FlowSample[]) {
|
|
264
|
+
return {
|
|
265
|
+
count: samples.length,
|
|
266
|
+
allOk: samples.every((sample) => sample.ok),
|
|
267
|
+
controllerCalls: samples[0]?.controllerCalls ?? 0,
|
|
268
|
+
processWaits: samples[0]?.processWaits ?? 0,
|
|
269
|
+
totalMs: {
|
|
270
|
+
p50: percentile(samples.map((sample) => sample.totalMs), 0.5),
|
|
271
|
+
p95: percentile(samples.map((sample) => sample.totalMs), 0.95),
|
|
272
|
+
},
|
|
273
|
+
startMs: { p50: percentile(samples.map((sample) => sample.startMs), 0.5), p95: percentile(samples.map((sample) => sample.startMs), 0.95) },
|
|
274
|
+
verifyWallMs: {
|
|
275
|
+
p50: percentile(samples.map((sample) => sample.verifySubmitMs + sample.verifyWaitMs + sample.verifyReattachMs), 0.5),
|
|
276
|
+
p95: percentile(samples.map((sample) => sample.verifySubmitMs + sample.verifyWaitMs + sample.verifyReattachMs), 0.95),
|
|
277
|
+
},
|
|
278
|
+
continueMs: { p50: percentile(samples.map((sample) => sample.continueMs), 0.5), p95: percentile(samples.map((sample) => sample.continueMs), 0.95) },
|
|
279
|
+
finalizeMs: { p50: percentile(samples.map((sample) => sample.finalizeMs), 0.5), p95: percentile(samples.map((sample) => sample.finalizeMs), 0.95) },
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function main(): Promise<void> {
|
|
284
|
+
const sampleCount = Math.min(argNumber('--samples', 3), 10);
|
|
285
|
+
const sourceHeadBefore = git(process.cwd(), ['rev-parse', 'HEAD']);
|
|
286
|
+
const streamlined: FlowSample[] = [];
|
|
287
|
+
const legacy: FlowSample[] = [];
|
|
288
|
+
|
|
289
|
+
for (let sample = 1; sample <= sampleCount; sample += 1) {
|
|
290
|
+
if (sample % 2 === 1) {
|
|
291
|
+
streamlined.push(await runFlow('streamlined', sample));
|
|
292
|
+
legacy.push(await runFlow('legacy_ceremony', sample));
|
|
293
|
+
} else {
|
|
294
|
+
legacy.push(await runFlow('legacy_ceremony', sample));
|
|
295
|
+
streamlined.push(await runFlow('streamlined', sample));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const sourceHeadAfter = git(process.cwd(), ['rev-parse', 'HEAD']);
|
|
300
|
+
const streamlinedSummary = summarize(streamlined);
|
|
301
|
+
const legacySummary = summarize(legacy);
|
|
302
|
+
const result = {
|
|
303
|
+
schemaVersion: 1,
|
|
304
|
+
benchmark: 'work-efficiency',
|
|
305
|
+
revision: sourceHeadAfter,
|
|
306
|
+
generatedAt: new Date().toISOString(),
|
|
307
|
+
sampleCount,
|
|
308
|
+
methodology: 'Real rh_work start + managed Check Process + authoritative reattach + finalize on isolated temporary repositories. Legacy comparison adds only the mechanical continue call.',
|
|
309
|
+
streamlined: streamlinedSummary,
|
|
310
|
+
legacyCeremony: legacySummary,
|
|
311
|
+
productivity: {
|
|
312
|
+
controllerCallsSavedPerWork: legacySummary.controllerCalls - streamlinedSummary.controllerCalls,
|
|
313
|
+
controlRoundTripReductionRatio: legacySummary.controllerCalls > 0
|
|
314
|
+
? Math.round(((legacySummary.controllerCalls - streamlinedSummary.controllerCalls) / legacySummary.controllerCalls) * 10_000) / 10_000
|
|
315
|
+
: 0,
|
|
316
|
+
measuredContinueCeremonyMsP50: legacySummary.continueMs.p50,
|
|
317
|
+
totalWallClockDeltaMsP50: Math.round((legacySummary.totalMs.p50 - streamlinedSummary.totalMs.p50) * 100) / 100,
|
|
318
|
+
},
|
|
319
|
+
acceptance: {
|
|
320
|
+
sourceCheckoutHeadStable: sourceHeadBefore === sourceHeadAfter,
|
|
321
|
+
streamlinedAllOk: streamlinedSummary.allOk,
|
|
322
|
+
legacyAllOk: legacySummary.allOk,
|
|
323
|
+
streamlinedDirectsFinalPassToFinalize: streamlined.every((sample) => sample.verificationNextStep === 'finalize'),
|
|
324
|
+
oneControllerCallSaved: legacySummary.controllerCalls - streamlinedSummary.controllerCalls === 1,
|
|
325
|
+
cleanupComplete: [...streamlined, ...legacy].every((sample) => sample.cleanupComplete),
|
|
326
|
+
},
|
|
327
|
+
samples: { streamlined, legacyCeremony: legacy },
|
|
328
|
+
};
|
|
329
|
+
const allAccepted = Object.values(result.acceptance).every(Boolean);
|
|
330
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
331
|
+
if (!allAccepted) process.exitCode = 1;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
await main();
|
package/scripts/capture-plan.sh
CHANGED
|
@@ -266,7 +266,7 @@ Use the captured planning output below as the execution source of truth.
|
|
|
266
266
|
### Trade-offs
|
|
267
267
|
| Option | Pros | Cons | Decision |
|
|
268
268
|
|--------|------|------|----------|
|
|
269
|
-
| Captured plan | Preserves the approved
|
|
269
|
+
| Captured plan | Preserves the approved Codex Plan or Waza think decision | Requires the captured text to be concrete enough to execute | Use |
|
|
270
270
|
|
|
271
271
|
## Detailed Design
|
|
272
272
|
### File Changes
|
|
@@ -302,8 +302,8 @@ See captured planning output.
|
|
|
302
302
|
|
|
303
303
|
- **State/progress path**: \`${plan_file}\` task breakdown, \`tasks/todos.md\` deferred-goal ledger, \`tasks/contracts/${artifact_stem}.contract.md\`, \`tasks/reviews/${artifact_stem}.review.md\`, and \`tasks/notes/${artifact_stem}.notes.md\`
|
|
304
304
|
- **Verification evidence**: \`.ai/harness/checks/latest.json\`, \`.ai/harness/runs/\`, and the commands named in the captured planning output
|
|
305
|
-
- **
|
|
306
|
-
- **Stop condition**: all task breakdown items are complete
|
|
305
|
+
- **Impact review**: after direct checks, reassess user intent, affected domains, downstream consumers, state transitions, and residual risks
|
|
306
|
+
- **Stop condition**: all task breakdown items are complete and sprint verification reports direct checks plus declared scope passing
|
|
307
307
|
- **Rollback surface**: before execution remove \`${plan_file}\`; after execution revert branch \`codex/${slug}\` or the generated task artifacts
|
|
308
308
|
|
|
309
309
|
## Captured Planning Output
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
-
if command -v
|
|
4
|
+
if command -v node >/dev/null 2>&1; then
|
|
5
|
+
RUNTIME_BIN="$(command -v node)"
|
|
6
|
+
elif command -v bun >/dev/null 2>&1; then
|
|
5
7
|
RUNTIME_BIN="$(command -v bun)"
|
|
6
8
|
elif [[ -x "${HOME}/.bun/bin/bun" ]]; then
|
|
7
9
|
RUNTIME_BIN="${HOME}/.bun/bin/bun"
|
|
8
|
-
elif command -v node >/dev/null 2>&1; then
|
|
9
|
-
RUNTIME_BIN="$(command -v node)"
|
|
10
10
|
else
|
|
11
|
-
echo "check-agent-tooling.sh requires
|
|
11
|
+
echo "check-agent-tooling.sh requires node or bun" >&2
|
|
12
12
|
exit 1
|
|
13
13
|
fi
|
|
14
14
|
|
|
15
|
-
export FORGE_TOOLING_PATH_SNAPSHOT="${PATH:-}"
|
|
16
15
|
exec "$RUNTIME_BIN" - "$@" <<'NODE_EOF'
|
|
17
16
|
const fs = require("fs");
|
|
18
17
|
const crypto = require("crypto");
|
|
@@ -77,7 +76,6 @@ const WAZA_RAW_BASE_URL = "https://raw.githubusercontent.com/tw93/Waza/main";
|
|
|
77
76
|
const WAZA_MANAGED_SKILLS = ["think", "hunt", "check", "health"];
|
|
78
77
|
const WAZA_SHARED_RULES = ["anti-patterns.md", "chinese.md", "durable-context.md", "english.md"];
|
|
79
78
|
const CODEX_AUTOMATION_SKILLS = ["health", "check", "mermaid"];
|
|
80
|
-
const SKILLS_CLI_TIMEOUT_MS = 5000;
|
|
81
79
|
const CODEGRAPH_PACKAGE = "@colbymchenry/codegraph";
|
|
82
80
|
const CODEGRAPH_GLOBAL_INSTALL_COMMAND = `bun add -g ${CODEGRAPH_PACKAGE} && forge tools configure codegraph --target codex --location global`;
|
|
83
81
|
const GBRAIN_INSTALL_COMMAND = "bun install -g github:garrytan/gbrain";
|
|
@@ -140,21 +138,7 @@ function fileIsExecutable(filePath) {
|
|
|
140
138
|
|
|
141
139
|
function detectTimeoutBin() {
|
|
142
140
|
if (timeoutBin !== undefined) return timeoutBin;
|
|
143
|
-
|
|
144
|
-
if (!candidate) {
|
|
145
|
-
timeoutBin = "";
|
|
146
|
-
return timeoutBin;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const capability = spawnSync(candidate, ["--version"], {
|
|
150
|
-
encoding: "utf8",
|
|
151
|
-
timeout: 500,
|
|
152
|
-
env: process.env,
|
|
153
|
-
});
|
|
154
|
-
const output = `${capability.stdout || ""}\n${capability.stderr || ""}`;
|
|
155
|
-
timeoutBin = capability.status === 0 && /GNU coreutils|coreutils/i.test(output)
|
|
156
|
-
? candidate
|
|
157
|
-
: "";
|
|
141
|
+
timeoutBin = resolvePathCommand("timeout") || "";
|
|
158
142
|
return timeoutBin;
|
|
159
143
|
}
|
|
160
144
|
|
|
@@ -705,7 +689,7 @@ function detectWaza() {
|
|
|
705
689
|
const skillLock = readJson(skillLockPath);
|
|
706
690
|
const skillsBin = resolvePathCommand("skills");
|
|
707
691
|
const skillsResult = skillsBin
|
|
708
|
-
? run(skillsBin, ["ls", "-g", "--json"], { timeoutMs:
|
|
692
|
+
? run(skillsBin, ["ls", "-g", "--json"], { timeoutMs: 1500 })
|
|
709
693
|
: { ok: false, status: null, stdout: "", stderr: "", error: "skills CLI is not installed", timed_out: false };
|
|
710
694
|
const skillItems = skillsResult.ok ? parseJson(skillsResult.stdout) || [] : [];
|
|
711
695
|
const wazaEntries = Object.entries(skillLock?.skills || {}).filter(([, meta]) => meta?.source === WAZA_SOURCE_REPO);
|
|
@@ -1178,7 +1162,7 @@ function parseCodeGraphProjectStatus(output) {
|
|
|
1178
1162
|
}
|
|
1179
1163
|
|
|
1180
1164
|
function resolvePathCommand(command) {
|
|
1181
|
-
const pathValue = process.env.
|
|
1165
|
+
const pathValue = process.env.PATH || "";
|
|
1182
1166
|
for (const dir of pathValue.split(path.delimiter)) {
|
|
1183
1167
|
if (!dir) continue;
|
|
1184
1168
|
const candidate = path.join(dir, command);
|
|
@@ -1203,18 +1187,7 @@ function codeGraphPlatformPackageName() {
|
|
|
1203
1187
|
|
|
1204
1188
|
function codeGraphPlatformBundleBin() {
|
|
1205
1189
|
if (process.platform === "win32") return null;
|
|
1206
|
-
|
|
1207
|
-
if (fileIsExecutable(direct)) return direct;
|
|
1208
|
-
// Git worktrees commonly reuse the canonical checkout's dependencies. Resolve
|
|
1209
|
-
// the platform package through Node/Bun module lookup instead of declaring the
|
|
1210
|
-
// bundled Runtime missing just because this worktree has no local node_modules.
|
|
1211
|
-
try {
|
|
1212
|
-
const packageJson = require.resolve(`${codeGraphPlatformPackageName()}/package.json`, { paths: [REPO_ROOT] });
|
|
1213
|
-
const resolved = path.join(path.dirname(packageJson), "bin", "codegraph");
|
|
1214
|
-
return fileIsExecutable(resolved) ? resolved : direct;
|
|
1215
|
-
} catch {
|
|
1216
|
-
return direct;
|
|
1217
|
-
}
|
|
1190
|
+
return path.join(REPO_ROOT, "node_modules", codeGraphPlatformPackageName(), "bin", "codegraph");
|
|
1218
1191
|
}
|
|
1219
1192
|
|
|
1220
1193
|
function resolveCodeGraphBinary() {
|