@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.
Files changed (396) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +26 -0
  3. package/CLAUDE.md +2 -0
  4. package/README.md +2 -2
  5. package/README.zh-CN.md +1 -1
  6. package/SKILL.md +2 -2
  7. package/THIRD_PARTY_NOTICES.md +1 -1
  8. package/agents/openai.yaml +1 -1
  9. package/assets/hooks/hook-input.sh +11 -8
  10. package/assets/hooks/lib/session-state.sh +10 -7
  11. package/assets/hooks/lib/workflow-state.sh +13 -177
  12. package/assets/hooks/post-tool-observer.sh +8 -2
  13. package/assets/hooks/prompt-guard.sh +5 -81
  14. package/assets/hooks/session-start-context.sh +56 -1
  15. package/assets/partials/05-workflow.partial.md +1 -1
  16. package/assets/partials-agents/03-orchestration.partial.md +1 -1
  17. package/assets/plugin-registry.v1.json +1 -1
  18. package/assets/reference-configs/document-generation.md +1 -1
  19. package/assets/reference-configs/harness-overview.md +1 -1
  20. package/assets/reference-configs/sprint-contracts.md +3 -3
  21. package/assets/skill-version.json +2 -2
  22. package/assets/templates/contract.template.md +2 -7
  23. package/assets/templates/helpers/capture-plan.sh +2 -2
  24. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  25. package/assets/templates/helpers/contract-worktree.sh +1 -21
  26. package/assets/templates/helpers/ensure-task-workflow.sh +11 -36
  27. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  28. package/assets/templates/helpers/new-plan.sh +1 -1
  29. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  30. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  31. package/assets/templates/helpers/verify-contract.sh +1 -111
  32. package/assets/templates/helpers/verify-sprint.sh +3 -180
  33. package/assets/templates/plan.template.md +1 -1
  34. package/assets/templates/review.template.md +9 -34
  35. package/assets/workflow-contract.v1.json +10 -19
  36. package/docs/README.md +10 -10
  37. package/docs/architecture/CURRENT.md +170 -0
  38. package/docs/architecture/EVOLUTION.md +42 -0
  39. package/docs/architecture/current/README.md +4 -156
  40. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  41. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  42. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  43. package/docs/architecture/history/README.md +7 -0
  44. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  45. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  46. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  47. package/docs/architecture/history.md +3 -34
  48. package/docs/architecture/index.md +15 -98
  49. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  50. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  51. package/docs/architecture/versions/1.6.md +38 -0
  52. package/docs/architecture/versions/1.7.md +41 -0
  53. package/docs/forge-chatgpt-browser-engine.md +2 -2
  54. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  55. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  56. package/docs/forge-github-issue-launcher.md +1 -1
  57. package/docs/forge-runtime-self-healing-loop.md +1 -1
  58. package/docs/operations/controller-browser-plugin.md +26 -6
  59. package/docs/operations/controller-performance-and-502.md +124 -0
  60. package/docs/operations/controller-reliability-runbook.md +1 -1
  61. package/docs/operations/features.md +2 -2
  62. package/docs/operations/github-repository.md +1 -1
  63. package/docs/operations/homebrew.md +2 -2
  64. package/docs/operations/mcp-tool-exposure.md +5 -3
  65. package/docs/wiki/Architecture.md +6 -6
  66. package/docs/wiki/Implementation.md +2 -2
  67. package/docs/wiki/Integrations.md +2 -2
  68. package/docs/wiki/Work-Lifecycle.md +1 -1
  69. package/package.json +29 -10
  70. package/scripts/activate-source-baseline.ts +17 -13
  71. package/scripts/benchmark-background-check-overlap.ts +228 -0
  72. package/scripts/benchmark-mcp-host.sh +117 -0
  73. package/scripts/benchmark-mcp-transport.ts +170 -0
  74. package/scripts/benchmark-quality-harness.ts +146 -0
  75. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  76. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  77. package/scripts/benchmark-typescript-navigation.ts +186 -0
  78. package/scripts/benchmark-work-efficiency.ts +334 -0
  79. package/scripts/capture-plan.sh +3 -3
  80. package/scripts/check-agent-tooling.sh +8 -35
  81. package/scripts/check-architecture-sync.sh +17 -86
  82. package/scripts/check-mcp-compatibility.ts +14 -0
  83. package/scripts/check-runtime-architecture.mjs +107 -64
  84. package/scripts/check-stable-baseline.ts +92 -0
  85. package/scripts/check-task-workflow.sh +4 -4
  86. package/scripts/contract-worktree.sh +1 -21
  87. package/scripts/ensure-task-workflow.sh +22 -55
  88. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  89. package/scripts/install-standalone-recovery.ts +24 -0
  90. package/scripts/lib/project-init-lib.sh +15 -44
  91. package/scripts/migrate-project-template.sh +23 -1179
  92. package/scripts/new-plan.sh +1 -1
  93. package/scripts/plan-to-todo.sh +11 -36
  94. package/scripts/run-governed-gate.ts +2 -1
  95. package/scripts/ship-worktrees.sh +2 -29
  96. package/scripts/smoke-ios-physical-device.ts +4 -2
  97. package/scripts/smoke-runtime-recovery.ts +1 -35
  98. package/scripts/smoke-schedule-engine.ts +1 -20
  99. package/scripts/verify-contract.sh +1 -111
  100. package/scripts/verify-forge-runtime.sh +0 -1
  101. package/scripts/verify-sprint.sh +3 -180
  102. package/scripts/workflow-contract.ts +1 -5
  103. package/src/cli/commands/init-hook.ts +3 -3
  104. package/src/cli/commands/mcp.ts +9 -5
  105. package/src/cli/commands/plugin.ts +1 -1
  106. package/src/cli/commands/recovery.ts +25 -3
  107. package/src/cli/commands/runtime.ts +55 -3
  108. package/src/cli/commands/security.ts +12 -1
  109. package/src/cli/commands/setup-profile.ts +31 -21
  110. package/src/cli/controller/check-runner.ts +106 -3
  111. package/src/cli/controller/composite-result.ts +1 -1
  112. package/src/cli/controller/context/focus.ts +51 -0
  113. package/src/cli/controller/context/instruction-context.ts +114 -0
  114. package/src/cli/controller/context/known-paths.ts +76 -0
  115. package/src/cli/controller/context/query-planning.ts +110 -0
  116. package/src/cli/controller/context/rule-resolution.ts +532 -0
  117. package/src/cli/controller/context/source-materializer.ts +278 -0
  118. package/src/cli/controller/context/structural.ts +16 -0
  119. package/src/cli/controller/context/types.ts +286 -0
  120. package/src/cli/controller/context-pack.ts +785 -469
  121. package/src/cli/controller/launch-agents.ts +77 -2
  122. package/src/cli/controller/operational-plan.ts +2 -2
  123. package/src/cli/controller/work-mode.ts +6 -4
  124. package/src/cli/editing/edit-session.ts +60 -7
  125. package/src/cli/github/github.ts +133 -0
  126. package/src/cli/installer/managed-entries.ts +15 -1
  127. package/src/cli/local-bridge/console-automations.ts +54 -78
  128. package/src/cli/local-bridge/console-view-models.ts +1 -35
  129. package/src/cli/local-bridge/facade-api.ts +0 -217
  130. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  131. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
  132. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  133. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
  134. package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
  135. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  136. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
  137. package/src/cli/local-bridge/frontend/src/styles.css +1 -1
  138. package/src/cli/local-bridge/frontend/src/types.ts +5 -8
  139. package/src/cli/local-bridge/job-store.ts +1 -490
  140. package/src/cli/local-bridge/server.ts +0 -513
  141. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  142. package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
  143. package/src/cli/mcp/auth.ts +5 -5
  144. package/src/cli/mcp/instructions.ts +3 -2
  145. package/src/cli/mcp/legacy-tool-service.ts +0 -189
  146. package/src/cli/mcp/multi-repository.ts +16 -5
  147. package/src/cli/mcp/oauth.ts +175 -26
  148. package/src/cli/mcp/repository-tools.ts +247 -107
  149. package/src/cli/mcp/server.ts +537 -111
  150. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  151. package/src/cli/mcp/toolset-selection.ts +1 -1
  152. package/src/cli/mcp/toolset.ts +42 -5
  153. package/src/cli/mcp/transports/http.ts +101 -14
  154. package/src/cli/mcp/transports/session-registry.ts +43 -5
  155. package/src/cli/mcp/types.ts +3 -3
  156. package/src/cli/repositories/command-classifier.ts +101 -19
  157. package/src/cli/repositories/command-executor.ts +55 -521
  158. package/src/cli/repositories/command-process.ts +108 -0
  159. package/src/cli/repositories/command-scope.ts +99 -41
  160. package/src/cli/repositories/controller-home.ts +7 -8
  161. package/src/cli/repositories/git-command-executor.ts +2 -0
  162. package/src/cli/repositories/locks.ts +53 -16
  163. package/src/cli/repositories/repository-snapshot.ts +121 -0
  164. package/src/cli/repositories/selected-path-actions.ts +17 -9
  165. package/src/cli/repositories/structured-git.ts +61 -3
  166. package/src/cli/repository/inspector.ts +553 -63
  167. package/src/cli/repository/session-cache.ts +58 -17
  168. package/src/cli/v81-entry.ts +1 -4
  169. package/src/effects/fs-transaction.ts +85 -17
  170. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  171. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  172. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  173. package/src/runtime/context/lsp-client.ts +283 -0
  174. package/src/runtime/context/semantic-navigation.ts +275 -0
  175. package/src/runtime/context/swift-navigation.ts +565 -0
  176. package/src/runtime/context/typescript-navigation.ts +226 -0
  177. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  178. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +47 -8
  179. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  180. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  181. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  182. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  183. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  184. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  185. package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
  186. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +143 -8
  187. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
  188. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +85 -8
  189. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  190. package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
  191. package/src/runtime/control-plane/facade/controller-session-store.ts +132 -1
  192. package/src/runtime/control-plane/facade/goal-workloop-access.ts +2 -0
  193. package/src/runtime/control-plane/facade/goal-workloop.ts +686 -129
  194. package/src/runtime/control-plane/facade/index.ts +1 -0
  195. package/src/runtime/control-plane/facade/plan-contract-store.ts +185 -20
  196. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  197. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  198. package/src/runtime/control-plane/facade/types.ts +22 -5
  199. package/src/runtime/control-plane/facade/work-contract-store.ts +175 -73
  200. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  201. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  202. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  203. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  204. package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
  205. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  206. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  207. package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
  208. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  209. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  210. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  211. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  212. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  213. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  214. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  215. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  216. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  217. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  218. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
  219. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +355 -116
  220. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
  221. package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
  222. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  223. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  224. package/src/runtime/control-plane/release-retention.ts +62 -2
  225. package/src/runtime/control-plane/routing/route-policy.ts +7 -16
  226. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  227. package/src/runtime/diagnostics/mcp-timing.ts +13 -0
  228. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  229. package/src/runtime/diagnostics/performance.ts +24 -1
  230. package/src/runtime/evidence/event-ledger.ts +1 -1
  231. package/src/runtime/execution/jobs/store.ts +58 -4
  232. package/src/runtime/execution/jobs/types.ts +1 -1
  233. package/src/runtime/execution/managed-workspace.ts +203 -1
  234. package/src/runtime/execution/process-runtime/check-facade.ts +51 -4
  235. package/src/runtime/execution/process-runtime/check-result.ts +53 -0
  236. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  237. package/src/runtime/execution/process-runtime/command-facade.ts +345 -40
  238. package/src/runtime/execution/process-runtime/gc.ts +38 -6
  239. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
  240. package/src/runtime/execution/process-runtime/persisted-check.ts +47 -4
  241. package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
  242. package/src/runtime/execution/process-runtime/runtime.ts +43 -3
  243. package/src/runtime/execution/process-runtime/store.ts +1 -0
  244. package/src/runtime/execution/process-runtime/types.ts +2 -0
  245. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  246. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  247. package/src/runtime/execution/workers/executor.ts +0 -48
  248. package/src/runtime/gateway/mcp/execution-tools.ts +1192 -114
  249. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  250. package/src/runtime/gateway/mcp/router.ts +184 -82
  251. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
  252. package/src/runtime/gateway/mcp/runtime-tools.ts +2224 -1589
  253. package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
  254. package/src/runtime/plugins/browser-adapter.ts +2901 -241
  255. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  256. package/src/runtime/plugins/browser-handoff.ts +92 -2
  257. package/src/runtime/plugins/browser-macos-bridge.ts +582 -49
  258. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  259. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  260. package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
  261. package/src/runtime/plugins/browser-runtime.ts +183 -0
  262. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  263. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  264. package/src/runtime/plugins/desktop-operator-registration.ts +8 -2
  265. package/src/runtime/plugins/external-adapter.ts +324 -3
  266. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  267. package/src/runtime/plugins/first-party-registry.ts +2 -0
  268. package/src/runtime/plugins/github-adapter.ts +125 -0
  269. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  270. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  271. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  272. package/src/runtime/plugins/ios-adapter.ts +106 -16
  273. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  274. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  275. package/src/runtime/plugins/lightweight-action.ts +153 -0
  276. package/src/runtime/plugins/local-system-adapter.ts +123 -6
  277. package/src/runtime/plugins/macos-capability-broker.ts +55 -9
  278. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  279. package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
  280. package/src/runtime/plugins/resend-adapter.ts +1 -1
  281. package/src/runtime/plugins/store.ts +269 -29
  282. package/src/runtime/plugins/types.ts +35 -2
  283. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  284. package/src/runtime/projections/git-status-sampler.ts +16 -16
  285. package/src/runtime/projections/materialized-view.ts +28 -10
  286. package/src/runtime/recovery/maintenance-executor.ts +393 -28
  287. package/src/runtime/root/mcp-transport.ts +180 -10
  288. package/src/runtime/root/package-connector-service.ts +186 -8
  289. package/src/runtime/root/package-runtime-release.ts +143 -17
  290. package/src/runtime/root/package-runtime-service.ts +430 -22
  291. package/src/runtime/root/release-manifest.ts +7 -2
  292. package/src/runtime/root/release-materialize.ts +19 -0
  293. package/src/runtime/root/release-store.ts +48 -11
  294. package/src/runtime/root/runtime.ts +23 -5
  295. package/src/runtime/root/service.ts +100 -29
  296. package/src/runtime/root/types.ts +2 -0
  297. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  298. package/src/runtime/shared/trusted-executable.ts +62 -0
  299. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  300. package/src/runtime/standalone-recovery/core.ts +700 -92
  301. package/src/runtime/standalone-recovery/entry.ts +99 -23
  302. package/src/runtime/standalone-recovery/installer.ts +19 -3
  303. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  304. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  305. package/src/runtime/workflow/schedules/browser-probe.ts +81 -3
  306. package/src/runtime/workflow/schedules/engine.ts +287 -151
  307. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  308. package/src/runtime/workflow/schedules/settlement.ts +48 -4
  309. package/src/runtime/workflow/schedules/store.ts +131 -10
  310. package/src/runtime/workflow/schedules/types.ts +2 -4
  311. package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
  312. package/src/testing/test-governance.ts +8 -40
  313. package/assets/reference-configs/heartbeat-triage.md +0 -57
  314. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  315. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  316. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  317. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  318. package/docs/architecture/current/architecture-invariants.md +0 -331
  319. package/docs/architecture/current/automation-and-schedule-engine.md +0 -459
  320. package/docs/architecture/current/codegraph-context-provider.md +0 -238
  321. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  322. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  323. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -373
  324. package/docs/architecture/current/entity-model.md +0 -612
  325. package/docs/architecture/current/external-plugin-governance.md +0 -396
  326. package/docs/architecture/current/failure-recovery.md +0 -447
  327. package/docs/architecture/current/governance.md +0 -213
  328. package/docs/architecture/current/human-interaction-plane.md +0 -87
  329. package/docs/architecture/current/implementation-status.md +0 -128
  330. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  331. package/docs/architecture/current/legacy-governance.md +0 -58
  332. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  333. package/docs/architecture/current/migration-roadmap.md +0 -105
  334. package/docs/architecture/current/multi-repository-execution.md +0 -371
  335. package/docs/architecture/current/operations-runbook.md +0 -45
  336. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  337. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  338. package/docs/architecture/current/repository-access-modes.md +0 -102
  339. package/docs/architecture/current/route-policy.md +0 -15
  340. package/docs/architecture/current/route-session-concurrency.md +0 -85
  341. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  342. package/docs/architecture/current/runtime-directory-map.md +0 -49
  343. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  344. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  345. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  346. package/docs/architecture/current/system-overview.md +0 -169
  347. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  348. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  349. package/docs/architecture/current/thin-harness-v1.md +0 -321
  350. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  351. package/docs/forge-autonomous-goal-loop.md +0 -9
  352. package/docs/forge-provider-configuration.md +0 -7
  353. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -93
  354. package/docs/operations/gmail-assistant-routines.md +0 -186
  355. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  356. package/docs/operations/provider-configuration.md +0 -31
  357. package/scripts/harness-trace-grade.sh +0 -150
  358. package/scripts/heartbeat-triage.sh +0 -361
  359. package/scripts/maintenance-triage.sh +0 -167
  360. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  361. package/src/cli/repositories/goal-registry.ts +0 -239
  362. package/src/runtime/assistant/action-proposals.ts +0 -279
  363. package/src/runtime/assistant/intent.ts +0 -395
  364. package/src/runtime/assistant/model-provider.ts +0 -460
  365. package/src/runtime/assistant/openapi.ts +0 -223
  366. package/src/runtime/assistant/policy.ts +0 -89
  367. package/src/runtime/assistant/readiness.ts +0 -258
  368. package/src/runtime/assistant/routine-runtime.ts +0 -477
  369. package/src/runtime/assistant/schedule-binding.ts +0 -171
  370. package/src/runtime/assistant/standing-grants.ts +0 -375
  371. package/src/runtime/assistant/store.ts +0 -243
  372. package/src/runtime/assistant/types.ts +0 -135
  373. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  374. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  375. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  376. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  377. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  378. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  379. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  380. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  381. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  382. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  383. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  384. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  385. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  386. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  387. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  388. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  389. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  390. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  391. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  392. package/src/runtime/workflow/findings/store.ts +0 -204
  393. package/src/runtime/workflow/findings/types.ts +0 -58
  394. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  395. package/src/runtime/workflow/portfolio/store.ts +0 -185
  396. package/src/runtime/workflow/portfolio/types.ts +0 -29
@@ -1,22 +1,20 @@
1
1
  /**
2
- * Repository-scoped Managed Process lifecycle MCP tools.
2
+ * Repository-scoped Lightweight/Durable Process lifecycle MCP tools.
3
3
  *
4
4
  * process_get / process_wait / process_logs / process_cancel
5
5
  *
6
- * These tools attach to an existing Process Runtime handle — they never
7
- * re-execute the original command.
6
+ * These tools attach to an existing in-memory lightweight or persisted durable
7
+ * handle. They never re-execute the original command.
8
8
  */
9
9
 
10
10
  import type { McpToolDefinition, CallToolResult } from '../../../cli/mcp/tools';
11
11
  import type { MultiRepositoryMcpToolContext } from '../../../cli/mcp/multi-repository';
12
- import { getRepository } from '../../../cli/repositories/registry';
13
12
  import {
14
- cancelProcess,
15
- getProcessHandle,
16
- readProcessLogs,
17
- waitForProcess,
13
+ cancelRepositoryCommandProcess,
14
+ getRepositoryCommandProcess,
15
+ readRepositoryCommandProcessLogs,
16
+ waitRepositoryCommandProcess,
18
17
  } from '../../execution/process-runtime';
19
- import { getProcessRecord } from '../../execution/process-runtime/store';
20
18
  import { redactSensitiveText, redactSensitiveValue } from '../../evidence/sensitive-output';
21
19
 
22
20
  function definition(
@@ -42,17 +40,36 @@ function definition(
42
40
 
43
41
  const repoIdProp = {
44
42
  type: 'string',
45
- description: 'Stable repository id. Process must belong to this repository.',
43
+ description: 'Repository or ephemeral workspace scope id returned by the originating command. Process must belong to this scope.',
46
44
  };
47
45
  const processIdProp = {
48
46
  type: 'string',
49
- description: 'Managed process id returned by Process Runtime (e.g. from run_check / repository_command).',
47
+ description: 'Lightweight or durable process id returned by run_check / repository_command_execute.',
50
48
  };
51
49
 
52
50
  export const processToolDefinitions: McpToolDefinition[] = [
51
+ definition(
52
+ 'run_check',
53
+ 'Run one focused repository check, or launch one resource-compatible check wave, through Process Runtime. Use check_id for the existing single-check behavior or check_ids for a batch; do not send both. Batch mode validates the existing check-scheduling resource model and starts every check in one compatible wave concurrently without waiting for completion or creating a second scheduler. Cross-wave, invalid, release, and multi-phase batches fail closed. Long ordinary checks return managed handles; attach only at a real dependency boundary.',
54
+ {
55
+ repo_id: repoIdProp,
56
+ checkout_id: { type: 'string' },
57
+ check_id: { type: 'string', description: 'Single check id. Mutually exclusive with check_ids.' },
58
+ check_ids: { type: 'array', items: { type: 'string' }, minItems: 1, maxItems: 32, uniqueItems: true, description: 'Batch check ids. All requested checks must fit one resource-compatible execution wave; mutually exclusive with check_id.' },
59
+ timeout_ms: { type: 'number' },
60
+ request_id: { type: 'string' },
61
+ issue_id: { type: 'string' },
62
+ task_id: { type: 'string' },
63
+ mode: { type: 'string', enum: ['direct', 'async', 'durable'] },
64
+ apply_mode: { type: 'string', enum: ['sync', 'async'] },
65
+ force_durable: { type: 'boolean' },
66
+ },
67
+ [],
68
+ false,
69
+ ),
53
70
  definition(
54
71
  'process_get',
55
- 'Get the current status of a managed process without re-executing the command. Readonly.',
72
+ 'Non-blocking observation of a lightweight or durable process; never re-executes. Use only when the observation can change the next decision. It is not a synchronization join.',
56
73
  {
57
74
  repo_id: repoIdProp,
58
75
  process_id: processIdProp,
@@ -62,7 +79,7 @@ export const processToolDefinitions: McpToolDefinition[] = [
62
79
  ),
63
80
  definition(
64
81
  'process_wait',
65
- 'Wait for a managed process to complete or until timeout_ms. Does not re-execute the command. Readonly attach/poll.',
82
+ 'Explicit dependency synchronization for one lightweight or durable process. Call only when the next decision or acceptance boundary is blocked on this exact result; do not use as periodic polling. Waits never re-execute the command.',
66
83
  {
67
84
  repo_id: repoIdProp,
68
85
  process_id: processIdProp,
@@ -73,7 +90,7 @@ export const processToolDefinitions: McpToolDefinition[] = [
73
90
  ),
74
91
  definition(
75
92
  'process_logs',
76
- 'Read a bounded tail of managed process stdout/stderr. Never loads unbounded logs. Readonly.',
93
+ 'Read a bounded tail of lightweight or durable process stdout/stderr. Never loads unbounded logs. Readonly.',
77
94
  {
78
95
  repo_id: repoIdProp,
79
96
  process_id: processIdProp,
@@ -84,7 +101,7 @@ export const processToolDefinitions: McpToolDefinition[] = [
84
101
  ),
85
102
  definition(
86
103
  'process_cancel',
87
- 'Cancel a managed process. Requires verified PID identity (start time + executable fingerprint). Untrusted PIDs are refused. Classified as workspace-write / process-control.',
104
+ 'Cancel a lightweight or durable process through its owning runtime handle. Classified as workspace-write / process-control.',
88
105
  {
89
106
  repo_id: repoIdProp,
90
107
  process_id: processIdProp,
@@ -96,10 +113,36 @@ export const processToolDefinitions: McpToolDefinition[] = [
96
113
  ];
97
114
 
98
115
  const processToolNames = new Set(processToolDefinitions.map((tool) => tool.name));
99
- // Public MCP clients commonly detach around one minute. Return a normal attach
100
- // snapshot before that deadline rather than allowing transport timeout to turn
101
- // a healthy Process into an error-shaped response.
102
- export const DEFAULT_PROCESS_WAIT_ATTACH_BUDGET_MS = 55_000;
116
+ const processAttachmentToolNames = new Set(['process_get', 'process_wait', 'process_logs', 'process_cancel']);
117
+ // A long-lived MCP wait can monopolize shared Runtime request/transport capacity
118
+ // even though the underlying Process wait is asynchronous. Keep public waits
119
+ // short and return a normal running snapshot; the Process continues unchanged
120
+ // and callers can attach again only when the result is a real dependency.
121
+ export const DEFAULT_PROCESS_WAIT_ATTACH_BUDGET_MS = 5_000;
122
+
123
+ /**
124
+ * Stable controller-facing continuation semantics for a returned Process.
125
+ * This is deliberately response-only: Process Runtime remains the sole owner
126
+ * of execution and no polling scheduler or second state authority is created.
127
+ */
128
+ export function managedProcessContinuation(handle: { completed?: boolean }): Record<string, string> {
129
+ if (handle.completed === true) {
130
+ return {
131
+ state: 'terminal',
132
+ nextAction: 'consume_terminal_result',
133
+ join: 'complete',
134
+ reexecution: 'forbidden',
135
+ };
136
+ }
137
+ return {
138
+ state: 'background',
139
+ nextAction: 'continue_independent_work',
140
+ join: 'required_at_dependency_boundary',
141
+ observation: 'process_get_if_it_can_change_the_next_decision',
142
+ repeatedWait: 'not_recommended',
143
+ reexecution: 'forbidden',
144
+ };
145
+ }
103
146
 
104
147
  function result(value: Record<string, unknown>, isError = false): CallToolResult {
105
148
  const safe = redactSensitiveValue(value).value;
@@ -125,24 +168,18 @@ function requireRepoAndProcess(
125
168
  if (!repoId) throw new Error('REPOSITORY_ID_REQUIRED: repo_id is required for process tools');
126
169
  if (!processId) throw new Error('PROCESS_ID_REQUIRED: process_id is required for process tools');
127
170
 
128
- // Force repo scope: repository must exist under this controller home.
129
- const repository = getRepository(repoId, ctx.controllerHome);
130
- if (!repository) {
131
- throw new Error(`REPOSITORY_NOT_FOUND: ${repoId}`);
132
- }
133
-
134
- // Process must belong to the requested repo.
135
- const record = getProcessRecord(ctx.controllerHome, repoId, processId);
136
- if (!record) {
171
+ // The Process handle is the scope authority. Ephemeral workspace targets are
172
+ // intentionally not registered in Repository Registry, so requiring a live
173
+ // repository record here would make their returned managed handles impossible
174
+ // to resume. Exact repo/workspace scope + process id still fails closed.
175
+ const handle = getRepositoryCommandProcess(ctx.controllerHome, repoId, processId);
176
+ if (!handle) {
137
177
  throw new Error(`PROCESS_NOT_FOUND: process ${processId} is not registered under repo ${repoId}`);
138
178
  }
139
- if (record.repoId !== repoId) {
140
- throw new Error(`PROCESS_REPO_MISMATCH: process ${processId} belongs to ${record.repoId}, not ${repoId}`);
141
- }
142
179
  return { repoId, processId };
143
180
  }
144
181
 
145
- function handleToPayload(handle: NonNullable<ReturnType<typeof getProcessHandle>>): Record<string, unknown> {
182
+ function handleToPayload(handle: NonNullable<ReturnType<typeof getRepositoryCommandProcess>>): Record<string, unknown> {
146
183
  return {
147
184
  processId: handle.processId,
148
185
  workId: handle.workId,
@@ -161,8 +198,13 @@ function handleToPayload(handle: NonNullable<ReturnType<typeof getProcessHandle>
161
198
  cancelled: handle.cancelled,
162
199
  stdout: handle.stdout,
163
200
  stderr: handle.stderr,
201
+ // Keep the bounded tail available after completion for callers that use it
202
+ // as their compact log view. Lightweight terminal receipts bound this tail
203
+ // separately, so retaining the established field does not restore the
204
+ // previous full-output duplication in persisted state.
164
205
  stdoutTail: handle.stdoutTail,
165
206
  stderrTail: handle.stderrTail,
207
+ continuation: managedProcessContinuation(handle),
166
208
  durableSideEffects: handle.durableSideEffects,
167
209
  };
168
210
  }
@@ -172,12 +214,15 @@ export async function callProcessTool(
172
214
  name: string,
173
215
  args: Record<string, unknown>,
174
216
  ): Promise<CallToolResult | undefined> {
175
- if (!processToolNames.has(name)) return undefined;
217
+ // run_check shares this module's public schema, but its execution authority is
218
+ // the Gateway check facade in router.ts. Only attachment/lifecycle operations
219
+ // consume an existing process_id here.
220
+ if (!processAttachmentToolNames.has(name)) return undefined;
176
221
  try {
177
222
  const { repoId, processId } = requireRepoAndProcess(ctx, args);
178
223
  switch (name) {
179
224
  case 'process_get': {
180
- const handle = getProcessHandle(ctx.controllerHome, repoId, processId);
225
+ const handle = getRepositoryCommandProcess(ctx.controllerHome, repoId, processId);
181
226
  if (!handle) throw new Error(`PROCESS_NOT_FOUND: ${processId}`);
182
227
  return result({
183
228
  repoId,
@@ -193,12 +238,13 @@ export async function callProcessTool(
193
238
  ? Math.max(1, Math.trunc(testBudget))
194
239
  : DEFAULT_PROCESS_WAIT_ATTACH_BUDGET_MS;
195
240
  const startedAt = Date.now();
196
- const handle = await waitForProcess(ctx.controllerHome, repoId, processId, {
241
+ const handle = await waitRepositoryCommandProcess(ctx.controllerHome, repoId, processId, {
197
242
  timeoutMs: Math.min(requestedWaitMs, attachBudgetMs),
198
243
  });
199
244
  return result({
200
245
  repoId,
201
246
  process: handleToPayload(handle),
247
+ synchronization: handle.completed === true ? 'terminal_result_available' : 'continue_independent_work',
202
248
  waitedMs: Date.now() - startedAt,
203
249
  requestedWaitMs,
204
250
  attachBudgetMs,
@@ -209,7 +255,7 @@ export async function callProcessTool(
209
255
  const maxBytes = typeof args.max_bytes === 'number' && Number.isFinite(args.max_bytes)
210
256
  ? Math.max(256, Math.trunc(args.max_bytes))
211
257
  : 32 * 1024;
212
- const logs = readProcessLogs(ctx.controllerHome, repoId, processId, maxBytes);
258
+ const logs = readRepositoryCommandProcessLogs(ctx.controllerHome, repoId, processId, maxBytes);
213
259
  if (!logs) throw new Error(`PROCESS_NOT_FOUND: ${processId}`);
214
260
  return result({
215
261
  repoId,
@@ -223,7 +269,7 @@ export async function callProcessTool(
223
269
  });
224
270
  }
225
271
  case 'process_cancel': {
226
- const handle = await cancelProcess(ctx.controllerHome, repoId, processId);
272
+ const handle = await cancelRepositoryCommandProcess(ctx.controllerHome, repoId, processId);
227
273
  return result({
228
274
  repoId,
229
275
  process: handleToPayload(handle),
@@ -4,19 +4,24 @@ import {
4
4
  buildMultiRepositoryToolDefinitions,
5
5
  type MultiRepositoryMcpToolContext,
6
6
  } from '../../../cli/mcp/multi-repository';
7
- import { callRepositoryTool, repositoryToolDefinitions } from '../../../cli/mcp/repository-tools';
7
+ import {
8
+ callRepositoryTool,
9
+ claimedSessionEditBinding,
10
+ repositoryToolDefinitions,
11
+ } from '../../../cli/mcp/repository-tools';
8
12
  import { runtimeToolDefinitions } from './runtime-tools';
9
13
  import { executionToolDefinitions } from './execution-tools';
10
14
  import { processToolDefinitions } from './process-tools';
11
15
  import { resolveRepositorySelection } from '../../../cli/repositories/registry';
16
+ import { listControllerChecks } from '../../../cli/controller/check-runner';
12
17
  import { executionIdentityForRepository } from '../../control-plane/execution/execution-identity';
13
- import { startOrJoinEditValidation } from '../../control-plane/execution/edit-validation-coordinator';
14
- import type {
15
- ExecutionOperationMetadata,
16
- ExecutionTimeoutPolicy,
17
- } from '../../execution/jobs/types';
18
- import { claimsForMcpOperation } from './resource-policy';
19
- import { classifyRepositoryCommand, classifyRepositoryCommandReplay } from '../../../cli/repositories/command-classifier';
18
+ import {
19
+ resolveEditValidationRepository,
20
+ startOrJoinEditValidation,
21
+ } from '../../control-plane/execution/edit-validation-coordinator';
22
+ import { assertEditSessionDurableBinding } from '../../../cli/editing/edit-session';
23
+ import type { ExecutionTimeoutPolicy } from '../../execution/jobs/types';
24
+ import { classifyRepositoryCommand } from '../../../cli/repositories/command-classifier';
20
25
  import {
21
26
  isFastEligibleTool,
22
27
  routeExecution,
@@ -27,6 +32,7 @@ import {
27
32
  classifyRepositoryCommandRoute,
28
33
  } from '../../execution/process-runtime';
29
34
  import { runPersistedCheckViaProcessRuntime } from './persisted-check-process';
35
+ import { buildCheckExecutionSchedule } from '../../execution/process-runtime/check-scheduling';
30
36
  import {
31
37
  isProcessIsolatedReadDiagnostic,
32
38
  runReadOnlyDiagnosticViaProcessRuntime,
@@ -93,8 +99,17 @@ export function isGatewayIsolatedTool(name: string): boolean {
93
99
  return GATEWAY_ISOLATED_TOOLS.has(name);
94
100
  }
95
101
 
96
- /** Tools that already own their direct-read versus durable-write boundary. */
97
- const SELF_MANAGED_DURABLE_TOOLS = new Set(['plugin_action_execute']);
102
+ /**
103
+ * Tools that own their execution boundary and must never fall through to
104
+ * retired generic ExecutionJob creation. Legacy iOS atomics are compatibility
105
+ * adapters over the typed iOS plugin authority.
106
+ */
107
+ const SELF_MANAGED_DURABLE_TOOLS = new Set([
108
+ 'plugin_action_execute',
109
+ 'ios_xcode_status', 'ios_simulators_list', 'ios_project_discover', 'ios_schemes_list',
110
+ 'ios_simulator_boot', 'ios_app_build', 'ios_app_install', 'ios_app_launch',
111
+ 'ios_simulator_screenshot', 'ios_simulator_log_tail', 'ios_ui_smoke_test',
112
+ ]);
98
113
 
99
114
  export function isSelfManagedDurableTool(name: string): boolean {
100
115
  return SELF_MANAGED_DURABLE_TOOLS.has(name);
@@ -106,7 +121,6 @@ const DIRECT_HOT_READ_TOOLS = new Set([
106
121
  'work_get', 'work_list', 'work_status_digest', 'work_result_summary',
107
122
  'controller_ready', 'repository_runtime_snapshot',
108
123
  'rh_status', 'rh_context', 'rh_inbox',
109
- 'controller_context_pack',
110
124
  'repository_git_status', 'repository_git_diff', 'git_diff_paths',
111
125
  ]);
112
126
 
@@ -145,7 +159,6 @@ const EXPLICIT_EXTERNAL_CONTROLLER_TOOLS = new Set([
145
159
  'publish_issue_to_github',
146
160
  'close_github_issue',
147
161
  'request_release_gate',
148
- 'promote_candidate_finding',
149
162
  ]);
150
163
 
151
164
  const GATEWAY_ROUTE_BEHAVIOR_PROBES: ReadonlyArray<{
@@ -296,8 +309,9 @@ function result(value: Record<string, unknown>, isError = false): CallToolResult
296
309
  }
297
310
 
298
311
  export function getMcpToolDefinition(ctx: MultiRepositoryMcpToolContext, name: string): McpToolDefinition | undefined {
299
- return [...runtimeToolDefinitions, ...executionToolDefinitions, ...processToolDefinitions, ...repositoryToolDefinitions, ...buildMultiRepositoryToolDefinitions(ctx)]
300
- .find((tool) => tool.name === name);
312
+ const currentDefinitions = [...runtimeToolDefinitions, ...executionToolDefinitions, ...processToolDefinitions, ...repositoryToolDefinitions];
313
+ if (ctx.toolset !== 'full') return currentDefinitions.find((tool) => tool.name === name);
314
+ return [...currentDefinitions, ...buildMultiRepositoryToolDefinitions(ctx)].find((tool) => tool.name === name);
301
315
  }
302
316
 
303
317
  /**
@@ -370,10 +384,16 @@ export function classifyGatewayExecutionPath(
370
384
  // run_check: Process Runtime for ordinary checks; Durable only for release/multi-phase.
371
385
  if (name === 'run_check') {
372
386
  const checkId = String(args.check_id ?? args.checkId ?? '').trim();
387
+ const batchCheckIds = Array.isArray(args.check_ids)
388
+ ? args.check_ids.map((value) => String(value).trim()).filter(Boolean)
389
+ : [];
373
390
  if (args.mode === 'durable' || args.force_durable === true) {
374
391
  return { path: 'durable', reasons: ['caller_requested_durable_check'] };
375
392
  }
376
- if (checkId && checkRequiresDurableWorkflow(checkId)) {
393
+ // A batch containing release/multi-phase checks is routed through the fast
394
+ // facade only so the batch validator can fail closed with structured
395
+ // scheduling evidence. It must never create a partial Durable workflow.
396
+ if (batchCheckIds.length === 0 && checkId && checkRequiresDurableWorkflow(checkId)) {
377
397
  return { path: 'durable', reasons: ['multi_phase_or_release_check'] };
378
398
  }
379
399
  // Route as "fast" so shouldCreateDurableJob returns false; actual execution
@@ -578,68 +598,6 @@ export function validateMcpToolArguments(name: string, definition: McpToolDefini
578
598
  }
579
599
  }
580
600
 
581
- export function operationMetadataForTool(
582
- name: string,
583
- definition: McpToolDefinition,
584
- claims: ReturnType<typeof claimsForMcpOperation>,
585
- timeoutMs: number,
586
- args: Record<string, unknown> = {},
587
- defaultBranch?: string,
588
- timeoutPolicy?: ExecutionTimeoutPolicy,
589
- ): ExecutionOperationMetadata {
590
- if (name === 'repository_command_execute' && args.command !== undefined) {
591
- const classification = classifyRepositoryCommand(args.command as string | string[], defaultBranch);
592
- const replay = classifyRepositoryCommandReplay(args.command as string | string[], defaultBranch);
593
- const mode = classification.risk === 'readonly'
594
- ? 'readonly'
595
- : classification.risk === 'remote_write'
596
- ? 'remote_write'
597
- : classification.risk === 'destructive'
598
- ? 'destructive'
599
- : 'mutating';
600
- return {
601
- mode,
602
- idempotent: replay.idempotent,
603
- replayable: replay.replayable,
604
- timeoutMs,
605
- admissionTimeoutMs: timeoutPolicy?.admissionTimeoutMs,
606
- queueTimeoutMs: timeoutPolicy?.queueTimeoutMs,
607
- executionTimeoutMs: timeoutPolicy?.executionTimeoutMs,
608
- interactiveWaitMs: timeoutPolicy?.interactiveWaitMs,
609
- retryPolicy: replay.retryPolicy,
610
- approvalPolicy: classification.risk === 'readonly'
611
- ? 'none'
612
- : classification.risk === 'destructive' ? 'required' : 'request',
613
- lockScope: claims.map((claim) => claim.resourceKey),
614
- resourceClaims: claims,
615
- };
616
- }
617
- const destructive = definition.annotations?.destructiveHint === true;
618
- const remoteWrite = claims.some((claim) => claim.resourceKey.startsWith('remote:'));
619
- const readOnly = definition.annotations?.readOnlyHint === true || claims.length === 0;
620
- const mode = destructive
621
- ? 'destructive'
622
- : remoteWrite
623
- ? 'remote_write'
624
- : readOnly
625
- ? 'readonly'
626
- : 'mutating';
627
- return {
628
- mode,
629
- idempotent: readOnly,
630
- replayable: readOnly,
631
- timeoutMs,
632
- admissionTimeoutMs: timeoutPolicy?.admissionTimeoutMs,
633
- queueTimeoutMs: timeoutPolicy?.queueTimeoutMs,
634
- executionTimeoutMs: timeoutPolicy?.executionTimeoutMs,
635
- interactiveWaitMs: timeoutPolicy?.interactiveWaitMs,
636
- retryPolicy: readOnly ? 'safe_retry' : 'idempotent_request',
637
- approvalPolicy: destructive ? 'required' : remoteWrite || !readOnly ? 'request' : 'none',
638
- lockScope: claims.map((claim) => claim.resourceKey),
639
- resourceClaims: claims,
640
- };
641
- }
642
-
643
601
  export function injectDurableCommandFields(tool: McpToolDefinition): McpToolDefinition {
644
602
  const schema = tool.inputSchema as { type?: unknown; properties?: Record<string, unknown>; [key: string]: unknown };
645
603
  if (schema.type !== 'object') return tool;
@@ -693,7 +651,14 @@ async function runEditSessionValidationViaProcessRuntime(
693
651
  editSessionId: string,
694
652
  args: Record<string, unknown>,
695
653
  ): Promise<CallToolResult> {
696
- const validation = await startOrJoinEditValidation(ctx.controllerHome, repository, {
654
+ const resolved = resolveEditValidationRepository(repository, editSessionId);
655
+ const binding = claimedSessionEditBinding(ctx.controllerHome, resolved.repository, {
656
+ sessionId: ctx.sessionId,
657
+ principalId: ctx.principalId,
658
+ controllerInstanceId: ctx.controllerInstanceId,
659
+ }, args.work_id);
660
+ assertEditSessionDurableBinding(resolved.session, binding, { requireBoundIdentity: true });
661
+ const validation = await startOrJoinEditValidation(ctx.controllerHome, resolved.repository, {
697
662
  editSessionId,
698
663
  checkIds: Array.isArray(args.check_ids) ? args.check_ids.map(String) : undefined,
699
664
  requestId: typeof args.request_id === 'string' ? args.request_id : undefined,
@@ -775,7 +740,11 @@ export async function routeDurableMcpCall(
775
740
  }, true);
776
741
  }
777
742
 
778
- if (classification.path === 'durable' && executionJobCreationRetired()) {
743
+ // repository_command_execute has its own durable boundary: non-destructive
744
+ // remote writes run through the durable Process Runtime, while destructive or
745
+ // explicitly delegated commands are refused by the repository facade itself.
746
+ // Do not intercept that tool with the retired ExecutionJob gate here.
747
+ if (classification.path === 'durable' && executionJobCreationRetired() && name !== 'repository_command_execute') {
779
748
  return result({
780
749
  accepted: false,
781
750
  mode: 'external_controller_required',
@@ -947,12 +916,145 @@ export async function routeDurableMcpCall(
947
916
  });
948
917
  }
949
918
  const checkId = String(args.check_id ?? '').trim();
950
- if (!checkId) {
919
+ const rawBatchCheckIds = args.check_ids;
920
+ const hasBatchInput = Array.isArray(rawBatchCheckIds);
921
+ const batchCheckIds: string[] = hasBatchInput
922
+ ? [...new Set(rawBatchCheckIds.map((value: unknown) => String(value).trim()).filter(Boolean))]
923
+ : [];
924
+ if (checkId && hasBatchInput) {
951
925
  return result({
952
926
  accepted: false,
953
927
  mode: 'reject',
954
928
  path: 'reject',
955
- message: 'run_check requires check_id',
929
+ message: 'run_check accepts either check_id or check_ids, not both',
930
+ }, true);
931
+ }
932
+ if (!checkId && batchCheckIds.length === 0) {
933
+ return result({
934
+ accepted: false,
935
+ mode: 'reject',
936
+ path: 'reject',
937
+ message: 'run_check requires check_id or a non-empty check_ids array',
938
+ }, true);
939
+ }
940
+ if (hasBatchInput) {
941
+ const availableChecks = listControllerChecks(repository.canonicalRoot);
942
+ const availableChecksById = new Map(availableChecks.map((check) => [check.id, check]));
943
+ const checkScheduling = buildCheckExecutionSchedule({
944
+ checks: availableChecks,
945
+ requestedCheckIds: batchCheckIds,
946
+ repoId: repository.repoId,
947
+ checkoutId: repository.activeCheckoutId,
948
+ });
949
+ const schedulePayload = {
950
+ waveCount: checkScheduling.waves.length,
951
+ maxParallel: checkScheduling.maxParallel,
952
+ waves: checkScheduling.waves,
953
+ conflicts: checkScheduling.conflicts,
954
+ invalidCheckIds: checkScheduling.invalidCheckIds,
955
+ guidance: checkScheduling.guidance,
956
+ };
957
+ if (checkScheduling.invalidCheckIds.length > 0) {
958
+ return result({
959
+ accepted: false,
960
+ mode: 'reject',
961
+ path: 'reject',
962
+ reason: 'invalid_check_ids',
963
+ checkIds: batchCheckIds,
964
+ checkScheduling: schedulePayload,
965
+ message: `run_check batch contains unregistered checks: ${checkScheduling.invalidCheckIds.join(', ')}`,
966
+ }, true);
967
+ }
968
+ const durableCheckIds = batchCheckIds.filter((id) => checkRequiresDurableWorkflow(id, availableChecksById.get(id)));
969
+ if (durableCheckIds.length > 0) {
970
+ return result({
971
+ accepted: false,
972
+ mode: 'reject',
973
+ path: 'reject',
974
+ reason: 'batch_contains_durable_check',
975
+ checkIds: batchCheckIds,
976
+ durableCheckIds,
977
+ checkScheduling: schedulePayload,
978
+ message: 'Batch run_check only launches ordinary focused checks; run release or multi-phase checks through an explicit durable workflow.',
979
+ }, true);
980
+ }
981
+ if (checkScheduling.waves.length !== 1 || checkScheduling.waves[0]?.checkIds.length !== batchCheckIds.length) {
982
+ return result({
983
+ accepted: false,
984
+ mode: 'reject',
985
+ path: 'reject',
986
+ reason: 'batch_spans_multiple_check_waves',
987
+ checkIds: batchCheckIds,
988
+ checkScheduling: schedulePayload,
989
+ message: 'Requested checks span multiple resource-conflicting waves. Launch one returned wave per run_check call; Forge will not hide serial waiting inside a batch.',
990
+ }, true);
991
+ }
992
+ const baseRequestId = typeof args.request_id === 'string' ? args.request_id.trim() : '';
993
+ const facades = await Promise.all(batchCheckIds.map((batchCheckId, index) => {
994
+ const suffix = createHash('sha256').update(batchCheckId).digest('hex').slice(0, 8);
995
+ return runPersistedCheckViaProcessRuntime({
996
+ controllerHome: ctx.controllerHome,
997
+ repoId: repository.repoId,
998
+ checkoutId: repository.activeCheckoutId,
999
+ repoRoot: repository.canonicalRoot,
1000
+ executionIdentity: executionIdentityForRepository(repository),
1001
+ checkId: batchCheckId,
1002
+ timeoutMs: typeof args.timeout_ms === 'number' ? args.timeout_ms : undefined,
1003
+ interactiveWaitMs: 0,
1004
+ requestId: baseRequestId ? `${baseRequestId}:batch:${index + 1}:${suffix}` : undefined,
1005
+ forceDurable: false,
1006
+ });
1007
+ }));
1008
+ const unexpectedDurable = facades.filter((facade) => facade.mode === 'durable');
1009
+ if (unexpectedDurable.length > 0) {
1010
+ return result({
1011
+ accepted: false,
1012
+ mode: 'reject',
1013
+ path: 'reject',
1014
+ reason: 'batch_check_escalated_to_durable',
1015
+ checkIds: batchCheckIds,
1016
+ checkScheduling: schedulePayload,
1017
+ message: 'At least one batch check unexpectedly requires Durable execution; no further batch orchestration will be created.',
1018
+ }, true);
1019
+ }
1020
+ const processes = facades.map((facade) => ({
1021
+ checkId: facade.checkId,
1022
+ processId: facade.process?.processId,
1023
+ status: facade.process?.status,
1024
+ completed: facade.process?.completed === true,
1025
+ ok: facade.process?.ok,
1026
+ exitCode: facade.process?.exitCode,
1027
+ timedOut: facade.process?.timedOut,
1028
+ deduplicated: facade.process?.deduplicated === true,
1029
+ semanticDeduplicated: facade.process?.semanticDeduplicated === true,
1030
+ durableSideEffects: facade.durableSideEffects,
1031
+ }));
1032
+ const completed = processes.every((process) => process.completed);
1033
+ const mode = processes.every((process) => process.completed) ? 'direct' : 'managed';
1034
+ const durableSideEffects = facades.reduce((total, facade) => ({
1035
+ executionJobCount: total.executionJobCount + facade.durableSideEffects.executionJobCount,
1036
+ localJobCount: total.localJobCount + facade.durableSideEffects.localJobCount,
1037
+ workerSpawnCount: total.workerSpawnCount + facade.durableSideEffects.workerSpawnCount,
1038
+ projectionUpdateCount: total.projectionUpdateCount + facade.durableSideEffects.projectionUpdateCount,
1039
+ }), { executionJobCount: 0, localJobCount: 0, workerSpawnCount: 0, projectionUpdateCount: 0 });
1040
+ return result({
1041
+ accepted: true,
1042
+ batch: true,
1043
+ mode,
1044
+ path: mode === 'direct' ? 'process_batch_direct' : 'process_batch_managed',
1045
+ routing: { path: 'fast', reasons: ['run_check_batch_process_runtime'] },
1046
+ repoId: repository.repoId,
1047
+ checkoutId: repository.activeCheckoutId,
1048
+ checkIds: batchCheckIds,
1049
+ checkScheduling: schedulePayload,
1050
+ processes,
1051
+ processIds: processes.map((process) => process.processId).filter(Boolean),
1052
+ completed,
1053
+ ...(completed ? { ok: processes.every((process) => process.ok === true) } : {}),
1054
+ durableSideEffects,
1055
+ next: completed
1056
+ ? 'Batch check wave finished on Process Runtime without ExecutionJob / LocalBridgeJob / Worker.'
1057
+ : 'Batch check wave is running concurrently. Continue independent work. Attach to each returned process only when that result becomes a real dependency; do not poll or re-run the checks.',
956
1058
  });
957
1059
  }
958
1060
  const facade = await runPersistedCheckViaProcessRuntime({
@@ -1012,7 +1114,7 @@ export async function routeDurableMcpCall(
1012
1114
  durableSideEffects: facade.durableSideEffects,
1013
1115
  next: handle?.completed
1014
1116
  ? 'Check finished on Process Runtime without ExecutionJob / LocalBridgeJob / Worker.'
1015
- : `Check still running as managed process ${handle?.processId}. Continue independent work; use process_wait once when this result becomes a real dependency. Do not re-run or repeatedly poll the same check.`,
1117
+ : `Check still running as managed process ${handle?.processId}. Continue independent work; attach with process_wait only when this exact result becomes a real dependency. An attach may return a running handle because transport time is bounded; continue useful work and attach again only at a later dependency boundary. Do not re-run or periodically poll the same check.`,
1016
1118
  });
1017
1119
  }
1018
1120