@moretea-labs/forge 1.6.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -0
- package/CHANGELOG.md +39 -0
- package/CLAUDE.md +4 -0
- package/README.md +2 -2
- package/README.zh-CN.md +1 -1
- package/SKILL.md +2 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/hooks/hook-input.sh +11 -8
- package/assets/hooks/lib/session-state.sh +10 -7
- package/assets/hooks/lib/workflow-state.sh +13 -177
- package/assets/hooks/post-tool-observer.sh +8 -2
- package/assets/hooks/prompt-guard.sh +5 -81
- package/assets/hooks/session-start-context.sh +56 -1
- package/assets/partials/05-workflow.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +2 -0
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +3 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/contract.template.md +2 -7
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-architecture-sync.sh +17 -0
- package/assets/templates/helpers/check-task-workflow.sh +4 -4
- package/assets/templates/helpers/contract-worktree.sh +1 -21
- package/assets/templates/helpers/ensure-task-workflow.sh +11 -36
- package/assets/templates/helpers/inspect-project-state.ts +8 -6
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
- package/assets/templates/helpers/new-plan.sh +1 -1
- package/assets/templates/helpers/plan-to-todo.sh +12 -37
- package/assets/templates/helpers/ship-worktrees.sh +2 -29
- package/assets/templates/helpers/verify-contract.sh +1 -111
- package/assets/templates/helpers/verify-sprint.sh +3 -180
- package/assets/templates/helpers/workflow-contract.ts +5 -1
- package/assets/templates/plan.template.md +1 -1
- package/assets/templates/review.template.md +9 -34
- package/assets/workflow-contract.v1.json +10 -19
- package/docs/README.md +10 -10
- package/docs/architecture/CURRENT.md +178 -0
- package/docs/architecture/EVOLUTION.md +42 -0
- package/docs/architecture/current/README.md +4 -156
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
- package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
- package/docs/architecture/history/README.md +7 -0
- package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
- package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
- package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
- package/docs/architecture/history.md +3 -34
- package/docs/architecture/index.md +15 -98
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
- package/docs/architecture/versions/1.6.md +38 -0
- package/docs/architecture/versions/1.7.md +41 -0
- package/docs/forge-chatgpt-browser-engine.md +2 -2
- package/docs/forge-chatgpt-mcp-setup.md +4 -28
- package/docs/forge-chatgpt-supervised-automation.md +3 -3
- package/docs/forge-github-issue-launcher.md +1 -1
- package/docs/forge-plugin-management.md +1 -1
- package/docs/forge-runtime-self-healing-loop.md +1 -1
- package/docs/operations/controller-browser-plugin.md +26 -6
- package/docs/operations/controller-performance-and-502.md +143 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +2 -2
- package/docs/operations/github-repository.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +5 -3
- package/docs/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/package.json +33 -11
- package/scripts/activate-source-baseline.ts +17 -13
- package/scripts/architecture-event.ts +2 -820
- package/scripts/architecture-queue.sh +2 -645
- package/scripts/archive-architecture-request.sh +2 -242
- package/scripts/archive-workflow.sh +1 -291
- package/scripts/benchmark-background-check-overlap.ts +228 -0
- package/scripts/benchmark-mcp-host.sh +117 -0
- package/scripts/benchmark-mcp-transport.ts +170 -0
- package/scripts/benchmark-quality-harness.ts +146 -0
- package/scripts/benchmark-route-session-concurrency.ts +207 -6
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
- package/scripts/benchmark-typescript-navigation.ts +186 -0
- package/scripts/benchmark-work-efficiency.ts +334 -0
- package/scripts/capability-config.ts +2 -392
- package/scripts/capability-resolver.ts +2 -503
- package/scripts/capture-plan.sh +1 -332
- package/scripts/check-agent-tooling.sh +2 -1558
- package/scripts/check-architecture-sync.sh +2 -371
- package/scripts/check-brain-manifest.sh +2 -253
- package/scripts/check-context-files.sh +2 -47
- package/scripts/check-deploy-sql-order.sh +2 -115
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-runtime-architecture.mjs +349 -79
- package/scripts/check-skill-version.ts +3 -191
- package/scripts/check-source-duplication.mjs +61 -0
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-sync.sh +2 -63
- package/scripts/check-task-workflow.sh +2 -1000
- package/scripts/codex-handoff-resume.sh +2 -267
- package/scripts/context-contract-sync.sh +2 -514
- package/scripts/contract-run.ts +2 -463
- package/scripts/contract-worktree.sh +1 -722
- package/scripts/ensure-task-workflow.sh +1 -1225
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/inspect-project-state.ts +4 -279
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +22 -46
- package/scripts/lib/run-forge-helper.sh +19 -0
- package/scripts/lib/run-forge-helper.ts +26 -0
- package/scripts/migrate-project-template.sh +1 -1189
- package/scripts/migrate-workflow-docs.ts +4 -412
- package/scripts/new-plan.sh +1 -180
- package/scripts/new-spec.sh +1 -47
- package/scripts/new-sprint.sh +1 -46
- package/scripts/plan-to-todo.sh +1 -796
- package/scripts/prepare-codex-handoff.sh +2 -201
- package/scripts/prepare-handoff.sh +1 -78
- package/scripts/refresh-current-status.sh +2 -467
- package/scripts/run-governed-gate.ts +5 -1
- package/scripts/select-agent-context-blocks.sh +2 -64
- package/scripts/ship-worktrees.sh +1 -558
- package/scripts/smoke-ios-physical-device.ts +4 -2
- package/scripts/smoke-runtime-recovery.ts +1 -35
- package/scripts/smoke-schedule-engine.ts +1 -20
- package/scripts/sprint-backlog.sh +1 -834
- package/scripts/stage-runtime-release.ts +2 -1
- package/scripts/summarize-failures.sh +2 -123
- package/scripts/switch-plan.sh +1 -150
- package/scripts/sync-brain-docs.sh +2 -379
- package/scripts/sync-generated-authority.mjs +175 -0
- package/scripts/verify-contract.sh +2 -703
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +1 -677
- package/scripts/workflow-contract.ts +4 -205
- package/scripts/workstream-sync.sh +2 -261
- package/src/cli/agent-jobs/executor-health.ts +1 -1
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +12 -3
- package/src/cli/commands/recovery.ts +25 -3
- package/src/cli/commands/runtime.ts +55 -3
- package/src/cli/commands/security.ts +12 -1
- package/src/cli/commands/setup-profile.ts +31 -21
- package/src/cli/controller/check-runner.ts +113 -5
- package/src/cli/controller/composite-result.ts +1 -1
- package/src/cli/controller/context/focus.ts +51 -0
- package/src/cli/controller/context/instruction-context.ts +114 -0
- package/src/cli/controller/context/known-paths.ts +76 -0
- package/src/cli/controller/context/query-planning.ts +110 -0
- package/src/cli/controller/context/rule-resolution.ts +532 -0
- package/src/cli/controller/context/source-materializer.ts +278 -0
- package/src/cli/controller/context/structural.ts +16 -0
- package/src/cli/controller/context/types.ts +286 -0
- package/src/cli/controller/context-pack.ts +828 -487
- package/src/cli/controller/launch-agents.ts +77 -2
- package/src/cli/controller/operational-plan.ts +2 -2
- package/src/cli/controller/work-mode.ts +6 -4
- package/src/cli/editing/edit-session.ts +60 -7
- package/src/cli/github/contracts.ts +16 -0
- package/src/cli/github/github.ts +135 -16
- package/src/cli/github/session.ts +2 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +54 -78
- package/src/cli/local-bridge/console-view-models.ts +1 -35
- package/src/cli/local-bridge/facade-api.ts +37 -264
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
- package/src/cli/local-bridge/frontend/src/styles.css +1 -1
- package/src/cli/local-bridge/frontend/src/types.ts +5 -8
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +2 -515
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
- package/src/cli/mcp/auth.ts +5 -5
- package/src/cli/mcp/instructions.ts +3 -2
- package/src/cli/mcp/legacy-tool-service.ts +10 -222
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
- package/src/cli/mcp/repository-tools.ts +282 -146
- package/src/cli/mcp/server.ts +586 -116
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/tool-contract.ts +14 -0
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +44 -7
- package/src/cli/mcp/transports/http.ts +124 -14
- package/src/cli/mcp/transports/session-registry.ts +43 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +103 -21
- package/src/cli/repositories/command-executor.ts +78 -526
- package/src/cli/repositories/command-process.ts +108 -0
- package/src/cli/repositories/command-scope.ts +99 -41
- package/src/cli/repositories/controller-home.ts +7 -8
- package/src/cli/repositories/git-command-executor.ts +2 -0
- package/src/cli/repositories/locks.ts +53 -16
- package/src/cli/repositories/repository-snapshot.ts +124 -0
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +118 -6
- package/src/cli/repository/inspector.ts +563 -65
- package/src/cli/repository/session-cache.ts +58 -17
- package/src/cli/v81-entry.ts +1 -4
- package/src/effects/fs-transaction.ts +85 -17
- package/src/runtime/context/codegraph-read-provider.ts +233 -2
- package/src/runtime/context/codegraph-sidecar.cjs +74 -40
- package/src/runtime/context/generic-lsp-provider.ts +355 -0
- package/src/runtime/context/lsp-client.ts +283 -0
- package/src/runtime/context/semantic-navigation-contract.ts +61 -0
- package/src/runtime/context/semantic-navigation.ts +223 -0
- package/src/runtime/context/swift-navigation.ts +565 -0
- package/src/runtime/context/typescript-navigation.ts +226 -0
- package/src/runtime/control-plane/dispatch-priority.ts +28 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +48 -16
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
- package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
- package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
- package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
- package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
- package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
- package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
- package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
- package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
- package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +22 -18
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +156 -11
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
- package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
- package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +90 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +1118 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +302 -12
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +17 -1
- package/src/runtime/control-plane/facade/goal-workloop.ts +928 -190
- package/src/runtime/control-plane/facade/index.ts +3 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +275 -42
- package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
- package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
- package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
- package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
- package/src/runtime/control-plane/facade/types.ts +90 -10
- package/src/runtime/control-plane/facade/work-contract-store.ts +157 -261
- package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
- package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
- package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
- package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +152 -0
- package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +278 -543
- package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
- package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
- package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
- package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
- package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +63 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +365 -117
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +89 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +244 -11
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
- package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
- package/src/runtime/control-plane/release-retention.ts +62 -2
- package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
- package/src/runtime/control-plane/routing/route-policy.ts +24 -21
- package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
- package/src/runtime/control-plane/runtime-status-client.ts +0 -2
- package/src/runtime/diagnostics/mcp-timing.ts +13 -0
- package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
- package/src/runtime/diagnostics/performance.ts +24 -1
- package/src/runtime/evidence/event-ledger.ts +1 -1
- package/src/runtime/evidence/process-check-execution.ts +18 -0
- package/src/runtime/execution/jobs/child-reference.ts +6 -2
- package/src/runtime/execution/jobs/store.ts +58 -4
- package/src/runtime/execution/jobs/types.ts +1 -1
- package/src/runtime/execution/managed-workspace.ts +203 -1
- package/src/runtime/execution/process-runtime/check-facade.ts +51 -4
- package/src/runtime/execution/process-runtime/check-result.ts +88 -0
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +367 -40
- package/src/runtime/execution/process-runtime/gc.ts +38 -6
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1201 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +51 -5
- package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
- package/src/runtime/execution/process-runtime/runtime.ts +53 -3
- package/src/runtime/execution/process-runtime/store.ts +1 -0
- package/src/runtime/execution/process-runtime/types.ts +4 -12
- package/src/runtime/execution/thin-harness/async-process.ts +12 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
- package/src/runtime/execution/work-activity.ts +21 -0
- package/src/runtime/execution/workers/executor.ts +18 -61
- package/src/runtime/gateway/mcp/execution-tools.ts +35 -1852
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +186 -84
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +565 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2378 -1947
- package/src/runtime/plugins/app-store-connect-adapter.ts +216 -47
- package/src/runtime/plugins/browser-adapter.ts +2662 -829
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +2 -25
- package/src/runtime/plugins/browser-handoff.ts +110 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +701 -63
- package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
- package/src/runtime/plugins/browser-native-session-service.ts +222 -0
- package/src/runtime/plugins/browser-node-bridge.ts +6 -34
- package/src/runtime/plugins/browser-provider-registry.ts +109 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +154 -0
- package/src/runtime/plugins/browser-runtime.ts +193 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/browser-session-store.ts +121 -0
- package/src/runtime/plugins/browser-session-types.ts +98 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +10 -4
- package/src/runtime/plugins/external-adapter.ts +358 -3
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +2 -0
- package/src/runtime/plugins/github-adapter.ts +125 -0
- package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
- package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
- package/src/runtime/plugins/ios-adapter.ts +106 -16
- package/src/runtime/plugins/ios-agent-device.ts +234 -64
- package/src/runtime/plugins/ios-physical-device.ts +1143 -392
- package/src/runtime/plugins/lightweight-action.ts +153 -0
- package/src/runtime/plugins/local-system-adapter.ts +123 -6
- package/src/runtime/plugins/macos-capability-broker.ts +47 -9
- package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
- package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +330 -33
- package/src/runtime/plugins/types.ts +38 -3
- package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
- package/src/runtime/projections/git-status-sampler.ts +16 -16
- package/src/runtime/projections/materialized-view.ts +28 -10
- package/src/runtime/recovery/maintenance-executor.ts +426 -25
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +230 -10
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +461 -22
- package/src/runtime/root/release-manifest.ts +144 -18
- package/src/runtime/root/release-materialize.ts +125 -32
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -29
- package/src/runtime/root/types.ts +12 -0
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- package/src/runtime/shared/trusted-executable.ts +62 -0
- package/src/runtime/shared/trusted-node-executable.ts +48 -0
- package/src/runtime/standalone-recovery/core.ts +1079 -240
- package/src/runtime/standalone-recovery/entry.ts +100 -24
- package/src/runtime/standalone-recovery/installer.ts +20 -4
- package/src/runtime/standalone-recovery/service-labels.ts +2 -0
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
- package/src/runtime/workflow/schedules/browser-probe.ts +81 -3
- package/src/runtime/workflow/schedules/engine.ts +364 -202
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +64 -17
- package/src/runtime/workflow/schedules/store.ts +209 -19
- package/src/runtime/workflow/schedules/types.ts +2 -4
- package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
- package/src/testing/test-governance.ts +8 -40
- package/assets/reference-configs/heartbeat-triage.md +0 -57
- package/assets/templates/helpers/harness-trace-grade.sh +0 -150
- package/assets/templates/helpers/heartbeat-triage.sh +0 -361
- package/assets/templates/helpers/maintenance-triage.sh +0 -167
- package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
- package/docs/architecture/current/architecture-invariants.md +0 -331
- package/docs/architecture/current/automation-and-schedule-engine.md +0 -459
- package/docs/architecture/current/codegraph-context-provider.md +0 -238
- package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
- package/docs/architecture/current/controller-repository-decoupling.md +0 -148
- package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -373
- package/docs/architecture/current/entity-model.md +0 -612
- package/docs/architecture/current/external-plugin-governance.md +0 -396
- package/docs/architecture/current/failure-recovery.md +0 -447
- package/docs/architecture/current/governance.md +0 -213
- package/docs/architecture/current/human-interaction-plane.md +0 -87
- package/docs/architecture/current/implementation-status.md +0 -128
- package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
- package/docs/architecture/current/legacy-governance.md +0 -58
- package/docs/architecture/current/local-workspace-target-grants.md +0 -70
- package/docs/architecture/current/migration-roadmap.md +0 -105
- package/docs/architecture/current/multi-repository-execution.md +0 -371
- package/docs/architecture/current/operations-runbook.md +0 -45
- package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
- package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
- package/docs/architecture/current/repository-access-modes.md +0 -102
- package/docs/architecture/current/route-policy.md +0 -15
- package/docs/architecture/current/route-session-concurrency.md +0 -85
- package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
- package/docs/architecture/current/runtime-directory-map.md +0 -49
- package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
- package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
- package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
- package/docs/architecture/current/system-overview.md +0 -169
- package/docs/architecture/current/target-requirements-traceability.md +0 -202
- package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
- package/docs/architecture/current/thin-harness-v1.md +0 -321
- package/docs/architecture/current/verification-and-release-gates.md +0 -391
- package/docs/forge-autonomous-goal-loop.md +0 -9
- package/docs/forge-provider-configuration.md +0 -7
- package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -93
- package/docs/operations/gmail-assistant-routines.md +0 -186
- package/docs/operations/personal-assistant-operator-guide.md +0 -61
- package/docs/operations/provider-configuration.md +0 -31
- package/scripts/harness-trace-grade.sh +0 -150
- package/scripts/heartbeat-triage.sh +0 -361
- package/scripts/maintenance-triage.sh +0 -167
- package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
- package/src/cli/repositories/goal-registry.ts +0 -239
- package/src/runtime/assistant/action-proposals.ts +0 -279
- package/src/runtime/assistant/intent.ts +0 -395
- package/src/runtime/assistant/model-provider.ts +0 -460
- package/src/runtime/assistant/openapi.ts +0 -223
- package/src/runtime/assistant/policy.ts +0 -89
- package/src/runtime/assistant/readiness.ts +0 -258
- package/src/runtime/assistant/routine-runtime.ts +0 -477
- package/src/runtime/assistant/schedule-binding.ts +0 -171
- package/src/runtime/assistant/standing-grants.ts +0 -375
- package/src/runtime/assistant/store.ts +0 -243
- package/src/runtime/assistant/types.ts +0 -135
- package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
- package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
- package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
- package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
- package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
- package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
- package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
- package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
- package/src/runtime/control-plane/goal-loop/index.ts +0 -13
- package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
- package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
- package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
- package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
- package/src/runtime/control-plane/goal-loop/types.ts +0 -378
- package/src/runtime/control-plane/startup-recovery.ts +0 -198
- package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
- package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
- package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
- package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
- package/src/runtime/workflow/findings/store.ts +0 -204
- package/src/runtime/workflow/findings/types.ts +0 -58
- package/src/runtime/workflow/portfolio/engine.ts +0 -20
- package/src/runtime/workflow/portfolio/store.ts +0 -185
- package/src/runtime/workflow/portfolio/types.ts +0 -29
|
@@ -2,9 +2,9 @@ import { bindRepositoryEntities } from '../repositories/entity-migration';
|
|
|
2
2
|
import { bootstrapLocalProject, diagnoseLatestLocalProjectSource } from '../repositories/local-project-onboarding';
|
|
3
3
|
import { resolveEphemeralWorkspaceTarget } from '../repositories/ephemeral-workspace';
|
|
4
4
|
import type { ResolvedExecutionIdentity } from '../../runtime/control-plane/execution/execution-identity';
|
|
5
|
-
import {
|
|
5
|
+
import { assertNoBoundExecutionSessionMutation, resolveClaimedRepositoryWorkId, resolveExplicitClaimedRepositoryWork, type RepositoryWorkAttributionCaller } from '../../runtime/control-plane/execution/repository-work-attribution';
|
|
6
6
|
import { getWorkContract } from '../../runtime/control-plane/facade/work-contract-store';
|
|
7
|
-
import {
|
|
7
|
+
import { assertWorkPathsWithinScope } from '../../runtime/control-plane/execution/work-path-scope';
|
|
8
8
|
import { isTerminalWorkContractStatus } from '../../runtime/control-plane/facade/types';
|
|
9
9
|
import { executeRepositoryCommand, previewRepositoryCommandExecution } from '../repositories/command-executor';
|
|
10
10
|
import { withControllerLock } from '../repositories/locks';
|
|
@@ -24,9 +24,8 @@ import {
|
|
|
24
24
|
} from '../repositories/registry';
|
|
25
25
|
import { buildControllerWorkbench } from '../repositories/workbench';
|
|
26
26
|
import { applySafePatch, buildSafePatchPlan } from '../repositories/safe-patch';
|
|
27
|
-
import { getEditSessionDiff, type EditSessionBinding } from '../editing/edit-session';
|
|
27
|
+
import { getEditSession, getEditSessionDiff, type EditSessionBinding } from '../editing/edit-session';
|
|
28
28
|
import { buildSyncOperationDigest, classifyUserFacingError } from '../../runtime/control-plane/facade/operation-digest';
|
|
29
|
-
import { diagnoseRepositoryStuckState, listRepositoryGoalRuns, readRepositoryGoalRegistry, runRepositoryGoal, upsertRepositoryGoal } from '../repositories/goal-registry';
|
|
30
29
|
import {
|
|
31
30
|
repositoryGitCommit,
|
|
32
31
|
repositoryGitCreateBranch,
|
|
@@ -54,8 +53,12 @@ import {
|
|
|
54
53
|
executeRepositoryCommandViaProcessRuntime,
|
|
55
54
|
} from '../../runtime/execution/process-runtime/command-facade';
|
|
56
55
|
import { assessWorkMode, parseExplicitTaskMode } from '../controller/work-mode';
|
|
56
|
+
import { classifyRepositoryCommand } from '../repositories/command-classifier';
|
|
57
57
|
import { normalizeRepositoryCommand } from '../repositories/command-normalization';
|
|
58
|
-
import
|
|
58
|
+
import { readRepositoryRange } from '../repository/inspector';
|
|
59
|
+
import { getMcpPolicy } from './policy';
|
|
60
|
+
import { redactMcpText } from './redaction';
|
|
61
|
+
import type { CallToolResult, McpToolDefinition } from './tool-contract';
|
|
59
62
|
import {
|
|
60
63
|
boundUtf8,
|
|
61
64
|
compactCommandOutput,
|
|
@@ -117,6 +120,13 @@ export const repositoryToolDefinitions: McpToolDefinition[] = [
|
|
|
117
120
|
include_removed: { type: 'boolean' },
|
|
118
121
|
detail_level: { type: 'string', enum: ['summary', 'detail'], description: 'Defaults to summary; detail returns the complete checkout history.' },
|
|
119
122
|
}, ['repo_id'], true),
|
|
123
|
+
definition('read_repository_file', 'Read a line range from one policy-readable repository file.', {
|
|
124
|
+
repo_id: repoId,
|
|
125
|
+
checkout_id: { type: 'string' },
|
|
126
|
+
path: { type: 'string' },
|
|
127
|
+
start_line: { type: 'number' },
|
|
128
|
+
end_line: { type: 'number' },
|
|
129
|
+
}, ['path'], true),
|
|
120
130
|
definition('repository_validate', 'Validate repository identity and migrate legacy ownership.', {
|
|
121
131
|
repo_id: repoId,
|
|
122
132
|
detail_level: { type: 'string', enum: ['summary', 'detail'], description: 'Defaults to summary; detail returns full migration evidence.' },
|
|
@@ -136,7 +146,7 @@ export const repositoryToolDefinitions: McpToolDefinition[] = [
|
|
|
136
146
|
}, ['repo_id']),
|
|
137
147
|
definition('repository_remove', 'Soft-remove a repository while retaining audit history.', {
|
|
138
148
|
repo_id: repoId,
|
|
139
|
-
}, ['repo_id']
|
|
149
|
+
}, ['repo_id']),
|
|
140
150
|
definition('repository_workbench', 'Return Workbench state or invoke one bounded Thin Harness operation without adding top-level MCP tools. Prefer batch_execute for multi-step status→search→read→diff or read→patch→check flows so ChatGPT pays one routing/receipt ownership cycle.', {
|
|
141
151
|
repo_id: repoId,
|
|
142
152
|
checkout_id: { type: 'string', description: 'Optional checkout identity for repository-scoped operations.' },
|
|
@@ -152,38 +162,6 @@ export const repositoryToolDefinitions: McpToolDefinition[] = [
|
|
|
152
162
|
additionalProperties: true,
|
|
153
163
|
},
|
|
154
164
|
}),
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
definition('repository_goal_list', 'List durable repository goals stored inside the checkout.', {
|
|
159
|
-
repo_id: repoId,
|
|
160
|
-
checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
|
|
161
|
-
}, [], true),
|
|
162
|
-
definition('repository_goal_upsert', 'Create or update one durable repository goal for repeated assistant workflows.', {
|
|
163
|
-
repo_id: repoId,
|
|
164
|
-
checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
|
|
165
|
-
id: { type: 'string' },
|
|
166
|
-
title: { type: 'string' },
|
|
167
|
-
status: { type: 'string', enum: ['active', 'paused', 'done'] },
|
|
168
|
-
checks: { type: 'array', items: { type: 'string' } },
|
|
169
|
-
notes: { type: 'string' },
|
|
170
|
-
}, []),
|
|
171
|
-
definition('repository_stuck_diagnose', 'Diagnose likely repository workflow blockers from Git state and registered goals.', {
|
|
172
|
-
repo_id: repoId,
|
|
173
|
-
checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
|
|
174
|
-
}, [], true),
|
|
175
|
-
definition('repository_goal_run', 'Run one durable repository goal iteration, optionally executing its configured checks and recording a goal-run artifact.', {
|
|
176
|
-
repo_id: repoId,
|
|
177
|
-
checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
|
|
178
|
-
goal_id: { type: 'string', description: 'Goal id. Defaults to the first active goal.' },
|
|
179
|
-
run_checks: { type: 'boolean', description: 'When true, execute configured checks. Defaults to diagnosis-only.' },
|
|
180
|
-
}, []),
|
|
181
|
-
definition('repository_goal_runs', 'List recent repository goal-run artifacts.', {
|
|
182
|
-
repo_id: repoId,
|
|
183
|
-
checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
|
|
184
|
-
limit: { type: 'number' },
|
|
185
|
-
}, [], true),
|
|
186
|
-
|
|
187
165
|
definition('repository_git_status', 'Return a structured Git status snapshot for the selected repository checkout.', {
|
|
188
166
|
repo_id: repoId,
|
|
189
167
|
checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
|
|
@@ -270,7 +248,7 @@ export const repositoryToolDefinitions: McpToolDefinition[] = [
|
|
|
270
248
|
cwd: { type: 'string', description: 'Optional root-relative working directory.' },
|
|
271
249
|
workspace_root: { type: 'string', description: 'Absolute existing local directory used as an ephemeral execution root. Mutually exclusive with repo_id/checkout_id; does not register or initialize the directory.' },
|
|
272
250
|
}, ['command'], true),
|
|
273
|
-
definition('repository_command_execute', 'Execute one repository-scoped
|
|
251
|
+
definition('repository_command_execute', 'Execute one repository-scoped command through the thinnest eligible lane: ephemeral for ordinary local work, an in-memory lightweight handle when it outlives the interaction budget, or explicit Durable handling for Work/external/release effects. Lightweight handles have no SQLite, Lease, recovery, or replay membership. Use rh_context for routine code discovery/reading; shell exploration is fallback-only.', {
|
|
274
252
|
repo_id: repoId,
|
|
275
253
|
checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
|
|
276
254
|
work_id: { type: 'string', description: 'Optional durable Work identity. Workflow controllers should pass the exact claimed Work id so attribution survives transient MCP transport sessions.' },
|
|
@@ -310,59 +288,15 @@ function withResponseMeta(payload: Record<string, unknown>, startedAt: number):
|
|
|
310
288
|
return response;
|
|
311
289
|
}
|
|
312
290
|
|
|
313
|
-
export
|
|
314
|
-
sessionId?: string;
|
|
315
|
-
principalId?: string;
|
|
316
|
-
controllerInstanceId?: string;
|
|
317
|
-
}
|
|
291
|
+
export type RepositoryToolCallerContext = RepositoryWorkAttributionCaller;
|
|
318
292
|
|
|
319
|
-
function
|
|
320
|
-
controllerHome: string,
|
|
321
|
-
repository: ReturnType<typeof resolveRepositorySelection>,
|
|
322
|
-
caller?: RepositoryToolCallerContext,
|
|
323
|
-
explicitWorkId?: unknown,
|
|
324
|
-
): string | undefined {
|
|
325
|
-
if (!caller?.principalId?.trim()) return undefined;
|
|
326
|
-
const requestedWorkId = typeof explicitWorkId === 'string' ? explicitWorkId.trim() : '';
|
|
327
|
-
if (requestedWorkId) {
|
|
328
|
-
const work = getWorkContract({ controllerHome, repoId: repository.repoId }, requestedWorkId);
|
|
329
|
-
if (!work || isTerminalWorkContractStatus(work.status)) throw new Error(`WORK_ATTRIBUTION_INVALID: ${requestedWorkId}`);
|
|
330
|
-
if (work.checkoutId && work.checkoutId !== repository.activeCheckoutId) throw new Error(`WORK_CHECKOUT_MISMATCH: ${requestedWorkId}:${repository.activeCheckoutId}`);
|
|
331
|
-
const owner = getControllerSession({ controllerHome, repoId: repository.repoId }, requestedWorkId);
|
|
332
|
-
if (!owner) throw new Error(`WORK_CONTROLLER_CLAIM_REQUIRED: ${requestedWorkId}`);
|
|
333
|
-
if ((owner.principalId?.trim() || owner.controllerId) !== caller.principalId.trim()) throw new Error(`WORK_CONTROLLER_OWNERSHIP_MISMATCH: ${requestedWorkId}`);
|
|
334
|
-
return requestedWorkId;
|
|
335
|
-
}
|
|
336
|
-
if (caller.sessionId?.trim()) {
|
|
337
|
-
const executionSession = readExecutionSession(controllerHome, {
|
|
338
|
-
sessionId: caller.sessionId,
|
|
339
|
-
principalId: caller.principalId,
|
|
340
|
-
controllerInstanceId: caller.controllerInstanceId,
|
|
341
|
-
});
|
|
342
|
-
const workId = executionSession?.activeWorkId?.trim();
|
|
343
|
-
if (workId && executionSession?.activeRepositoryId === repository.repoId && (!executionSession.activeCheckoutId || executionSession.activeCheckoutId === repository.activeCheckoutId)) {
|
|
344
|
-
const work = getWorkContract({ controllerHome, repoId: repository.repoId }, workId);
|
|
345
|
-
const owner = getControllerSession({ controllerHome, repoId: repository.repoId }, workId);
|
|
346
|
-
if (work && !isTerminalWorkContractStatus(work.status) && owner?.sessionId === caller.sessionId && (owner.principalId?.trim() || owner.controllerId) === caller.principalId.trim()) return workId;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
const principal = caller.principalId.trim();
|
|
350
|
-
const candidates = listControllerSessions({ controllerHome, repoId: repository.repoId })
|
|
351
|
-
.filter((owner) => (owner.principalId?.trim() || owner.controllerId) === principal)
|
|
352
|
-
.map((owner) => ({ owner, work: getWorkContract({ controllerHome, repoId: repository.repoId }, owner.workId) }))
|
|
353
|
-
.filter((entry): entry is { owner: ReturnType<typeof listControllerSessions>[number]; work: NonNullable<ReturnType<typeof getWorkContract>> } => Boolean(entry.work && !isTerminalWorkContractStatus(entry.work.status) && (!entry.work.checkoutId || entry.work.checkoutId === repository.activeCheckoutId)));
|
|
354
|
-
if (candidates.length === 1) return candidates[0].work.workId;
|
|
355
|
-
if (candidates.length > 1) throw new Error(`WORK_ATTRIBUTION_AMBIGUOUS: principal ${principal} owns ${candidates.length} active Works on checkout ${repository.activeCheckoutId}`);
|
|
356
|
-
return undefined;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function claimedSessionEditBinding(
|
|
293
|
+
export function claimedSessionEditBinding(
|
|
360
294
|
controllerHome: string,
|
|
361
295
|
repository: ReturnType<typeof resolveRepositorySelection>,
|
|
362
296
|
caller?: RepositoryToolCallerContext,
|
|
363
297
|
explicitWorkId?: unknown,
|
|
364
298
|
): EditSessionBinding | undefined {
|
|
365
|
-
const workId =
|
|
299
|
+
const workId = resolveClaimedRepositoryWorkId(controllerHome, repository, caller, explicitWorkId);
|
|
366
300
|
if (!workId || !caller?.principalId?.trim()) return undefined;
|
|
367
301
|
const work = getWorkContract({ controllerHome, repoId: repository.repoId }, workId);
|
|
368
302
|
if (!work) return undefined;
|
|
@@ -376,8 +310,52 @@ function claimedSessionEditBinding(
|
|
|
376
310
|
};
|
|
377
311
|
}
|
|
378
312
|
|
|
379
|
-
function
|
|
380
|
-
|
|
313
|
+
function safePatchEditBinding(
|
|
314
|
+
controllerHome: string,
|
|
315
|
+
repository: ReturnType<typeof resolveRepositorySelection>,
|
|
316
|
+
caller: RepositoryToolCallerContext | undefined,
|
|
317
|
+
args: Record<string, unknown>,
|
|
318
|
+
): EditSessionBinding | undefined {
|
|
319
|
+
const explicitWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
|
|
320
|
+
if (explicitWorkId) return claimedSessionEditBinding(controllerHome, repository, caller, explicitWorkId);
|
|
321
|
+
const sessionId = typeof args.session_id === 'string' ? args.session_id.trim() : '';
|
|
322
|
+
if (sessionId) {
|
|
323
|
+
const existingWorkId = getEditSession(repository.canonicalRoot, sessionId).workId?.trim();
|
|
324
|
+
return existingWorkId
|
|
325
|
+
? claimedSessionEditBinding(controllerHome, repository, caller, existingWorkId)
|
|
326
|
+
: undefined;
|
|
327
|
+
}
|
|
328
|
+
assertNoBoundExecutionSessionMutation(controllerHome, repository, caller);
|
|
329
|
+
return undefined;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function resolveRepositorySelectionForClaimedWork(
|
|
333
|
+
controllerHome: string,
|
|
334
|
+
args: Record<string, unknown>,
|
|
335
|
+
repoIdValue: string,
|
|
336
|
+
caller?: RepositoryToolCallerContext,
|
|
337
|
+
): ReturnType<typeof resolveRepositorySelection> {
|
|
338
|
+
const checkoutId = typeof args.checkout_id === 'string' ? args.checkout_id.trim() : '';
|
|
339
|
+
const explicitWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
|
|
340
|
+
const repository = resolveRepositorySelection({
|
|
341
|
+
repoId: repoIdValue || undefined,
|
|
342
|
+
checkoutId: checkoutId || undefined,
|
|
343
|
+
controllerHome,
|
|
344
|
+
allowSoleRepository: true,
|
|
345
|
+
});
|
|
346
|
+
if (!explicitWorkId || checkoutId) return repository;
|
|
347
|
+
const work = resolveExplicitClaimedRepositoryWork(controllerHome, repository, caller, explicitWorkId);
|
|
348
|
+
if (!work?.checkoutId || work.checkoutId === repository.activeCheckoutId) return repository;
|
|
349
|
+
return resolveRepositorySelection({
|
|
350
|
+
repoId: repository.repoId,
|
|
351
|
+
checkoutId: work.checkoutId,
|
|
352
|
+
controllerHome,
|
|
353
|
+
allowSoleRepository: true,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function rawDefaultBranchMergeCommand(repository: ReturnType<typeof resolveRepositorySelection>, command: unknown): boolean {
|
|
358
|
+
if (!repository.defaultBranch) return false;
|
|
381
359
|
const checkout = repository.checkouts.find((entry) => entry.checkoutId === repository.activeCheckoutId);
|
|
382
360
|
if (checkout?.branch !== repository.defaultBranch) return false;
|
|
383
361
|
const normalized = normalizeRepositoryCommand(command);
|
|
@@ -388,6 +366,32 @@ function activeWorkflowRawDefaultMergeBlocked(repository: ReturnType<typeof reso
|
|
|
388
366
|
return /(?:^|[;&|]\s*)git\s+merge\b/.test(normalized.shellCommand ?? '');
|
|
389
367
|
}
|
|
390
368
|
|
|
369
|
+
interface HistoricalReadOnlyWorkContext {
|
|
370
|
+
workId: string;
|
|
371
|
+
status: string;
|
|
372
|
+
mode: 'historical_read_only_observation';
|
|
373
|
+
attribution: 'not_active_work';
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function historicalReadOnlyWorkContext(
|
|
377
|
+
controllerHome: string,
|
|
378
|
+
repository: ReturnType<typeof resolveRepositorySelection>,
|
|
379
|
+
args: Record<string, unknown>,
|
|
380
|
+
): HistoricalReadOnlyWorkContext | undefined {
|
|
381
|
+
const requestedWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
|
|
382
|
+
if (!requestedWorkId) return undefined;
|
|
383
|
+
const work = getWorkContract({ controllerHome, repoId: repository.repoId }, requestedWorkId);
|
|
384
|
+
if (!work || !isTerminalWorkContractStatus(work.status)) return undefined;
|
|
385
|
+
const classification = classifyRepositoryCommand(args.command as string | string[], repository.defaultBranch);
|
|
386
|
+
if (classification.risk !== 'readonly') return undefined;
|
|
387
|
+
return {
|
|
388
|
+
workId: work.workId,
|
|
389
|
+
status: work.status,
|
|
390
|
+
mode: 'historical_read_only_observation',
|
|
391
|
+
attribution: 'not_active_work',
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
391
395
|
function resolveRepositoryCommandTarget(
|
|
392
396
|
controllerHome: string,
|
|
393
397
|
args: Record<string, unknown>,
|
|
@@ -397,6 +401,7 @@ function resolveRepositoryCommandTarget(
|
|
|
397
401
|
repository: ReturnType<typeof resolveRepositorySelection>;
|
|
398
402
|
executionIdentity: ResolvedExecutionIdentity;
|
|
399
403
|
workspace?: { workspaceId: string; root: string; registered: false };
|
|
404
|
+
historicalWorkContext?: HistoricalReadOnlyWorkContext;
|
|
400
405
|
} {
|
|
401
406
|
const workspaceRoot = typeof args.workspace_root === 'string' ? args.workspace_root.trim() : '';
|
|
402
407
|
const checkoutId = typeof args.checkout_id === 'string' ? args.checkout_id.trim() : '';
|
|
@@ -417,13 +422,38 @@ function resolveRepositoryCommandTarget(
|
|
|
417
422
|
workspace: { workspaceId: target.workspaceId, root: target.canonicalRoot, registered: false },
|
|
418
423
|
};
|
|
419
424
|
}
|
|
420
|
-
|
|
425
|
+
// A terminal Work no longer owns mutation or checkout authority. An exact
|
|
426
|
+
// terminal work_id may still accompany a read-only observation immediately
|
|
427
|
+
// after finalize, so preserve it as explicit historical context while
|
|
428
|
+
// executing against the caller-selected/current repository checkout. Any
|
|
429
|
+
// non-read-only command continues through claimed Work resolution and fails
|
|
430
|
+
// closed for terminal attribution.
|
|
431
|
+
const selectedRepository = resolveRepositorySelection({
|
|
421
432
|
repoId: repoIdValue || undefined,
|
|
422
433
|
checkoutId: checkoutId || undefined,
|
|
423
434
|
controllerHome,
|
|
424
435
|
allowSoleRepository: true,
|
|
425
436
|
});
|
|
426
|
-
const
|
|
437
|
+
const historicalWorkContext = historicalReadOnlyWorkContext(controllerHome, selectedRepository, args);
|
|
438
|
+
if (historicalWorkContext) {
|
|
439
|
+
return {
|
|
440
|
+
repository: selectedRepository,
|
|
441
|
+
executionIdentity: {
|
|
442
|
+
schemaVersion: 1,
|
|
443
|
+
authority: 'repository',
|
|
444
|
+
repositoryId: selectedRepository.repoId,
|
|
445
|
+
checkoutId: selectedRepository.activeCheckoutId,
|
|
446
|
+
canonicalRoot: selectedRepository.canonicalRoot,
|
|
447
|
+
},
|
|
448
|
+
historicalWorkContext,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const repository = resolveRepositorySelectionForClaimedWork(controllerHome, args, repoIdValue, caller);
|
|
453
|
+
const explicitWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
|
|
454
|
+
const workId = explicitWorkId
|
|
455
|
+
? resolveClaimedRepositoryWorkId(controllerHome, repository, caller, explicitWorkId)
|
|
456
|
+
: undefined;
|
|
427
457
|
return {
|
|
428
458
|
repository,
|
|
429
459
|
executionIdentity: {
|
|
@@ -523,6 +553,33 @@ function failure(error: unknown): RepositoryToolResult {
|
|
|
523
553
|
return { ...result({ error: { code, message, ...(compactDetails !== undefined ? { details: compactDetails } : {}) } }), isError: true };
|
|
524
554
|
}
|
|
525
555
|
|
|
556
|
+
interface RepositoryExplorationGuidance {
|
|
557
|
+
code: 'FRAGMENTED_REPOSITORY_EXPLORATION';
|
|
558
|
+
recommendedTool: 'rh_context';
|
|
559
|
+
recommendedOperation: 'search';
|
|
560
|
+
message: string;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function fragmentedRepositoryExplorationGuidance(command: unknown): RepositoryExplorationGuidance | undefined {
|
|
564
|
+
if (typeof command !== 'string') return undefined;
|
|
565
|
+
const segments = command.split(/(?:&&|\|\||[;|])/g);
|
|
566
|
+
const readPrograms = new Set<string>();
|
|
567
|
+
let readStepCount = 0;
|
|
568
|
+
for (const segment of segments) {
|
|
569
|
+
const match = segment.trim().match(/^(?:(?:command|env)\s+)?(?:[A-Za-z_][A-Za-z0-9_]*=[^\s]+\s+)*(rg|grep|sed|cat|head|tail)\b/i);
|
|
570
|
+
if (!match) continue;
|
|
571
|
+
readStepCount += 1;
|
|
572
|
+
readPrograms.add(match[1]!.toLowerCase());
|
|
573
|
+
}
|
|
574
|
+
if (readStepCount < 2) return undefined;
|
|
575
|
+
return {
|
|
576
|
+
code: 'FRAGMENTED_REPOSITORY_EXPLORATION',
|
|
577
|
+
recommendedTool: 'rh_context',
|
|
578
|
+
recommendedOperation: 'search',
|
|
579
|
+
message: `Detected ${readStepCount} chained repository read steps (${[...readPrograms].join(', ')}). Prefer a broad rh_context request first, then repeat rh_context with selected paths or relationships when more evidence can improve correctness; keep shell search as fallback when the Context Plane cannot supply the needed evidence.`,
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
|
|
526
583
|
function compactProcessCommandPayload(input: {
|
|
527
584
|
accepted?: boolean;
|
|
528
585
|
mode: string;
|
|
@@ -533,6 +590,7 @@ function compactProcessCommandPayload(input: {
|
|
|
533
590
|
repoId: string;
|
|
534
591
|
checkoutId?: string;
|
|
535
592
|
workspace?: { workspaceId: string; root: string; registered: false };
|
|
593
|
+
historicalWorkContext?: HistoricalReadOnlyWorkContext;
|
|
536
594
|
processId?: string;
|
|
537
595
|
process?: unknown;
|
|
538
596
|
completed?: boolean;
|
|
@@ -545,6 +603,7 @@ function compactProcessCommandPayload(input: {
|
|
|
545
603
|
/** summary (default) omits nested process / routing dumps; detail restores diagnostics. */
|
|
546
604
|
detailLevel?: 'summary' | 'detail';
|
|
547
605
|
includeFullProcess?: boolean;
|
|
606
|
+
guidance?: RepositoryExplorationGuidance;
|
|
548
607
|
}): Record<string, unknown> {
|
|
549
608
|
const output = compactCommandOutput(input.stdout, input.stderr, { ok: input.ok === true });
|
|
550
609
|
const detail = input.detailLevel === 'detail' || input.includeFullProcess === true;
|
|
@@ -570,12 +629,17 @@ function compactProcessCommandPayload(input: {
|
|
|
570
629
|
repoId: input.repoId,
|
|
571
630
|
...(input.checkoutId ? { checkoutId: input.checkoutId } : {}),
|
|
572
631
|
...(input.workspace ? { workspace: input.workspace } : {}),
|
|
632
|
+
...(input.historicalWorkContext ? { historicalWorkContext: input.historicalWorkContext } : {}),
|
|
573
633
|
...(input.processId ? { processId: input.processId } : {}),
|
|
574
634
|
...(completed ? { exitCode: input.exitCode ?? (ok ? 0 : 1) } : {}),
|
|
635
|
+
// A running default response otherwise loses its only dependency-bound
|
|
636
|
+
// continuation advice when the detailed Process record is omitted.
|
|
637
|
+
...(!completed ? { next: input.next } : {}),
|
|
575
638
|
stdout: output.stdout ?? '',
|
|
576
639
|
stderr: output.stderr ?? '',
|
|
577
640
|
...(output.stdoutTruncated ? { stdoutTruncated: true, stdoutBytes: output.stdoutBytes } : {}),
|
|
578
641
|
...(output.stderrTruncated ? { stderrTruncated: true, stderrBytes: output.stderrBytes } : {}),
|
|
642
|
+
...(input.guidance ? { guidance: input.guidance, suggestedOperation: 'rh_context' } : {}),
|
|
579
643
|
};
|
|
580
644
|
if (completed && !ok) {
|
|
581
645
|
payload.error = {
|
|
@@ -606,6 +670,7 @@ function compactProcessCommandPayload(input: {
|
|
|
606
670
|
repoId: input.repoId,
|
|
607
671
|
...(input.checkoutId ? { checkoutId: input.checkoutId } : {}),
|
|
608
672
|
...(input.workspace ? { workspace: input.workspace } : {}),
|
|
673
|
+
...(input.historicalWorkContext ? { historicalWorkContext: input.historicalWorkContext } : {}),
|
|
609
674
|
...(input.processId ? { processId: input.processId } : {}),
|
|
610
675
|
ok: input.ok,
|
|
611
676
|
exitCode: input.exitCode,
|
|
@@ -623,6 +688,7 @@ function compactProcessCommandPayload(input: {
|
|
|
623
688
|
}
|
|
624
689
|
: {}),
|
|
625
690
|
durableSideEffects: effects,
|
|
691
|
+
...(input.guidance ? { guidance: input.guidance, suggestedOperation: 'rh_context' } : {}),
|
|
626
692
|
next: input.next,
|
|
627
693
|
detailLevel: 'detail',
|
|
628
694
|
};
|
|
@@ -664,10 +730,33 @@ export async function callRepositoryTool(
|
|
|
664
730
|
args: Record<string, unknown>,
|
|
665
731
|
caller?: RepositoryToolCallerContext,
|
|
666
732
|
): Promise<RepositoryToolResult | undefined> {
|
|
667
|
-
if (!name.startsWith('repository_')) return undefined;
|
|
733
|
+
if (!name.startsWith('repository_') && name !== 'read_repository_file') return undefined;
|
|
668
734
|
try {
|
|
669
735
|
const repoIdValue = typeof args.repo_id === 'string' ? args.repo_id.trim() : '';
|
|
670
736
|
switch (name) {
|
|
737
|
+
case 'read_repository_file': {
|
|
738
|
+
const repository = resolveRepositorySelection({
|
|
739
|
+
repoId: typeof args.repo_id === 'string' ? args.repo_id : undefined,
|
|
740
|
+
checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined,
|
|
741
|
+
controllerHome,
|
|
742
|
+
allowSoleRepository: true,
|
|
743
|
+
});
|
|
744
|
+
const path = String(args.path ?? '').trim();
|
|
745
|
+
if (!path) throw new Error('REPOSITORY_PATH_REQUIRED: path is required');
|
|
746
|
+
const session = caller?.sessionId
|
|
747
|
+
? { sessionId: caller.sessionId, repoId: repository.repoId, checkoutId: repository.activeCheckoutId }
|
|
748
|
+
: undefined;
|
|
749
|
+
const range = readRepositoryRange(
|
|
750
|
+
repository.canonicalRoot,
|
|
751
|
+
getMcpPolicy('controller', { repoRoot: repository.canonicalRoot }),
|
|
752
|
+
path,
|
|
753
|
+
typeof args.start_line === 'number' ? args.start_line : 1,
|
|
754
|
+
typeof args.end_line === 'number' ? args.end_line : 200,
|
|
755
|
+
session,
|
|
756
|
+
);
|
|
757
|
+
const redacted = redactMcpText(range.content);
|
|
758
|
+
return result({ ...range, content: redacted.text, redactions: redacted.redactions });
|
|
759
|
+
}
|
|
671
760
|
case 'repository_register': {
|
|
672
761
|
const startedAt = performance.now();
|
|
673
762
|
const registerInput = {
|
|
@@ -824,38 +913,6 @@ export async function callRepositoryTool(
|
|
|
824
913
|
checkout_id: typeof args.checkout_id === 'string' ? args.checkout_id : payload.checkout_id,
|
|
825
914
|
});
|
|
826
915
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
case 'repository_goal_list': {
|
|
831
|
-
const repository = resolveRepositorySelection({ repoId: repoIdValue || undefined, checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined, controllerHome, allowSoleRepository: true });
|
|
832
|
-
return result({ repoId: repository.repoId, checkoutId: repository.activeCheckoutId, registry: readRepositoryGoalRegistry(repository) });
|
|
833
|
-
}
|
|
834
|
-
case 'repository_goal_upsert': {
|
|
835
|
-
const repository = resolveRepositorySelection({ repoId: repoIdValue || undefined, checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined, controllerHome, allowSoleRepository: true });
|
|
836
|
-
return result({ repoId: repository.repoId, checkoutId: repository.activeCheckoutId, ...upsertRepositoryGoal(repository, { id: args.id, title: args.title, status: args.status, checks: args.checks, notes: args.notes }) as unknown as Record<string, unknown> });
|
|
837
|
-
}
|
|
838
|
-
case 'repository_stuck_diagnose': {
|
|
839
|
-
const repository = resolveRepositorySelection({ repoId: repoIdValue || undefined, checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined, controllerHome, allowSoleRepository: true });
|
|
840
|
-
return result({ diagnosis: diagnoseRepositoryStuckState(repository) });
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
case 'repository_goal_run': {
|
|
844
|
-
const repository = resolveRepositorySelection({ repoId: repoIdValue || undefined, checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined, controllerHome, allowSoleRepository: true });
|
|
845
|
-
const ran = withControllerLock(
|
|
846
|
-
controllerHome,
|
|
847
|
-
{ scope: 'repository', repoId: repository.repoId },
|
|
848
|
-
'mcp:repository_goal_run',
|
|
849
|
-
() => runRepositoryGoal(repository, { goalId: args.goal_id, runChecks: args.run_checks }),
|
|
850
|
-
60_000,
|
|
851
|
-
);
|
|
852
|
-
return result({ repoId: repository.repoId, checkoutId: repository.activeCheckoutId, ...ran as unknown as Record<string, unknown> });
|
|
853
|
-
}
|
|
854
|
-
case 'repository_goal_runs': {
|
|
855
|
-
const repository = resolveRepositorySelection({ repoId: repoIdValue || undefined, checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined, controllerHome, allowSoleRepository: true });
|
|
856
|
-
const limit = typeof args.limit === 'number' ? args.limit : typeof args.limit === 'string' ? Number(args.limit) : undefined;
|
|
857
|
-
return result({ repoId: repository.repoId, checkoutId: repository.activeCheckoutId, runs: listRepositoryGoalRuns(repository, limit) });
|
|
858
|
-
}
|
|
859
916
|
case 'repository_git_status': {
|
|
860
917
|
const repository = resolveRepositorySelection({ repoId: repoIdValue || undefined, checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined, controllerHome, allowSoleRepository: true });
|
|
861
918
|
const status = args.refresh === true
|
|
@@ -917,13 +974,18 @@ export async function callRepositoryTool(
|
|
|
917
974
|
});
|
|
918
975
|
}
|
|
919
976
|
case 'repository_safe_patch_apply': {
|
|
920
|
-
const repository =
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
controllerHome,
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
977
|
+
const repository = resolveRepositorySelectionForClaimedWork(controllerHome, args, repoIdValue, caller);
|
|
978
|
+
const binding = safePatchEditBinding(controllerHome, repository, caller, args);
|
|
979
|
+
if (binding?.workId) {
|
|
980
|
+
const work = getWorkContract({ controllerHome, repoId: repository.repoId }, binding.workId);
|
|
981
|
+
if (!work) throw new Error(`WORK_NOT_FOUND: ${binding.workId}`);
|
|
982
|
+
const requestedPaths = buildSafePatchPlan(repository, { operations: args.operations, chunkSize: args.chunk_size })
|
|
983
|
+
.chunks.flatMap((chunk) => chunk.paths);
|
|
984
|
+
assertWorkPathsWithinScope(work, requestedPaths, {
|
|
985
|
+
forbidden: 'WORK_MUTATION_FORBIDDEN_PATH',
|
|
986
|
+
outOfScope: 'WORK_MUTATION_PATH_OUT_OF_SCOPE',
|
|
987
|
+
});
|
|
988
|
+
}
|
|
927
989
|
const applied = withControllerLock(
|
|
928
990
|
controllerHome,
|
|
929
991
|
{ scope: 'repository', repoId: repository.repoId },
|
|
@@ -1022,10 +1084,16 @@ export async function callRepositoryTool(
|
|
|
1022
1084
|
});
|
|
1023
1085
|
}
|
|
1024
1086
|
case 'repository_command_execute': {
|
|
1087
|
+
const explorationGuidance = fragmentedRepositoryExplorationGuidance(args.command);
|
|
1025
1088
|
const target = resolveRepositoryCommandTarget(controllerHome, args, repoIdValue, caller);
|
|
1026
|
-
const { repository, executionIdentity } = target;
|
|
1027
|
-
|
|
1028
|
-
|
|
1089
|
+
const { repository, executionIdentity, historicalWorkContext } = target;
|
|
1090
|
+
const explicitWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
|
|
1091
|
+
if (!explicitWorkId) assertNoBoundExecutionSessionMutation(controllerHome, repository, caller);
|
|
1092
|
+
const deliveryWorkId = rawDefaultBranchMergeCommand(repository, args.command)
|
|
1093
|
+
? executionIdentity.workId
|
|
1094
|
+
: undefined;
|
|
1095
|
+
if (deliveryWorkId) {
|
|
1096
|
+
throw new Error(`WORK_DELIVERY_REQUIRES_FINALIZE: ${deliveryWorkId} must pass Work verification and use rh_work finalize before default-branch integration`);
|
|
1029
1097
|
}
|
|
1030
1098
|
const timeoutMs = typeof args.timeout_ms === 'number'
|
|
1031
1099
|
? args.timeout_ms
|
|
@@ -1052,16 +1120,33 @@ export async function callRepositoryTool(
|
|
|
1052
1120
|
const forceDurable = fromDurableWorker
|
|
1053
1121
|
|| args.mode === 'durable'
|
|
1054
1122
|
|| args.force_durable === true;
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1123
|
+
// repository_command_execute owns its command execution architecture.
|
|
1124
|
+
// Do not send ordinary command text through Thin Harness semantic risk
|
|
1125
|
+
// routing: that creates duplicate regex/classifier policy and turns
|
|
1126
|
+
// unknown CLI shapes into false durable/reject decisions. Only an
|
|
1127
|
+
// explicitly requested durable mode uses the generic durable router.
|
|
1128
|
+
const routingDecision = forceDurable
|
|
1129
|
+
? routeExecution({
|
|
1130
|
+
operation: 'repository_command_execute',
|
|
1131
|
+
mode: 'durable',
|
|
1132
|
+
timeoutMs,
|
|
1133
|
+
background: args.background === true || args.async === true,
|
|
1134
|
+
})
|
|
1135
|
+
: {
|
|
1136
|
+
mode: 'fast' as const,
|
|
1137
|
+
reasons: ['repository_command_process_runtime_authoritative'],
|
|
1138
|
+
risk: 'unknown' as const,
|
|
1139
|
+
estimatedClass: 'unknown' as const,
|
|
1140
|
+
requiresIsolation: false,
|
|
1141
|
+
requiresRecovery: false,
|
|
1142
|
+
suggestedOperation: undefined,
|
|
1143
|
+
effects: {
|
|
1144
|
+
readsWorkspace: true,
|
|
1145
|
+
mutatesWorkspace: true,
|
|
1146
|
+
mutatesGitRefs: false,
|
|
1147
|
+
remoteWrite: false,
|
|
1148
|
+
},
|
|
1149
|
+
};
|
|
1065
1150
|
// Unified Process Runtime for local commands (Direct/Managed) when not forced durable.
|
|
1066
1151
|
// Ephemeral workspaces cannot persist a recoverable async Process handle,
|
|
1067
1152
|
// so their async requests remain promotion-required below.
|
|
@@ -1072,7 +1157,50 @@ export async function callRepositoryTool(
|
|
|
1072
1157
|
defaultBranch: repository.defaultBranch,
|
|
1073
1158
|
timeoutMs,
|
|
1074
1159
|
});
|
|
1075
|
-
if (routeClass.route === '
|
|
1160
|
+
if (routeClass.route === 'reject') {
|
|
1161
|
+
return result({
|
|
1162
|
+
accepted: false,
|
|
1163
|
+
mode: 'reject',
|
|
1164
|
+
path: routeClass.reason,
|
|
1165
|
+
route: 'reject',
|
|
1166
|
+
status: 'rejected',
|
|
1167
|
+
repoId: repository.repoId,
|
|
1168
|
+
checkoutId: repository.activeCheckoutId,
|
|
1169
|
+
workspace: target.workspace,
|
|
1170
|
+
message: routeClass.reason === 'standalone_recovery_lifecycle_required'
|
|
1171
|
+
? 'Canonical Runtime and connector lifecycle operations must be submitted to the standalone Forge Recovery owner, not executed as a child of repository Process Runtime.'
|
|
1172
|
+
: 'Repository command execution was rejected by Process Runtime routing policy.',
|
|
1173
|
+
suggestedOperation: routeClass.reason === 'standalone_recovery_lifecycle_required'
|
|
1174
|
+
? 'Use the standalone Forge Recovery connector.'
|
|
1175
|
+
: routingDecision.suggestedOperation,
|
|
1176
|
+
durableSideEffects: {
|
|
1177
|
+
executionJobCount: 0,
|
|
1178
|
+
localJobCount: 0,
|
|
1179
|
+
workerSpawnCount: 0,
|
|
1180
|
+
projectionUpdateCount: 0,
|
|
1181
|
+
},
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
if (routeClass.route === 'durable' && target.workspace) {
|
|
1185
|
+
return result({
|
|
1186
|
+
accepted: false,
|
|
1187
|
+
mode: 'durable',
|
|
1188
|
+
path: 'ephemeral_workspace_promotion_required',
|
|
1189
|
+
repoId: repository.repoId,
|
|
1190
|
+
checkoutId: repository.activeCheckoutId,
|
|
1191
|
+
workspace: target.workspace,
|
|
1192
|
+
message: 'Ephemeral workspaces must be registered before durable remote effects so Process identity and reconciliation have a stable repository authority.',
|
|
1193
|
+
suggestedOperation: 'repository_register',
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
if (routeClass.route === 'process_direct' || routeClass.route === 'process_managed' || routeClass.route === 'durable') {
|
|
1197
|
+
const processRequestId = typeof args.request_id === 'string' ? args.request_id.trim() : '';
|
|
1198
|
+
if (executionIdentity.workId && !processRequestId) {
|
|
1199
|
+
throw new Error(
|
|
1200
|
+
`WORK_PROCESS_REQUEST_ID_REQUIRED: ${executionIdentity.workId}; `
|
|
1201
|
+
+ 'Work-attributed Process Runtime commands require a stable request_id so reconnect/retry can resume the original Process without duplicate execution.',
|
|
1202
|
+
);
|
|
1203
|
+
}
|
|
1076
1204
|
const processResult = await executeRepositoryCommandViaProcessRuntime({
|
|
1077
1205
|
controllerHome,
|
|
1078
1206
|
repository,
|
|
@@ -1084,7 +1212,7 @@ export async function callRepositoryTool(
|
|
|
1084
1212
|
: typeof args.interactive_wait_ms === 'number' ? args.interactive_wait_ms : undefined,
|
|
1085
1213
|
maxOutputBytes,
|
|
1086
1214
|
returnHandleImmediately,
|
|
1087
|
-
requestId:
|
|
1215
|
+
requestId: processRequestId || undefined,
|
|
1088
1216
|
workId: executionIdentity.workId,
|
|
1089
1217
|
executionIdentity,
|
|
1090
1218
|
allowNonGitWorkspace: target.workspace !== undefined,
|
|
@@ -1139,6 +1267,7 @@ export async function callRepositoryTool(
|
|
|
1139
1267
|
repoId: repository.repoId,
|
|
1140
1268
|
checkoutId: repository.activeCheckoutId,
|
|
1141
1269
|
workspace: target.workspace,
|
|
1270
|
+
historicalWorkContext,
|
|
1142
1271
|
processId: handle?.processId,
|
|
1143
1272
|
process: detailLevel === 'detail' ? handle : undefined,
|
|
1144
1273
|
completed,
|
|
@@ -1147,13 +1276,14 @@ export async function callRepositoryTool(
|
|
|
1147
1276
|
stdout: processResult.stdout,
|
|
1148
1277
|
stderr: processResult.stderr,
|
|
1149
1278
|
durableSideEffects: processResult.durableSideEffects,
|
|
1279
|
+
guidance: explorationGuidance,
|
|
1150
1280
|
next: directWithoutHandle
|
|
1151
1281
|
? processResult.reason === 'readonly_fast_path'
|
|
1152
1282
|
? 'Bounded readonly execution completed without Process record / Lease / Local Job / ExecutionJob / Worker.'
|
|
1153
1283
|
: 'Bounded ephemeral workspace execution completed without Process record / Lease / Local Job / ExecutionJob / Worker.'
|
|
1154
1284
|
: processResult.route === 'process_direct' || completed
|
|
1155
1285
|
? 'Process Runtime completed without Local Job / ExecutionJob / Worker.'
|
|
1156
|
-
: `Process Runtime is managing ${handle?.processId};
|
|
1286
|
+
: `Process Runtime is managing ${handle?.processId}. Continue independent work; use process_get only if an observation can change the next decision, then join with process_wait when this result becomes a dependency. Do not re-run or periodically poll.`,
|
|
1157
1287
|
detailLevel,
|
|
1158
1288
|
});
|
|
1159
1289
|
payload.status = status;
|
|
@@ -1270,6 +1400,12 @@ export async function callRepositoryTool(
|
|
|
1270
1400
|
routing: compactRoutingSummary({ path: 'durable', mode: 'durable', reasons: [routingDecision.reasons.join(','), 'local_bridge_execution_retired'] }),
|
|
1271
1401
|
message: 'This command requires explicit external Controller handling; Local Bridge Jobs are retired for repository commands.',
|
|
1272
1402
|
suggestedOperation: 'Create or claim WorkContract, then use rh_work.launcher_start or a Process Runtime-compatible command.',
|
|
1403
|
+
externalEffect: {
|
|
1404
|
+
outcome: 'not_started',
|
|
1405
|
+
ambiguousFailureOutcome: 'outcome_unknown',
|
|
1406
|
+
replayPolicy: 'never_auto_retry',
|
|
1407
|
+
reconciliation: 'After an ambiguous dispatch failure, inspect the remote ref/registry/release state before deciding whether to retry.',
|
|
1408
|
+
},
|
|
1273
1409
|
});
|
|
1274
1410
|
}
|
|
1275
1411
|
case 'repository_batch_execute': {
|