@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
@@ -0,0 +1,479 @@
1
+ import { createHash } from 'crypto';
2
+ import { spawnSync } from 'child_process';
3
+ import type { MultiRepositoryMcpToolContext } from '../../../cli/mcp/multi-repository';
4
+ import type { RepositoryRecord } from '../../../cli/repositories/types';
5
+ import { getRepository, resolveRepositorySelection, selectRepositoryCheckout } from '../../../cli/repositories/registry';
6
+ import { repositoryGitStatus } from '../../../cli/repositories/structured-git';
7
+ import { ensureManagedWorkspace } from '../../execution/managed-workspace';
8
+ import { readRepositoryAccessPolicy } from '../governance/access-policy';
9
+ import { appendWorkEvidence, getWorkContract, updateWorkContract } from '../facade/work-contract-store';
10
+ import { admitPreparedRepositoryWorkContract } from '../facade/repository-work-admission';
11
+ import { isTerminalWorkContractStatus, type WorkReconciliationRecord } from '../facade/types';
12
+ import { claimControllerSession, getControllerSession, resumeControllerSession } from '../facade/controller-session-store';
13
+ import { updateExecutionSession, type ExecutionSessionContext } from './session-store';
14
+ import { currentPermissionSnapshotVersion, validateWorkHandle } from './validation';
15
+ import { assertExecutionIdentity, executionIdentityFromCoordinates } from './execution-identity';
16
+ import { withWorkPrepareRequest } from './work-prepare-request-store';
17
+ import { markWorkHandleFailed, newWorkId, readWorkHandle, transitionWorkHandle, writeWorkHandle, type WorkFinalizationStages, type WorkHandleState } from './work-handle-store';
18
+ import { assertWorkPathsWithinScope } from './work-path-scope';
19
+ import { createGoalDelegation } from '../governance/authorization';
20
+ import { compactHandle, contractFor, findWorkHandle, gitChangedPaths, gitCommit, gitHead, gitMergeBase, identityFor, requireSession, selectWorkFinalizationTarget } from './work-execution-support';
21
+
22
+ function requireExplicitRepoId(args: Record<string, unknown>): string {
23
+ const value = typeof args.repo_id === 'string' ? args.repo_id.trim() : '';
24
+ if (!value) throw new Error('REPOSITORY_ID_REQUIRED: repository selection must be explicit for session binding');
25
+ return value;
26
+ }
27
+
28
+ function selectedRepository(ctx: MultiRepositoryMcpToolContext, session: ExecutionSessionContext, args: Record<string, unknown>, allowSession = true) {
29
+ const requested = typeof args.repo_id === 'string' && args.repo_id.trim() ? args.repo_id.trim() : undefined;
30
+ const selectedRepoId = requested ?? (allowSession ? session.activeRepositoryId : undefined);
31
+ if (!selectedRepoId) throw new Error('SESSION_REPOSITORY_REQUIRED: bind a repository before using this work tool');
32
+ if (session.activeRepositoryId && requested && session.activeRepositoryId !== requested) {
33
+ throw new Error('SESSION_REPOSITORY_MISMATCH: call session_bind_repository before switching repositories');
34
+ }
35
+ return resolveRepositorySelection({ repoId: selectedRepoId, checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : session.activeCheckoutId, controllerHome: ctx.controllerHome, allowSoleRepository: false });
36
+ }
37
+
38
+ function initialStage(): WorkFinalizationStages {
39
+ return { validation: 'pending', commit: 'pending', merge: 'pending', branchCleanup: 'pending', worktreeCleanup: 'pending' };
40
+ }
41
+
42
+ /**
43
+ * A previous finalization request may have validated a Work and explicitly
44
+ * skipped every effectful stage without delivering or cleaning anything. That
45
+ * is retryable preparation history, not an irreversible finalization boundary.
46
+ * Any done/failed effectful stage or retained finalization error stays fenced.
47
+ */
48
+ export function workHeadAdoptionFinalizationIsRetryable(stages: WorkFinalizationStages): boolean {
49
+ if (stages.validation === 'failed' || stages.lastError) return false;
50
+ return [stages.commit, stages.merge, stages.branchCleanup, stages.worktreeCleanup]
51
+ .every((stage) => stage === 'pending' || stage === 'skipped');
52
+ }
53
+
54
+ function normalizedRequiredString(args: Record<string, unknown>, key: string): string | undefined {
55
+ return typeof args[key] === 'string' && args[key].trim() ? args[key].trim() : undefined;
56
+ }
57
+
58
+ function boundedStringArray(value: unknown, limit: number): string[] {
59
+ return Array.isArray(value) ? value.map(String).slice(0, limit) : [];
60
+ }
61
+
62
+ function workPrepareFingerprint(input: {
63
+ repoId: string;
64
+ requestedCheckoutId?: string;
65
+ isolation: 'reuse' | 'new_worktree' | 'auto';
66
+ objective: string;
67
+ goalId?: string;
68
+ acceptanceCriteria: string[];
69
+ allowedPaths: string[];
70
+ checks: string[];
71
+ baseRef?: string;
72
+ needsDependencies: boolean;
73
+ }): string {
74
+ return createHash('sha256').update(JSON.stringify({ schemaVersion: 1, operation: 'work_prepare', ...input })).digest('hex');
75
+ }
76
+
77
+ function claimPreparedWorkOwnership(
78
+ ctx: MultiRepositoryMcpToolContext,
79
+ session: ExecutionSessionContext,
80
+ handle: WorkHandleState,
81
+ args: Record<string, unknown>,
82
+ ): void {
83
+ const workIdValue = handle.workContractId ?? handle.workId;
84
+ const controllerId = typeof args.controller_id === 'string' && args.controller_id.trim()
85
+ ? args.controller_id.trim()
86
+ : session.principalId;
87
+ claimControllerSession({ controllerHome: ctx.controllerHome, repoId: handle.repositoryId }, {
88
+ workId: workIdValue,
89
+ controllerId,
90
+ controllerType: 'chatgpt',
91
+ sessionId: session.sessionId,
92
+ principalId: session.principalId,
93
+ controllerInstanceId: session.controllerInstanceId,
94
+ leaseMs: 3_600_000,
95
+ });
96
+ }
97
+
98
+ function claimHeadAdoptionOwnership(
99
+ ctx: MultiRepositoryMcpToolContext,
100
+ session: ExecutionSessionContext,
101
+ handle: WorkHandleState,
102
+ args: Record<string, unknown>,
103
+ ): void {
104
+ const workIdValue = handle.workContractId ?? handle.workId;
105
+ const controllerId = normalizedRequiredString(args, 'controller_id') ?? session.principalId;
106
+ if (controllerId !== session.principalId) {
107
+ throw new Error('WORK_CONTROLLER_IDENTITY_MISMATCH: controller_id must match the authenticated principal');
108
+ }
109
+ const options = { controllerHome: ctx.controllerHome, repoId: handle.repositoryId };
110
+ const current = getControllerSession(options, workIdValue);
111
+ const input = {
112
+ workId: workIdValue,
113
+ controllerId,
114
+ controllerType: current?.controllerType ?? 'chatgpt' as const,
115
+ sessionId: session.sessionId,
116
+ principalId: session.principalId,
117
+ controllerInstanceId: session.controllerInstanceId,
118
+ expectedClaimGeneration: current?.claimGeneration ?? 0,
119
+ leaseMs: 3_600_000,
120
+ };
121
+ const claimed = current
122
+ ? resumeControllerSession(options, input)
123
+ : claimControllerSession(options, input);
124
+ if (
125
+ claimed.controllerId !== controllerId
126
+ || claimed.sessionId !== session.sessionId
127
+ || claimed.principalId !== session.principalId
128
+ || claimed.controllerInstanceId !== session.controllerInstanceId
129
+ || (claimed.claimGeneration ?? 0) < 1
130
+ ) {
131
+ throw new Error('WORK_HEAD_ADOPTION_OWNERSHIP_FENCE_MISMATCH');
132
+ }
133
+ }
134
+
135
+ function adoptExistingWorkHead(
136
+ ctx: MultiRepositoryMcpToolContext,
137
+ session: ExecutionSessionContext,
138
+ repository: RepositoryRecord,
139
+ handle: WorkHandleState,
140
+ args: Record<string, unknown>,
141
+ ): Record<string, unknown> | undefined {
142
+ const previousInput = normalizedRequiredString(args, 'expected_previous_head');
143
+ const candidateInput = normalizedRequiredString(args, 'adopt_candidate_head');
144
+ if (!previousInput && !candidateInput) return undefined;
145
+ if (!previousInput || !candidateInput) {
146
+ throw new Error('WORK_HEAD_ADOPTION_ARGUMENTS_REQUIRED: expected_previous_head and adopt_candidate_head must be provided together');
147
+ }
148
+ const requestedCheckoutId = normalizedRequiredString(args, 'checkout_id');
149
+ if (!requestedCheckoutId) throw new Error('WORK_HEAD_ADOPTION_CHECKOUT_REQUIRED: checkout_id must be explicit');
150
+ if (repository.repoId !== handle.repositoryId) throw new Error('WORK_HEAD_ADOPTION_REPOSITORY_MISMATCH');
151
+ if (requestedCheckoutId !== handle.checkoutId || repository.activeCheckoutId !== handle.checkoutId) {
152
+ throw new Error(`WORK_HEAD_ADOPTION_CHECKOUT_MISMATCH: expected ${handle.checkoutId}, found ${requestedCheckoutId}`);
153
+ }
154
+ if (!handle.managedWorktree) throw new Error('WORK_HEAD_ADOPTION_MANAGED_WORKTREE_REQUIRED');
155
+ if (handle.principalId !== session.principalId) throw new Error('WORK_HANDLE_PRINCIPAL_MISMATCH: work handle belongs to another principal');
156
+ if (handle.state !== 'prepared' && handle.state !== 'editing') {
157
+ throw new Error(`WORK_HEAD_ADOPTION_STATE_INVALID: ${handle.state}`);
158
+ }
159
+ if (!workHeadAdoptionFinalizationIsRetryable(handle.finalization)) {
160
+ throw new Error('WORK_HEAD_ADOPTION_FINALIZATION_ALREADY_STARTED');
161
+ }
162
+
163
+ const registered = getRepository(handle.repositoryId, ctx.controllerHome, { includeRemoved: true });
164
+ const registeredCheckout = registered.checkouts.find((entry) => entry.checkoutId === handle.checkoutId);
165
+ if (!registeredCheckout || registeredCheckout.lifecycle !== 'active' || registeredCheckout.worktree !== true) {
166
+ throw new Error('WORK_HEAD_ADOPTION_CHECKOUT_NOT_ACTIVE_MANAGED');
167
+ }
168
+ const worktreeRepository = selectRepositoryCheckout(registered, handle.checkoutId);
169
+ const guarded = assertExecutionIdentity({
170
+ controllerHome: ctx.controllerHome,
171
+ identity: executionIdentityFromCoordinates({
172
+ repositoryId: handle.repositoryId,
173
+ checkoutId: handle.checkoutId,
174
+ canonicalRoot: handle.worktreePath,
175
+ workId: handle.workId,
176
+ worktreePath: handle.worktreePath,
177
+ branch: handle.branch,
178
+ }),
179
+ cwd: handle.worktreePath,
180
+ requestedRepoId: repository.repoId,
181
+ requestedCheckoutId,
182
+ });
183
+ const status = repositoryGitStatus(worktreeRepository);
184
+ if (!status.clean) throw new Error('WORK_HEAD_ADOPTION_WORKTREE_DIRTY');
185
+
186
+ const previousHead = gitCommit(handle.worktreePath, previousInput, 'PREVIOUS_HEAD');
187
+ const candidateHead = gitCommit(handle.worktreePath, candidateInput, 'CANDIDATE_HEAD');
188
+ const authoritativePrevious = handle.expectedHead ? gitCommit(handle.worktreePath, handle.expectedHead, 'AUTHORITATIVE_PREVIOUS_HEAD') : undefined;
189
+ if (!authoritativePrevious || authoritativePrevious !== previousHead) {
190
+ throw new Error(`WORK_HEAD_ADOPTION_PREVIOUS_HEAD_MISMATCH: expected ${authoritativePrevious ?? 'missing'}, found ${previousHead}`);
191
+ }
192
+ if (guarded.currentHead !== candidateHead || status.head !== candidateHead) {
193
+ throw new Error(`WORK_HEAD_ADOPTION_CANDIDATE_NOT_CURRENT: expected current HEAD ${candidateHead}, found ${guarded.currentHead ?? status.head ?? 'missing'}`);
194
+ }
195
+ if (previousHead === candidateHead) throw new Error('WORK_HEAD_ADOPTION_SUCCESSOR_REQUIRED');
196
+ const ancestry = spawnSync('git', ['-C', handle.worktreePath, 'merge-base', '--is-ancestor', previousHead, candidateHead], {
197
+ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 10_000,
198
+ });
199
+ if (ancestry.status !== 0 || ancestry.error) throw new Error('WORK_HEAD_ADOPTION_NOT_DESCENDANT');
200
+
201
+ const contract = contractFor(ctx, handle);
202
+ if (!contract || contract.repoId !== handle.repositoryId) throw new Error('WORK_HEAD_ADOPTION_CONTRACT_MISSING');
203
+ if (isTerminalWorkContractStatus(contract.status) || contract.completionReceipt) {
204
+ throw new Error('WORK_HEAD_ADOPTION_CONTRACT_TERMINAL');
205
+ }
206
+ // expectedHead can predate unrelated commits that landed on the source checkout
207
+ // before this Work was rebased. Scope adoption to the candidate's unique delta
208
+ // from the current source-checkout merge-base; otherwise those target-branch
209
+ // commits are incorrectly attributed to the Work and fail its allow-list.
210
+ const sourceRepository = selectWorkFinalizationTarget(registered, handle);
211
+ const sourceHead = handle.sourceCheckoutId && handle.sourceCheckoutId !== handle.checkoutId
212
+ ? repositoryGitStatus(sourceRepository).head
213
+ : undefined;
214
+ const scopeBaseHead = sourceHead ? gitMergeBase(handle.worktreePath, sourceHead, candidateHead) : previousHead;
215
+ const changedPaths = gitChangedPaths(handle.worktreePath, scopeBaseHead, candidateHead);
216
+ assertWorkPathsWithinScope(contract, changedPaths, {
217
+ forbidden: 'WORK_HEAD_ADOPTION_FORBIDDEN_PATH',
218
+ outOfScope: 'WORK_HEAD_ADOPTION_PATH_OUT_OF_SCOPE',
219
+ });
220
+
221
+ claimHeadAdoptionOwnership(ctx, session, handle, args);
222
+
223
+ const reviewedAt = new Date().toISOString();
224
+ const reconciliationId = `RECNC-${createHash('sha256').update([
225
+ handle.repositoryId, handle.workId, previousHead, candidateHead, handle.checkoutId, handle.branch,
226
+ ].join('\0')).digest('hex').slice(0, 16)}`;
227
+ const reconciliation: WorkReconciliationRecord = {
228
+ schemaVersion: 1,
229
+ reconciliationId,
230
+ originalExpectedRevision: previousHead,
231
+ observedTargetRevision: candidateHead,
232
+ baseRevision: gitCommit(handle.worktreePath, handle.baseCommit ?? previousHead, 'BASE_HEAD'),
233
+ targetBranch: handle.branch,
234
+ reachable: true,
235
+ method: 'exact_commit',
236
+ comparedPaths: changedPaths,
237
+ reviewer: session.principalId.slice(0, 200),
238
+ reviewedAt,
239
+ unrecoverableStages: [],
240
+ cleanupOwnershipProof: `No cleanup was performed; managed checkout ${handle.checkoutId} remains owned by Work finalizer.`,
241
+ rationale: 'Adopted an exact clean successor commit after repository, checkout, worktree, branch, controller ownership, ancestry, and WorkContract path-scope verification. This reconciliation is not completion evidence.',
242
+ outcome: 'accepted_equivalence',
243
+ };
244
+
245
+ const adopted = transitionWorkHandle(ctx.controllerHome, handle, 'editing', {
246
+ deliveryBaseCommit: scopeBaseHead,
247
+ expectedHead: candidateHead,
248
+ failureReason: undefined,
249
+ finalization: initialStage(),
250
+ validationRun: undefined,
251
+ validatedInputFingerprint: undefined,
252
+ });
253
+ try {
254
+ updateWorkContract({ controllerHome: ctx.controllerHome, repoId: handle.repositoryId }, contract.workId, {
255
+ evidenceState: contract.checkRefs.length === 0
256
+ ? contract.evidenceState
257
+ : contract.evidenceState === 'valid' || contract.evidenceState === 'stale'
258
+ ? 'stale'
259
+ : 'partial',
260
+ reconciliations: [reconciliation, ...contract.reconciliations.filter((entry) => entry.reconciliationId !== reconciliationId)],
261
+ });
262
+ appendWorkEvidence({ controllerHome: ctx.controllerHome, repoId: handle.repositoryId }, contract.workId, {
263
+ title: 'audited WorkHandle successor HEAD adoption',
264
+ summary: `${previousHead} -> ${candidateHead}; ${changedPaths.length} candidate-unique path(s) from scope base ${scopeBaseHead} remained within the WorkContract allow-list. Historical validation and completion receipts were not rewritten.`,
265
+ detailLevel: 'summary',
266
+ });
267
+ } catch (error) {
268
+ try {
269
+ writeWorkHandle(ctx.controllerHome, { ...handle, recordRevision: adopted.recordRevision });
270
+ } catch (rollbackError) {
271
+ throw new Error(`WORK_HEAD_ADOPTION_AUDIT_WRITE_FAILED_AND_ROLLBACK_FAILED: ${String(error)}; ${String(rollbackError)}`);
272
+ }
273
+ throw error;
274
+ }
275
+ const nextSession = updateExecutionSession(ctx.controllerHome, identityFor(ctx, args), {
276
+ activeRepositoryId: handle.repositoryId,
277
+ activeCheckoutId: handle.checkoutId,
278
+ activeWorkId: handle.workId,
279
+ permissionSnapshotVersion: handle.permissionSnapshotVersion,
280
+ lastValidatedAt: reviewedAt,
281
+ });
282
+ return {
283
+ session: nextSession,
284
+ work: compactHandle(adopted),
285
+ reused: true,
286
+ adopted: true,
287
+ adoption: { previousHead, candidateHead, changedPaths, reconciliationId },
288
+ controllerClaimed: true,
289
+ };
290
+ }
291
+
292
+ function invalidateActiveWork(ctx: MultiRepositoryMcpToolContext, session: ExecutionSessionContext, reason: string): void {
293
+ if (!session.activeRepositoryId || !session.activeWorkId) return;
294
+ const handle = readWorkHandle(ctx.controllerHome, session.activeRepositoryId, session.activeWorkId);
295
+ if (!handle || handle.state === 'cleaned') return;
296
+ const contract = contractFor(ctx, handle);
297
+ if (contract?.status === 'completed') return;
298
+ markWorkHandleFailed(ctx.controllerHome, handle, reason);
299
+ }
300
+
301
+ export function bindSessionRepository(ctx: MultiRepositoryMcpToolContext, args: Record<string, unknown>): Record<string, unknown> {
302
+ const session = requireSession(ctx, args);
303
+ const repository = resolveRepositorySelection({ repoId: requireExplicitRepoId(args), checkoutId: typeof args.checkout_id === 'string' ? args.checkout_id : undefined, controllerHome: ctx.controllerHome, allowSoleRepository: false });
304
+ const switching = session.activeRepositoryId !== undefined && (session.activeRepositoryId !== repository.repoId || session.activeCheckoutId !== repository.activeCheckoutId);
305
+ if (switching) invalidateActiveWork(ctx, session, 'explicit repository or checkout switch invalidated the previous active work handle');
306
+ const next = updateExecutionSession(ctx.controllerHome, identityFor(ctx, args), {
307
+ activeRepositoryId: repository.repoId,
308
+ activeCheckoutId: repository.activeCheckoutId,
309
+ activeWorkId: undefined,
310
+ goalDelegation: undefined,
311
+ permissionSnapshotVersion: currentPermissionSnapshotVersion(ctx.controllerHome, repository.repoId),
312
+ lastValidatedAt: new Date().toISOString(),
313
+ });
314
+ return { session: next, repository: { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, canonicalRoot: repository.canonicalRoot, branch: repository.checkouts.find((entry) => entry.checkoutId === repository.activeCheckoutId)?.branch ?? null }, switched: switching };
315
+ }
316
+
317
+ export function prepareWork(ctx: MultiRepositoryMcpToolContext, args: Record<string, unknown>): Record<string, unknown> {
318
+ const session = requireSession(ctx, args);
319
+ const repository = selectedRepository(ctx, session, args, true);
320
+ if (!session.activeRepositoryId) {
321
+ updateExecutionSession(ctx.controllerHome, identityFor(ctx, args), { activeRepositoryId: repository.repoId, activeCheckoutId: repository.activeCheckoutId, permissionSnapshotVersion: currentPermissionSnapshotVersion(ctx.controllerHome, repository.repoId) });
322
+ }
323
+ const existingId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
324
+ if (existingId) {
325
+ const existing = readWorkHandle(ctx.controllerHome, repository.repoId, existingId)
326
+ ?? findWorkHandle(ctx, session, { ...args, work_id: existingId, repo_id: repository.repoId });
327
+ if (existing.principalId !== session.principalId) throw new Error('WORK_HANDLE_ACCESS_DENIED');
328
+ const adopted = adoptExistingWorkHead(ctx, session, repository, existing, args);
329
+ if (adopted) return adopted;
330
+ validateWorkHandle(ctx.controllerHome, existing, identityFor(ctx, args), 'cheap', 'inspect');
331
+ updateExecutionSession(ctx.controllerHome, identityFor(ctx, args), { activeRepositoryId: existing.repositoryId, activeCheckoutId: existing.checkoutId, activeWorkId: existing.workId, permissionSnapshotVersion: existing.permissionSnapshotVersion });
332
+ claimPreparedWorkOwnership(ctx, session, existing, args);
333
+ return { session: requireSession(ctx, args), work: compactHandle(existing), reused: true, controllerClaimed: true };
334
+ }
335
+
336
+ const requestId = typeof args.request_id === 'string' ? args.request_id.trim() : '';
337
+ if (!requestId) throw new Error('WORK_PREPARE_REQUEST_ID_REQUIRED: new work preparation requires request_id');
338
+ const isolation = args.isolation === 'reuse' || args.isolation === 'new_worktree' || args.isolation === 'auto' ? args.isolation : 'auto';
339
+ const objective = String(args.objective ?? 'Controller-managed repository work').trim().slice(0, 2_000);
340
+ const goalId = typeof args.goal_id === 'string' && args.goal_id.trim() ? args.goal_id.trim() : undefined;
341
+ const acceptanceCriteria = boundedStringArray(args.acceptance_criteria, 20);
342
+ const allowedPaths = boundedStringArray(args.allowed_paths, 50);
343
+ const checks = boundedStringArray(args.checks, 30);
344
+ const baseRef = typeof args.base_ref === 'string' && args.base_ref.trim() ? args.base_ref.trim() : undefined;
345
+ const requestedCheckoutId = typeof args.checkout_id === 'string' && args.checkout_id.trim() ? args.checkout_id.trim() : undefined;
346
+ const needsDependencies = args.needs_dependencies === true;
347
+ const baseCheckoutId = repository.activeCheckoutId;
348
+ const baseStatus = repositoryGitStatus(repository);
349
+ if (isolation === 'reuse' && !baseStatus.clean) throw new Error('WORKTREE_DIRTY: reuse was requested but the selected checkout is dirty; choose new_worktree or auto');
350
+ const useWorktree = isolation === 'new_worktree' || (isolation === 'auto' && !baseStatus.clean);
351
+ const policy = readRepositoryAccessPolicy(ctx.controllerHome, repository.repoId);
352
+ const fingerprint = workPrepareFingerprint({
353
+ repoId: repository.repoId,
354
+ requestedCheckoutId,
355
+ isolation,
356
+ objective,
357
+ goalId,
358
+ acceptanceCriteria,
359
+ allowedPaths,
360
+ checks,
361
+ baseRef,
362
+ needsDependencies,
363
+ });
364
+
365
+ return withWorkPrepareRequest({
366
+ controllerHome: ctx.controllerHome,
367
+ repoId: repository.repoId,
368
+ sessionId: session.sessionId,
369
+ principalId: session.principalId,
370
+ requestId,
371
+ fingerprint,
372
+ proposedWorkId: newWorkId(),
373
+ }, (request, requestReused) => {
374
+ const createdWorkId = request.workId;
375
+ const existingHandle = readWorkHandle(ctx.controllerHome, repository.repoId, createdWorkId);
376
+ if (existingHandle) {
377
+ if (existingHandle.principalId !== session.principalId || existingHandle.sessionId !== session.sessionId) {
378
+ throw new Error(`WORK_PREPARE_REQUEST_INDEX_CORRUPT: ${requestId}`);
379
+ }
380
+ const existingContract = getWorkContract({ controllerHome: ctx.controllerHome, repoId: repository.repoId }, createdWorkId);
381
+ if (!existingContract) throw new Error(`WORK_PREPARE_RESULT_LOST: ${requestId} has a Work handle without its WorkContract`);
382
+ const terminal = isTerminalWorkContractStatus(existingContract.status)
383
+ && !(existingContract.status === 'failed' && request.status === 'claimed');
384
+ if (terminal) {
385
+ return {
386
+ session: requireSession(ctx, args),
387
+ work: compactHandle(existingHandle),
388
+ reused: true,
389
+ terminal: true,
390
+ workContractStatus: existingContract.status,
391
+ controllerClaimed: false,
392
+ };
393
+ }
394
+ if (existingContract.status === 'open' || existingContract.status === 'failed') {
395
+ updateWorkContract({ controllerHome: ctx.controllerHome, repoId: repository.repoId }, createdWorkId, { status: 'running', worktreeRef: existingHandle.worktreePath });
396
+ }
397
+ const delegation = createGoalDelegation({
398
+ sessionId: session.sessionId,
399
+ repositoryId: repository.repoId,
400
+ workId: createdWorkId,
401
+ goalId,
402
+ allowedRiskClasses: ['readonly', 'local_repo_write', 'workspace_write', 'local_command', 'dependency_change', 'local_git'],
403
+ deniedRiskClasses: ['remote_write', 'destructive', 'secret_access', 'outside_repository'],
404
+ permissionSnapshotVersion: policy.revision,
405
+ source: 'gpt_risk_delegate',
406
+ });
407
+ const nextSession = updateExecutionSession(ctx.controllerHome, identityFor(ctx, args), { activeRepositoryId: repository.repoId, activeCheckoutId: existingHandle.checkoutId, activeWorkId: createdWorkId, permissionSnapshotVersion: policy.revision, goalDelegation: delegation, lastValidatedAt: new Date().toISOString() });
408
+ claimPreparedWorkOwnership(ctx, nextSession, existingHandle, args);
409
+ return { session: nextSession, work: compactHandle(existingHandle), reused: true, isolation: existingHandle.managedWorktree ? 'isolated' : 'current', controllerClaimed: true };
410
+ }
411
+
412
+ let contract = getWorkContract({ controllerHome: ctx.controllerHome, repoId: repository.repoId }, createdWorkId);
413
+ if (contract?.requestId && contract.requestId !== requestId) throw new Error(`WORK_PREPARE_REQUEST_INDEX_CORRUPT: ${requestId}`);
414
+ if (request.status === 'prepared') {
415
+ throw new Error(`WORK_PREPARE_RESULT_LOST: ${requestId} completed without a readable Work handle`);
416
+ }
417
+ if (contract && (contract.status === 'completed' || contract.status === 'cancelled')) {
418
+ throw new Error(`WORK_PREPARE_REQUEST_TERMINAL: ${requestId} belongs to ${contract.status} Work ${createdWorkId}`);
419
+ }
420
+ if (!contract) {
421
+ contract = admitPreparedRepositoryWorkContract(
422
+ { controllerHome: ctx.controllerHome, repoId: repository.repoId },
423
+ {
424
+ workId: createdWorkId,
425
+ repoId: repository.repoId,
426
+ objective,
427
+ acceptanceCriteria,
428
+ allowedPaths,
429
+ checks,
430
+ accessMode: policy.mode,
431
+ isolated: useWorktree,
432
+ requestedBy: 'chatgpt',
433
+ requestId,
434
+ },
435
+ );
436
+ }
437
+ const delegation = createGoalDelegation({
438
+ sessionId: session.sessionId,
439
+ repositoryId: repository.repoId,
440
+ workId: createdWorkId,
441
+ goalId,
442
+ allowedRiskClasses: ['readonly', 'local_repo_write', 'workspace_write', 'local_command', 'dependency_change', 'local_git'],
443
+ deniedRiskClasses: ['remote_write', 'destructive', 'secret_access', 'outside_repository'],
444
+ permissionSnapshotVersion: policy.revision,
445
+ source: 'gpt_risk_delegate',
446
+ });
447
+ try {
448
+ const workspace = useWorktree
449
+ ? ensureManagedWorkspace(ctx.controllerHome, repository, {
450
+ requestId: createdWorkId,
451
+ title: objective,
452
+ baseRef,
453
+ prepareDependencies: needsDependencies,
454
+ })
455
+ : { mode: 'current' as const, checkoutId: baseCheckoutId, root: repository.canonicalRoot, branch: baseStatus.branch ?? 'detached', baseRevision: baseStatus.head ?? undefined, managed: false };
456
+ const refreshed = getRepository(repository.repoId, ctx.controllerHome);
457
+ const checkout = selectRepositoryCheckout(refreshed, workspace.checkoutId);
458
+ const branch = workspace.branch || repositoryGitStatus(checkout).branch;
459
+ if (!branch) throw new Error('WORKTREE_DETACHED: selected worktree has no branch');
460
+ const head = gitHead(checkout.canonicalRoot);
461
+ const handle: WorkHandleState = {
462
+ schemaVersion: 1, workId: createdWorkId, sessionId: session.sessionId, principalId: session.principalId,
463
+ repositoryId: repository.repoId, checkoutId: checkout.activeCheckoutId, worktreePath: checkout.canonicalRoot, branch,
464
+ sourceCheckoutId: baseCheckoutId, managedWorktree: workspace.managed, workContractId: contract.workId, goalId, delegationVersion: delegation.version,
465
+ baseCommit: workspace.baseRevision ?? head, deliveryBaseCommit: workspace.baseRevision ?? head, expectedHead: head, permissionSnapshotVersion: policy.revision,
466
+ state: 'prepared', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), finalization: initialStage(),
467
+ cleanupResponsibility: { owner: 'work_finalizer', registeredAt: new Date().toISOString() },
468
+ };
469
+ writeWorkHandle(ctx.controllerHome, handle);
470
+ updateWorkContract({ controllerHome: ctx.controllerHome, repoId: repository.repoId }, contract.workId, { status: 'running', worktreeRef: checkout.canonicalRoot });
471
+ const nextSession = updateExecutionSession(ctx.controllerHome, identityFor(ctx, args), { activeRepositoryId: repository.repoId, activeCheckoutId: checkout.activeCheckoutId, activeWorkId: createdWorkId, permissionSnapshotVersion: policy.revision, goalDelegation: delegation, lastValidatedAt: new Date().toISOString() });
472
+ claimPreparedWorkOwnership(ctx, nextSession, handle, args);
473
+ return { session: nextSession, work: compactHandle(handle), reused: requestReused, isolation: workspace.mode, controllerClaimed: true };
474
+ } catch (error) {
475
+ updateWorkContract({ controllerHome: ctx.controllerHome, repoId: repository.repoId }, contract.workId, { status: 'failed' });
476
+ throw error;
477
+ }
478
+ });
479
+ }
@@ -0,0 +1,129 @@
1
+ import { createHash } from 'crypto';
2
+ import { basename } from 'path';
3
+ import {
4
+ effectiveProcessStatus,
5
+ isManagedProcessTerminal,
6
+ listProcessRecords,
7
+ } from '../../execution/process-runtime';
8
+
9
+ export interface WorkBoundRepositoryProcessEvidence {
10
+ processId: string;
11
+ commandId?: string;
12
+ finishedAt?: string;
13
+ }
14
+
15
+ export interface WorkBoundRepositoryRemoteEffectProcessEvidence extends WorkBoundRepositoryProcessEvidence {
16
+ authority: 'repository_process';
17
+ actionId: 'git_push';
18
+ requestId: string;
19
+ semanticKey: string;
20
+ resultDigest: string;
21
+ }
22
+
23
+ function isSuccessfulWorkRepositoryProcess(
24
+ record: ReturnType<typeof listProcessRecords>[number],
25
+ input: { workId: string; checkoutId: string },
26
+ ): boolean {
27
+ return record.workId === input.workId
28
+ && record.checkoutId === input.checkoutId
29
+ && record.origin?.surface === 'command'
30
+ && record.origin.toolName === 'repository_command_execute'
31
+ && record.origin.correlationId === input.workId
32
+ && isManagedProcessTerminal(record)
33
+ && record.terminalWritten === true
34
+ && effectiveProcessStatus(record, true) === 'succeeded'
35
+ && record.exitCode === 0
36
+ && record.timedOut !== true
37
+ && record.cancelled !== true
38
+ && !record.error;
39
+ }
40
+
41
+ /**
42
+ * Re-derive bounded completion evidence from the canonical durable Process store.
43
+ *
44
+ * This deliberately does not create a second evidence authority. A qualifying
45
+ * record must be the terminal successful repository_command_execute Process for
46
+ * the exact Work + checkout, and the command-origin correlation must still name
47
+ * the same Work. Lightweight handles never enter listProcessRecords(), so they
48
+ * cannot satisfy this contract.
49
+ */
50
+ export function listWorkBoundRepositoryProcessEvidence(input: {
51
+ controllerHome: string;
52
+ repoId: string;
53
+ checkoutId: string;
54
+ workId: string;
55
+ limit?: number;
56
+ }): WorkBoundRepositoryProcessEvidence[] {
57
+ const workId = input.workId.trim();
58
+ const checkoutId = input.checkoutId.trim();
59
+ if (!workId || !checkoutId) return [];
60
+
61
+ return listProcessRecords(input.controllerHome, input.repoId, input.limit ?? 500)
62
+ .filter((record) => isSuccessfulWorkRepositoryProcess(record, { workId, checkoutId }))
63
+ .map((record) => ({
64
+ processId: record.processId,
65
+ ...(record.commandId ? { commandId: record.commandId } : {}),
66
+ ...(record.finishedAt ? { finishedAt: record.finishedAt } : {}),
67
+ }));
68
+ }
69
+
70
+ /**
71
+ * Re-derive the narrow repository-command authority allowed to complete a pure
72
+ * remote_effect Work. Only a trusted argv-form `git push` that held the exact
73
+ * repository remote lease may qualify. Shell commands, generic successful
74
+ * commands, untrusted PID identity, and processes from another Work/checkout
75
+ * remain non-authoritative.
76
+ */
77
+ export function listWorkBoundRepositoryRemoteEffectProcessEvidence(input: {
78
+ controllerHome: string;
79
+ repoId: string;
80
+ checkoutId: string;
81
+ workId: string;
82
+ limit?: number;
83
+ }): WorkBoundRepositoryRemoteEffectProcessEvidence[] {
84
+ const workId = input.workId.trim();
85
+ const checkoutId = input.checkoutId.trim();
86
+ if (!workId || !checkoutId) return [];
87
+
88
+ return listProcessRecords(input.controllerHome, input.repoId, input.limit ?? 500)
89
+ .filter((record) => isSuccessfulWorkRepositoryProcess(record, { workId, checkoutId }))
90
+ .filter((record) => (
91
+ record.identity !== undefined
92
+ && record.identityUntrusted !== true
93
+ && record.command.kind === 'argv'
94
+ && basename(record.command.executable ?? '') === 'git'
95
+ && record.command.args?.[0] === 'push'
96
+ && record.resourceClaims.some((claim) => (
97
+ claim.resourceKey === `remote:${input.repoId}`
98
+ && claim.mode === 'exclusive'
99
+ && claim.repoId === input.repoId
100
+ && claim.workId === workId
101
+ ))
102
+ ))
103
+ .map((record) => {
104
+ const requestId = record.origin?.requestId?.trim() || record.commandId?.trim() || record.processId;
105
+ const semanticKey = createHash('sha256').update(JSON.stringify({
106
+ repoId: input.repoId,
107
+ checkoutId,
108
+ workId,
109
+ command: record.command,
110
+ resourceClaims: record.resourceClaims,
111
+ })).digest('hex');
112
+ const resultDigest = createHash('sha256').update(JSON.stringify({
113
+ processId: record.processId,
114
+ exitCode: record.exitCode,
115
+ finishedAt: record.finishedAt,
116
+ terminalWritten: record.terminalWritten,
117
+ })).digest('hex');
118
+ return {
119
+ processId: record.processId,
120
+ ...(record.commandId ? { commandId: record.commandId } : {}),
121
+ ...(record.finishedAt ? { finishedAt: record.finishedAt } : {}),
122
+ authority: 'repository_process' as const,
123
+ actionId: 'git_push' as const,
124
+ requestId,
125
+ semanticKey,
126
+ resultDigest,
127
+ };
128
+ });
129
+ }