@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
@@ -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,
@@ -55,6 +54,9 @@ import {
55
54
  } from '../../runtime/execution/process-runtime/command-facade';
56
55
  import { assessWorkMode, parseExplicitTaskMode } from '../controller/work-mode';
57
56
  import { normalizeRepositoryCommand } from '../repositories/command-normalization';
57
+ import { readRepositoryRange } from '../repository/inspector';
58
+ import { getMcpPolicy } from './policy';
59
+ import { redactMcpText } from './redaction';
58
60
  import type { CallToolResult, McpToolDefinition } from './tools';
59
61
  import {
60
62
  boundUtf8,
@@ -117,6 +119,13 @@ export const repositoryToolDefinitions: McpToolDefinition[] = [
117
119
  include_removed: { type: 'boolean' },
118
120
  detail_level: { type: 'string', enum: ['summary', 'detail'], description: 'Defaults to summary; detail returns the complete checkout history.' },
119
121
  }, ['repo_id'], true),
122
+ definition('read_repository_file', 'Read a line range from one policy-readable repository file.', {
123
+ repo_id: repoId,
124
+ checkout_id: { type: 'string' },
125
+ path: { type: 'string' },
126
+ start_line: { type: 'number' },
127
+ end_line: { type: 'number' },
128
+ }, ['path'], true),
120
129
  definition('repository_validate', 'Validate repository identity and migrate legacy ownership.', {
121
130
  repo_id: repoId,
122
131
  detail_level: { type: 'string', enum: ['summary', 'detail'], description: 'Defaults to summary; detail returns full migration evidence.' },
@@ -136,7 +145,7 @@ export const repositoryToolDefinitions: McpToolDefinition[] = [
136
145
  }, ['repo_id']),
137
146
  definition('repository_remove', 'Soft-remove a repository while retaining audit history.', {
138
147
  repo_id: repoId,
139
- }, ['repo_id'], true),
148
+ }, ['repo_id']),
140
149
  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
150
  repo_id: repoId,
142
151
  checkout_id: { type: 'string', description: 'Optional checkout identity for repository-scoped operations.' },
@@ -152,38 +161,6 @@ export const repositoryToolDefinitions: McpToolDefinition[] = [
152
161
  additionalProperties: true,
153
162
  },
154
163
  }),
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
164
  definition('repository_git_status', 'Return a structured Git status snapshot for the selected repository checkout.', {
188
165
  repo_id: repoId,
189
166
  checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
@@ -270,7 +247,7 @@ export const repositoryToolDefinitions: McpToolDefinition[] = [
270
247
  cwd: { type: 'string', description: 'Optional root-relative working directory.' },
271
248
  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
249
  }, ['command'], true),
273
- definition('repository_command_execute', 'Execute one repository-scoped local command through Full Access, Goal delegation, or a resumable approval request. Legacy preview-token callers remain compatible.', {
250
+ 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
251
  repo_id: repoId,
275
252
  checkout_id: { type: 'string', description: 'Optional checkout identity for repositories with multiple local clones.' },
276
253
  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.' },
@@ -316,23 +293,56 @@ export interface RepositoryToolCallerContext {
316
293
  controllerInstanceId?: string;
317
294
  }
318
295
 
296
+ function claimedExplicitWork(
297
+ controllerHome: string,
298
+ repoId: string,
299
+ caller: RepositoryToolCallerContext | undefined,
300
+ requestedWorkId: string,
301
+ ) {
302
+ if (!caller?.principalId?.trim()) return undefined;
303
+ const work = getWorkContract({ controllerHome, repoId }, requestedWorkId);
304
+ if (!work || isTerminalWorkContractStatus(work.status)) throw new Error(`WORK_ATTRIBUTION_INVALID: ${requestedWorkId}`);
305
+ const owner = getControllerSession({ controllerHome, repoId }, requestedWorkId);
306
+ if (!owner) throw new Error(`WORK_CONTROLLER_CLAIM_REQUIRED: ${requestedWorkId}`);
307
+ if ((owner.principalId?.trim() || owner.controllerId) !== caller.principalId.trim()) throw new Error(`WORK_CONTROLLER_OWNERSHIP_MISMATCH: ${requestedWorkId}`);
308
+ return work;
309
+ }
310
+
311
+ function assertNoBoundExecutionSessionMutation(
312
+ controllerHome: string,
313
+ repository: ReturnType<typeof resolveRepositorySelection>,
314
+ caller?: RepositoryToolCallerContext,
315
+ ): void {
316
+ if (!caller?.principalId?.trim() || !caller.sessionId?.trim()) return;
317
+ const executionSession = readExecutionSession(controllerHome, {
318
+ sessionId: caller.sessionId,
319
+ principalId: caller.principalId,
320
+ controllerInstanceId: caller.controllerInstanceId,
321
+ });
322
+ const workId = executionSession?.activeWorkId?.trim();
323
+ if (!workId || executionSession?.activeRepositoryId !== repository.repoId) return;
324
+ const work = getWorkContract({ controllerHome, repoId: repository.repoId }, workId);
325
+ if (!work) throw new Error(`WORK_ATTRIBUTION_INVALID: ${workId}`);
326
+ if (isTerminalWorkContractStatus(work.status)) {
327
+ throw new Error(`WORK_ATTRIBUTION_TERMINAL: ${work.workId}:${work.status}`);
328
+ }
329
+ throw new Error(`WORK_ATTRIBUTION_REQUIRED: ${work.workId}; active execution session mutations must pass work_id explicitly`);
330
+ }
331
+
319
332
  function claimedSessionWorkId(
320
333
  controllerHome: string,
321
334
  repository: ReturnType<typeof resolveRepositorySelection>,
322
335
  caller?: RepositoryToolCallerContext,
323
336
  explicitWorkId?: unknown,
324
337
  ): string | undefined {
325
- if (!caller?.principalId?.trim()) return undefined;
326
338
  const requestedWorkId = typeof explicitWorkId === 'string' ? explicitWorkId.trim() : '';
327
339
  if (requestedWorkId) {
328
- const work = getWorkContract({ controllerHome, repoId: repository.repoId }, requestedWorkId);
329
- if (!work || isTerminalWorkContractStatus(work.status)) throw new Error(`WORK_ATTRIBUTION_INVALID: ${requestedWorkId}`);
340
+ const work = claimedExplicitWork(controllerHome, repository.repoId, caller, requestedWorkId);
341
+ if (!work) return undefined;
330
342
  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
343
  return requestedWorkId;
335
344
  }
345
+ if (!caller?.principalId?.trim()) return undefined;
336
346
  if (caller.sessionId?.trim()) {
337
347
  const executionSession = readExecutionSession(controllerHome, {
338
348
  sessionId: caller.sessionId,
@@ -342,8 +352,11 @@ function claimedSessionWorkId(
342
352
  const workId = executionSession?.activeWorkId?.trim();
343
353
  if (workId && executionSession?.activeRepositoryId === repository.repoId && (!executionSession.activeCheckoutId || executionSession.activeCheckoutId === repository.activeCheckoutId)) {
344
354
  const work = getWorkContract({ controllerHome, repoId: repository.repoId }, workId);
355
+ if (work && isTerminalWorkContractStatus(work.status)) {
356
+ throw new Error(`WORK_ATTRIBUTION_TERMINAL: ${work.workId}:${work.status}`);
357
+ }
345
358
  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;
359
+ if (work && owner?.sessionId === caller.sessionId && (owner.principalId?.trim() || owner.controllerId) === caller.principalId.trim()) return workId;
347
360
  }
348
361
  }
349
362
  const principal = caller.principalId.trim();
@@ -356,7 +369,7 @@ function claimedSessionWorkId(
356
369
  return undefined;
357
370
  }
358
371
 
359
- function claimedSessionEditBinding(
372
+ export function claimedSessionEditBinding(
360
373
  controllerHome: string,
361
374
  repository: ReturnType<typeof resolveRepositorySelection>,
362
375
  caller?: RepositoryToolCallerContext,
@@ -376,8 +389,52 @@ function claimedSessionEditBinding(
376
389
  };
377
390
  }
378
391
 
379
- function activeWorkflowRawDefaultMergeBlocked(repository: ReturnType<typeof resolveRepositorySelection>, workId: string | undefined, command: unknown): boolean {
380
- if (!workId || !repository.defaultBranch) return false;
392
+ function safePatchEditBinding(
393
+ controllerHome: string,
394
+ repository: ReturnType<typeof resolveRepositorySelection>,
395
+ caller: RepositoryToolCallerContext | undefined,
396
+ args: Record<string, unknown>,
397
+ ): EditSessionBinding | undefined {
398
+ const explicitWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
399
+ if (explicitWorkId) return claimedSessionEditBinding(controllerHome, repository, caller, explicitWorkId);
400
+ const sessionId = typeof args.session_id === 'string' ? args.session_id.trim() : '';
401
+ if (sessionId) {
402
+ const existingWorkId = getEditSession(repository.canonicalRoot, sessionId).workId?.trim();
403
+ return existingWorkId
404
+ ? claimedSessionEditBinding(controllerHome, repository, caller, existingWorkId)
405
+ : undefined;
406
+ }
407
+ assertNoBoundExecutionSessionMutation(controllerHome, repository, caller);
408
+ return undefined;
409
+ }
410
+
411
+ function resolveRepositorySelectionForClaimedWork(
412
+ controllerHome: string,
413
+ args: Record<string, unknown>,
414
+ repoIdValue: string,
415
+ caller?: RepositoryToolCallerContext,
416
+ ): ReturnType<typeof resolveRepositorySelection> {
417
+ const checkoutId = typeof args.checkout_id === 'string' ? args.checkout_id.trim() : '';
418
+ const explicitWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
419
+ const repository = resolveRepositorySelection({
420
+ repoId: repoIdValue || undefined,
421
+ checkoutId: checkoutId || undefined,
422
+ controllerHome,
423
+ allowSoleRepository: true,
424
+ });
425
+ if (!explicitWorkId || checkoutId) return repository;
426
+ const work = claimedExplicitWork(controllerHome, repository.repoId, caller, explicitWorkId);
427
+ if (!work?.checkoutId || work.checkoutId === repository.activeCheckoutId) return repository;
428
+ return resolveRepositorySelection({
429
+ repoId: repository.repoId,
430
+ checkoutId: work.checkoutId,
431
+ controllerHome,
432
+ allowSoleRepository: true,
433
+ });
434
+ }
435
+
436
+ function rawDefaultBranchMergeCommand(repository: ReturnType<typeof resolveRepositorySelection>, command: unknown): boolean {
437
+ if (!repository.defaultBranch) return false;
381
438
  const checkout = repository.checkouts.find((entry) => entry.checkoutId === repository.activeCheckoutId);
382
439
  if (checkout?.branch !== repository.defaultBranch) return false;
383
440
  const normalized = normalizeRepositoryCommand(command);
@@ -417,13 +474,11 @@ function resolveRepositoryCommandTarget(
417
474
  workspace: { workspaceId: target.workspaceId, root: target.canonicalRoot, registered: false },
418
475
  };
419
476
  }
420
- const repository = resolveRepositorySelection({
421
- repoId: repoIdValue || undefined,
422
- checkoutId: checkoutId || undefined,
423
- controllerHome,
424
- allowSoleRepository: true,
425
- });
426
- const workId = claimedSessionWorkId(controllerHome, repository, caller, args.work_id);
477
+ const repository = resolveRepositorySelectionForClaimedWork(controllerHome, args, repoIdValue, caller);
478
+ const explicitWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
479
+ const workId = explicitWorkId
480
+ ? claimedSessionWorkId(controllerHome, repository, caller, explicitWorkId)
481
+ : undefined;
427
482
  return {
428
483
  repository,
429
484
  executionIdentity: {
@@ -523,6 +578,33 @@ function failure(error: unknown): RepositoryToolResult {
523
578
  return { ...result({ error: { code, message, ...(compactDetails !== undefined ? { details: compactDetails } : {}) } }), isError: true };
524
579
  }
525
580
 
581
+ interface RepositoryExplorationGuidance {
582
+ code: 'FRAGMENTED_REPOSITORY_EXPLORATION';
583
+ recommendedTool: 'rh_context';
584
+ recommendedOperation: 'search';
585
+ message: string;
586
+ }
587
+
588
+ function fragmentedRepositoryExplorationGuidance(command: unknown): RepositoryExplorationGuidance | undefined {
589
+ if (typeof command !== 'string') return undefined;
590
+ const segments = command.split(/(?:&&|\|\||[;|])/g);
591
+ const readPrograms = new Set<string>();
592
+ let readStepCount = 0;
593
+ for (const segment of segments) {
594
+ 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);
595
+ if (!match) continue;
596
+ readStepCount += 1;
597
+ readPrograms.add(match[1]!.toLowerCase());
598
+ }
599
+ if (readStepCount < 2) return undefined;
600
+ return {
601
+ code: 'FRAGMENTED_REPOSITORY_EXPLORATION',
602
+ recommendedTool: 'rh_context',
603
+ recommendedOperation: 'search',
604
+ 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.`,
605
+ };
606
+ }
607
+
526
608
  function compactProcessCommandPayload(input: {
527
609
  accepted?: boolean;
528
610
  mode: string;
@@ -545,6 +627,7 @@ function compactProcessCommandPayload(input: {
545
627
  /** summary (default) omits nested process / routing dumps; detail restores diagnostics. */
546
628
  detailLevel?: 'summary' | 'detail';
547
629
  includeFullProcess?: boolean;
630
+ guidance?: RepositoryExplorationGuidance;
548
631
  }): Record<string, unknown> {
549
632
  const output = compactCommandOutput(input.stdout, input.stderr, { ok: input.ok === true });
550
633
  const detail = input.detailLevel === 'detail' || input.includeFullProcess === true;
@@ -572,10 +655,14 @@ function compactProcessCommandPayload(input: {
572
655
  ...(input.workspace ? { workspace: input.workspace } : {}),
573
656
  ...(input.processId ? { processId: input.processId } : {}),
574
657
  ...(completed ? { exitCode: input.exitCode ?? (ok ? 0 : 1) } : {}),
658
+ // A running default response otherwise loses its only dependency-bound
659
+ // continuation advice when the detailed Process record is omitted.
660
+ ...(!completed ? { next: input.next } : {}),
575
661
  stdout: output.stdout ?? '',
576
662
  stderr: output.stderr ?? '',
577
663
  ...(output.stdoutTruncated ? { stdoutTruncated: true, stdoutBytes: output.stdoutBytes } : {}),
578
664
  ...(output.stderrTruncated ? { stderrTruncated: true, stderrBytes: output.stderrBytes } : {}),
665
+ ...(input.guidance ? { guidance: input.guidance, suggestedOperation: 'rh_context' } : {}),
579
666
  };
580
667
  if (completed && !ok) {
581
668
  payload.error = {
@@ -623,6 +710,7 @@ function compactProcessCommandPayload(input: {
623
710
  }
624
711
  : {}),
625
712
  durableSideEffects: effects,
713
+ ...(input.guidance ? { guidance: input.guidance, suggestedOperation: 'rh_context' } : {}),
626
714
  next: input.next,
627
715
  detailLevel: 'detail',
628
716
  };
@@ -664,10 +752,33 @@ export async function callRepositoryTool(
664
752
  args: Record<string, unknown>,
665
753
  caller?: RepositoryToolCallerContext,
666
754
  ): Promise<RepositoryToolResult | undefined> {
667
- if (!name.startsWith('repository_')) return undefined;
755
+ if (!name.startsWith('repository_') && name !== 'read_repository_file') return undefined;
668
756
  try {
669
757
  const repoIdValue = typeof args.repo_id === 'string' ? args.repo_id.trim() : '';
670
758
  switch (name) {
759
+ case 'read_repository_file': {
760
+ const repository = resolveRepositorySelection({
761
+ repoId: typeof args.repo_id === 'string' ? args.repo_id : undefined,
762
+ checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined,
763
+ controllerHome,
764
+ allowSoleRepository: true,
765
+ });
766
+ const path = String(args.path ?? '').trim();
767
+ if (!path) throw new Error('REPOSITORY_PATH_REQUIRED: path is required');
768
+ const session = caller?.sessionId
769
+ ? { sessionId: caller.sessionId, repoId: repository.repoId, checkoutId: repository.activeCheckoutId }
770
+ : undefined;
771
+ const range = readRepositoryRange(
772
+ repository.canonicalRoot,
773
+ getMcpPolicy('controller', { repoRoot: repository.canonicalRoot }),
774
+ path,
775
+ typeof args.start_line === 'number' ? args.start_line : 1,
776
+ typeof args.end_line === 'number' ? args.end_line : 200,
777
+ session,
778
+ );
779
+ const redacted = redactMcpText(range.content);
780
+ return result({ ...range, content: redacted.text, redactions: redacted.redactions });
781
+ }
671
782
  case 'repository_register': {
672
783
  const startedAt = performance.now();
673
784
  const registerInput = {
@@ -824,38 +935,6 @@ export async function callRepositoryTool(
824
935
  checkout_id: typeof args.checkout_id === 'string' ? args.checkout_id : payload.checkout_id,
825
936
  });
826
937
  }
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
938
  case 'repository_git_status': {
860
939
  const repository = resolveRepositorySelection({ repoId: repoIdValue || undefined, checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined, controllerHome, allowSoleRepository: true });
861
940
  const status = args.refresh === true
@@ -917,13 +996,8 @@ export async function callRepositoryTool(
917
996
  });
918
997
  }
919
998
  case 'repository_safe_patch_apply': {
920
- const repository = resolveRepositorySelection({
921
- repoId: repoIdValue || undefined,
922
- checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined,
923
- controllerHome,
924
- allowSoleRepository: true,
925
- });
926
- const binding = claimedSessionEditBinding(controllerHome, repository, caller, args.work_id);
999
+ const repository = resolveRepositorySelectionForClaimedWork(controllerHome, args, repoIdValue, caller);
1000
+ const binding = safePatchEditBinding(controllerHome, repository, caller, args);
927
1001
  const applied = withControllerLock(
928
1002
  controllerHome,
929
1003
  { scope: 'repository', repoId: repository.repoId },
@@ -1022,10 +1096,16 @@ export async function callRepositoryTool(
1022
1096
  });
1023
1097
  }
1024
1098
  case 'repository_command_execute': {
1099
+ const explorationGuidance = fragmentedRepositoryExplorationGuidance(args.command);
1025
1100
  const target = resolveRepositoryCommandTarget(controllerHome, args, repoIdValue, caller);
1026
1101
  const { repository, executionIdentity } = target;
1027
- if (activeWorkflowRawDefaultMergeBlocked(repository, executionIdentity.workId, args.command)) {
1028
- throw new Error(`WORK_DELIVERY_REQUIRES_FINALIZE: ${executionIdentity.workId} must pass Work verification and use rh_work finalize before default-branch integration`);
1102
+ const explicitWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
1103
+ if (!explicitWorkId) assertNoBoundExecutionSessionMutation(controllerHome, repository, caller);
1104
+ const deliveryWorkId = rawDefaultBranchMergeCommand(repository, args.command)
1105
+ ? executionIdentity.workId
1106
+ : undefined;
1107
+ if (deliveryWorkId) {
1108
+ throw new Error(`WORK_DELIVERY_REQUIRES_FINALIZE: ${deliveryWorkId} must pass Work verification and use rh_work finalize before default-branch integration`);
1029
1109
  }
1030
1110
  const timeoutMs = typeof args.timeout_ms === 'number'
1031
1111
  ? args.timeout_ms
@@ -1052,16 +1132,33 @@ export async function callRepositoryTool(
1052
1132
  const forceDurable = fromDurableWorker
1053
1133
  || args.mode === 'durable'
1054
1134
  || args.force_durable === true;
1055
- const routingDecision = routeExecution({
1056
- operation: 'repository_command_execute',
1057
- mode: forceDurable ? 'durable' : args.mode === 'fast' ? 'fast' : 'auto',
1058
- command: args.command as string | string[] | undefined,
1059
- timeoutMs,
1060
- background: forceDurable && (args.background === true || args.async === true),
1061
- defaultBranch: repository.defaultBranch,
1062
- approvalContinuation: typeof args.approval_request_id === 'string'
1063
- || typeof args.approval_token === 'string',
1064
- });
1135
+ // repository_command_execute owns its command execution architecture.
1136
+ // Do not send ordinary command text through Thin Harness semantic risk
1137
+ // routing: that creates duplicate regex/classifier policy and turns
1138
+ // unknown CLI shapes into false durable/reject decisions. Only an
1139
+ // explicitly requested durable mode uses the generic durable router.
1140
+ const routingDecision = forceDurable
1141
+ ? routeExecution({
1142
+ operation: 'repository_command_execute',
1143
+ mode: 'durable',
1144
+ timeoutMs,
1145
+ background: args.background === true || args.async === true,
1146
+ })
1147
+ : {
1148
+ mode: 'fast' as const,
1149
+ reasons: ['repository_command_process_runtime_authoritative'],
1150
+ risk: 'unknown' as const,
1151
+ estimatedClass: 'unknown' as const,
1152
+ requiresIsolation: false,
1153
+ requiresRecovery: false,
1154
+ suggestedOperation: undefined,
1155
+ effects: {
1156
+ readsWorkspace: true,
1157
+ mutatesWorkspace: true,
1158
+ mutatesGitRefs: false,
1159
+ remoteWrite: false,
1160
+ },
1161
+ };
1065
1162
  // Unified Process Runtime for local commands (Direct/Managed) when not forced durable.
1066
1163
  // Ephemeral workspaces cannot persist a recoverable async Process handle,
1067
1164
  // so their async requests remain promotion-required below.
@@ -1072,7 +1169,43 @@ export async function callRepositoryTool(
1072
1169
  defaultBranch: repository.defaultBranch,
1073
1170
  timeoutMs,
1074
1171
  });
1075
- if (routeClass.route === 'process_direct' || routeClass.route === 'process_managed') {
1172
+ if (routeClass.route === 'reject') {
1173
+ return result({
1174
+ accepted: false,
1175
+ mode: 'reject',
1176
+ path: routeClass.reason,
1177
+ route: 'reject',
1178
+ status: 'rejected',
1179
+ repoId: repository.repoId,
1180
+ checkoutId: repository.activeCheckoutId,
1181
+ workspace: target.workspace,
1182
+ message: routeClass.reason === 'standalone_recovery_lifecycle_required'
1183
+ ? 'Canonical Runtime and connector lifecycle operations must be submitted to the standalone Forge Recovery owner, not executed as a child of repository Process Runtime.'
1184
+ : 'Repository command execution was rejected by Process Runtime routing policy.',
1185
+ suggestedOperation: routeClass.reason === 'standalone_recovery_lifecycle_required'
1186
+ ? 'Use the standalone Forge Recovery connector.'
1187
+ : routingDecision.suggestedOperation,
1188
+ durableSideEffects: {
1189
+ executionJobCount: 0,
1190
+ localJobCount: 0,
1191
+ workerSpawnCount: 0,
1192
+ projectionUpdateCount: 0,
1193
+ },
1194
+ });
1195
+ }
1196
+ if (routeClass.route === 'durable' && target.workspace) {
1197
+ return result({
1198
+ accepted: false,
1199
+ mode: 'durable',
1200
+ path: 'ephemeral_workspace_promotion_required',
1201
+ repoId: repository.repoId,
1202
+ checkoutId: repository.activeCheckoutId,
1203
+ workspace: target.workspace,
1204
+ message: 'Ephemeral workspaces must be registered before durable remote effects so Process identity and reconciliation have a stable repository authority.',
1205
+ suggestedOperation: 'repository_register',
1206
+ });
1207
+ }
1208
+ if (routeClass.route === 'process_direct' || routeClass.route === 'process_managed' || routeClass.route === 'durable') {
1076
1209
  const processResult = await executeRepositoryCommandViaProcessRuntime({
1077
1210
  controllerHome,
1078
1211
  repository,
@@ -1147,13 +1280,14 @@ export async function callRepositoryTool(
1147
1280
  stdout: processResult.stdout,
1148
1281
  stderr: processResult.stderr,
1149
1282
  durableSideEffects: processResult.durableSideEffects,
1283
+ guidance: explorationGuidance,
1150
1284
  next: directWithoutHandle
1151
1285
  ? processResult.reason === 'readonly_fast_path'
1152
1286
  ? 'Bounded readonly execution completed without Process record / Lease / Local Job / ExecutionJob / Worker.'
1153
1287
  : 'Bounded ephemeral workspace execution completed without Process record / Lease / Local Job / ExecutionJob / Worker.'
1154
1288
  : processResult.route === 'process_direct' || completed
1155
1289
  ? 'Process Runtime completed without Local Job / ExecutionJob / Worker.'
1156
- : `Process Runtime is managing ${handle?.processId}; poll process_get/process_wait instead of creating a Local Job.`,
1290
+ : `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
1291
  detailLevel,
1158
1292
  });
1159
1293
  payload.status = status;
@@ -1270,6 +1404,12 @@ export async function callRepositoryTool(
1270
1404
  routing: compactRoutingSummary({ path: 'durable', mode: 'durable', reasons: [routingDecision.reasons.join(','), 'local_bridge_execution_retired'] }),
1271
1405
  message: 'This command requires explicit external Controller handling; Local Bridge Jobs are retired for repository commands.',
1272
1406
  suggestedOperation: 'Create or claim WorkContract, then use rh_work.launcher_start or a Process Runtime-compatible command.',
1407
+ externalEffect: {
1408
+ outcome: 'not_started',
1409
+ ambiguousFailureOutcome: 'outcome_unknown',
1410
+ replayPolicy: 'never_auto_retry',
1411
+ reconciliation: 'After an ambiguous dispatch failure, inspect the remote ref/registry/release state before deciding whether to retry.',
1412
+ },
1273
1413
  });
1274
1414
  }
1275
1415
  case 'repository_batch_execute': {