@moretea-labs/forge 1.7.2 → 1.8.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 (900) hide show
  1. package/AGENTS.md +121 -62
  2. package/CHANGELOG.md +40 -0
  3. package/CLAUDE.md +57 -62
  4. package/CONTRIBUTING.md +3 -2
  5. package/README.md +2 -2
  6. package/SKILL.md +0 -1
  7. package/THIRD_PARTY_NOTICES.md +5 -2
  8. package/adapters/browser/index.ts +2 -0
  9. package/adapters/chatgpt/browser-delivery-host.ts +77 -0
  10. package/adapters/chatgpt/browser-delivery-runtime.ts +1256 -0
  11. package/adapters/chatgpt/controller-binding-store.ts +134 -0
  12. package/adapters/chatgpt/controller-round-host.ts +68 -0
  13. package/adapters/chatgpt/controller-round-settlement-store.ts +99 -0
  14. package/adapters/chatgpt/provider-delivery.ts +340 -0
  15. package/adapters/chatgpt/work-conversation-binding-store.ts +218 -0
  16. package/adapters/chatgpt/wsl-bridge-delivery-host.ts +63 -0
  17. package/adapters/computer/chatgpt-extension-target.ts +463 -0
  18. package/adapters/computer/chatgpt-target-router.ts +103 -0
  19. package/adapters/computer/chrome-extension/background.js +385 -0
  20. package/adapters/computer/chrome-extension/content.js +378 -0
  21. package/adapters/computer/chrome-extension/core.js +24 -0
  22. package/adapters/computer/chrome-extension/manifest.json +30 -0
  23. package/adapters/computer/desktop-operator-contract.ts +7 -0
  24. package/adapters/computer/desktop-operator-discovery.ts +181 -0
  25. package/adapters/computer/desktop-operator-negotiation.ts +174 -0
  26. package/adapters/computer/desktop-operator-provider.ts +312 -0
  27. package/adapters/computer/index.ts +1 -0
  28. package/adapters/computer/interaction-target-authority.ts +1068 -0
  29. package/adapters/controller-process/binding-store.ts +34 -0
  30. package/adapters/controller-process/controller-host.ts +26 -0
  31. package/adapters/mcp/access-mode.ts +132 -0
  32. package/adapters/mcp/audit.ts +32 -0
  33. package/adapters/mcp/auth.ts +406 -0
  34. package/adapters/mcp/instructions.ts +37 -0
  35. package/adapters/mcp/legacy-context.ts +18 -0
  36. package/adapters/mcp/multi-repository.ts +421 -0
  37. package/adapters/mcp/oauth.ts +464 -0
  38. package/adapters/mcp/paths.ts +143 -0
  39. package/adapters/mcp/policy.ts +232 -0
  40. package/adapters/mcp/proxy-env.ts +62 -0
  41. package/adapters/mcp/readiness-projection.ts +24 -0
  42. package/adapters/mcp/redaction.ts +21 -0
  43. package/adapters/mcp/repo.ts +24 -0
  44. package/adapters/mcp/runtime-gateway/artifact-adapter.ts +52 -0
  45. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
  46. package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
  47. package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
  48. package/adapters/mcp/runtime-gateway/context-adapter.ts +1167 -0
  49. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
  50. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +206 -0
  51. package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
  52. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +130 -0
  53. package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
  54. package/adapters/mcp/runtime-gateway/execution-control-adapter.ts +28 -0
  55. package/adapters/mcp/runtime-gateway/execution-tools.ts +173 -0
  56. package/adapters/mcp/runtime-gateway/filesystem-adapter.ts +38 -0
  57. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +412 -0
  58. package/adapters/mcp/runtime-gateway/legacy-ios-tool-adapter.ts +105 -0
  59. package/adapters/mcp/runtime-gateway/maintenance-adapter.ts +44 -0
  60. package/adapters/mcp/runtime-gateway/model-adapter.ts +63 -0
  61. package/adapters/mcp/runtime-gateway/persisted-check-process.ts +3 -0
  62. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +380 -0
  63. package/adapters/mcp/runtime-gateway/process-tools.ts +457 -0
  64. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +88 -0
  65. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +285 -0
  66. package/adapters/mcp/runtime-gateway/recovery-client-adapter.ts +70 -0
  67. package/adapters/mcp/runtime-gateway/recovery-tool-contract.ts +99 -0
  68. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +79 -0
  69. package/adapters/mcp/runtime-gateway/result-adapter.ts +114 -0
  70. package/adapters/mcp/runtime-gateway/router.ts +242 -0
  71. package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
  72. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1200 -0
  73. package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
  74. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +574 -0
  75. package/adapters/mcp/runtime-gateway/runtime-tool-shared.ts +27 -0
  76. package/adapters/mcp/runtime-gateway/runtime-tools.ts +78 -0
  77. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +187 -0
  78. package/adapters/mcp/runtime-gateway/shared-adapter.ts +45 -0
  79. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +962 -0
  80. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
  81. package/adapters/mcp/runtime-gateway/work-adapter.ts +325 -0
  82. package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
  83. package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
  84. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
  85. package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
  86. package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
  87. package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
  88. package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
  89. package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
  90. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
  91. package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +1 -0
  92. package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
  93. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
  94. package/adapters/mcp/server.ts +1092 -0
  95. package/adapters/mcp/setup.ts +789 -0
  96. package/adapters/mcp/tool-capability-cache.ts +87 -0
  97. package/adapters/mcp/tool-mapping/access-tools.ts +387 -0
  98. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +5139 -0
  99. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +145 -0
  100. package/adapters/mcp/tool-mapping/repository-tools.ts +1682 -0
  101. package/adapters/mcp/tool-mapping/tools.ts +9 -0
  102. package/adapters/mcp/tool-mapping/umbrella-tools.ts +117 -0
  103. package/adapters/mcp/toolset-names.ts +79 -0
  104. package/adapters/mcp/toolset-selection.ts +41 -0
  105. package/adapters/mcp/toolset.ts +337 -0
  106. package/adapters/mcp/transports/http-observation.ts +365 -0
  107. package/adapters/mcp/transports/http.ts +933 -0
  108. package/adapters/mcp/transports/oauth-http.ts +322 -0
  109. package/adapters/mcp/transports/session-registry.ts +519 -0
  110. package/adapters/mcp/transports/stdio.ts +8 -0
  111. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +223 -0
  112. package/adapters/mcp/types.ts +41 -0
  113. package/assets/AGENTS.md +2 -16
  114. package/assets/CLAUDE.md +2 -16
  115. package/assets/hooks/AGENTS.md +3 -14
  116. package/assets/hooks/CLAUDE.md +3 -14
  117. package/assets/hooks/hook-input.sh +9 -2
  118. package/assets/hooks/lib/workflow-state.sh +28 -10
  119. package/assets/hooks/prompt-guard.sh +63 -37
  120. package/assets/hooks/security-sentinel.sh +2 -1
  121. package/assets/hooks/session-start-context.sh +7 -5
  122. package/assets/hooks/stop-orchestrator.sh +13 -3
  123. package/assets/initializer-question-pack.v4.json +11 -7
  124. package/assets/partials/05-workflow.partial.md +18 -73
  125. package/assets/partials/07-footer.partial.md +1 -1
  126. package/assets/partials-agents/02-operating-mode.partial.md +1 -2
  127. package/assets/partials-agents/04-task-protocol.partial.md +14 -59
  128. package/assets/partials-agents/06-quality-safety.partial.md +11 -16
  129. package/assets/partials-agents/08-deep-docs.partial.md +1 -2
  130. package/assets/plan-map.json +11 -11
  131. package/assets/plugin-registry.v1.json +11 -3
  132. package/assets/plugin-trust-policy.v1.json +6 -0
  133. package/assets/recovery/ForgeRecovery.ps1 +100 -0
  134. package/assets/recovery/forge-wsl-rescue +271 -0
  135. package/assets/reference-configs/agentic-development-flow.md +25 -0
  136. package/assets/reference-configs/development-protocol.md +11 -15
  137. package/assets/reference-configs/document-generation.md +1 -1
  138. package/assets/reference-configs/global-working-rules.md +28 -1
  139. package/assets/reference-configs/harness-overview.md +22 -112
  140. package/assets/reference-configs/hook-operations.md +1 -1
  141. package/assets/reference-configs/sprint-contracts.md +2 -2
  142. package/assets/skill-version.json +2 -2
  143. package/assets/templates/helpers/architecture-event.ts +3 -34
  144. package/assets/templates/helpers/architecture-queue.sh +61 -10
  145. package/assets/templates/helpers/archive-workflow.sh +90 -180
  146. package/assets/templates/helpers/capability-config.ts +8 -11
  147. package/assets/templates/helpers/capability-resolver.ts +37 -19
  148. package/assets/templates/helpers/capture-plan.sh +2 -2
  149. package/assets/templates/helpers/check-architecture-sync.sh +1 -9
  150. package/assets/templates/helpers/check-task-sync.sh +82 -11
  151. package/assets/templates/helpers/check-task-workflow.sh +1 -3
  152. package/assets/templates/helpers/context-contract-sync.sh +1 -12
  153. package/assets/templates/helpers/contract-worktree.sh +26 -24
  154. package/assets/templates/helpers/ensure-task-workflow.sh +6 -8
  155. package/assets/templates/helpers/inspect-project-state.ts +1 -1
  156. package/assets/templates/helpers/migrate-project-template.sh +1 -1
  157. package/assets/templates/helpers/migrate-workflow-docs.ts +53 -239
  158. package/assets/templates/helpers/new-plan.sh +2 -2
  159. package/assets/templates/helpers/plan-to-todo.sh +3 -31
  160. package/assets/templates/helpers/sprint-backlog.sh +1 -1
  161. package/assets/templates/helpers/switch-plan.sh +1 -1
  162. package/assets/templates/helpers/workflow-contract.ts +1 -0
  163. package/assets/workflow-contract.v1.json +63 -171
  164. package/assets/workflows/xiaohongshu/xiaohongshu.collect-metrics.v1.draft.json +118 -0
  165. package/assets/workflows/xiaohongshu/xiaohongshu.publish-image-note.v1.draft.json +316 -0
  166. package/assets/workflows/xiaohongshu/xiaohongshu.publish-long-text.v1.draft.json +324 -0
  167. package/docs/architecture/CURRENT.md +233 -28
  168. package/docs/architecture/EVOLUTION.md +13 -0
  169. package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +2 -1
  170. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
  171. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
  172. package/docs/architecture/decisions/20260831-independent-windows-wsl-host-rescue.md +59 -0
  173. package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +120 -0
  174. package/docs/architecture/decisions/20260904-repository-runtime-data-boundary.md +42 -0
  175. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +37 -0
  176. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +311 -0
  177. package/docs/architecture/decisions/20260907-maintenance-diagnosis-bounded-read.md +39 -0
  178. package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
  179. package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
  180. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
  181. package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
  182. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
  183. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
  184. package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
  185. package/docs/architecture/domains/verification.md +8 -0
  186. package/docs/architecture/domains/workflow-engine.md +7 -1
  187. package/docs/architecture/index.md +3 -3
  188. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +19 -8
  189. package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +124 -0
  190. package/docs/forge-chatgpt-mcp-setup.md +5 -3
  191. package/docs/forge-plugin-management.md +20 -4
  192. package/docs/forge-runtime-self-healing-loop.md +2 -0
  193. package/docs/operations/benchmark-cross-version-freeze.md +38 -0
  194. package/docs/operations/controller-browser-plugin.md +3 -1
  195. package/docs/operations/controller-performance-and-502.md +17 -0
  196. package/docs/operations/controller-reliability-runbook.md +2 -2
  197. package/docs/operations/features.md +1 -1
  198. package/docs/operations/features.zh-CN.md +1 -1
  199. package/docs/operations/homebrew.md +2 -2
  200. package/docs/operations/mcp-tool-exposure.md +2 -0
  201. package/docs/operations/platform-support.md +16 -8
  202. package/docs/operations/platform-support.zh-CN.md +2 -2
  203. package/docs/operations/releasing.md +2 -0
  204. package/docs/operations/standalone-disaster-recovery.md +38 -5
  205. package/docs/operations/uu-remote-rescue.md +41 -0
  206. package/docs/operations/windows-wsl-host-rescue.md +133 -0
  207. package/docs/public-usage-guide.md +1 -1
  208. package/docs/public-usage-guide.zh-CN.md +1 -1
  209. package/docs/tutorials/01-install-and-start.md +1 -1
  210. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  211. package/docs/tutorials/02-connect-chatgpt.md +4 -4
  212. package/docs/tutorials/02-connect-chatgpt.zh-CN.md +4 -4
  213. package/docs/wiki/Implementation.md +1 -1
  214. package/package.json +46 -26
  215. package/packages/kernel/cognition/api/index.ts +6 -0
  216. package/packages/kernel/cognition/application/activation-service.ts +451 -0
  217. package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
  218. package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
  219. package/packages/kernel/cognition/application/memory-service.ts +64 -0
  220. package/packages/kernel/cognition/domain/learning.ts +106 -0
  221. package/packages/kernel/cognition/domain/memory.ts +254 -0
  222. package/packages/kernel/controller/api/index.ts +3 -0
  223. package/packages/kernel/controller/application/continuation-service.ts +281 -0
  224. package/packages/kernel/controller/application/controller-round-service.ts +41 -0
  225. package/packages/kernel/controller/application/controller-service.ts +30 -0
  226. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +529 -0
  227. package/packages/kernel/controller/domain/controller-round.ts +110 -0
  228. package/packages/kernel/controller/domain/execution-quality.ts +135 -0
  229. package/packages/kernel/controller/domain/types.ts +56 -0
  230. package/packages/kernel/controller/index.ts +1 -0
  231. package/packages/kernel/controller/infrastructure/controller-binding-store.ts +84 -0
  232. package/packages/kernel/controller/infrastructure/controller-round-store.ts +1970 -0
  233. package/packages/kernel/controller/infrastructure/controller-session-store.ts +804 -0
  234. package/packages/kernel/controller/ports/controller-host.ts +18 -0
  235. package/packages/kernel/goal/api/index.ts +1 -0
  236. package/packages/kernel/goal/domain/types.ts +40 -0
  237. package/packages/kernel/goal/index.ts +1 -0
  238. package/packages/kernel/identity/api/index.ts +15 -0
  239. package/packages/kernel/identity/application/identity-service.ts +67 -0
  240. package/packages/kernel/identity/domain/activity-projection.ts +43 -0
  241. package/packages/kernel/identity/domain/capability-broker.ts +60 -0
  242. package/packages/kernel/identity/domain/grant.ts +72 -0
  243. package/packages/kernel/identity/domain/owned-resource.ts +116 -0
  244. package/packages/kernel/identity/domain/scope.ts +63 -0
  245. package/packages/kernel/identity/domain/semantic-sync.ts +81 -0
  246. package/packages/kernel/identity/domain/types.ts +44 -0
  247. package/packages/kernel/identity/domain/user-request.ts +93 -0
  248. package/packages/kernel/identity/domain/workspace.ts +56 -0
  249. package/packages/kernel/identity/index.ts +1 -0
  250. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
  251. package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
  252. package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
  253. package/packages/kernel/identity/infrastructure/identity-store.ts +75 -0
  254. package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
  255. package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
  256. package/packages/kernel/memory/api/index.ts +5 -0
  257. package/packages/kernel/memory/application/experience-service.ts +118 -0
  258. package/packages/kernel/memory/application/outcome-service.ts +77 -0
  259. package/packages/kernel/memory/domain/experience.ts +103 -0
  260. package/packages/kernel/memory/domain/operational-prior.ts +92 -0
  261. package/packages/kernel/memory/index.ts +1 -0
  262. package/packages/kernel/scheduler/api/index.ts +4 -0
  263. package/packages/kernel/scheduler/application/eligibility.ts +252 -0
  264. package/packages/kernel/scheduler/application/schedule-service.ts +27 -0
  265. package/packages/kernel/scheduler/application/settlement.ts +182 -0
  266. package/packages/kernel/scheduler/domain/schedule.ts +236 -0
  267. package/packages/kernel/scheduler/index.ts +1 -0
  268. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +805 -0
  269. package/packages/kernel/work/api/index.ts +16 -0
  270. package/packages/kernel/work/application/work-service.ts +123 -0
  271. package/packages/kernel/work/domain/check-receipt.ts +43 -0
  272. package/packages/kernel/work/domain/context-closure-receipt.ts +32 -0
  273. package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
  274. package/packages/kernel/work/domain/engineering-contracts.ts +157 -0
  275. package/packages/kernel/work/domain/engineering-design.ts +286 -0
  276. package/packages/kernel/work/domain/engineering-profile.ts +238 -0
  277. package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
  278. package/packages/kernel/work/domain/execution-concurrency.ts +247 -0
  279. package/packages/kernel/work/domain/execution-snapshot.ts +2 -0
  280. package/packages/kernel/work/domain/implementation-review.ts +193 -0
  281. package/packages/kernel/work/domain/objective-graph.ts +119 -0
  282. package/packages/kernel/work/domain/project-engineering-contract.ts +224 -0
  283. package/packages/kernel/work/domain/repository-completion-receipt.ts +73 -0
  284. package/{src/runtime/control-plane/facade/work-state-machine.ts → packages/kernel/work/domain/state-machine.ts} +37 -66
  285. package/packages/kernel/work/domain/types.ts +534 -0
  286. package/packages/kernel/work/index.ts +1 -0
  287. package/packages/kernel/work/infrastructure/work-contract-store.ts +1967 -0
  288. package/packages/kernel/work/ports/work-contract-store.ts +21 -0
  289. package/packages/plugin-runtime/browser/index.ts +3 -0
  290. package/packages/plugin-runtime/browser/provider-registry.ts +110 -0
  291. package/packages/plugin-runtime/browser/runtime-contract.ts +150 -0
  292. package/packages/plugin-runtime/browser/session-authority.ts +62 -0
  293. package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
  294. package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
  295. package/packages/plugin-runtime/computer/index.ts +8 -0
  296. package/packages/plugin-runtime/computer/provider-error.ts +26 -0
  297. package/packages/plugin-runtime/computer/provider-registration.ts +52 -0
  298. package/packages/plugin-runtime/computer/provider-registry.ts +63 -0
  299. package/packages/plugin-runtime/computer/provider.ts +19 -0
  300. package/packages/plugin-runtime/computer/target-authority.ts +215 -0
  301. package/packages/plugin-runtime/computer/target-persistence.ts +54 -0
  302. package/packages/plugin-runtime/external/index.ts +1 -0
  303. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +581 -0
  304. package/packages/plugin-runtime/index.ts +3 -0
  305. package/packages/protocols/browser/index.ts +1 -0
  306. package/packages/protocols/browser/session.ts +98 -0
  307. package/packages/protocols/computer/contract.ts +225 -0
  308. package/packages/protocols/computer/index.ts +1 -0
  309. package/packages/protocols/failure/contract.ts +158 -0
  310. package/packages/protocols/failure/index.ts +1 -0
  311. package/packages/protocols/handoff/index.ts +1 -0
  312. package/packages/protocols/handoff/status.ts +22 -0
  313. package/packages/protocols/mcp/execution-context.ts +11 -0
  314. package/packages/protocols/mcp/index.ts +2 -0
  315. package/packages/protocols/mcp/tool-contract.ts +42 -0
  316. package/packages/workflow-runtime/api/index.ts +2 -0
  317. package/packages/workflow-runtime/application/interpreter.ts +342 -0
  318. package/packages/workflow-runtime/domain/workflow-asset.ts +223 -0
  319. package/packages/workflow-runtime/index.ts +1 -0
  320. package/scripts/activate-source-baseline.ts +7 -9
  321. package/scripts/assemble-template.ts +1 -1
  322. package/scripts/bootstrap-runtime-maintenance-recovery.sh +4 -1
  323. package/scripts/canary-chatgpt-provider-delivery.ts +97 -0
  324. package/scripts/canary-controller-semantic-wait.ts +183 -0
  325. package/scripts/canary-global-hook.sh +2 -2
  326. package/scripts/check-mcp-compatibility.ts +85 -7
  327. package/scripts/check-platform-support.mjs +28 -2
  328. package/scripts/check-public-docs.sh +1 -1
  329. package/scripts/check-repository-hygiene.mjs +92 -0
  330. package/scripts/check-runtime-architecture.mjs +1643 -127
  331. package/scripts/check-source-duplication.mjs +9 -1
  332. package/scripts/controller-ngrok-rotation.sh +5 -4
  333. package/scripts/create-project-dirs.sh +10 -74
  334. package/scripts/forge-local-recovery-helper.mjs +282 -0
  335. package/scripts/forge-uu-remote-rescue-helper.d.mts +31 -0
  336. package/scripts/forge-uu-remote-rescue-helper.mjs +409 -0
  337. package/scripts/forge-windows-host-recovery-helper.mjs +136 -0
  338. package/scripts/hook-shim.sh +2 -2
  339. package/scripts/init-project.sh +12 -70
  340. package/scripts/install-desktop-operator-registration.ts +4 -2
  341. package/scripts/install-independent-windows-wsl-recovery.ts +125 -0
  342. package/scripts/install-standalone-recovery.ts +122 -10
  343. package/scripts/install-uu-remote-rescue-registration.ts +74 -0
  344. package/scripts/install-windows-host-recovery-registration.ts +22 -0
  345. package/scripts/lib/controller-home-env.sh +6 -3
  346. package/scripts/lib/project-init-lib.sh +42 -582
  347. package/scripts/migrate-chatgpt-automation-schedules.ts +2 -2
  348. package/scripts/migrate-windows-wsl-controller-home.ts +306 -0
  349. package/scripts/open-source-audit-allowlist.txt +11 -1
  350. package/scripts/portability-bindings.mjs +70 -0
  351. package/scripts/run-bounded-command.mjs +60 -0
  352. package/scripts/run-bun-test-file.ts +22 -6
  353. package/scripts/run-governed-gate.ts +4 -2
  354. package/scripts/run-mobile-monitor-bridge.ts +0 -1
  355. package/scripts/smoke-control-plane-failure-domain.ts +94 -0
  356. package/scripts/smoke-mcp-http-runtime.ts +6 -1
  357. package/scripts/smoke-runtime-recovery.ts +13 -11
  358. package/scripts/smoke-schedule-engine.ts +24 -16
  359. package/scripts/smoke-unattended-transport-recovery.ts +223 -0
  360. package/scripts/smoke-user-request-continuation-restart.ts +232 -0
  361. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
  362. package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
  363. package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
  364. package/scripts/smoke-workflow-supervisor.ts +103 -0
  365. package/scripts/test-governance.ts +51 -2
  366. package/scripts/verify-forge-runtime.sh +2 -1
  367. package/src/cli/agent-jobs/executor-health.ts +11 -34
  368. package/src/cli/agent-jobs/integration.ts +18 -49
  369. package/src/cli/agent-jobs/job-manager.ts +17 -4
  370. package/src/cli/chatgpt-browser/bind-server.ts +2 -1
  371. package/src/cli/chatgpt-browser/binding.ts +20 -10
  372. package/src/cli/chatgpt-browser/bridge-extension.ts +75 -0
  373. package/src/cli/chatgpt-browser/bridge-provider.ts +376 -11
  374. package/src/cli/chatgpt-browser/engine.ts +10 -11
  375. package/src/cli/chatgpt-browser/native-provider.ts +24 -83
  376. package/src/cli/chatgpt-browser/oracle-provider.ts +5 -3
  377. package/src/cli/chatgpt-browser/types.ts +1 -0
  378. package/src/cli/commands/bootstrap-control.ts +334 -0
  379. package/src/cli/commands/brain-assistant.ts +52 -0
  380. package/src/cli/commands/brain.ts +191 -40
  381. package/src/cli/commands/chatgpt.ts +32 -67
  382. package/src/cli/commands/computer.ts +437 -0
  383. package/src/cli/commands/doctor.ts +18 -1
  384. package/src/cli/commands/init-hook.ts +71 -61
  385. package/src/cli/commands/init.ts +3 -1
  386. package/src/cli/commands/mcp.ts +16 -10
  387. package/src/cli/commands/plugin.ts +38 -12
  388. package/src/cli/commands/recovery.ts +507 -80
  389. package/src/cli/commands/runtime.ts +12 -7
  390. package/src/cli/commands/setup-profile.ts +97 -39
  391. package/src/cli/commands/status.ts +2 -1
  392. package/src/cli/controller/check-runner.ts +500 -100
  393. package/src/cli/controller/completion-backlog.ts +3 -3
  394. package/src/cli/controller/completion-orchestrator.ts +4 -43
  395. package/src/cli/controller/completion-target.ts +3 -72
  396. package/src/cli/controller/context/source-materializer.ts +81 -100
  397. package/src/cli/controller/context/types.ts +7 -1
  398. package/src/cli/controller/context-pack.ts +28 -6
  399. package/src/cli/controller/execution-completion.ts +4 -7
  400. package/src/cli/controller/execution-policy.ts +36 -153
  401. package/src/cli/controller/governance.ts +2 -3
  402. package/src/cli/controller/issue-store.ts +4 -99
  403. package/src/cli/controller/launch-agents.ts +59 -18
  404. package/src/cli/controller/operational-plan.ts +24 -51
  405. package/src/cli/controller/runtime-config.ts +5 -1
  406. package/src/cli/controller/stuck-state-migration.ts +2 -3
  407. package/src/cli/controller/systemd-user.ts +148 -0
  408. package/src/cli/controller/types.ts +10 -70
  409. package/src/cli/controller/worklog.ts +67 -13
  410. package/src/cli/editing/edit-operation-contract.ts +92 -0
  411. package/src/cli/editing/edit-session.ts +290 -20
  412. package/src/cli/github/plugin.ts +17 -12
  413. package/src/cli/hook/route-registry.ts +3 -5
  414. package/src/cli/hook/runtime.ts +49 -3
  415. package/src/cli/index.ts +3 -0
  416. package/src/cli/local-bridge/connector-freshness.ts +2 -2
  417. package/src/cli/local-bridge/console-automations.ts +20 -15
  418. package/src/cli/local-bridge/console-view-models.ts +3 -12
  419. package/src/cli/local-bridge/facade-api.ts +105 -205
  420. package/src/cli/local-bridge/job-store.ts +1 -1
  421. package/src/cli/local-bridge/server.ts +48 -174
  422. package/src/cli/local-bridge/types.ts +0 -1
  423. package/src/cli/mcp/access-mode.ts +2 -132
  424. package/src/cli/mcp/access-tools.ts +2 -387
  425. package/src/cli/mcp/audit.ts +2 -32
  426. package/src/cli/mcp/auth.ts +2 -404
  427. package/src/cli/mcp/instructions.ts +2 -34
  428. package/src/cli/mcp/legacy-context.ts +2 -16
  429. package/src/cli/mcp/legacy-tool-service.ts +2 -5308
  430. package/src/cli/mcp/multi-repository.ts +2 -436
  431. package/src/cli/mcp/oauth-client-retirement.ts +74 -0
  432. package/src/cli/mcp/oauth.ts +2 -375
  433. package/src/cli/mcp/openai-secure-tunnel.ts +2 -0
  434. package/src/cli/mcp/paths.ts +2 -140
  435. package/src/cli/mcp/policy.ts +2 -232
  436. package/src/cli/mcp/post-finalize-work-attribution.ts +2 -150
  437. package/src/cli/mcp/proxy-env.ts +2 -62
  438. package/src/cli/mcp/readiness-projection.ts +2 -24
  439. package/src/cli/mcp/redaction.ts +2 -21
  440. package/src/cli/mcp/repo.ts +2 -24
  441. package/src/cli/mcp/repository-tools.ts +2 -1613
  442. package/src/cli/mcp/server.ts +2 -951
  443. package/src/cli/mcp/setup.ts +2 -737
  444. package/src/cli/mcp/tool-capability-cache.ts +2 -87
  445. package/src/cli/mcp/tool-contract.ts +2 -14
  446. package/src/cli/mcp/tools.ts +2 -9
  447. package/src/cli/mcp/toolset-names.ts +2 -70
  448. package/src/cli/mcp/toolset-selection.ts +2 -41
  449. package/src/cli/mcp/toolset.ts +2 -336
  450. package/src/cli/mcp/transports/AGENTS.md +1 -10
  451. package/src/cli/mcp/transports/CLAUDE.md +1 -10
  452. package/src/cli/mcp/transports/http.ts +2 -1414
  453. package/src/cli/mcp/transports/session-registry.ts +2 -490
  454. package/src/cli/mcp/transports/stdio.ts +2 -8
  455. package/src/cli/mcp/types.ts +2 -41
  456. package/src/cli/mcp/umbrella-tools.ts +2 -117
  457. package/src/cli/repositories/command-executor.ts +91 -39
  458. package/src/cli/repositories/command-scope.ts +139 -4
  459. package/src/cli/repositories/controller-home.ts +167 -1
  460. package/src/cli/repositories/ephemeral-workspace.ts +20 -30
  461. package/src/cli/repositories/git-command-executor.ts +2 -2
  462. package/src/cli/repositories/identity.ts +13 -0
  463. package/src/cli/repositories/registry.ts +145 -60
  464. package/src/cli/repositories/repository-snapshot.ts +53 -7
  465. package/src/cli/repositories/runtime-storage.ts +27 -2
  466. package/src/cli/repositories/safe-patch.ts +34 -38
  467. package/src/cli/repositories/selected-path-actions.ts +22 -2
  468. package/src/cli/repositories/structured-git.ts +167 -27
  469. package/src/cli/repository/session-cache.ts +92 -6
  470. package/src/cli/runtime/helper-runner.ts +7 -0
  471. package/src/cli/runtime-invocation.ts +8 -1
  472. package/src/cli/tools/codegraph.ts +44 -25
  473. package/src/core/adoption/manifest-templates.ts +1 -1
  474. package/src/core/adoption/plan.ts +3 -26
  475. package/src/core/adoption/workflow-contract-plan.ts +17 -9
  476. package/src/effects/process-runner.ts +8 -14
  477. package/src/runtime/context/assistant-context.ts +167 -0
  478. package/src/runtime/context/assistant-work-context.ts +209 -0
  479. package/src/runtime/context/automatic-learning.ts +565 -0
  480. package/src/runtime/context/codegraph-cache-boundary.ts +255 -0
  481. package/src/runtime/context/codegraph-read-provider.ts +55 -22
  482. package/src/runtime/context/codegraph-sidecar.cjs +8 -1
  483. package/src/runtime/context/cognitive-attention.ts +173 -0
  484. package/src/runtime/context/cognitive-skill-canary.ts +158 -0
  485. package/src/runtime/context/context-closure.ts +305 -0
  486. package/src/runtime/context/context-pack-process.ts +103 -0
  487. package/src/runtime/context/context-plane.ts +203 -0
  488. package/src/runtime/context/direct-controller-learning.ts +298 -0
  489. package/src/runtime/context/project-engineering-contract.ts +60 -0
  490. package/src/runtime/context/semantic-navigation-contract.ts +9 -0
  491. package/src/runtime/context/semantic-navigation.ts +6 -34
  492. package/src/runtime/context/typescript-navigation-process.ts +145 -0
  493. package/src/runtime/context/typescript-navigation.ts +89 -3
  494. package/src/runtime/control-plane/bootstrap/capability-provider.ts +74 -0
  495. package/src/runtime/control-plane/bootstrap/control-api.ts +57 -0
  496. package/src/runtime/control-plane/bootstrap/index.ts +5 -0
  497. package/src/runtime/control-plane/bootstrap/state-machine.ts +141 -0
  498. package/src/runtime/control-plane/bootstrap/store.ts +21 -0
  499. package/src/runtime/control-plane/bootstrap/types.ts +87 -0
  500. package/src/runtime/control-plane/cleanup-artifact-retention.ts +531 -0
  501. package/src/runtime/control-plane/codegraph-cache-retention.ts +164 -0
  502. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +282 -0
  503. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +380 -0
  504. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +113 -16
  505. package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
  506. package/src/runtime/control-plane/execution/implementation-review-content.ts +95 -0
  507. package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
  508. package/src/runtime/control-plane/execution/retained-work-resume.ts +439 -102
  509. package/src/runtime/control-plane/execution/session-store.ts +31 -1
  510. package/src/runtime/control-plane/execution/validation.ts +34 -11
  511. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +87 -0
  512. package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
  513. package/src/runtime/control-plane/execution/work-completion-authority.ts +31 -44
  514. package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
  515. package/src/runtime/control-plane/execution/work-evidence-policy.ts +46 -53
  516. package/src/runtime/control-plane/execution/work-execution-support.ts +85 -164
  517. package/src/runtime/control-plane/execution/work-handle-authority.ts +349 -73
  518. package/src/runtime/control-plane/execution/work-handle-store.ts +55 -2
  519. package/src/runtime/control-plane/execution/work-head-settlement.ts +108 -0
  520. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +173 -28
  521. package/src/runtime/control-plane/execution/work-operation-service.ts +92 -40
  522. package/src/runtime/control-plane/execution/work-preparation-service.ts +145 -269
  523. package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
  524. package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
  525. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +543 -225
  526. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +59 -45
  527. package/src/runtime/control-plane/execution/work-verification-context.ts +1 -1
  528. package/src/runtime/control-plane/execution/work-verification-service.ts +662 -52
  529. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +205 -16
  530. package/src/runtime/control-plane/facade/capability-registry.ts +380 -44
  531. package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
  532. package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
  533. package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
  534. package/src/runtime/control-plane/facade/controller-session-store.ts +2 -488
  535. package/src/runtime/control-plane/facade/goal-workloop-access.ts +6 -22
  536. package/src/runtime/control-plane/facade/goal-workloop.ts +565 -1202
  537. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +145 -0
  538. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +266 -52
  539. package/src/runtime/control-plane/facade/index.ts +4 -3
  540. package/src/runtime/control-plane/facade/operation-digest.ts +34 -73
  541. package/src/runtime/control-plane/facade/plan-contract-store.ts +671 -245
  542. package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
  543. package/src/runtime/control-plane/facade/repository-work-admission.ts +31 -23
  544. package/src/runtime/control-plane/facade/requirement-authority.ts +121 -0
  545. package/src/runtime/control-plane/facade/requirement-board.ts +9 -4
  546. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +85 -0
  547. package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
  548. package/src/runtime/control-plane/facade/semantic-admission.ts +8 -16
  549. package/src/runtime/control-plane/facade/suggested-actions.ts +15 -15
  550. package/src/runtime/control-plane/facade/types.ts +218 -620
  551. package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
  552. package/src/runtime/control-plane/facade/work-contract-store.ts +2 -1043
  553. package/src/runtime/control-plane/generated-cache-retention.ts +336 -19
  554. package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
  555. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +13 -2
  556. package/src/runtime/control-plane/global-scheduler/maintenance.ts +274 -84
  557. package/src/runtime/control-plane/global-scheduler/periodic-cleanup-entry.ts +55 -0
  558. package/src/runtime/control-plane/global-scheduler/periodic-cleanup-process.ts +98 -0
  559. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -2
  560. package/src/runtime/control-plane/global-scheduler/scheduler-worker-entry.ts +10 -0
  561. package/src/runtime/control-plane/global-scheduler/scheduler.ts +227 -109
  562. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
  563. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +18 -6
  564. package/src/runtime/control-plane/governance/access-policy.ts +19 -2
  565. package/src/runtime/control-plane/governance/authorization.ts +20 -3
  566. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +160 -0
  567. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +2 -177
  568. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +139 -670
  569. package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
  570. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +25 -6
  571. package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -194
  572. package/src/runtime/control-plane/lifecycle-retention-metrics.ts +60 -0
  573. package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
  574. package/src/runtime/control-plane/persistence/experience-store.ts +302 -0
  575. package/src/runtime/control-plane/persistence/operational-prior-store.ts +348 -0
  576. package/src/runtime/control-plane/persistence/requirement-store.ts +230 -80
  577. package/src/runtime/control-plane/persistence/sqlite-store.ts +654 -78
  578. package/src/runtime/control-plane/persistence/workflow-content-store.ts +98 -0
  579. package/src/runtime/control-plane/persistence/workflow-registry-store.ts +186 -0
  580. package/src/runtime/control-plane/persistence/workflow-run-store.ts +123 -0
  581. package/src/runtime/control-plane/release-retention.ts +154 -26
  582. package/src/runtime/control-plane/repository-namespace-retention.ts +208 -0
  583. package/src/runtime/control-plane/runtime-cleanup.ts +844 -38
  584. package/src/runtime/control-plane/runtime-generation.ts +6 -0
  585. package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
  586. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +479 -0
  587. package/src/runtime/control-plane/workspace/workspace-store.ts +249 -0
  588. package/src/runtime/diagnostics/incident-repair.ts +573 -0
  589. package/src/runtime/diagnostics/mcp-timing.ts +239 -6
  590. package/src/runtime/diagnostics/performance.ts +6 -14
  591. package/src/runtime/diagnostics/read-only-tool.ts +1 -1
  592. package/src/runtime/evidence/artifact-store.ts +216 -35
  593. package/src/runtime/evidence/evidence-store.ts +112 -8
  594. package/src/runtime/evidence/operational-shadow.ts +38 -0
  595. package/src/runtime/evidence/output-handle-index.ts +225 -0
  596. package/src/runtime/evidence/process-check-receipt.ts +5 -43
  597. package/src/runtime/evidence/result-store.ts +158 -44
  598. package/src/runtime/evidence/sensitive-output.ts +4 -4
  599. package/src/runtime/execution/jobs/receipt-recovery.ts +1 -1
  600. package/src/runtime/execution/jobs/store.ts +124 -6
  601. package/src/runtime/execution/managed-workspace.ts +112 -5
  602. package/src/runtime/execution/process-runtime/canary.ts +19 -5
  603. package/src/runtime/execution/process-runtime/check-classification.ts +48 -0
  604. package/src/runtime/execution/process-runtime/check-facade.ts +24 -10
  605. package/src/runtime/execution/process-runtime/check-receipt.ts +1 -1
  606. package/src/runtime/execution/process-runtime/check-result-retention.ts +132 -0
  607. package/src/runtime/execution/process-runtime/check-result.ts +177 -2
  608. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +58 -9
  609. package/src/runtime/execution/process-runtime/check-storage.ts +187 -0
  610. package/src/runtime/execution/process-runtime/command-facade.ts +117 -114
  611. package/src/runtime/execution/process-runtime/gc.ts +15 -2
  612. package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
  613. package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
  614. package/src/runtime/execution/process-runtime/index.ts +4 -0
  615. package/src/runtime/execution/process-runtime/interactive-admission.ts +2 -1
  616. package/src/runtime/execution/process-runtime/lightweight-managed.ts +283 -73
  617. package/src/runtime/execution/process-runtime/persisted-check.ts +130 -23
  618. package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
  619. package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
  620. package/src/runtime/execution/process-runtime/resource-claims.ts +125 -64
  621. package/src/runtime/execution/process-runtime/runtime.ts +167 -17
  622. package/src/runtime/execution/process-runtime/store.ts +30 -2
  623. package/src/runtime/execution/process-runtime/types.ts +27 -0
  624. package/src/runtime/execution/workers/executor.ts +18 -19
  625. package/src/runtime/execution/workers/worker-entry.ts +1 -1
  626. package/src/runtime/gateway/mcp/execution-tools.ts +2 -207
  627. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +2 -61
  628. package/src/runtime/gateway/mcp/persisted-check-process.ts +2 -3
  629. package/src/runtime/gateway/mcp/process-tools.ts +2 -289
  630. package/src/runtime/gateway/mcp/router.ts +2 -1125
  631. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +2 -565
  632. package/src/runtime/gateway/mcp/runtime-tools.ts +2 -6655
  633. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +2 -1
  634. package/src/runtime/maintenance/cleanup.ts +38 -24
  635. package/src/runtime/platform/browser-product-discovery.ts +174 -0
  636. package/src/runtime/platform/computer-platform.ts +14 -0
  637. package/src/runtime/platform/executable-discovery.ts +54 -0
  638. package/src/runtime/platform/fetch-http-server.ts +90 -0
  639. package/src/runtime/platform/service-inventory.ts +130 -0
  640. package/src/runtime/platform/service-manager.ts +146 -0
  641. package/src/runtime/platform/windows-host-discovery.ts +118 -0
  642. package/src/runtime/platform/windows-recovery-deployment.ts +67 -0
  643. package/src/runtime/plugins/action-application.ts +192 -0
  644. package/src/runtime/plugins/app-store-connect-adapter.ts +47 -35
  645. package/src/runtime/plugins/browser-adapter.ts +898 -135
  646. package/src/runtime/plugins/browser-automation-service.ts +33 -34
  647. package/src/runtime/plugins/browser-macos-bridge.ts +386 -46
  648. package/src/runtime/plugins/browser-manifest-surface.ts +75 -17
  649. package/src/runtime/plugins/browser-native-session-service.ts +64 -14
  650. package/src/runtime/plugins/browser-provider-registry.ts +2 -109
  651. package/src/runtime/plugins/browser-registration.ts +32 -0
  652. package/src/runtime/plugins/browser-runtime-contract.ts +2 -154
  653. package/src/runtime/plugins/browser-runtime.ts +55 -10
  654. package/src/runtime/plugins/browser-session-authority.ts +101 -291
  655. package/src/runtime/plugins/browser-session-legacy-migration.ts +203 -0
  656. package/src/runtime/plugins/browser-session-store.ts +243 -80
  657. package/src/runtime/plugins/browser-session-types.ts +2 -98
  658. package/src/runtime/plugins/capability-authorization-grants.ts +272 -59
  659. package/src/runtime/plugins/catalog-trust.ts +82 -0
  660. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
  661. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
  662. package/src/runtime/plugins/computer-registration.ts +1050 -0
  663. package/src/runtime/plugins/config-store.ts +119 -0
  664. package/src/runtime/plugins/desktop-operator-external-policy.ts +964 -0
  665. package/src/runtime/plugins/desktop-operator-registration.ts +123 -12
  666. package/src/runtime/plugins/errors.ts +8 -1
  667. package/src/runtime/plugins/external-adapter.ts +82 -323
  668. package/src/runtime/plugins/external-provider-policy.ts +48 -0
  669. package/src/runtime/plugins/external-registration.ts +30 -2
  670. package/src/runtime/plugins/external-unix-socket-probe.cjs +9 -3
  671. package/src/runtime/plugins/external-unix-socket.ts +64 -193
  672. package/src/runtime/plugins/first-party-external-registration.ts +163 -0
  673. package/src/runtime/plugins/first-party-registry.ts +3 -1
  674. package/src/runtime/plugins/github-adapter.ts +1 -2
  675. package/src/runtime/plugins/gmail-adapter.ts +29 -8
  676. package/src/runtime/plugins/google-calendar-adapter.ts +8 -8
  677. package/src/runtime/plugins/google-shared.ts +45 -53
  678. package/src/runtime/plugins/google-tasks-adapter.ts +8 -8
  679. package/src/runtime/plugins/ios-adapter.ts +2 -3
  680. package/src/runtime/plugins/lightweight-action.ts +208 -2
  681. package/src/runtime/plugins/local-system-adapter.ts +192 -2
  682. package/src/runtime/plugins/macos-capability-broker.ts +15 -105
  683. package/src/runtime/plugins/managed-process-adapter.ts +12 -5
  684. package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
  685. package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
  686. package/src/runtime/plugins/resend-adapter.ts +15 -24
  687. package/src/runtime/plugins/store.ts +1003 -387
  688. package/src/runtime/plugins/types.ts +28 -1
  689. package/src/runtime/plugins/uu-remote-rescue-registration.ts +155 -0
  690. package/src/runtime/plugins/windows-host-recovery-install.ts +68 -0
  691. package/src/runtime/plugins/windows-host-recovery-registration.ts +85 -0
  692. package/src/runtime/plugins/xiaohongshu-publish.ts +102 -430
  693. package/src/runtime/projections/controller-context.ts +12 -6
  694. package/src/runtime/projections/git-status-sampler.ts +73 -22
  695. package/src/runtime/projections/invalidation.ts +7 -3
  696. package/src/runtime/projections/materialized-view.ts +93 -43
  697. package/src/runtime/recovery/actions.ts +3 -3
  698. package/src/runtime/recovery/capability-action-application.ts +229 -0
  699. package/src/runtime/recovery/index.ts +3 -0
  700. package/src/runtime/recovery/lifecycle-inventory.ts +338 -0
  701. package/src/runtime/recovery/local-jobs-repair.ts +14 -14
  702. package/src/runtime/recovery/maintenance-executor.ts +701 -168
  703. package/src/runtime/recovery/quarantine-retention.ts +256 -0
  704. package/src/runtime/recovery/store.ts +29 -11
  705. package/src/runtime/release/identity.ts +6 -0
  706. package/src/runtime/release/release-coordinator.ts +296 -0
  707. package/src/runtime/release/release-session.ts +716 -0
  708. package/src/runtime/release/release-state-migration.ts +25 -0
  709. package/src/runtime/resources/leases/store.ts +56 -25
  710. package/src/runtime/root/active-execution-power-assertion.ts +139 -0
  711. package/src/runtime/root/assistant-learning-loop.ts +45 -0
  712. package/src/runtime/root/browser-session-composition.ts +59 -0
  713. package/src/runtime/root/computer-composition.ts +376 -0
  714. package/src/runtime/root/computer-target-composition.ts +16 -0
  715. package/src/runtime/root/computer-target-persistence.ts +39 -0
  716. package/src/runtime/root/controller-progression-composition.ts +192 -0
  717. package/src/runtime/root/controller-round-composition.ts +126 -0
  718. package/src/runtime/root/controller-services.ts +2 -0
  719. package/src/runtime/root/deployment-topology.ts +106 -0
  720. package/src/runtime/root/entry.ts +8 -6
  721. package/src/runtime/root/gateway-adapter.ts +3 -3
  722. package/src/runtime/root/known-good-recovery.ts +184 -0
  723. package/src/runtime/root/local-bridge.ts +5 -3
  724. package/src/runtime/root/mcp-transport.ts +116 -23
  725. package/src/runtime/root/ownership.ts +261 -9
  726. package/src/runtime/root/package-connector-service.ts +212 -74
  727. package/src/runtime/root/package-runtime-release.ts +199 -33
  728. package/src/runtime/root/package-runtime-service.ts +77 -108
  729. package/src/runtime/root/release-execution-canary.ts +103 -0
  730. package/src/runtime/root/release-loader.ts +150 -0
  731. package/src/runtime/root/release-manifest.ts +185 -7
  732. package/src/runtime/root/release-materialize.ts +474 -31
  733. package/src/runtime/root/release-store.ts +425 -37
  734. package/src/runtime/root/runtime-lane.ts +191 -0
  735. package/src/runtime/root/runtime.ts +379 -32
  736. package/src/runtime/root/scheduled-controller-composition.ts +76 -0
  737. package/src/runtime/root/scheduler.ts +12 -4
  738. package/src/runtime/root/service-runner.ts +3 -3
  739. package/src/runtime/root/service.ts +73 -45
  740. package/src/runtime/root/status.ts +49 -0
  741. package/src/runtime/root/types.ts +55 -3
  742. package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
  743. package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
  744. package/src/runtime/root/write-fence.ts +50 -2
  745. package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
  746. package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
  747. package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
  748. package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
  749. package/src/runtime/shared/local-bridge-surface.ts +1 -1
  750. package/src/runtime/shared/process-environment.ts +36 -10
  751. package/src/runtime/shared/response-budget.ts +1 -3
  752. package/src/runtime/shared/storage-capacity.ts +68 -0
  753. package/src/runtime/standalone-recovery/controller-home-migration.ts +1108 -0
  754. package/src/runtime/standalone-recovery/core.ts +4609 -495
  755. package/src/runtime/standalone-recovery/entry.ts +642 -81
  756. package/src/runtime/standalone-recovery/independent-host-rescue.ts +172 -0
  757. package/src/runtime/standalone-recovery/installer.ts +399 -177
  758. package/src/runtime/standalone-recovery/mcp-server.ts +79 -0
  759. package/src/runtime/standalone-recovery/mutation-identity-contract.ts +21 -0
  760. package/src/runtime/standalone-recovery/operation-lock.ts +160 -0
  761. package/src/runtime/standalone-recovery/performance.ts +173 -0
  762. package/src/runtime/standalone-recovery/release.ts +58 -5
  763. package/src/runtime/standalone-recovery/service-labels.ts +5 -2
  764. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
  765. package/src/runtime/watchdog/workflow-watchdog.ts +1 -1
  766. package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
  767. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +11 -4
  768. package/src/runtime/workflow/schedules/engine.ts +298 -484
  769. package/src/runtime/workflow/schedules/pending-activation.ts +1 -1
  770. package/src/runtime/workflow/schedules/settlement.ts +2 -191
  771. package/src/runtime/workflow/schedules/store.ts +2 -607
  772. package/src/runtime/workflow/schedules/types.ts +2 -127
  773. package/src/runtime/workflow/schedules/work-continuation.ts +220 -16
  774. package/src/runtime/workflows/first-party/xiaohongshu.ts +122 -0
  775. package/src/runtime/workflows/runtime.ts +482 -0
  776. package/src/testing/test-governance.ts +95 -30
  777. package/supervisor/chatgpt-conversation.ts +23 -0
  778. package/supervisor/client.ts +201 -0
  779. package/supervisor/control-plane.ts +868 -0
  780. package/supervisor/entry.ts +15 -0
  781. package/supervisor/forge-validators.ts +80 -0
  782. package/supervisor/index.ts +5 -0
  783. package/supervisor/native-browser-adapter.ts +786 -0
  784. package/supervisor/native-messaging/host.ts +39 -0
  785. package/supervisor/native-messaging/manifest.ts +26 -0
  786. package/supervisor/native-messaging/protocol.ts +27 -0
  787. package/supervisor/paths.ts +18 -0
  788. package/supervisor/protocol.ts +202 -0
  789. package/supervisor/server.ts +404 -0
  790. package/supervisor/store.ts +1451 -0
  791. package/supervisor/tsconfig.json +8 -0
  792. package/supervisor/types.ts +255 -0
  793. package/assets/templates/helpers/archive-architecture-request.sh +0 -244
  794. package/docs/architecture/history/README.md +0 -7
  795. package/docs/architecture/history/chatgpt-handoff-facade.md +0 -397
  796. package/docs/architecture/history/global-hook-runtime.md +0 -166
  797. package/docs/architecture/history/ios-semantic-automation-provider-v2.md +0 -170
  798. package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  799. package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +0 -59
  800. package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +0 -59
  801. package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +0 -59
  802. package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +0 -59
  803. package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  804. package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  805. package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  806. package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  807. package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +0 -59
  808. package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  809. package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  810. package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  811. package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  812. package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  813. package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  814. package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  815. package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  816. package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  817. package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +0 -59
  818. package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +0 -59
  819. package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +0 -63
  820. package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
  821. package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
  822. package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
  823. package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
  824. package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +0 -60
  825. package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +0 -60
  826. package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +0 -68
  827. package/docs/architecture/requests/archive/2026/root.md +0 -68
  828. package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +0 -76
  829. package/docs/architecture/requests/archive/2026/verification-evals-checks.md +0 -68
  830. package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +0 -69
  831. package/scripts/archive-architecture-request.sh +0 -4
  832. package/scripts/benchmark-background-check-overlap.ts +0 -228
  833. package/scripts/benchmark-controller-hotpath.ts +0 -212
  834. package/scripts/benchmark-controller-round2.ts +0 -139
  835. package/scripts/benchmark-ios-agent-device.ts +0 -514
  836. package/scripts/benchmark-mcp-host.sh +0 -117
  837. package/scripts/benchmark-mcp-transport.ts +0 -170
  838. package/scripts/benchmark-quality-harness.ts +0 -146
  839. package/scripts/benchmark-route-session-concurrency.ts +0 -915
  840. package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
  841. package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
  842. package/scripts/benchmark-thin-harness.ts +0 -251
  843. package/scripts/benchmark-typescript-navigation.ts +0 -186
  844. package/scripts/benchmark-work-efficiency.ts +0 -334
  845. package/scripts/build-controller-ui.ts +0 -28
  846. package/scripts/check-npm-release.sh +0 -32
  847. package/scripts/check-public-release-surface.sh +0 -19
  848. package/scripts/check-release-published.sh +0 -57
  849. package/scripts/check-release-readiness.sh +0 -37
  850. package/scripts/check-release-version.mjs +0 -74
  851. package/scripts/check-tarball-install-smoke.sh +0 -67
  852. package/scripts/package-source-archive.sh +0 -147
  853. package/scripts/public-release-files.txt +0 -39
  854. package/scripts/public-release.ts +0 -174
  855. package/scripts/publish-release-tarball.sh +0 -27
  856. package/scripts/route-nl-vs-ts-eval.ts +0 -679
  857. package/scripts/run-skill-evals.ts +0 -1022
  858. package/scripts/stage-runtime-release.ts +0 -39
  859. package/src/cli/controller/progress.ts +0 -656
  860. package/src/cli/controller/work-mode.ts +0 -181
  861. package/src/cli/local-bridge/console-assets.ts +0 -17
  862. package/src/cli/local-bridge/dashboard.ts +0 -17
  863. package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
  864. package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
  865. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
  866. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
  867. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
  868. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
  869. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
  870. package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
  871. package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
  872. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
  873. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
  874. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
  875. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
  876. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
  877. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
  878. package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
  879. package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
  880. package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
  881. package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
  882. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
  883. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
  884. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
  885. package/src/cli/local-bridge/frontend/src/styles.css +0 -28
  886. package/src/cli/local-bridge/frontend/src/types.ts +0 -15
  887. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
  888. package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
  889. package/src/cli/local-bridge/ui-dist/app.css +0 -1
  890. package/src/cli/local-bridge/ui-dist/app.js +0 -11228
  891. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -385
  892. package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -1913
  893. package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
  894. package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -449
  895. package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -1118
  896. package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -93
  897. package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
  898. package/src/runtime/control-plane/routing/index.ts +0 -1
  899. package/src/runtime/control-plane/routing/route-policy.ts +0 -382
  900. package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
@@ -5,7 +5,11 @@ import { spawn, spawnSync } from 'child_process';
5
5
  import { capProcessOutput, redactProcessOutput } from '../../effects/process-runner';
6
6
  import { commandEnvironment, collectOutput } from './command-process';
7
7
 
8
+ export type RepositoryCommandMutationEvidence = 'observed' | 'readonly_unobserved' | 'not_applicable';
9
+
8
10
  export interface RepositoryCommandSnapshot {
11
+ /** Whether this value contains authoritative mutation evidence for comparison. */
12
+ mutationEvidence: RepositoryCommandMutationEvidence;
9
13
  head: string | null;
10
14
  branch: string | null;
11
15
  status: string;
@@ -15,8 +19,17 @@ export interface RepositoryCommandSnapshot {
15
19
  pathFingerprints: Record<string, string>;
16
20
  }
17
21
 
22
+ function neutralSnapshot(mutationEvidence: Exclude<RepositoryCommandMutationEvidence, 'observed'>): RepositoryCommandSnapshot {
23
+ return { mutationEvidence, head: null, branch: null, status: '', dirty: false, refsHash: createHash('sha256').update('').digest('hex'), paths: [], pathFingerprints: {} };
24
+ }
25
+
18
26
  export function emptyWorkspaceSnapshot(): RepositoryCommandSnapshot {
19
- return { head: null, branch: null, status: '', dirty: false, refsHash: createHash('sha256').update('').digest('hex'), paths: [], pathFingerprints: {} };
27
+ return neutralSnapshot('not_applicable');
28
+ }
29
+
30
+ /** Proven-readonly execution deliberately owns no before/after mutation observation. */
31
+ export function readonlyUnobservedRepositorySnapshot(): RepositoryCommandSnapshot {
32
+ return neutralSnapshot('readonly_unobserved');
20
33
  }
21
34
 
22
35
  function commandOutput(command: string, args: string[], cwd: string, maxOutputBytes: number): { ok: boolean; stdout: string } {
@@ -54,7 +67,7 @@ function buildSnapshot(root: string, head: string | null, branch: string | null,
54
67
  byPath.set(path, [...(byPath.get(path) ?? []), line]);
55
68
  }
56
69
  const paths = [...byPath.keys()].sort();
57
- return { head, branch, status, dirty: paths.length > 0, refsHash: createHash('sha256').update(refs).digest('hex'), paths, pathFingerprints: Object.fromEntries(paths.map((path) => [path, pathFingerprint(root, path, byPath.get(path) ?? [])])) };
70
+ return { mutationEvidence: 'observed', head, branch, status, dirty: paths.length > 0, refsHash: createHash('sha256').update(refs).digest('hex'), paths, pathFingerprints: Object.fromEntries(paths.map((path) => [path, pathFingerprint(root, path, byPath.get(path) ?? [])])) };
58
71
  }
59
72
 
60
73
  export function repositorySnapshot(root: string): RepositoryCommandSnapshot {
@@ -84,7 +97,7 @@ const MAX_DIRTY_PATHS = 200;
84
97
  export async function repositorySnapshotAsync(
85
98
  root: string,
86
99
  signal?: AbortSignal,
87
- options: { pathFingerprints?: boolean; fingerprintTimeoutMs?: number } = {},
100
+ options: { pathFingerprints?: boolean; fingerprintTimeoutMs?: number; fingerprintPaths?: readonly string[] } = {},
88
101
  ): Promise<RepositoryCommandSnapshot> {
89
102
  const [headResult, branchResult, statusResult, refsResult] = await Promise.all([
90
103
  gitAsync(root, ['rev-parse', '--verify', 'HEAD'], signal), gitAsync(root, ['branch', '--show-current'], signal),
@@ -100,25 +113,58 @@ export async function repositorySnapshotAsync(
100
113
  if (signal?.aborted) throw new Error('CANCELLED: repository snapshot aborted');
101
114
  const lines = statusResult.stdout.split(/\r?\n/).filter((line) => line && !line.startsWith('##'));
102
115
  const includePathFingerprints = options.pathFingerprints !== false;
103
- if (includePathFingerprints && lines.length > MAX_DIRTY_PATHS) throw new Error(`SNAPSHOT_TOO_DIRTY: ${lines.length} dirty paths exceeds Fast Path cap ${MAX_DIRTY_PATHS}`);
104
116
  const byPath = new Map<string, string[]>();
105
117
  for (const line of lines) { const path = statusPath(line); if (path) byPath.set(path, [...(byPath.get(path) ?? []), line]); }
106
118
  const paths = [...byPath.keys()].sort();
119
+ const requestedFingerprintPaths = options.fingerprintPaths
120
+ ? [...new Set(options.fingerprintPaths.map((path) => path.trim().replace(/\\/g, '/').replace(/^\.\//, '')).filter(Boolean))]
121
+ .filter((path) => byPath.has(path))
122
+ .sort()
123
+ : undefined;
124
+ const fingerprintPaths = requestedFingerprintPaths ?? paths;
125
+ if (includePathFingerprints && fingerprintPaths.length > MAX_DIRTY_PATHS) {
126
+ throw new Error(`SNAPSHOT_TOO_DIRTY: ${fingerprintPaths.length} fingerprint paths exceeds Fast Path cap ${MAX_DIRTY_PATHS}`);
127
+ }
107
128
  let pathFingerprints: Record<string, string> = {};
108
129
  if (includePathFingerprints) {
109
130
  const { computePathFingerprintsAsync } = await import('../../runtime/execution/thin-harness/fingerprint-worker');
110
131
  const fingerprintTimeoutMs = typeof options.fingerprintTimeoutMs === 'number' && Number.isFinite(options.fingerprintTimeoutMs)
111
132
  ? Math.max(1, Math.trunc(options.fingerprintTimeoutMs))
112
133
  : 5_000;
113
- const fingerprint = await computePathFingerprintsAsync({ root, paths, statusByPath: Object.fromEntries(byPath), maxFileBytes: 256 * 1024, maxTotalBytes: 8 * 1024 * 1024, maxPaths: MAX_DIRTY_PATHS }, { signal, timeoutMs: fingerprintTimeoutMs });
134
+ const fingerprintStatusByPath = Object.fromEntries(fingerprintPaths.map((path) => [path, byPath.get(path) ?? []]));
135
+ const fingerprint = await computePathFingerprintsAsync({ root, paths: fingerprintPaths, statusByPath: fingerprintStatusByPath, maxFileBytes: 256 * 1024, maxTotalBytes: 8 * 1024 * 1024, maxPaths: MAX_DIRTY_PATHS }, { signal, timeoutMs: fingerprintTimeoutMs });
114
136
  pathFingerprints = fingerprint.pathFingerprints;
115
137
  }
116
- return { head, branch: branchResult.ok ? branchResult.stdout || null : null, status: statusResult.stdout, dirty: paths.length > 0, refsHash: createHash('sha256').update(refs).digest('hex'), paths, pathFingerprints };
138
+ return { mutationEvidence: 'observed', head, branch: branchResult.ok ? branchResult.stdout || null : null, status: statusResult.stdout, dirty: paths.length > 0, refsHash: createHash('sha256').update(refs).digest('hex'), paths, pathFingerprints };
139
+ }
140
+
141
+ function assertMutationEvidenceComparable(before: RepositoryCommandSnapshot, after: RepositoryCommandSnapshot): void {
142
+ if (before.mutationEvidence === 'readonly_unobserved' || after.mutationEvidence === 'readonly_unobserved') {
143
+ throw new Error('SNAPSHOT_COMPARISON_UNOBSERVED: readonly execution has no mutation snapshot to compare');
144
+ }
145
+ }
146
+
147
+ function snapshotStatusByPath(snapshot: RepositoryCommandSnapshot): Map<string, string[]> {
148
+ const byPath = new Map<string, string[]>();
149
+ for (const line of snapshot.status.split(/\r?\n/).filter((value) => value && !value.startsWith('##'))) {
150
+ const path = statusPath(line);
151
+ if (path) byPath.set(path, [...(byPath.get(path) ?? []), line]);
152
+ }
153
+ return byPath;
117
154
  }
118
155
 
119
156
  export function changedSnapshotPaths(before: RepositoryCommandSnapshot, after: RepositoryCommandSnapshot): string[] {
120
- return [...new Set([...before.paths, ...after.paths])].filter((path) => before.pathFingerprints[path] !== after.pathFingerprints[path]).sort();
157
+ assertMutationEvidenceComparable(before, after);
158
+ const beforeStatus = snapshotStatusByPath(before);
159
+ const afterStatus = snapshotStatusByPath(after);
160
+ return [...new Set([...before.paths, ...after.paths])].filter((path) => {
161
+ if ((beforeStatus.get(path) ?? []).join('\n') !== (afterStatus.get(path) ?? []).join('\n')) return true;
162
+ const beforeFingerprint = before.pathFingerprints[path];
163
+ const afterFingerprint = after.pathFingerprints[path];
164
+ return beforeFingerprint !== undefined && afterFingerprint !== undefined && beforeFingerprint !== afterFingerprint;
165
+ }).sort();
121
166
  }
122
167
  export function snapshotChanged(before: RepositoryCommandSnapshot, after: RepositoryCommandSnapshot): boolean {
168
+ assertMutationEvidenceComparable(before, after);
123
169
  return before.head !== after.head || before.branch !== after.branch || before.refsHash !== after.refsHash || changedSnapshotPaths(before, after).length > 0;
124
170
  }
@@ -49,6 +49,7 @@ interface RuntimeStorageSpec {
49
49
  name: string;
50
50
  sourceName: string;
51
51
  controllerName: string;
52
+ sourceRoot?: 'harness' | 'forge';
52
53
  preserveNonEmpty?: boolean;
53
54
  detectActiveRuns?: boolean;
54
55
  detectActiveLocalJobs?: boolean;
@@ -68,6 +69,15 @@ const RUNTIME_STORAGE_SPECS: RuntimeStorageSpec[] = [
68
69
  { name: 'mcp', sourceName: 'mcp', controllerName: 'mcp' },
69
70
  { name: 'local-bridge', sourceName: 'local-bridge', controllerName: 'local-bridge' },
70
71
  { name: 'ephemeral-issues', sourceName: 'ephemeral-issues', controllerName: 'ephemeral-issues' },
72
+ // Legacy callers may still use these repository-relative paths, but the
73
+ // physical state is Controller Home-owned. Keep them as compatibility links
74
+ // until the corresponding adapters consume Controller paths directly.
75
+ { name: 'session', sourceName: 'session', controllerName: 'session' },
76
+ { name: 'planning', sourceName: 'planning', controllerName: 'planning' },
77
+ { name: 'security', sourceName: 'security', controllerName: 'security' },
78
+ { name: 'transfers', sourceName: 'transfers', controllerName: 'transfers' },
79
+ { name: 'browser-provider', sourceName: 'browser', controllerName: 'browser', sourceRoot: 'forge' },
80
+ { name: 'interaction-sessions', sourceName: 'interactions', controllerName: 'interactions', sourceRoot: 'forge' },
71
81
  ];
72
82
 
73
83
  function directoryEntries(path: string): string[] {
@@ -257,12 +267,14 @@ function legacyRuntimeBlocker(repositoryPath: string, spec: RuntimeStorageSpec):
257
267
  }
258
268
 
259
269
  function bindRuntimeDirectory(
270
+ repositoryRoot: string,
260
271
  harnessRoot: string,
261
272
  controllerRoot: string,
262
273
  repoId: string,
263
274
  spec: RuntimeStorageSpec,
264
275
  ): RuntimeStorageBinding {
265
- const repositoryPath = join(harnessRoot, spec.sourceName);
276
+ const sourceRoot = spec.sourceRoot === 'forge' ? join(repositoryRoot, '.forge') : harnessRoot;
277
+ const repositoryPath = join(sourceRoot, spec.sourceName);
266
278
  const controllerPath = join(controllerRoot, spec.controllerName);
267
279
  mkdirSync(controllerPath, { recursive: true });
268
280
  writeOwnerMarker(controllerPath, repoId, spec.name);
@@ -378,6 +390,19 @@ function bindRuntimeDirectory(
378
390
  return { name: spec.name, repositoryPath, controllerPath, status: 'migrated' };
379
391
  }
380
392
 
393
+ export function ensureRepositoryRuntimeStorageBinding(
394
+ repository: RepositoryRecord,
395
+ name: string,
396
+ controllerHome?: string,
397
+ ): RuntimeStorageBinding {
398
+ const spec = RUNTIME_STORAGE_SPECS.find((entry) => entry.name === name);
399
+ if (!spec) throw new Error(`RUNTIME_STORAGE_BINDING_UNKNOWN: ${name}`);
400
+ const controllerRoot = ensureRepositoryControllerLayout(controllerHome ?? '', repository.repoId);
401
+ const harnessRoot = join(repository.canonicalRoot, '.ai', 'harness');
402
+ mkdirSync(harnessRoot, { recursive: true });
403
+ return bindRuntimeDirectory(repository.canonicalRoot, harnessRoot, controllerRoot, repository.repoId, spec);
404
+ }
405
+
381
406
  export function ensureRepositoryRuntimeStorage(
382
407
  repository: RepositoryRecord,
383
408
  controllerHome?: string,
@@ -386,7 +411,7 @@ export function ensureRepositoryRuntimeStorage(
386
411
  const harnessRoot = join(repository.canonicalRoot, '.ai', 'harness');
387
412
  mkdirSync(harnessRoot, { recursive: true });
388
413
 
389
- const bindings = RUNTIME_STORAGE_SPECS.map((spec) => bindRuntimeDirectory(harnessRoot, controllerRoot, repository.repoId, spec));
414
+ const bindings = RUNTIME_STORAGE_SPECS.map((spec) => bindRuntimeDirectory(repository.canonicalRoot, harnessRoot, controllerRoot, repository.repoId, spec));
390
415
  const warnings = bindings
391
416
  .filter((binding) => binding.status === 'legacy-active' || binding.status === 'conflict')
392
417
  .map((binding) => `${binding.name}: ${binding.message ?? binding.status}`);
@@ -2,16 +2,18 @@ import { createHash } from 'crypto';
2
2
  import { existsSync, readFileSync } from 'fs';
3
3
  import { join, relative, resolve } from 'path';
4
4
  import {
5
+ adoptEditSessionSuccessorHead,
5
6
  applyEditOperations,
6
7
  beginEditSession,
7
8
  getEditSession,
8
- type EditOperation,
9
9
  type EditSession,
10
10
  type EditSessionBinding,
11
11
  type EditSessionPatchError,
12
12
  } from '../editing/edit-session';
13
+ import { normalizeEditOperation, type EditOperation } from '../editing/edit-operation-contract';
13
14
  import { getMcpPolicy } from '../mcp/policy';
14
15
  import type { RepositoryRecord } from './types';
16
+ import { ensureRepositoryRuntimeStorageBinding } from './runtime-storage';
15
17
 
16
18
  export interface SafePatchFingerprint {
17
19
  path: string;
@@ -100,46 +102,15 @@ function objectEntries(value: unknown): Record<string, unknown>[] {
100
102
  return value.filter((entry): entry is Record<string, unknown> => typeof entry === 'object' && entry !== null && !Array.isArray(entry));
101
103
  }
102
104
 
103
- function normalizeReplacement(value: unknown): Array<{ oldText: string; newText: string; replaceAll?: boolean }> {
104
- return objectEntries(value).map((replacement) => ({
105
- oldText: String(replacement.old_text ?? replacement.oldText ?? ''),
106
- newText: String(replacement.new_text ?? replacement.newText ?? ''),
107
- replaceAll: replacement.replace_all === true || replacement.replaceAll === true,
108
- }));
109
- }
110
-
111
105
  function normalizeOperation(entry: Record<string, unknown>, originalIndex: number): NormalizedOperation {
112
- const type = String(entry.type ?? '');
113
106
  const path = String(entry.path ?? '').trim();
114
- const expectedSha256 = String(entry.expected_sha256 ?? entry.expectedSha256 ?? '').trim();
115
107
  if (!path) throw new Error(`SAFE_PATCH_OPERATION_INVALID: operation ${originalIndex + 1} path is required`);
116
- if (type === 'create') return { type, path, content: String(entry.content ?? ''), __originalIndex: originalIndex };
117
- if (type === 'delete') return { type, path, expectedSha256, __originalIndex: originalIndex };
118
- if (type === 'write') return { type, path, expectedSha256, content: String(entry.content ?? ''), __originalIndex: originalIndex };
119
- if (type === 'replace') {
120
- const replacements = Array.isArray(entry.replacements)
121
- ? normalizeReplacement(entry.replacements)
122
- : (entry.old_text !== undefined || entry.oldText !== undefined)
123
- ? normalizeReplacement([entry])
124
- : [];
125
- if (replacements.length === 0) {
126
- throw new Error(`SAFE_PATCH_OPERATION_INVALID: operation ${originalIndex + 1} replace requires replacements[] or old_text/new_text`);
127
- }
128
- return { type, path, expectedSha256, replacements, __originalIndex: originalIndex };
129
- }
130
- if (type === 'insert_before' || type === 'insert_after') {
131
- return {
132
- type,
133
- path,
134
- expectedSha256,
135
- anchor: String(entry.anchor ?? ''),
136
- content: String(entry.content ?? ''),
137
- occurrence: typeof entry.occurrence === 'number' ? Math.trunc(entry.occurrence) : undefined,
138
- __originalIndex: originalIndex,
139
- };
108
+ try {
109
+ return { ...normalizeEditOperation({ ...entry, path }), __originalIndex: originalIndex } as NormalizedOperation;
110
+ } catch (error) {
111
+ const message = error instanceof Error ? error.message : String(error);
112
+ throw new Error(`SAFE_PATCH_OPERATION_INVALID: operation ${originalIndex + 1} ${message}`);
140
113
  }
141
- if (type === 'prepend' || type === 'append') return { type, path, expectedSha256, content: String(entry.content ?? ''), __originalIndex: originalIndex };
142
- throw new Error(`SAFE_PATCH_OPERATION_INVALID: operation ${originalIndex + 1} has invalid type: ${type}`);
143
114
  }
144
115
 
145
116
  export function normalizeSafePatchOperations(value: unknown): EditOperation[] {
@@ -348,6 +319,10 @@ export function applySafePatch(repository: RepositoryRecord, input: {
348
319
  recoverStaleSession?: unknown;
349
320
  binding?: EditSessionBinding;
350
321
  }): SafePatchApplyResult {
322
+ const editStorage = ensureRepositoryRuntimeStorageBinding(repository, 'edit-sessions');
323
+ if (editStorage.status === 'legacy-active' || editStorage.status === 'conflict') {
324
+ throw new Error(`SAFE_PATCH_EDIT_SESSION_STORAGE_NOT_READY: ${editStorage.message ?? editStorage.status}`);
325
+ }
351
326
  const operations = normalizedSafePatchOperations(input.operations);
352
327
  if (operations.length === 0) throw new Error('SAFE_PATCH_OPERATIONS_REQUIRED: provide at least one operation');
353
328
  const size = chunkSize(input.chunkSize);
@@ -381,7 +356,28 @@ export function applySafePatch(repository: RepositoryRecord, input: {
381
356
  session = applyEditOperations(repository.canonicalRoot, policy, session.sessionId, preflight.operations.map(stripInternalIndex), { expectedRevision, maxBatchOperations: MAX_SAFE_PATCH_CHUNK_SIZE, binding: input.binding });
382
357
  } catch (error) {
383
358
  const message = error instanceof Error ? error.message : String(error);
384
- if (!sessionId && input.recoverStaleSession !== false && message.includes('EDIT_SESSION_FINGERPRINT_STALE')) {
359
+ if (sessionId && input.recoverStaleSession !== false && message.includes('EDIT_SESSION_BASE_REVISION_CHANGED')) {
360
+ const previousSessionId = session.sessionId;
361
+ try {
362
+ session = adoptEditSessionSuccessorHead(repository.canonicalRoot, session.sessionId, { binding: input.binding });
363
+ expectedRevision = session.currentRevision;
364
+ recoveredSession = { reason: 'Existing Work-bound edit session adopted a proven non-overlapping successor HEAD.', previousSessionId, newSessionId: session.sessionId };
365
+ const retry = preflightChunk(repository, group, chunkIndex, refresh);
366
+ if (retry.failures.length === 0) {
367
+ session = applyEditOperations(repository.canonicalRoot, policy, session.sessionId, retry.operations.map(stripInternalIndex), { expectedRevision, maxBatchOperations: MAX_SAFE_PATCH_CHUNK_SIZE, binding: input.binding });
368
+ } else {
369
+ failures.push(...retry.failures);
370
+ failedChunk = chunkIndex;
371
+ if (!continueOnError) break;
372
+ continue;
373
+ }
374
+ } catch (adoptionError) {
375
+ failures.push(...patchErrorFailures(adoptionError, chunkIndex));
376
+ failedChunk = chunkIndex;
377
+ if (!continueOnError) break;
378
+ continue;
379
+ }
380
+ } else if (!sessionId && input.recoverStaleSession !== false && message.includes('EDIT_SESSION_FINGERPRINT_STALE')) {
385
381
  const previousSessionId = session.sessionId;
386
382
  session = beginEditSession(repository.canonicalRoot, { purpose: `${String(input.purpose ?? 'Safe repository patch').trim() || 'Safe repository patch'} (recovered)`, allowedPaths, binding: input.binding });
387
383
  expectedRevision = session.currentRevision;
@@ -4,6 +4,7 @@ import { join, relative, resolve } from 'path';
4
4
  import { capProcessOutput, redactProcessOutput } from '../../effects/process-runner';
5
5
  import { buildPatchHandoffArtifact } from '../../runtime/recovery/patch-handoff';
6
6
  import { executeRepositoryGitCommand, type RepositoryGitExecution } from './git-command-executor';
7
+ import { resolveRepositoryGitCommitScope } from './structured-git';
7
8
  import { withControllerLock } from './locks';
8
9
  import type { RepositoryRecord } from './types';
9
10
 
@@ -32,6 +33,16 @@ export interface SelectedPathCommitResult {
32
33
  error?: { code: string; message: string };
33
34
  }
34
35
 
36
+ export interface SelectedPathBeforeCommitGuardInput {
37
+ repository: RepositoryRecord;
38
+ requestedPaths: string[];
39
+ stagedPaths: string[];
40
+ /** Exact HEAD observed after staging and immediately before the physical commit. */
41
+ currentHead: string | null;
42
+ }
43
+
44
+ export type SelectedPathBeforeCommitGuard = (input: SelectedPathBeforeCommitGuardInput) => void;
45
+
35
46
  export interface TransferArtifactPreview {
36
47
  path: string;
37
48
  exists: boolean;
@@ -249,9 +260,12 @@ export function stageSelectedPaths(
249
260
  export function commitSelectedPaths(
250
261
  controllerHome: string,
251
262
  repository: RepositoryRecord,
252
- input: { paths: unknown; message: unknown },
263
+ input: { paths: unknown; message: unknown; beforeCommitGuard?: SelectedPathBeforeCommitGuard },
253
264
  ): SelectedPathCommitResult {
254
- const paths = normalizeSelectedPaths(repository, input.paths);
265
+ const selectedPaths = normalizeSelectedPaths(repository, input.paths);
266
+ const scope = resolveRepositoryGitCommitScope(repository, { paths: selectedPaths });
267
+ if (scope.source !== 'explicit_paths') throw new Error('SELECTED_PATH_COMMIT_SCOPE_INVALID: selected-path commit requires explicit path scope');
268
+ const paths = scope.paths;
255
269
  const message = String(input.message ?? '').trim();
256
270
  if (!message) throw new Error('COMMIT_MESSAGE_REQUIRED: message is required');
257
271
 
@@ -283,6 +297,12 @@ export function commitSelectedPaths(
283
297
  };
284
298
  }
285
299
 
300
+ // The repository layer owns staging and exact staged-path discovery, but it
301
+ // does not own Work lifecycle/review policy. Callers may inject one typed
302
+ // fail-closed guard at the last safe boundary before the physical commit.
303
+ const currentHead = gitText(repository, ['rev-parse', '--verify', 'HEAD']) || null;
304
+ input.beforeCommitGuard?.({ repository, requestedPaths: paths, stagedPaths: staged, currentHead });
305
+
286
306
  const commit = executeRepositoryGitCommand(controllerHome, repository, {
287
307
  args: ['commit', '--only', '-m', message, '--', ...paths],
288
308
  authorization: 'explicit_user_request',
@@ -1,4 +1,7 @@
1
1
  import { spawnSync } from 'child_process';
2
+ import { randomUUID } from 'crypto';
3
+ import { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from 'fs';
4
+ import { isAbsolute, resolve } from 'path';
2
5
  import { capProcessOutput, redactProcessOutput } from '../../effects/process-runner';
3
6
  import { executeRepositoryGitCommand, type RepositoryGitExecution } from './git-command-executor';
4
7
  import { validateBranchName } from './branch-name-policy';
@@ -51,6 +54,11 @@ export interface RepositoryGitCommitResult {
51
54
  error?: { code: string; message: string };
52
55
  }
53
56
 
57
+ export interface RepositoryGitCommitScope {
58
+ source: 'explicit_paths' | 'staged_index';
59
+ paths: string[];
60
+ }
61
+
54
62
  export interface RepositoryGitFinishResult {
55
63
  repoId: string;
56
64
  checkoutId: string;
@@ -90,6 +98,16 @@ function gitText(repository: RepositoryRecord, args: string[]): string | null {
90
98
  return result.ok && result.stdout.trim() ? result.stdout.trim() : null;
91
99
  }
92
100
 
101
+ function stashSelectorForOid(repository: RepositoryRecord, oid: string): string | null {
102
+ const result = runGit(repository, ['stash', 'list', '--format=%H%x00%gd'], 64 * 1024);
103
+ if (!result.ok) return null;
104
+ for (const line of result.stdout.split(/\r?\n/)) {
105
+ const [candidateOid, selector] = line.split('\0');
106
+ if (candidateOid === oid && selector) return selector;
107
+ }
108
+ return null;
109
+ }
110
+
93
111
  function assertSafeBranchName(raw: unknown): string {
94
112
  try {
95
113
  return validateBranchName(raw, { purpose: 'GIT_BRANCH' });
@@ -114,6 +132,28 @@ function normalizePaths(input: unknown): string[] {
114
132
  return [...new Set(input.map((entry) => String(entry ?? '').trim().replace(/\\/g, '/')).filter(Boolean))].sort();
115
133
  }
116
134
 
135
+ export function repositoryGitStagedPaths(repository: RepositoryRecord): string[] {
136
+ const staged = runGit(repository, ['diff', '--cached', '--name-only', '-z'], 128 * 1024);
137
+ if (!staged.ok) {
138
+ throw new Error(`GIT_COMMIT_SCOPE_INSPECTION_FAILED: ${staged.stderr || 'Unable to inspect the staged Git index.'}`);
139
+ }
140
+ return staged.stdout.split('\0').map((path) => path.trim()).filter(Boolean).sort();
141
+ }
142
+
143
+ /**
144
+ * Commit scope has one repository authority. Explicit pathspecs narrow the
145
+ * transaction; otherwise the exact staged Git index is the scope. Callers do
146
+ * not need to restate the same staged paths merely to satisfy routing policy.
147
+ */
148
+ export function resolveRepositoryGitCommitScope(
149
+ repository: RepositoryRecord,
150
+ input: { paths?: unknown },
151
+ ): RepositoryGitCommitScope {
152
+ const explicitPaths = normalizePaths(input.paths);
153
+ if (explicitPaths.length > 0) return { source: 'explicit_paths', paths: explicitPaths };
154
+ return { source: 'staged_index', paths: repositoryGitStagedPaths(repository) };
155
+ }
156
+
117
157
  function splitStatus(porcelain: string): { staged: string[]; unstaged: string[]; untracked: string[] } {
118
158
  const staged: string[] = [];
119
159
  const unstaged: string[] = [];
@@ -262,57 +302,108 @@ export function repositoryGitDeleteBranch(controllerHome: string, repository: Re
262
302
  export function repositoryGitCommit(controllerHome: string, repository: RepositoryRecord, input: { message: unknown; paths?: unknown; allowEmpty?: unknown; authorizationDecision?: AuthorizationDecision; sessionId?: string; principalId?: string; workId?: string; goalId?: string }): RepositoryGitCommitResult {
263
303
  const before = repositoryGitStatus(repository);
264
304
  const message = normalizeCommitMessage(input.message);
265
- const paths = normalizePaths(input.paths);
305
+ const scope = resolveRepositoryGitCommitScope(repository, { paths: input.paths });
306
+ const paths = scope.source === 'explicit_paths' ? scope.paths : [];
266
307
  let stage: RepositoryGitExecution | undefined;
267
- if (paths.length > 0) {
308
+ let explicitIndexSnapshot: { path: string; existed: boolean; contents?: Buffer } | undefined;
309
+ const restoreExplicitIndex = (): { ok: boolean; message?: string } => {
310
+ if (!explicitIndexSnapshot) return { ok: true };
311
+ const restorePath = `${explicitIndexSnapshot.path}.forge-restore-${randomUUID()}`;
312
+ try {
313
+ if (!explicitIndexSnapshot.existed) {
314
+ rmSync(explicitIndexSnapshot.path, { force: true });
315
+ return { ok: true };
316
+ }
317
+ if (!explicitIndexSnapshot.contents) return { ok: false, message: 'pre-stage index contents are unavailable' };
318
+ writeFileSync(restorePath, explicitIndexSnapshot.contents);
319
+ renameSync(restorePath, explicitIndexSnapshot.path);
320
+ return { ok: true };
321
+ } catch (error) {
322
+ rmSync(restorePath, { force: true });
323
+ return { ok: false, message: error instanceof Error ? error.message : String(error) };
324
+ }
325
+ };
326
+ const failedAfterExplicitStage = (code: string, message: string, commit?: RepositoryGitExecution): RepositoryGitCommitResult => {
327
+ const restored = restoreExplicitIndex();
328
+ return {
329
+ repoId: repository.repoId,
330
+ checkoutId: repository.activeCheckoutId,
331
+ before,
332
+ ...(stage ? { stage } : {}),
333
+ ...(commit ? { commit } : {}),
334
+ after: repositoryGitStatus(repository),
335
+ committed: false,
336
+ error: restored.ok
337
+ ? { code, message }
338
+ : { code: `${code}_INDEX_RESTORE_FAILED`, message: `${message}; failed to restore the exact pre-stage index: ${restored.message}` },
339
+ };
340
+ };
341
+ if (scope.source === 'explicit_paths') {
342
+ const rawIndexPath = gitText(repository, ['rev-parse', '--git-path', 'index']);
343
+ if (!rawIndexPath) {
344
+ return {
345
+ repoId: repository.repoId,
346
+ checkoutId: repository.activeCheckoutId,
347
+ before,
348
+ after: repositoryGitStatus(repository),
349
+ committed: false,
350
+ error: { code: 'GIT_INDEX_SNAPSHOT_FAILED', message: 'Unable to resolve the Git index path before an explicit-path commit.' },
351
+ };
352
+ }
353
+ const indexPath = isAbsolute(rawIndexPath) ? rawIndexPath : resolve(repository.canonicalRoot, rawIndexPath);
354
+ try {
355
+ const existed = existsSync(indexPath);
356
+ explicitIndexSnapshot = {
357
+ path: indexPath,
358
+ existed,
359
+ ...(existed ? { contents: readFileSync(indexPath) } : {}),
360
+ };
361
+ } catch (error) {
362
+ return {
363
+ repoId: repository.repoId,
364
+ checkoutId: repository.activeCheckoutId,
365
+ before,
366
+ after: repositoryGitStatus(repository),
367
+ committed: false,
368
+ error: { code: 'GIT_INDEX_SNAPSHOT_FAILED', message: error instanceof Error ? error.message : String(error) },
369
+ };
370
+ }
268
371
  stage = executeRepositoryGitCommand(controllerHome, repository, { args: ['add', '--all', '--', ...paths], authorization: 'explicit_user_request', ...input });
269
372
  if (stage.status !== 'executed' || stage.ok !== true) {
270
- return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, before, stage, after: repositoryGitStatus(repository), committed: false, error: { code: 'GIT_STAGE_FAILED', message: stage.stderr || 'git add failed' } };
373
+ return failedAfterExplicitStage('GIT_STAGE_FAILED', stage.stderr || 'git add failed');
271
374
  }
272
375
  }
273
376
  const diffCheck = runGit(repository, ['diff', '--cached', '--quiet'], 64 * 1024);
274
377
  if (diffCheck.status === 0 && input.allowEmpty !== true) {
275
- return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, before, stage, after: repositoryGitStatus(repository), committed: false, error: { code: 'GIT_NOTHING_STAGED', message: 'No staged changes to commit. Pass paths to stage, or allow_empty=true for an empty commit.' } };
378
+ return failedAfterExplicitStage('GIT_NOTHING_STAGED', 'No staged changes to commit. Pass paths to stage, or allow_empty=true for an empty commit.');
276
379
  }
277
380
  const mergeInProgress = runGit(repository, ['rev-parse', '--verify', 'MERGE_HEAD'], 64 * 1024).ok;
278
381
  if (mergeInProgress) {
279
382
  const unresolved = runGit(repository, ['diff', '--name-only', '--diff-filter=U', '-z'], 128 * 1024);
280
383
  const unresolvedPaths = unresolved.stdout.split('\0').map((path) => path.trim()).filter(Boolean);
281
384
  if (!unresolved.ok || unresolvedPaths.length > 0) {
282
- return {
283
- repoId: repository.repoId,
284
- checkoutId: repository.activeCheckoutId,
285
- before,
286
- stage,
287
- after: repositoryGitStatus(repository),
288
- committed: false,
289
- error: { code: 'GIT_MERGE_UNRESOLVED', message: unresolvedPaths.length > 0 ? `Merge still has unresolved path(s): ${unresolvedPaths.join(', ')}` : unresolved.stderr || 'Unable to inspect unresolved merge paths.' },
290
- };
385
+ return failedAfterExplicitStage(
386
+ 'GIT_MERGE_UNRESOLVED',
387
+ unresolvedPaths.length > 0 ? `Merge still has unresolved path(s): ${unresolvedPaths.join(', ')}` : unresolved.stderr || 'Unable to inspect unresolved merge paths.',
388
+ );
291
389
  }
292
390
  if (paths.length > 0) {
293
391
  const stagedNames = runGit(repository, ['diff', '--cached', '--name-only', '-z'], 128 * 1024);
294
392
  if (!stagedNames.ok) {
295
- return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, before, stage, after: repositoryGitStatus(repository), committed: false, error: { code: 'GIT_MERGE_STAGED_SCOPE_INSPECTION_FAILED', message: stagedNames.stderr || 'Unable to inspect the merge index.' } };
393
+ return failedAfterExplicitStage('GIT_MERGE_STAGED_SCOPE_INSPECTION_FAILED', stagedNames.stderr || 'Unable to inspect the merge index.');
296
394
  }
297
395
  const allowed = new Set(paths);
298
396
  const stagedPaths = stagedNames.stdout.split('\0').map((path) => path.trim()).filter(Boolean);
299
397
  const outsideScope = stagedPaths.filter((path) => !allowed.has(path));
300
398
  if (outsideScope.length > 0) {
301
- return {
302
- repoId: repository.repoId,
303
- checkoutId: repository.activeCheckoutId,
304
- before,
305
- stage,
306
- after: repositoryGitStatus(repository),
307
- committed: false,
308
- error: { code: 'GIT_MERGE_STAGED_SCOPE_MISMATCH', message: `Resolved merge index contains staged path(s) outside the requested commit scope: ${outsideScope.join(', ')}` },
309
- };
399
+ return failedAfterExplicitStage('GIT_MERGE_STAGED_SCOPE_MISMATCH', `Resolved merge index contains staged path(s) outside the requested commit scope: ${outsideScope.join(', ')}`);
310
400
  }
311
401
  }
312
402
  }
313
403
  const commitArgs = ['commit', '-m', message, ...(input.allowEmpty === true ? ['--allow-empty'] : []), ...(!mergeInProgress && paths.length > 0 ? ['--only', '--', ...paths] : [])];
314
404
  const commit = executeRepositoryGitCommand(controllerHome, repository, { args: commitArgs, authorization: 'explicit_user_request', ...input });
315
405
  const ok = commit.status === 'executed' && commit.ok === true;
406
+ if (!ok) return failedAfterExplicitStage('GIT_COMMIT_FAILED', commit.stderr || 'git commit failed', commit);
316
407
  return {
317
408
  repoId: repository.repoId,
318
409
  checkoutId: repository.activeCheckoutId,
@@ -320,8 +411,7 @@ export function repositoryGitCommit(controllerHome: string, repository: Reposito
320
411
  ...(stage ? { stage } : {}),
321
412
  commit,
322
413
  after: repositoryGitStatus(repository),
323
- committed: ok,
324
- ...(ok ? {} : { error: { code: 'GIT_COMMIT_FAILED', message: commit.stderr || 'git commit failed' } }),
414
+ committed: true,
325
415
  };
326
416
  }
327
417
 
@@ -334,6 +424,7 @@ export function repositoryGitFinishWorkflow(controllerHome: string, repository:
334
424
  const requestedPreservedDirtyPaths = normalizePaths(input.preserveDirtyTargetPaths);
335
425
  const currentDirtyPaths = [...new Set([...before.staged, ...before.unstaged, ...before.untracked])].sort();
336
426
  const preserveDirtyTargetInPlace = alreadyOnTarget && requestedPreservedDirtyPaths.length > 0;
427
+ let equivalentOverlappingDirtyPaths: string[] = [];
337
428
  if (preserveDirtyTargetInPlace) {
338
429
  const requested = new Set(requestedPreservedDirtyPaths);
339
430
  if (requested.size !== currentDirtyPaths.length || currentDirtyPaths.some((path) => !requested.has(path))) {
@@ -346,7 +437,19 @@ export function repositoryGitFinishWorkflow(controllerHome: string, repository:
346
437
  const candidatePaths = new Set(candidateDiff.stdout.split(/\r?\n/).map((path) => path.trim()).filter(Boolean));
347
438
  const overlapping = currentDirtyPaths.filter((path) => candidatePaths.has(path));
348
439
  if (overlapping.length > 0) {
349
- return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, featureBranch, targetBranch, before, steps, after: before, completed: false, error: { code: 'GIT_DIRTY_TARGET_PATH_CONFLICT', message: `Work-owned dirty target path(s) overlap the integration candidate: ${overlapping.join(', ')}` } };
440
+ const staged = new Set(before.staged);
441
+ const unstaged = new Set(before.unstaged);
442
+ const untracked = new Set(before.untracked);
443
+ const equivalent = overlapping.every((path) => {
444
+ if (untracked.has(path) || (!staged.has(path) && !unstaged.has(path))) return false;
445
+ if (staged.has(path) && !runGit(repository, ['diff', '--cached', '--quiet', featureBranch, '--', path], 8 * 1024).ok) return false;
446
+ if (unstaged.has(path) && !runGit(repository, ['diff', '--quiet', featureBranch, '--', path], 8 * 1024).ok) return false;
447
+ return true;
448
+ });
449
+ if (!equivalent) {
450
+ return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, featureBranch, targetBranch, before, steps, after: before, completed: false, error: { code: 'GIT_DIRTY_TARGET_PATH_CONFLICT', message: `Work-owned dirty target path(s) overlap the integration candidate: ${overlapping.join(', ')}` } };
451
+ }
452
+ equivalentOverlappingDirtyPaths = overlapping;
350
453
  }
351
454
  }
352
455
  if (!before.clean && !alreadyOnTarget) {
@@ -362,6 +465,30 @@ export function repositoryGitFinishWorkflow(controllerHome: string, repository:
362
465
  }
363
466
  const protectTrackedChanges = alreadyOnTarget && !preserveDirtyTargetInPlace && (before.staged.length > 0 || before.unstaged.length > 0);
364
467
  const finishAuthorization = 'explicit_user_request' as const;
468
+ let equivalentOverlapStashRef: string | null = null;
469
+ if (equivalentOverlappingDirtyPaths.length > 0) {
470
+ const stash = executeRepositoryGitCommand(controllerHome, repository, { args: ['stash', 'push', '-m', `forge-finish-equivalent:${input.workId ?? featureBranch}`, '--', ...equivalentOverlappingDirtyPaths], authorization: finishAuthorization, ...input });
471
+ steps.push({ name: 'stash_equivalent_target_overlap', execution: stash });
472
+ if (stash.status !== 'executed' || stash.ok !== true) {
473
+ return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, featureBranch, targetBranch, before, steps, after: repositoryGitStatus(repository), completed: false, error: { code: 'GIT_EQUIVALENT_TARGET_STASH_FAILED', message: stash.stderr || 'Unable to preserve candidate-equivalent dirty target paths before integration.' } };
474
+ }
475
+ equivalentOverlapStashRef = gitText(repository, ['rev-parse', 'refs/stash']);
476
+ if (!equivalentOverlapStashRef) {
477
+ return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, featureBranch, targetBranch, before, steps, after: repositoryGitStatus(repository), completed: false, error: { code: 'GIT_EQUIVALENT_TARGET_STASH_REFERENCE_MISSING', message: 'Candidate-equivalent target paths were stashed but the recovery stash reference could not be resolved.' } };
478
+ }
479
+ }
480
+ const restoreEquivalentOverlap = (name: string): RepositoryGitExecution | undefined => {
481
+ if (!equivalentOverlapStashRef) return undefined;
482
+ const execution = executeRepositoryGitCommand(controllerHome, repository, { args: ['stash', 'apply', '--index', equivalentOverlapStashRef], authorization: finishAuthorization, ...input });
483
+ steps.push({ name, execution });
484
+ return execution;
485
+ };
486
+ const dropEquivalentOverlapStash = (): void => {
487
+ if (!equivalentOverlapStashRef) return;
488
+ const selector = stashSelectorForOid(repository, equivalentOverlapStashRef) ?? equivalentOverlapStashRef;
489
+ const execution = executeRepositoryGitCommand(controllerHome, repository, { args: ['stash', 'drop', selector], authorization: finishAuthorization, ...input });
490
+ steps.push({ name: 'drop_equivalent_target_stash', execution });
491
+ };
365
492
  let stashRef: string | null = null;
366
493
  if (protectTrackedChanges) {
367
494
  const stash = executeRepositoryGitCommand(controllerHome, repository, { args: ['stash', 'push', '-m', `forge-finish:${input.workId ?? featureBranch}`], authorization: finishAuthorization, ...input });
@@ -388,17 +515,30 @@ export function repositoryGitFinishWorkflow(controllerHome: string, repository:
388
515
  };
389
516
  const dropTrackedStash = (): void => {
390
517
  if (!stashRef) return;
391
- const execution = executeRepositoryGitCommand(controllerHome, repository, { args: ['stash', 'drop', stashRef], authorization: finishAuthorization, ...input });
518
+ const selector = stashSelectorForOid(repository, stashRef) ?? stashRef;
519
+ const execution = executeRepositoryGitCommand(controllerHome, repository, { args: ['stash', 'drop', selector], authorization: finishAuthorization, ...input });
392
520
  steps.push({ name: 'drop_target_stash', execution });
393
521
  };
394
522
  const merge = executeRepositoryGitCommand(controllerHome, repository, { args: ['merge', ...(input.noFf === true ? ['--no-ff'] : ['--ff-only']), featureBranch], authorization: finishAuthorization, ...input });
395
523
  steps.push({ name: 'merge_feature', execution: merge });
396
524
  if (merge.status !== 'executed' || merge.ok !== true) {
525
+ const restoreEquivalent = restoreEquivalentOverlap('restore_equivalent_target_overlap_after_merge_failure');
526
+ if (restoreEquivalent && (restoreEquivalent.status !== 'executed' || restoreEquivalent.ok !== true)) return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, featureBranch, targetBranch, before, steps, after: repositoryGitStatus(repository), completed: false, error: { code: 'GIT_EQUIVALENT_TARGET_RESTORE_FAILED', message: restoreEquivalent.stderr || 'Candidate-equivalent target paths could not be restored after merge failure; recovery stash was retained.' } };
527
+ dropEquivalentOverlapStash();
397
528
  const restore = applyTrackedStash('restore_target_changes_after_merge_failure');
398
529
  if (restore && (restore.status !== 'executed' || restore.ok !== true)) return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, featureBranch, targetBranch, before, steps, after: repositoryGitStatus(repository), completed: false, error: { code: 'GIT_LOCAL_CHANGES_RESTORE_FAILED', message: restore.stderr || 'git stash apply failed while restoring the pre-merge target state' } };
399
530
  dropTrackedStash();
400
531
  return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, featureBranch, targetBranch, before, steps, after: repositoryGitStatus(repository), completed: false, error: { code: 'GIT_MERGE_FAILED', message: merge.stderr || 'git merge failed' } };
401
532
  }
533
+ if (equivalentOverlappingDirtyPaths.length > 0) {
534
+ const afterMerge = repositoryGitStatus(repository);
535
+ const remainingDirty = new Set([...afterMerge.staged, ...afterMerge.unstaged, ...afterMerge.untracked]);
536
+ const contentMatchesCandidate = runGit(repository, ['diff', '--quiet', featureBranch, '--', ...equivalentOverlappingDirtyPaths], 32 * 1024).ok;
537
+ if (!contentMatchesCandidate || equivalentOverlappingDirtyPaths.some((path) => remainingDirty.has(path))) {
538
+ return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, featureBranch, targetBranch, before, steps, after: afterMerge, completed: false, error: { code: 'GIT_EQUIVALENT_TARGET_POSTCONDITION_FAILED', message: 'Integrated target did not retain the exact candidate content for a reconciled dirty overlap; recovery stash was retained.' } };
539
+ }
540
+ dropEquivalentOverlapStash();
541
+ }
402
542
  const reapply = applyTrackedStash('reapply_target_changes');
403
543
  if (reapply && (reapply.status !== 'executed' || reapply.ok !== true)) return { repoId: repository.repoId, checkoutId: repository.activeCheckoutId, featureBranch, targetBranch, before, steps, after: repositoryGitStatus(repository), completed: false, error: { code: 'GIT_LOCAL_CHANGES_RESTORE_FAILED', message: reapply.stderr || 'Tracked target changes passed merge-tree preflight but could not be reapplied after merge; recovery stash was retained.' } };
404
544
  dropTrackedStash();