@moretea-labs/forge 1.6.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (469) hide show
  1. package/AGENTS.md +4 -0
  2. package/CHANGELOG.md +39 -0
  3. package/CLAUDE.md +4 -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/02-operating-mode.partial.md +2 -0
  17. package/assets/partials-agents/03-orchestration.partial.md +1 -1
  18. package/assets/plugin-registry.v1.json +3 -3
  19. package/assets/reference-configs/document-generation.md +1 -1
  20. package/assets/reference-configs/harness-overview.md +1 -1
  21. package/assets/reference-configs/sprint-contracts.md +3 -3
  22. package/assets/skill-version.json +2 -2
  23. package/assets/templates/contract.template.md +2 -7
  24. package/assets/templates/helpers/capture-plan.sh +2 -2
  25. package/assets/templates/helpers/check-architecture-sync.sh +17 -0
  26. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  27. package/assets/templates/helpers/contract-worktree.sh +1 -21
  28. package/assets/templates/helpers/ensure-task-workflow.sh +11 -36
  29. package/assets/templates/helpers/inspect-project-state.ts +8 -6
  30. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  31. package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
  32. package/assets/templates/helpers/new-plan.sh +1 -1
  33. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  34. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  35. package/assets/templates/helpers/verify-contract.sh +1 -111
  36. package/assets/templates/helpers/verify-sprint.sh +3 -180
  37. package/assets/templates/helpers/workflow-contract.ts +5 -1
  38. package/assets/templates/plan.template.md +1 -1
  39. package/assets/templates/review.template.md +9 -34
  40. package/assets/workflow-contract.v1.json +10 -19
  41. package/docs/README.md +10 -10
  42. package/docs/architecture/CURRENT.md +178 -0
  43. package/docs/architecture/EVOLUTION.md +42 -0
  44. package/docs/architecture/current/README.md +4 -156
  45. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  46. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  47. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  48. package/docs/architecture/history/README.md +7 -0
  49. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  50. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  51. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  52. package/docs/architecture/history.md +3 -34
  53. package/docs/architecture/index.md +15 -98
  54. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  55. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  56. package/docs/architecture/versions/1.6.md +38 -0
  57. package/docs/architecture/versions/1.7.md +41 -0
  58. package/docs/forge-chatgpt-browser-engine.md +2 -2
  59. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  60. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  61. package/docs/forge-github-issue-launcher.md +1 -1
  62. package/docs/forge-plugin-management.md +1 -1
  63. package/docs/forge-runtime-self-healing-loop.md +1 -1
  64. package/docs/operations/controller-browser-plugin.md +26 -6
  65. package/docs/operations/controller-performance-and-502.md +143 -0
  66. package/docs/operations/controller-reliability-runbook.md +1 -1
  67. package/docs/operations/features.md +2 -2
  68. package/docs/operations/github-repository.md +1 -1
  69. package/docs/operations/homebrew.md +2 -2
  70. package/docs/operations/mcp-tool-exposure.md +5 -3
  71. package/docs/wiki/Architecture.md +6 -6
  72. package/docs/wiki/Implementation.md +2 -2
  73. package/docs/wiki/Integrations.md +2 -2
  74. package/docs/wiki/Work-Lifecycle.md +1 -1
  75. package/package.json +33 -11
  76. package/scripts/activate-source-baseline.ts +17 -13
  77. package/scripts/architecture-event.ts +2 -820
  78. package/scripts/architecture-queue.sh +2 -645
  79. package/scripts/archive-architecture-request.sh +2 -242
  80. package/scripts/archive-workflow.sh +1 -291
  81. package/scripts/benchmark-background-check-overlap.ts +228 -0
  82. package/scripts/benchmark-mcp-host.sh +117 -0
  83. package/scripts/benchmark-mcp-transport.ts +170 -0
  84. package/scripts/benchmark-quality-harness.ts +146 -0
  85. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  86. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  87. package/scripts/benchmark-typescript-navigation.ts +186 -0
  88. package/scripts/benchmark-work-efficiency.ts +334 -0
  89. package/scripts/capability-config.ts +2 -392
  90. package/scripts/capability-resolver.ts +2 -503
  91. package/scripts/capture-plan.sh +1 -332
  92. package/scripts/check-agent-tooling.sh +2 -1558
  93. package/scripts/check-architecture-sync.sh +2 -371
  94. package/scripts/check-brain-manifest.sh +2 -253
  95. package/scripts/check-context-files.sh +2 -47
  96. package/scripts/check-deploy-sql-order.sh +2 -115
  97. package/scripts/check-mcp-compatibility.ts +14 -0
  98. package/scripts/check-runtime-architecture.mjs +349 -79
  99. package/scripts/check-skill-version.ts +3 -191
  100. package/scripts/check-source-duplication.mjs +61 -0
  101. package/scripts/check-stable-baseline.ts +92 -0
  102. package/scripts/check-task-sync.sh +2 -63
  103. package/scripts/check-task-workflow.sh +2 -1000
  104. package/scripts/codex-handoff-resume.sh +2 -267
  105. package/scripts/context-contract-sync.sh +2 -514
  106. package/scripts/contract-run.ts +2 -463
  107. package/scripts/contract-worktree.sh +1 -722
  108. package/scripts/ensure-task-workflow.sh +1 -1225
  109. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  110. package/scripts/inspect-project-state.ts +4 -279
  111. package/scripts/install-standalone-recovery.ts +24 -0
  112. package/scripts/lib/project-init-lib.sh +22 -46
  113. package/scripts/lib/run-forge-helper.sh +19 -0
  114. package/scripts/lib/run-forge-helper.ts +26 -0
  115. package/scripts/migrate-project-template.sh +1 -1189
  116. package/scripts/migrate-workflow-docs.ts +4 -412
  117. package/scripts/new-plan.sh +1 -180
  118. package/scripts/new-spec.sh +1 -47
  119. package/scripts/new-sprint.sh +1 -46
  120. package/scripts/plan-to-todo.sh +1 -796
  121. package/scripts/prepare-codex-handoff.sh +2 -201
  122. package/scripts/prepare-handoff.sh +1 -78
  123. package/scripts/refresh-current-status.sh +2 -467
  124. package/scripts/run-governed-gate.ts +5 -1
  125. package/scripts/select-agent-context-blocks.sh +2 -64
  126. package/scripts/ship-worktrees.sh +1 -558
  127. package/scripts/smoke-ios-physical-device.ts +4 -2
  128. package/scripts/smoke-runtime-recovery.ts +1 -35
  129. package/scripts/smoke-schedule-engine.ts +1 -20
  130. package/scripts/sprint-backlog.sh +1 -834
  131. package/scripts/stage-runtime-release.ts +2 -1
  132. package/scripts/summarize-failures.sh +2 -123
  133. package/scripts/switch-plan.sh +1 -150
  134. package/scripts/sync-brain-docs.sh +2 -379
  135. package/scripts/sync-generated-authority.mjs +175 -0
  136. package/scripts/verify-contract.sh +2 -703
  137. package/scripts/verify-forge-runtime.sh +0 -1
  138. package/scripts/verify-sprint.sh +1 -677
  139. package/scripts/workflow-contract.ts +4 -205
  140. package/scripts/workstream-sync.sh +2 -261
  141. package/src/cli/agent-jobs/executor-health.ts +1 -1
  142. package/src/cli/commands/init-hook.ts +3 -3
  143. package/src/cli/commands/mcp.ts +9 -5
  144. package/src/cli/commands/plugin.ts +12 -3
  145. package/src/cli/commands/recovery.ts +25 -3
  146. package/src/cli/commands/runtime.ts +55 -3
  147. package/src/cli/commands/security.ts +12 -1
  148. package/src/cli/commands/setup-profile.ts +31 -21
  149. package/src/cli/controller/check-runner.ts +113 -5
  150. package/src/cli/controller/composite-result.ts +1 -1
  151. package/src/cli/controller/context/focus.ts +51 -0
  152. package/src/cli/controller/context/instruction-context.ts +114 -0
  153. package/src/cli/controller/context/known-paths.ts +76 -0
  154. package/src/cli/controller/context/query-planning.ts +110 -0
  155. package/src/cli/controller/context/rule-resolution.ts +532 -0
  156. package/src/cli/controller/context/source-materializer.ts +278 -0
  157. package/src/cli/controller/context/structural.ts +16 -0
  158. package/src/cli/controller/context/types.ts +286 -0
  159. package/src/cli/controller/context-pack.ts +828 -487
  160. package/src/cli/controller/launch-agents.ts +77 -2
  161. package/src/cli/controller/operational-plan.ts +2 -2
  162. package/src/cli/controller/work-mode.ts +6 -4
  163. package/src/cli/editing/edit-session.ts +60 -7
  164. package/src/cli/github/contracts.ts +16 -0
  165. package/src/cli/github/github.ts +135 -16
  166. package/src/cli/github/session.ts +2 -1
  167. package/src/cli/installer/managed-entries.ts +15 -1
  168. package/src/cli/local-bridge/console-automations.ts +54 -78
  169. package/src/cli/local-bridge/console-view-models.ts +1 -35
  170. package/src/cli/local-bridge/facade-api.ts +37 -264
  171. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  172. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
  173. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  174. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
  175. package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
  176. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  177. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
  178. package/src/cli/local-bridge/frontend/src/styles.css +1 -1
  179. package/src/cli/local-bridge/frontend/src/types.ts +5 -8
  180. package/src/cli/local-bridge/job-store.ts +1 -490
  181. package/src/cli/local-bridge/server.ts +2 -515
  182. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  183. package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
  184. package/src/cli/mcp/auth.ts +5 -5
  185. package/src/cli/mcp/instructions.ts +3 -2
  186. package/src/cli/mcp/legacy-tool-service.ts +10 -222
  187. package/src/cli/mcp/multi-repository.ts +16 -5
  188. package/src/cli/mcp/oauth.ts +175 -26
  189. package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
  190. package/src/cli/mcp/repository-tools.ts +282 -146
  191. package/src/cli/mcp/server.ts +586 -116
  192. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  193. package/src/cli/mcp/tool-contract.ts +14 -0
  194. package/src/cli/mcp/toolset-selection.ts +1 -1
  195. package/src/cli/mcp/toolset.ts +44 -7
  196. package/src/cli/mcp/transports/http.ts +124 -14
  197. package/src/cli/mcp/transports/session-registry.ts +43 -5
  198. package/src/cli/mcp/types.ts +3 -3
  199. package/src/cli/repositories/command-classifier.ts +103 -21
  200. package/src/cli/repositories/command-executor.ts +78 -526
  201. package/src/cli/repositories/command-process.ts +108 -0
  202. package/src/cli/repositories/command-scope.ts +99 -41
  203. package/src/cli/repositories/controller-home.ts +7 -8
  204. package/src/cli/repositories/git-command-executor.ts +2 -0
  205. package/src/cli/repositories/locks.ts +53 -16
  206. package/src/cli/repositories/repository-snapshot.ts +124 -0
  207. package/src/cli/repositories/selected-path-actions.ts +17 -9
  208. package/src/cli/repositories/structured-git.ts +118 -6
  209. package/src/cli/repository/inspector.ts +563 -65
  210. package/src/cli/repository/session-cache.ts +58 -17
  211. package/src/cli/v81-entry.ts +1 -4
  212. package/src/effects/fs-transaction.ts +85 -17
  213. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  214. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  215. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  216. package/src/runtime/context/lsp-client.ts +283 -0
  217. package/src/runtime/context/semantic-navigation-contract.ts +61 -0
  218. package/src/runtime/context/semantic-navigation.ts +223 -0
  219. package/src/runtime/context/swift-navigation.ts +565 -0
  220. package/src/runtime/context/typescript-navigation.ts +226 -0
  221. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  222. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +48 -16
  223. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  224. package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
  225. package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
  226. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  227. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  228. package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
  229. package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
  230. package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
  231. package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
  232. package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
  233. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  234. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  235. package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
  236. package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
  237. package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
  238. package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
  239. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  240. package/src/runtime/control-plane/execution/work-task-receipt.ts +22 -18
  241. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +156 -11
  242. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
  243. package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
  244. package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
  245. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +90 -9
  246. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  247. package/src/runtime/control-plane/facade/controller-round-relay.ts +1118 -0
  248. package/src/runtime/control-plane/facade/controller-session-store.ts +302 -12
  249. package/src/runtime/control-plane/facade/goal-workloop-access.ts +17 -1
  250. package/src/runtime/control-plane/facade/goal-workloop.ts +928 -190
  251. package/src/runtime/control-plane/facade/index.ts +3 -0
  252. package/src/runtime/control-plane/facade/plan-contract-store.ts +275 -42
  253. package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
  254. package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
  255. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  256. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  257. package/src/runtime/control-plane/facade/types.ts +90 -10
  258. package/src/runtime/control-plane/facade/work-contract-store.ts +157 -261
  259. package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
  260. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  261. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  262. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  263. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  264. package/src/runtime/control-plane/global-scheduler/maintenance.ts +152 -0
  265. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  266. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  267. package/src/runtime/control-plane/global-scheduler/scheduler.ts +278 -543
  268. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  269. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  270. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  271. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  272. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  273. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  274. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  275. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  276. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  277. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  278. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +63 -0
  279. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +365 -117
  280. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +89 -0
  281. package/src/runtime/control-plane/launcher/thin-launcher.ts +244 -11
  282. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  283. package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
  284. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  285. package/src/runtime/control-plane/release-retention.ts +62 -2
  286. package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
  287. package/src/runtime/control-plane/routing/route-policy.ts +24 -21
  288. package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
  289. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  290. package/src/runtime/diagnostics/mcp-timing.ts +13 -0
  291. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  292. package/src/runtime/diagnostics/performance.ts +24 -1
  293. package/src/runtime/evidence/event-ledger.ts +1 -1
  294. package/src/runtime/evidence/process-check-execution.ts +18 -0
  295. package/src/runtime/execution/jobs/child-reference.ts +6 -2
  296. package/src/runtime/execution/jobs/store.ts +58 -4
  297. package/src/runtime/execution/jobs/types.ts +1 -1
  298. package/src/runtime/execution/managed-workspace.ts +203 -1
  299. package/src/runtime/execution/process-runtime/check-facade.ts +51 -4
  300. package/src/runtime/execution/process-runtime/check-result.ts +88 -0
  301. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
  302. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  303. package/src/runtime/execution/process-runtime/command-facade.ts +367 -40
  304. package/src/runtime/execution/process-runtime/gc.ts +38 -6
  305. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1201 -0
  306. package/src/runtime/execution/process-runtime/persisted-check.ts +51 -5
  307. package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
  308. package/src/runtime/execution/process-runtime/runtime.ts +53 -3
  309. package/src/runtime/execution/process-runtime/store.ts +1 -0
  310. package/src/runtime/execution/process-runtime/types.ts +4 -12
  311. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  312. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  313. package/src/runtime/execution/work-activity.ts +21 -0
  314. package/src/runtime/execution/workers/executor.ts +18 -61
  315. package/src/runtime/gateway/mcp/execution-tools.ts +35 -1852
  316. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
  317. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  318. package/src/runtime/gateway/mcp/router.ts +186 -84
  319. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +565 -0
  320. package/src/runtime/gateway/mcp/runtime-tools.ts +2378 -1947
  321. package/src/runtime/plugins/app-store-connect-adapter.ts +216 -47
  322. package/src/runtime/plugins/browser-adapter.ts +2662 -829
  323. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  324. package/src/runtime/plugins/browser-handoff-host.ts +2 -25
  325. package/src/runtime/plugins/browser-handoff.ts +110 -5
  326. package/src/runtime/plugins/browser-macos-bridge.ts +701 -63
  327. package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
  328. package/src/runtime/plugins/browser-native-session-service.ts +222 -0
  329. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  330. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  331. package/src/runtime/plugins/browser-runtime-contract.ts +154 -0
  332. package/src/runtime/plugins/browser-runtime.ts +193 -0
  333. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  334. package/src/runtime/plugins/browser-session-store.ts +121 -0
  335. package/src/runtime/plugins/browser-session-types.ts +98 -0
  336. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  337. package/src/runtime/plugins/desktop-operator-registration.ts +10 -4
  338. package/src/runtime/plugins/external-adapter.ts +358 -3
  339. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  340. package/src/runtime/plugins/first-party-registry.ts +2 -0
  341. package/src/runtime/plugins/github-adapter.ts +125 -0
  342. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  343. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  344. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  345. package/src/runtime/plugins/ios-adapter.ts +106 -16
  346. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  347. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  348. package/src/runtime/plugins/lightweight-action.ts +153 -0
  349. package/src/runtime/plugins/local-system-adapter.ts +123 -6
  350. package/src/runtime/plugins/macos-capability-broker.ts +47 -9
  351. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  352. package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
  353. package/src/runtime/plugins/resend-adapter.ts +1 -1
  354. package/src/runtime/plugins/store.ts +330 -33
  355. package/src/runtime/plugins/types.ts +38 -3
  356. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  357. package/src/runtime/projections/git-status-sampler.ts +16 -16
  358. package/src/runtime/projections/materialized-view.ts +28 -10
  359. package/src/runtime/recovery/maintenance-executor.ts +426 -25
  360. package/src/runtime/root/mcp-transport.ts +180 -10
  361. package/src/runtime/root/package-connector-service.ts +230 -10
  362. package/src/runtime/root/package-runtime-release.ts +143 -17
  363. package/src/runtime/root/package-runtime-service.ts +461 -22
  364. package/src/runtime/root/release-manifest.ts +144 -18
  365. package/src/runtime/root/release-materialize.ts +125 -32
  366. package/src/runtime/root/release-store.ts +48 -11
  367. package/src/runtime/root/runtime.ts +23 -5
  368. package/src/runtime/root/service.ts +100 -29
  369. package/src/runtime/root/types.ts +12 -0
  370. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  371. package/src/runtime/shared/trusted-executable.ts +62 -0
  372. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  373. package/src/runtime/standalone-recovery/core.ts +1079 -240
  374. package/src/runtime/standalone-recovery/entry.ts +100 -24
  375. package/src/runtime/standalone-recovery/installer.ts +20 -4
  376. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  377. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  378. package/src/runtime/workflow/schedules/browser-probe.ts +81 -3
  379. package/src/runtime/workflow/schedules/engine.ts +364 -202
  380. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  381. package/src/runtime/workflow/schedules/settlement.ts +64 -17
  382. package/src/runtime/workflow/schedules/store.ts +209 -19
  383. package/src/runtime/workflow/schedules/types.ts +2 -4
  384. package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
  385. package/src/testing/test-governance.ts +8 -40
  386. package/assets/reference-configs/heartbeat-triage.md +0 -57
  387. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  388. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  389. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  390. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  391. package/docs/architecture/current/architecture-invariants.md +0 -331
  392. package/docs/architecture/current/automation-and-schedule-engine.md +0 -459
  393. package/docs/architecture/current/codegraph-context-provider.md +0 -238
  394. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  395. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  396. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -373
  397. package/docs/architecture/current/entity-model.md +0 -612
  398. package/docs/architecture/current/external-plugin-governance.md +0 -396
  399. package/docs/architecture/current/failure-recovery.md +0 -447
  400. package/docs/architecture/current/governance.md +0 -213
  401. package/docs/architecture/current/human-interaction-plane.md +0 -87
  402. package/docs/architecture/current/implementation-status.md +0 -128
  403. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  404. package/docs/architecture/current/legacy-governance.md +0 -58
  405. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  406. package/docs/architecture/current/migration-roadmap.md +0 -105
  407. package/docs/architecture/current/multi-repository-execution.md +0 -371
  408. package/docs/architecture/current/operations-runbook.md +0 -45
  409. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  410. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  411. package/docs/architecture/current/repository-access-modes.md +0 -102
  412. package/docs/architecture/current/route-policy.md +0 -15
  413. package/docs/architecture/current/route-session-concurrency.md +0 -85
  414. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  415. package/docs/architecture/current/runtime-directory-map.md +0 -49
  416. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  417. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  418. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  419. package/docs/architecture/current/system-overview.md +0 -169
  420. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  421. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  422. package/docs/architecture/current/thin-harness-v1.md +0 -321
  423. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  424. package/docs/forge-autonomous-goal-loop.md +0 -9
  425. package/docs/forge-provider-configuration.md +0 -7
  426. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -93
  427. package/docs/operations/gmail-assistant-routines.md +0 -186
  428. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  429. package/docs/operations/provider-configuration.md +0 -31
  430. package/scripts/harness-trace-grade.sh +0 -150
  431. package/scripts/heartbeat-triage.sh +0 -361
  432. package/scripts/maintenance-triage.sh +0 -167
  433. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  434. package/src/cli/repositories/goal-registry.ts +0 -239
  435. package/src/runtime/assistant/action-proposals.ts +0 -279
  436. package/src/runtime/assistant/intent.ts +0 -395
  437. package/src/runtime/assistant/model-provider.ts +0 -460
  438. package/src/runtime/assistant/openapi.ts +0 -223
  439. package/src/runtime/assistant/policy.ts +0 -89
  440. package/src/runtime/assistant/readiness.ts +0 -258
  441. package/src/runtime/assistant/routine-runtime.ts +0 -477
  442. package/src/runtime/assistant/schedule-binding.ts +0 -171
  443. package/src/runtime/assistant/standing-grants.ts +0 -375
  444. package/src/runtime/assistant/store.ts +0 -243
  445. package/src/runtime/assistant/types.ts +0 -135
  446. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  447. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  448. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  449. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  450. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  451. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  452. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  453. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  454. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  455. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  456. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  457. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  458. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  459. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  460. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  461. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  462. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  463. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  464. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  465. package/src/runtime/workflow/findings/store.ts +0 -204
  466. package/src/runtime/workflow/findings/types.ts +0 -58
  467. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  468. package/src/runtime/workflow/portfolio/store.ts +0 -185
  469. package/src/runtime/workflow/portfolio/types.ts +0 -29
@@ -1,5 +1,16 @@
1
1
  import { randomUUID } from 'crypto';
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from 'fs';
2
+ import {
3
+ chmodSync,
4
+ closeSync,
5
+ existsSync,
6
+ fsyncSync,
7
+ mkdirSync,
8
+ openSync,
9
+ readFileSync,
10
+ renameSync,
11
+ rmSync,
12
+ writeFileSync,
13
+ } from 'fs';
3
14
  import { dirname } from 'path';
4
15
  import type { OAuthRegisteredClientsStore } from '@modelcontextprotocol/sdk/server/auth/clients.js';
5
16
  import { InvalidGrantError, InvalidTokenError } from '@modelcontextprotocol/sdk/server/auth/errors.js';
@@ -25,6 +36,20 @@ function issueToken(): string {
25
36
  return randomUUID();
26
37
  }
27
38
 
39
+ function fsyncFile(path: string): void {
40
+ const fd = openSync(path, 'r');
41
+ try { fsyncSync(fd); } finally { closeSync(fd); }
42
+ }
43
+
44
+ function fsyncDirectory(path: string): void {
45
+ try {
46
+ const fd = openSync(path, 'r');
47
+ try { fsyncSync(fd); } finally { closeSync(fd); }
48
+ } catch {
49
+ // Directory fsync is unavailable on some supported platforms/filesystems.
50
+ }
51
+ }
52
+
28
53
  export class McpOAuthTokenStore implements OAuthRegisteredClientsStore {
29
54
  private accessTokens = new Map<string, AuthInfo>();
30
55
  private refreshTokens = new Map<string, string>();
@@ -33,8 +58,12 @@ export class McpOAuthTokenStore implements OAuthRegisteredClientsStore {
33
58
  constructor(private readonly path: string, private readonly fallbackPaths: string[] = []) {}
34
59
 
35
60
  load(): void {
61
+ this.accessTokens.clear();
62
+ this.refreshTokens.clear();
63
+ this.clients.clear();
36
64
  let loaded = false;
37
65
  let mergedFallback = false;
66
+ let primaryCorrupt = false;
38
67
  for (const [index, path] of [this.path, ...this.fallbackPaths].entries()) {
39
68
  if (!existsSync(path)) continue;
40
69
  try {
@@ -59,22 +88,35 @@ export class McpOAuthTokenStore implements OAuthRegisteredClientsStore {
59
88
  }
60
89
  loaded = true;
61
90
  } catch (_error) {
62
- // Corrupt local auth state should not prevent starting the server.
91
+ if (index === 0) primaryCorrupt = true;
63
92
  }
64
93
  }
65
- if (loaded && mergedFallback) this.flush();
94
+ if (primaryCorrupt && !loaded) {
95
+ throw new Error('MCP_OAUTH_STORE_CORRUPT: primary OAuth state is unreadable and no valid fallback is available');
96
+ }
97
+ if (loaded && (mergedFallback || primaryCorrupt)) this.flush();
66
98
  }
67
99
 
68
100
  flush(): void {
69
- mkdirSync(dirname(this.path), { recursive: true, mode: 0o700 });
70
- chmodSync(dirname(this.path), 0o700);
101
+ const directory = dirname(this.path);
102
+ mkdirSync(directory, { recursive: true, mode: 0o700 });
103
+ chmodSync(directory, 0o700);
71
104
  const data: TokenData = {
72
105
  accessTokens: Object.fromEntries(this.accessTokens),
73
106
  refreshTokens: Object.fromEntries(this.refreshTokens),
74
107
  clients: Object.fromEntries(this.clients),
75
108
  };
76
- writeFileSync(this.path, `${JSON.stringify(data, null, 2)}\n`, { encoding: 'utf-8', mode: 0o600 });
77
- chmodSync(this.path, 0o600);
109
+ const temporary = `${this.path}.${process.pid}.${randomUUID()}.tmp`;
110
+ try {
111
+ writeFileSync(temporary, `${JSON.stringify(data, null, 2)}\n`, { encoding: 'utf-8', mode: 0o600 });
112
+ chmodSync(temporary, 0o600);
113
+ fsyncFile(temporary);
114
+ renameSync(temporary, this.path);
115
+ chmodSync(this.path, 0o600);
116
+ fsyncDirectory(directory);
117
+ } finally {
118
+ rmSync(temporary, { force: true });
119
+ }
78
120
  }
79
121
 
80
122
  getClient(clientId: string): OAuthClientInformationFull | undefined {
@@ -127,10 +169,115 @@ export class McpOAuthTokenStore implements OAuthRegisteredClientsStore {
127
169
  }
128
170
  return undefined;
129
171
  }
172
+
173
+ setTokenPair(accessToken: string, info: AuthInfo, refreshToken: string): void {
174
+ this.accessTokens.set(accessToken, info);
175
+ this.refreshTokens.set(refreshToken, accessToken);
176
+ this.flush();
177
+ }
178
+
179
+ rotateRefreshToken(
180
+ previousRefreshToken: string,
181
+ nextRefreshToken: string,
182
+ accessToken: string,
183
+ info: AuthInfo,
184
+ ): void {
185
+ this.refreshTokens.delete(previousRefreshToken);
186
+ this.accessTokens.set(accessToken, info);
187
+ this.refreshTokens.set(nextRefreshToken, accessToken);
188
+ this.flush();
189
+ }
190
+
191
+ revokeToken(token: string): void {
192
+ const linkedAccessToken = this.refreshTokens.get(token);
193
+ if (linkedAccessToken) {
194
+ this.refreshTokens.delete(token);
195
+ this.accessTokens.delete(linkedAccessToken);
196
+ for (const [refreshToken, accessToken] of this.refreshTokens) {
197
+ if (accessToken === linkedAccessToken) this.refreshTokens.delete(refreshToken);
198
+ }
199
+ this.flush();
200
+ return;
201
+ }
202
+
203
+ this.accessTokens.delete(token);
204
+ for (const [refreshToken, accessToken] of this.refreshTokens) {
205
+ if (accessToken === token) this.refreshTokens.delete(refreshToken);
206
+ }
207
+ this.flush();
208
+ }
130
209
  }
131
210
 
132
- export function createMcpOAuthProvider(store: McpOAuthTokenStore): OAuthServerProvider {
133
- const authCodes = new Map<string, { challenge: string; clientId: string }>();
211
+ interface PendingAuthorizationCode {
212
+ challenge: string;
213
+ clientId: string;
214
+ issuedAt: number;
215
+ expiresAt: number;
216
+ }
217
+
218
+ export interface McpOAuthProviderOptions {
219
+ now?: () => number;
220
+ authorizationCodeTtlSeconds?: number;
221
+ maxPendingAuthorizationCodes?: number;
222
+ maxPendingAuthorizationCodesPerClient?: number;
223
+ }
224
+
225
+ const DEFAULT_AUTHORIZATION_CODE_TTL_SECONDS = 10 * 60;
226
+ const DEFAULT_MAX_PENDING_AUTHORIZATION_CODES = 512;
227
+ const DEFAULT_MAX_PENDING_AUTHORIZATION_CODES_PER_CLIENT = 32;
228
+
229
+ export function createMcpOAuthProvider(
230
+ store: McpOAuthTokenStore,
231
+ options: McpOAuthProviderOptions = {},
232
+ ): OAuthServerProvider {
233
+ const authCodes = new Map<string, PendingAuthorizationCode>();
234
+ const currentTime = options.now ?? nowSeconds;
235
+ const ttlSeconds = Math.max(30, Math.trunc(options.authorizationCodeTtlSeconds ?? DEFAULT_AUTHORIZATION_CODE_TTL_SECONDS));
236
+ const globalLimit = Math.max(8, Math.trunc(options.maxPendingAuthorizationCodes ?? DEFAULT_MAX_PENDING_AUTHORIZATION_CODES));
237
+ const clientLimit = Math.max(2, Math.min(globalLimit, Math.trunc(
238
+ options.maxPendingAuthorizationCodesPerClient ?? DEFAULT_MAX_PENDING_AUTHORIZATION_CODES_PER_CLIENT,
239
+ )));
240
+
241
+ const purgeExpiredCodes = (now = currentTime()): void => {
242
+ for (const [code, pending] of authCodes) {
243
+ if (pending.expiresAt <= now) authCodes.delete(code);
244
+ }
245
+ };
246
+
247
+ const evictOldest = (predicate: (entry: PendingAuthorizationCode) => boolean): boolean => {
248
+ let oldest: { code: string; issuedAt: number } | undefined;
249
+ for (const [code, pending] of authCodes) {
250
+ if (!predicate(pending)) continue;
251
+ if (!oldest || pending.issuedAt < oldest.issuedAt) oldest = { code, issuedAt: pending.issuedAt };
252
+ }
253
+ if (!oldest) return false;
254
+ authCodes.delete(oldest.code);
255
+ return true;
256
+ };
257
+
258
+ const reserveAuthorizationCodeCapacity = (clientId: string, now: number): void => {
259
+ purgeExpiredCodes(now);
260
+ while ([...authCodes.values()].filter((pending) => pending.clientId === clientId).length >= clientLimit) {
261
+ if (!evictOldest((pending) => pending.clientId === clientId)) break;
262
+ }
263
+ while (authCodes.size >= globalLimit) {
264
+ if (!evictOldest(() => true)) break;
265
+ }
266
+ };
267
+
268
+ const pendingAuthorizationCode = (
269
+ client: OAuthClientInformationFull,
270
+ authorizationCode: string,
271
+ ): PendingAuthorizationCode => {
272
+ const now = currentTime();
273
+ purgeExpiredCodes(now);
274
+ const stored = authCodes.get(authorizationCode);
275
+ if (!stored || stored.clientId !== client.client_id || stored.expiresAt <= now) {
276
+ if (stored?.expiresAt !== undefined && stored.expiresAt <= now) authCodes.delete(authorizationCode);
277
+ throw new InvalidGrantError('Invalid authorization code');
278
+ }
279
+ return stored;
280
+ };
134
281
 
135
282
  return {
136
283
  get clientsStore(): OAuthRegisteredClientsStore {
@@ -138,10 +285,14 @@ export function createMcpOAuthProvider(store: McpOAuthTokenStore): OAuthServerPr
138
285
  },
139
286
 
140
287
  async authorize(client: OAuthClientInformationFull, params: AuthorizationParams, res): Promise<void> {
288
+ const now = currentTime();
289
+ reserveAuthorizationCodeCapacity(client.client_id, now);
141
290
  const code = issueToken();
142
291
  authCodes.set(code, {
143
292
  challenge: params.codeChallenge,
144
293
  clientId: client.client_id,
294
+ issuedAt: now,
295
+ expiresAt: now + ttlSeconds,
145
296
  });
146
297
  const redirectUrl = new URL(params.redirectUri);
147
298
  redirectUrl.searchParams.set('code', code);
@@ -149,10 +300,8 @@ export function createMcpOAuthProvider(store: McpOAuthTokenStore): OAuthServerPr
149
300
  res.redirect(302, redirectUrl.toString());
150
301
  },
151
302
 
152
- async challengeForAuthorizationCode(_client: OAuthClientInformationFull, authorizationCode: string): Promise<string> {
153
- const stored = authCodes.get(authorizationCode);
154
- if (!stored) throw new InvalidGrantError('Invalid authorization code');
155
- return stored.challenge;
303
+ async challengeForAuthorizationCode(client: OAuthClientInformationFull, authorizationCode: string): Promise<string> {
304
+ return pendingAuthorizationCode(client, authorizationCode).challenge;
156
305
  },
157
306
 
158
307
  async exchangeAuthorizationCode(
@@ -160,22 +309,21 @@ export function createMcpOAuthProvider(store: McpOAuthTokenStore): OAuthServerPr
160
309
  authorizationCode: string,
161
310
  _codeVerifier?: string,
162
311
  ): Promise<OAuthTokens> {
163
- const stored = authCodes.get(authorizationCode);
164
- if (!stored || stored.clientId !== client.client_id) {
165
- throw new InvalidGrantError('Invalid authorization code');
166
- }
312
+ pendingAuthorizationCode(client, authorizationCode);
313
+ // Delete before issuing credentials. A failed downstream persistence is
314
+ // retried as a new OAuth flow rather than making an authorization code
315
+ // replayable after a partial token response.
167
316
  authCodes.delete(authorizationCode);
168
317
  const accessToken = issueToken();
169
318
  const refreshToken = issueToken();
170
319
  const expiresIn = 30 * 24 * 60 * 60;
171
320
  const expiresAt = nowSeconds() + expiresIn;
172
- store.setAccessToken(accessToken, {
321
+ store.setTokenPair(accessToken, {
173
322
  token: accessToken,
174
323
  clientId: client.client_id,
175
324
  scopes: ['forge'],
176
325
  expiresAt,
177
- });
178
- store.setRefreshToken(refreshToken, accessToken);
326
+ }, refreshToken);
179
327
  return {
180
328
  access_token: accessToken,
181
329
  token_type: 'Bearer',
@@ -191,11 +339,14 @@ export function createMcpOAuthProvider(store: McpOAuthTokenStore): OAuthServerPr
191
339
  if (!accessToken || !existing || existing.clientId !== client.client_id) {
192
340
  throw new InvalidGrantError('Invalid refresh token');
193
341
  }
194
- store.deleteRefreshToken(refreshToken);
195
342
  const nextRefreshToken = issueToken();
196
343
  const expiresIn = 30 * 24 * 60 * 60;
197
- store.setAccessToken(accessToken, { ...existing, expiresAt: nowSeconds() + expiresIn });
198
- store.setRefreshToken(nextRefreshToken, accessToken);
344
+ store.rotateRefreshToken(
345
+ refreshToken,
346
+ nextRefreshToken,
347
+ accessToken,
348
+ { ...existing, expiresAt: nowSeconds() + expiresIn },
349
+ );
199
350
  return {
200
351
  access_token: accessToken,
201
352
  token_type: 'Bearer',
@@ -218,9 +369,7 @@ export function createMcpOAuthProvider(store: McpOAuthTokenStore): OAuthServerPr
218
369
  },
219
370
 
220
371
  async revokeToken(_client: OAuthClientInformationFull, request: OAuthTokenRevocationRequest): Promise<void> {
221
- store.deleteAccessToken(request.token);
222
- const refreshToken = store.findRefreshTokenByAccessToken(request.token);
223
- if (refreshToken) store.deleteRefreshToken(refreshToken);
372
+ store.revokeToken(request.token);
224
373
  },
225
374
  };
226
375
  }
@@ -0,0 +1,150 @@
1
+ import { classifyRepositoryCommand } from '../repositories/command-classifier';
2
+ import { resolveRepositorySelection } from '../repositories/registry';
3
+ import { executionIdentityForRepository } from '../../runtime/control-plane/execution/execution-identity';
4
+ import { getWorkContract } from '../../runtime/control-plane/facade/work-contract-store';
5
+ import { isTerminalWorkContractStatus } from '../../runtime/control-plane/facade/types';
6
+ import {
7
+ classifyRepositoryCommandRoute,
8
+ executeRepositoryCommandViaProcessRuntime,
9
+ } from '../../runtime/execution/process-runtime/command-facade';
10
+ import {
11
+ callRepositoryTool,
12
+ type RepositoryToolCallerContext,
13
+ } from './repository-tools';
14
+ import type { CallToolResult } from './tools';
15
+
16
+ function result(payload: Record<string, unknown>, isError = false): CallToolResult {
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(payload) }],
19
+ structuredContent: payload,
20
+ ...(isError ? { isError: true } : {}),
21
+ };
22
+ }
23
+
24
+ function optionalNumber(value: unknown): number | undefined {
25
+ if (typeof value === 'number' && Number.isFinite(value)) return value;
26
+ if (typeof value === 'string' && value.trim()) {
27
+ const parsed = Number(value);
28
+ return Number.isFinite(parsed) ? parsed : undefined;
29
+ }
30
+ return undefined;
31
+ }
32
+
33
+ /**
34
+ * A completed Work is historical attribution, never mutation authority.
35
+ *
36
+ * Finalize cleanup may remove the Work-owned checkout and release its Controller
37
+ * lease, but a Controller can still need to observe the repository immediately
38
+ * afterwards (for example `git status -sb`). Keep that observation attributed to
39
+ * the completed Work without reopening the Work lifecycle or writer lease.
40
+ *
41
+ * This path intentionally accepts only typed argv commands that the same command
42
+ * classifier used by Process Runtime proves readonly. Everything else falls
43
+ * through to the normal repository facade so active-Work ownership, terminal
44
+ * mutation fences, and completion-receipt remote-delivery rules stay authoritative.
45
+ */
46
+ export async function callPostFinalizeWorkReadOnlyCommand(
47
+ controllerHome: string,
48
+ name: string,
49
+ args: Record<string, unknown>,
50
+ caller?: RepositoryToolCallerContext,
51
+ ): Promise<CallToolResult | undefined> {
52
+ if (name !== 'repository_command_execute') return undefined;
53
+ if (typeof args.workspace_root === 'string' && args.workspace_root.trim()) return undefined;
54
+
55
+ const requestedWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
56
+ const principalId = caller?.principalId?.trim() ?? '';
57
+ const command = args.command;
58
+ if (!requestedWorkId || !principalId || !Array.isArray(command) || !command.every((entry) => typeof entry === 'string')) {
59
+ return undefined;
60
+ }
61
+
62
+ const repository = resolveRepositorySelection({
63
+ repoId: typeof args.repo_id === 'string' && args.repo_id.trim() ? args.repo_id.trim() : undefined,
64
+ controllerHome,
65
+ allowSoleRepository: true,
66
+ });
67
+ if (!repository) return undefined;
68
+
69
+ const work = getWorkContract({ controllerHome, repoId: repository.repoId }, requestedWorkId);
70
+ if (
71
+ !work
72
+ || !isTerminalWorkContractStatus(work.status)
73
+ || work.status !== 'completed'
74
+ || !work.completionReceipt
75
+ || work.completionReceipt.workId !== requestedWorkId
76
+ || !work.principalId?.trim()
77
+ || work.principalId.trim() !== principalId
78
+ ) {
79
+ return undefined;
80
+ }
81
+
82
+ const classification = classifyRepositoryCommand(command, repository.defaultBranch);
83
+ if (classification.risk !== 'readonly') return undefined;
84
+ const route = classifyRepositoryCommandRoute(command, {
85
+ defaultBranch: repository.defaultBranch,
86
+ timeoutMs: optionalNumber(args.timeout_ms),
87
+ });
88
+ if (route.route !== 'process_direct' || route.reason !== 'readonly_fast_path') return undefined;
89
+
90
+ const executionIdentity = executionIdentityForRepository(repository, { workId: requestedWorkId });
91
+ const execution = await executeRepositoryCommandViaProcessRuntime({
92
+ controllerHome,
93
+ repository,
94
+ command,
95
+ cwd: typeof args.cwd === 'string' ? args.cwd : undefined,
96
+ timeoutMs: optionalNumber(args.timeout_ms),
97
+ interactiveWaitMs: optionalNumber(args.interactive_wait_ms),
98
+ maxOutputBytes: optionalNumber(args.max_output_bytes),
99
+ requestId: typeof args.request_id === 'string' ? args.request_id : undefined,
100
+ workId: requestedWorkId,
101
+ executionIdentity,
102
+ });
103
+
104
+ if (execution.route !== 'process_direct' || execution.process) {
105
+ return result({
106
+ accepted: false,
107
+ mode: 'reject',
108
+ path: 'post_finalize_readonly_route_mismatch',
109
+ route: 'reject',
110
+ repoId: repository.repoId,
111
+ checkoutId: repository.activeCheckoutId,
112
+ workId: requestedWorkId,
113
+ lifecycleClosed: true,
114
+ error: {
115
+ code: 'POST_FINALIZE_READONLY_ROUTE_MISMATCH',
116
+ message: 'Post-finalize Work attribution may execute only through the bounded readonly direct lane.',
117
+ },
118
+ }, true);
119
+ }
120
+
121
+ return result({
122
+ accepted: true,
123
+ mode: 'process_direct',
124
+ path: 'process_direct',
125
+ route: 'process_direct',
126
+ reason: 'post_finalize_work_readonly_followup',
127
+ repoId: repository.repoId,
128
+ checkoutId: repository.activeCheckoutId,
129
+ workId: requestedWorkId,
130
+ lifecycleClosed: true,
131
+ postFinalizeAttribution: 'readonly_followup',
132
+ completed: true,
133
+ ok: execution.ok === true,
134
+ exitCode: execution.exitCode,
135
+ stdout: execution.stdout,
136
+ stderr: execution.stderr,
137
+ durableSideEffects: execution.durableSideEffects,
138
+ next: 'Post-finalize readonly observation completed without reopening Work mutation authority or creating durable execution state.',
139
+ });
140
+ }
141
+
142
+ export async function callRepositoryToolWithPostFinalizeAttribution(
143
+ controllerHome: string,
144
+ name: string,
145
+ args: Record<string, unknown>,
146
+ caller?: RepositoryToolCallerContext,
147
+ ): Promise<CallToolResult | undefined> {
148
+ const followup = await callPostFinalizeWorkReadOnlyCommand(controllerHome, name, args, caller);
149
+ return followup ?? callRepositoryTool(controllerHome, name, args, caller);
150
+ }