@moretea-labs/forge 1.7.2 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (685) hide show
  1. package/AGENTS.md +58 -62
  2. package/CHANGELOG.md +26 -0
  3. package/CLAUDE.md +42 -62
  4. package/README.md +2 -2
  5. package/SKILL.md +0 -1
  6. package/THIRD_PARTY_NOTICES.md +5 -2
  7. package/adapters/browser/index.ts +2 -0
  8. package/adapters/chatgpt/browser-delivery-host.ts +71 -0
  9. package/adapters/chatgpt/browser-delivery-runtime.ts +783 -0
  10. package/adapters/chatgpt/controller-binding-store.ts +55 -0
  11. package/adapters/chatgpt/controller-host.ts +119 -0
  12. package/adapters/chatgpt/controller-round-host.ts +78 -0
  13. package/adapters/chatgpt/controller-round-settlement-store.ts +45 -0
  14. package/adapters/chatgpt/provider-delivery.ts +113 -0
  15. package/adapters/chatgpt/work-conversation-binding-store.ts +192 -0
  16. package/adapters/chatgpt/wsl-bridge-delivery-host.ts +63 -0
  17. package/adapters/computer/desktop-operator-contract.ts +7 -0
  18. package/adapters/computer/desktop-operator-discovery.ts +201 -0
  19. package/adapters/computer/desktop-operator-negotiation.ts +174 -0
  20. package/adapters/computer/desktop-operator-provider.ts +312 -0
  21. package/adapters/computer/index.ts +1 -0
  22. package/adapters/computer/interaction-target-authority.ts +944 -0
  23. package/adapters/controller-process/binding-store.ts +34 -0
  24. package/adapters/controller-process/controller-host.ts +26 -0
  25. package/adapters/mcp/access-mode.ts +132 -0
  26. package/adapters/mcp/audit.ts +32 -0
  27. package/adapters/mcp/auth.ts +407 -0
  28. package/adapters/mcp/controller-round-compatibility.ts +184 -0
  29. package/adapters/mcp/frozen-client-semantic-compatibility.ts +292 -0
  30. package/adapters/mcp/instructions.ts +36 -0
  31. package/adapters/mcp/legacy-context.ts +18 -0
  32. package/adapters/mcp/multi-repository.ts +437 -0
  33. package/adapters/mcp/oauth.ts +391 -0
  34. package/adapters/mcp/paths.ts +140 -0
  35. package/adapters/mcp/policy.ts +232 -0
  36. package/adapters/mcp/proxy-env.ts +62 -0
  37. package/adapters/mcp/readiness-projection.ts +24 -0
  38. package/adapters/mcp/redaction.ts +21 -0
  39. package/adapters/mcp/repo.ts +24 -0
  40. package/adapters/mcp/runtime-gateway/artifact-adapter.ts +52 -0
  41. package/adapters/mcp/runtime-gateway/context-adapter.ts +829 -0
  42. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +191 -0
  43. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +147 -0
  44. package/adapters/mcp/runtime-gateway/execution-control-adapter.ts +28 -0
  45. package/adapters/mcp/runtime-gateway/execution-tools.ts +207 -0
  46. package/adapters/mcp/runtime-gateway/filesystem-adapter.ts +38 -0
  47. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +411 -0
  48. package/adapters/mcp/runtime-gateway/legacy-ios-tool-adapter.ts +105 -0
  49. package/adapters/mcp/runtime-gateway/maintenance-adapter.ts +44 -0
  50. package/adapters/mcp/runtime-gateway/model-adapter.ts +63 -0
  51. package/adapters/mcp/runtime-gateway/persisted-check-process.ts +3 -0
  52. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +308 -0
  53. package/adapters/mcp/runtime-gateway/process-tools.ts +289 -0
  54. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +76 -0
  55. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +268 -0
  56. package/adapters/mcp/runtime-gateway/recovery-client-adapter.ts +70 -0
  57. package/adapters/mcp/runtime-gateway/recovery-tool-contract.ts +99 -0
  58. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +110 -0
  59. package/adapters/mcp/runtime-gateway/result-adapter.ts +108 -0
  60. package/adapters/mcp/runtime-gateway/router.ts +728 -0
  61. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1251 -0
  62. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +634 -0
  63. package/adapters/mcp/runtime-gateway/runtime-tool-shared.ts +27 -0
  64. package/adapters/mcp/runtime-gateway/runtime-tools.ts +68 -0
  65. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +186 -0
  66. package/adapters/mcp/runtime-gateway/shared-adapter.ts +25 -0
  67. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +870 -0
  68. package/adapters/mcp/runtime-gateway/work-adapter.ts +3186 -0
  69. package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +502 -0
  70. package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +1 -0
  71. package/adapters/mcp/server.ts +1048 -0
  72. package/adapters/mcp/setup.ts +791 -0
  73. package/adapters/mcp/tool-capability-cache.ts +87 -0
  74. package/adapters/mcp/tool-mapping/access-tools.ts +387 -0
  75. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +5265 -0
  76. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +150 -0
  77. package/adapters/mcp/tool-mapping/repository-tools.ts +1691 -0
  78. package/adapters/mcp/tool-mapping/tools.ts +9 -0
  79. package/adapters/mcp/tool-mapping/umbrella-tools.ts +117 -0
  80. package/adapters/mcp/toolset-names.ts +74 -0
  81. package/adapters/mcp/toolset-selection.ts +41 -0
  82. package/adapters/mcp/toolset.ts +336 -0
  83. package/adapters/mcp/transports/http.ts +1456 -0
  84. package/adapters/mcp/transports/session-registry.ts +513 -0
  85. package/adapters/mcp/transports/stdio.ts +8 -0
  86. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +139 -0
  87. package/adapters/mcp/types.ts +41 -0
  88. package/assets/AGENTS.md +2 -16
  89. package/assets/CLAUDE.md +2 -16
  90. package/assets/hooks/AGENTS.md +3 -14
  91. package/assets/hooks/CLAUDE.md +3 -14
  92. package/assets/hooks/hook-input.sh +9 -2
  93. package/assets/hooks/lib/workflow-state.sh +28 -10
  94. package/assets/hooks/prompt-guard.sh +63 -37
  95. package/assets/hooks/security-sentinel.sh +2 -1
  96. package/assets/hooks/session-start-context.sh +7 -5
  97. package/assets/hooks/stop-orchestrator.sh +13 -3
  98. package/assets/initializer-question-pack.v4.json +11 -7
  99. package/assets/partials/05-workflow.partial.md +18 -73
  100. package/assets/partials/07-footer.partial.md +1 -1
  101. package/assets/partials-agents/02-operating-mode.partial.md +1 -2
  102. package/assets/partials-agents/04-task-protocol.partial.md +14 -59
  103. package/assets/partials-agents/06-quality-safety.partial.md +11 -16
  104. package/assets/partials-agents/08-deep-docs.partial.md +1 -2
  105. package/assets/plan-map.json +11 -11
  106. package/assets/plugin-registry.v1.json +9 -3
  107. package/assets/plugin-trust-policy.v1.json +6 -0
  108. package/assets/recovery/ForgeRecovery.ps1 +100 -0
  109. package/assets/recovery/forge-wsl-rescue +271 -0
  110. package/assets/reference-configs/development-protocol.md +11 -15
  111. package/assets/reference-configs/document-generation.md +1 -1
  112. package/assets/reference-configs/global-working-rules.md +9 -1
  113. package/assets/reference-configs/harness-overview.md +22 -112
  114. package/assets/reference-configs/hook-operations.md +1 -1
  115. package/assets/reference-configs/sprint-contracts.md +2 -2
  116. package/assets/skill-version.json +2 -2
  117. package/assets/templates/helpers/architecture-event.ts +3 -34
  118. package/assets/templates/helpers/architecture-queue.sh +61 -10
  119. package/assets/templates/helpers/archive-workflow.sh +90 -180
  120. package/assets/templates/helpers/capability-config.ts +8 -11
  121. package/assets/templates/helpers/capability-resolver.ts +37 -19
  122. package/assets/templates/helpers/capture-plan.sh +2 -2
  123. package/assets/templates/helpers/check-architecture-sync.sh +1 -9
  124. package/assets/templates/helpers/check-task-sync.sh +82 -11
  125. package/assets/templates/helpers/check-task-workflow.sh +1 -3
  126. package/assets/templates/helpers/context-contract-sync.sh +1 -12
  127. package/assets/templates/helpers/contract-worktree.sh +26 -24
  128. package/assets/templates/helpers/ensure-task-workflow.sh +6 -8
  129. package/assets/templates/helpers/inspect-project-state.ts +1 -1
  130. package/assets/templates/helpers/migrate-project-template.sh +1 -1
  131. package/assets/templates/helpers/migrate-workflow-docs.ts +53 -239
  132. package/assets/templates/helpers/new-plan.sh +2 -2
  133. package/assets/templates/helpers/plan-to-todo.sh +3 -31
  134. package/assets/templates/helpers/sprint-backlog.sh +1 -1
  135. package/assets/templates/helpers/switch-plan.sh +1 -1
  136. package/assets/templates/helpers/workflow-contract.ts +1 -0
  137. package/assets/workflow-contract.v1.json +63 -171
  138. package/assets/workflows/xiaohongshu/xiaohongshu.collect-metrics.v1.draft.json +118 -0
  139. package/assets/workflows/xiaohongshu/xiaohongshu.publish-image-note.v1.draft.json +316 -0
  140. package/assets/workflows/xiaohongshu/xiaohongshu.publish-long-text.v1.draft.json +324 -0
  141. package/docs/architecture/CURRENT.md +148 -13
  142. package/docs/architecture/EVOLUTION.md +13 -0
  143. package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +2 -1
  144. package/docs/architecture/decisions/20260831-independent-windows-wsl-host-rescue.md +59 -0
  145. package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +120 -0
  146. package/docs/architecture/decisions/20260904-repository-runtime-data-boundary.md +42 -0
  147. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +35 -0
  148. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +296 -0
  149. package/docs/architecture/decisions/20260907-maintenance-diagnosis-bounded-read.md +39 -0
  150. package/docs/architecture/domains/verification.md +7 -0
  151. package/docs/architecture/domains/workflow-engine.md +1 -1
  152. package/docs/architecture/index.md +3 -3
  153. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +19 -8
  154. package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +124 -0
  155. package/docs/forge-chatgpt-mcp-setup.md +5 -3
  156. package/docs/forge-plugin-management.md +20 -4
  157. package/docs/forge-runtime-self-healing-loop.md +2 -0
  158. package/docs/operations/benchmark-cross-version-freeze.md +38 -0
  159. package/docs/operations/controller-browser-plugin.md +3 -1
  160. package/docs/operations/homebrew.md +2 -2
  161. package/docs/operations/platform-support.md +16 -8
  162. package/docs/operations/platform-support.zh-CN.md +2 -2
  163. package/docs/operations/standalone-disaster-recovery.md +26 -1
  164. package/docs/operations/uu-remote-rescue.md +41 -0
  165. package/docs/operations/windows-wsl-host-rescue.md +133 -0
  166. package/docs/public-usage-guide.md +1 -1
  167. package/docs/public-usage-guide.zh-CN.md +1 -1
  168. package/docs/tutorials/01-install-and-start.md +1 -1
  169. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  170. package/docs/tutorials/02-connect-chatgpt.md +4 -4
  171. package/docs/tutorials/02-connect-chatgpt.zh-CN.md +4 -4
  172. package/docs/wiki/Implementation.md +1 -1
  173. package/package.json +23 -14
  174. package/packages/kernel/controller/api/index.ts +2 -0
  175. package/packages/kernel/controller/application/controller-round-service.ts +29 -0
  176. package/packages/kernel/controller/application/controller-service.ts +30 -0
  177. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +308 -0
  178. package/packages/kernel/controller/domain/controller-round.ts +107 -0
  179. package/packages/kernel/controller/domain/execution-quality.ts +133 -0
  180. package/packages/kernel/controller/domain/types.ts +56 -0
  181. package/packages/kernel/controller/index.ts +1 -0
  182. package/packages/kernel/controller/infrastructure/controller-binding-store.ts +84 -0
  183. package/packages/kernel/controller/infrastructure/controller-round-store.ts +1384 -0
  184. package/packages/kernel/controller/infrastructure/controller-session-store.ts +578 -0
  185. package/packages/kernel/controller/ports/controller-host.ts +16 -0
  186. package/packages/kernel/goal/api/index.ts +1 -0
  187. package/packages/kernel/goal/domain/types.ts +40 -0
  188. package/packages/kernel/goal/index.ts +1 -0
  189. package/packages/kernel/identity/api/index.ts +5 -0
  190. package/packages/kernel/identity/application/identity-service.ts +67 -0
  191. package/packages/kernel/identity/domain/scope.ts +63 -0
  192. package/packages/kernel/identity/domain/semantic-sync.ts +81 -0
  193. package/packages/kernel/identity/domain/types.ts +44 -0
  194. package/packages/kernel/identity/domain/workspace.ts +56 -0
  195. package/packages/kernel/identity/index.ts +1 -0
  196. package/packages/kernel/identity/infrastructure/identity-store.ts +75 -0
  197. package/packages/kernel/memory/api/index.ts +5 -0
  198. package/packages/kernel/memory/application/experience-service.ts +118 -0
  199. package/packages/kernel/memory/application/outcome-service.ts +77 -0
  200. package/packages/kernel/memory/domain/experience.ts +103 -0
  201. package/packages/kernel/memory/domain/operational-prior.ts +92 -0
  202. package/packages/kernel/memory/index.ts +1 -0
  203. package/packages/kernel/progression/api/index.ts +2 -0
  204. package/packages/kernel/progression/application/projector.ts +211 -0
  205. package/packages/kernel/progression/domain/types.ts +116 -0
  206. package/packages/kernel/progression/index.ts +1 -0
  207. package/packages/kernel/scheduler/api/index.ts +6 -0
  208. package/packages/kernel/scheduler/application/continuation-service.ts +212 -0
  209. package/packages/kernel/scheduler/application/eligibility.ts +252 -0
  210. package/packages/kernel/scheduler/application/schedule-service.ts +24 -0
  211. package/packages/kernel/scheduler/application/settlement.ts +197 -0
  212. package/packages/kernel/scheduler/domain/continuation.ts +38 -0
  213. package/packages/kernel/scheduler/domain/schedule.ts +149 -0
  214. package/packages/kernel/scheduler/index.ts +1 -0
  215. package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +38 -0
  216. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +785 -0
  217. package/packages/kernel/work/api/index.ts +15 -0
  218. package/packages/kernel/work/application/work-service.ts +148 -0
  219. package/packages/kernel/work/domain/admission-policy.ts +34 -0
  220. package/packages/kernel/work/domain/check-receipt.ts +43 -0
  221. package/packages/kernel/work/domain/context-closure-receipt.ts +32 -0
  222. package/packages/kernel/work/domain/engineering-contracts.ts +157 -0
  223. package/packages/kernel/work/domain/engineering-design.ts +281 -0
  224. package/packages/kernel/work/domain/engineering-profile.ts +242 -0
  225. package/packages/kernel/work/domain/execution-concurrency.ts +254 -0
  226. package/packages/kernel/work/domain/execution-snapshot.ts +33 -0
  227. package/packages/kernel/work/domain/implementation-review.ts +510 -0
  228. package/packages/kernel/work/domain/project-engineering-contract.ts +202 -0
  229. package/packages/kernel/work/domain/repository-completion-receipt.ts +73 -0
  230. package/packages/kernel/work/domain/state-machine.ts +259 -0
  231. package/packages/kernel/work/domain/types.ts +528 -0
  232. package/packages/kernel/work/index.ts +1 -0
  233. package/packages/kernel/work/infrastructure/work-contract-store.ts +1876 -0
  234. package/packages/kernel/work/ports/work-contract-store.ts +18 -0
  235. package/packages/plugin-runtime/browser/index.ts +3 -0
  236. package/packages/plugin-runtime/browser/provider-registry.ts +110 -0
  237. package/packages/plugin-runtime/browser/runtime-contract.ts +150 -0
  238. package/packages/plugin-runtime/browser/session-authority.ts +61 -0
  239. package/packages/plugin-runtime/computer/index.ts +6 -0
  240. package/packages/plugin-runtime/computer/provider-error.ts +26 -0
  241. package/packages/plugin-runtime/computer/provider-registration.ts +52 -0
  242. package/packages/plugin-runtime/computer/provider-registry.ts +63 -0
  243. package/packages/plugin-runtime/computer/provider.ts +19 -0
  244. package/packages/plugin-runtime/computer/target-authority.ts +190 -0
  245. package/packages/plugin-runtime/computer/target-persistence.ts +54 -0
  246. package/packages/plugin-runtime/external/index.ts +1 -0
  247. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +457 -0
  248. package/packages/plugin-runtime/index.ts +3 -0
  249. package/packages/protocols/browser/index.ts +1 -0
  250. package/packages/protocols/browser/session.ts +98 -0
  251. package/packages/protocols/computer/contract.ts +199 -0
  252. package/packages/protocols/computer/index.ts +1 -0
  253. package/packages/protocols/failure/contract.ts +158 -0
  254. package/packages/protocols/failure/index.ts +1 -0
  255. package/packages/protocols/handoff/index.ts +1 -0
  256. package/packages/protocols/handoff/status.ts +22 -0
  257. package/packages/protocols/mcp/execution-context.ts +11 -0
  258. package/packages/protocols/mcp/index.ts +2 -0
  259. package/packages/protocols/mcp/tool-contract.ts +42 -0
  260. package/packages/workflow-runtime/api/index.ts +2 -0
  261. package/packages/workflow-runtime/application/interpreter.ts +342 -0
  262. package/packages/workflow-runtime/domain/workflow-asset.ts +223 -0
  263. package/packages/workflow-runtime/index.ts +1 -0
  264. package/scripts/assemble-template.ts +1 -1
  265. package/scripts/benchmark-computer-hotpath.ts +255 -0
  266. package/scripts/benchmark-controller-round2.ts +54 -2
  267. package/scripts/benchmark-ios-agent-device.ts +3 -6
  268. package/scripts/benchmark-mcp-transport.ts +3 -4
  269. package/scripts/benchmark-operational-memory-activation.ts +235 -0
  270. package/scripts/benchmark-operational-shadow.ts +28 -0
  271. package/scripts/bootstrap-runtime-maintenance-recovery.sh +4 -1
  272. package/scripts/canary-chatgpt-provider-delivery.ts +97 -0
  273. package/scripts/canary-controller-semantic-wait.ts +195 -0
  274. package/scripts/canary-global-hook.sh +2 -2
  275. package/scripts/check-mcp-compatibility.ts +173 -7
  276. package/scripts/check-platform-support.mjs +28 -2
  277. package/scripts/check-public-docs.sh +1 -1
  278. package/scripts/check-release-readiness.sh +1 -1
  279. package/scripts/check-repository-hygiene.mjs +92 -0
  280. package/scripts/check-runtime-architecture.mjs +1206 -95
  281. package/scripts/check-source-duplication.mjs +9 -1
  282. package/scripts/check-tarball-install-smoke.sh +98 -15
  283. package/scripts/controller-ngrok-rotation.sh +5 -4
  284. package/scripts/create-project-dirs.sh +10 -74
  285. package/scripts/forge-local-recovery-helper.mjs +204 -0
  286. package/scripts/forge-uu-remote-rescue-helper.d.mts +31 -0
  287. package/scripts/forge-uu-remote-rescue-helper.mjs +409 -0
  288. package/scripts/forge-windows-host-recovery-helper.mjs +136 -0
  289. package/scripts/hook-shim.sh +2 -2
  290. package/scripts/init-project.sh +12 -70
  291. package/scripts/install-desktop-operator-registration.ts +4 -2
  292. package/scripts/install-independent-windows-wsl-recovery.ts +125 -0
  293. package/scripts/install-standalone-recovery.ts +122 -10
  294. package/scripts/install-uu-remote-rescue-registration.ts +74 -0
  295. package/scripts/install-windows-host-recovery-registration.ts +22 -0
  296. package/scripts/lib/controller-home-env.sh +6 -3
  297. package/scripts/lib/project-init-lib.sh +39 -582
  298. package/scripts/migrate-chatgpt-automation-schedules.ts +2 -2
  299. package/scripts/migrate-windows-wsl-controller-home.ts +306 -0
  300. package/scripts/open-source-audit-allowlist.txt +12 -1
  301. package/scripts/portability-bindings.mjs +70 -0
  302. package/scripts/run-bounded-command.mjs +55 -0
  303. package/scripts/run-bun-test-file.ts +22 -6
  304. package/scripts/run-governed-gate.ts +4 -1
  305. package/scripts/smoke-mcp-http-runtime.ts +1 -1
  306. package/scripts/smoke-runtime-recovery.ts +34 -1
  307. package/scripts/smoke-schedule-engine.ts +1 -1
  308. package/scripts/stage-runtime-release.ts +6 -1
  309. package/scripts/test-governance.ts +51 -2
  310. package/src/cli/agent-jobs/job-manager.ts +10 -1
  311. package/src/cli/chatgpt-browser/bind-server.ts +2 -1
  312. package/src/cli/chatgpt-browser/binding.ts +20 -10
  313. package/src/cli/chatgpt-browser/bridge-extension.ts +75 -0
  314. package/src/cli/chatgpt-browser/bridge-provider.ts +376 -11
  315. package/src/cli/chatgpt-browser/engine.ts +10 -11
  316. package/src/cli/chatgpt-browser/native-provider.ts +24 -83
  317. package/src/cli/chatgpt-browser/oracle-provider.ts +5 -3
  318. package/src/cli/chatgpt-browser/types.ts +1 -0
  319. package/src/cli/commands/bootstrap-control.ts +334 -0
  320. package/src/cli/commands/brain-assistant.ts +38 -0
  321. package/src/cli/commands/brain.ts +193 -40
  322. package/src/cli/commands/chatgpt.ts +127 -0
  323. package/src/cli/commands/computer.ts +437 -0
  324. package/src/cli/commands/doctor.ts +18 -1
  325. package/src/cli/commands/init-hook.ts +71 -61
  326. package/src/cli/commands/init.ts +3 -1
  327. package/src/cli/commands/mcp.ts +16 -10
  328. package/src/cli/commands/plugin.ts +38 -12
  329. package/src/cli/commands/recovery.ts +493 -80
  330. package/src/cli/commands/runtime.ts +9 -4
  331. package/src/cli/commands/setup-profile.ts +89 -39
  332. package/src/cli/commands/status.ts +2 -1
  333. package/src/cli/controller/check-runner.ts +487 -98
  334. package/src/cli/controller/context/types.ts +7 -1
  335. package/src/cli/controller/context-pack.ts +23 -3
  336. package/src/cli/controller/issue-store.ts +1 -1
  337. package/src/cli/controller/systemd-user.ts +110 -0
  338. package/src/cli/controller/types.ts +10 -70
  339. package/src/cli/controller/worklog.ts +67 -13
  340. package/src/cli/editing/edit-operation-contract.ts +92 -0
  341. package/src/cli/editing/edit-session.ts +289 -13
  342. package/src/cli/github/plugin.ts +17 -12
  343. package/src/cli/hook/route-registry.ts +3 -5
  344. package/src/cli/hook/runtime.ts +49 -3
  345. package/src/cli/index.ts +3 -0
  346. package/src/cli/local-bridge/connector-freshness.ts +2 -2
  347. package/src/cli/local-bridge/console-automations.ts +2 -2
  348. package/src/cli/local-bridge/facade-api.ts +41 -14
  349. package/src/cli/local-bridge/job-store.ts +1 -1
  350. package/src/cli/local-bridge/server.ts +24 -27
  351. package/src/cli/mcp/access-mode.ts +2 -132
  352. package/src/cli/mcp/access-tools.ts +2 -387
  353. package/src/cli/mcp/audit.ts +2 -32
  354. package/src/cli/mcp/auth.ts +2 -404
  355. package/src/cli/mcp/instructions.ts +2 -34
  356. package/src/cli/mcp/legacy-context.ts +2 -16
  357. package/src/cli/mcp/legacy-tool-service.ts +2 -5308
  358. package/src/cli/mcp/multi-repository.ts +2 -436
  359. package/src/cli/mcp/oauth.ts +2 -375
  360. package/src/cli/mcp/openai-secure-tunnel.ts +2 -0
  361. package/src/cli/mcp/paths.ts +2 -140
  362. package/src/cli/mcp/policy.ts +2 -232
  363. package/src/cli/mcp/post-finalize-work-attribution.ts +2 -150
  364. package/src/cli/mcp/proxy-env.ts +2 -62
  365. package/src/cli/mcp/readiness-projection.ts +2 -24
  366. package/src/cli/mcp/redaction.ts +2 -21
  367. package/src/cli/mcp/repo.ts +2 -24
  368. package/src/cli/mcp/repository-tools.ts +2 -1613
  369. package/src/cli/mcp/server.ts +2 -951
  370. package/src/cli/mcp/setup.ts +2 -737
  371. package/src/cli/mcp/tool-capability-cache.ts +2 -87
  372. package/src/cli/mcp/tool-contract.ts +2 -14
  373. package/src/cli/mcp/tools.ts +2 -9
  374. package/src/cli/mcp/toolset-names.ts +2 -70
  375. package/src/cli/mcp/toolset-selection.ts +2 -41
  376. package/src/cli/mcp/toolset.ts +2 -336
  377. package/src/cli/mcp/transports/AGENTS.md +1 -10
  378. package/src/cli/mcp/transports/CLAUDE.md +1 -10
  379. package/src/cli/mcp/transports/http.ts +2 -1414
  380. package/src/cli/mcp/transports/session-registry.ts +2 -490
  381. package/src/cli/mcp/transports/stdio.ts +2 -8
  382. package/src/cli/mcp/types.ts +2 -41
  383. package/src/cli/mcp/umbrella-tools.ts +2 -117
  384. package/src/cli/repositories/command-executor.ts +64 -18
  385. package/src/cli/repositories/command-scope.ts +117 -1
  386. package/src/cli/repositories/controller-home.ts +119 -1
  387. package/src/cli/repositories/identity.ts +13 -0
  388. package/src/cli/repositories/registry.ts +68 -49
  389. package/src/cli/repositories/repository-snapshot.ts +53 -7
  390. package/src/cli/repositories/runtime-storage.ts +27 -2
  391. package/src/cli/repositories/safe-patch.ts +34 -38
  392. package/src/cli/repositories/selected-path-actions.ts +22 -2
  393. package/src/cli/repositories/structured-git.ts +105 -25
  394. package/src/cli/runtime/helper-runner.ts +7 -0
  395. package/src/cli/runtime-invocation.ts +8 -1
  396. package/src/cli/tools/codegraph.ts +44 -25
  397. package/src/core/adoption/manifest-templates.ts +1 -1
  398. package/src/core/adoption/plan.ts +3 -26
  399. package/src/core/adoption/workflow-contract-plan.ts +17 -9
  400. package/src/effects/process-runner.ts +8 -14
  401. package/src/runtime/context/assistant-context.ts +154 -0
  402. package/src/runtime/context/assistant-work-context.ts +147 -0
  403. package/src/runtime/context/codegraph-cache-boundary.ts +255 -0
  404. package/src/runtime/context/codegraph-read-provider.ts +55 -22
  405. package/src/runtime/context/codegraph-sidecar.cjs +8 -1
  406. package/src/runtime/context/context-closure.ts +268 -0
  407. package/src/runtime/context/context-plane.ts +211 -0
  408. package/src/runtime/context/project-engineering-contract.ts +60 -0
  409. package/src/runtime/control-plane/bootstrap/capability-provider.ts +74 -0
  410. package/src/runtime/control-plane/bootstrap/control-api.ts +57 -0
  411. package/src/runtime/control-plane/bootstrap/index.ts +5 -0
  412. package/src/runtime/control-plane/bootstrap/state-machine.ts +141 -0
  413. package/src/runtime/control-plane/bootstrap/store.ts +21 -0
  414. package/src/runtime/control-plane/bootstrap/types.ts +87 -0
  415. package/src/runtime/control-plane/cleanup-artifact-retention.ts +328 -0
  416. package/src/runtime/control-plane/codegraph-cache-retention.ts +164 -0
  417. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +320 -0
  418. package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +169 -0
  419. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +350 -0
  420. package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +85 -0
  421. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +369 -99
  422. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +103 -15
  423. package/src/runtime/control-plane/execution/implementation-review-content.ts +95 -0
  424. package/src/runtime/control-plane/execution/repository-work-attribution.ts +2 -2
  425. package/src/runtime/control-plane/execution/retained-work-resume.ts +336 -6
  426. package/src/runtime/control-plane/execution/validation.ts +28 -3
  427. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +116 -0
  428. package/src/runtime/control-plane/execution/work-completion-authority.ts +44 -2
  429. package/src/runtime/control-plane/execution/work-evidence-policy.ts +34 -3
  430. package/src/runtime/control-plane/execution/work-execution-support.ts +42 -22
  431. package/src/runtime/control-plane/execution/work-finalization-service.ts +1103 -166
  432. package/src/runtime/control-plane/execution/work-handle-authority.ts +219 -22
  433. package/src/runtime/control-plane/execution/work-handle-store.ts +77 -0
  434. package/src/runtime/control-plane/execution/work-head-settlement.ts +75 -0
  435. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +145 -23
  436. package/src/runtime/control-plane/execution/work-operation-service.ts +49 -13
  437. package/src/runtime/control-plane/execution/work-preparation-service.ts +31 -15
  438. package/src/runtime/control-plane/execution/work-remote-delivery.ts +1 -1
  439. package/src/runtime/control-plane/execution/work-task-receipt.ts +20 -1
  440. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +407 -76
  441. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +88 -18
  442. package/src/runtime/control-plane/execution/work-verification-context.ts +1 -1
  443. package/src/runtime/control-plane/execution/work-verification-service.ts +258 -4
  444. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +200 -15
  445. package/src/runtime/control-plane/facade/capability-registry.ts +21 -10
  446. package/src/runtime/control-plane/facade/controller-round-relay.ts +3 -1118
  447. package/src/runtime/control-plane/facade/controller-session-store.ts +2 -488
  448. package/src/runtime/control-plane/facade/goal-workloop-access.ts +6 -3
  449. package/src/runtime/control-plane/facade/goal-workloop.ts +972 -137
  450. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +158 -0
  451. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +10 -0
  452. package/src/runtime/control-plane/facade/index.ts +4 -2
  453. package/src/runtime/control-plane/facade/operation-digest.ts +22 -58
  454. package/src/runtime/control-plane/facade/plan-contract-store.ts +1004 -38
  455. package/src/runtime/control-plane/facade/repository-work-admission.ts +19 -1
  456. package/src/runtime/control-plane/facade/requirement-authority.ts +218 -0
  457. package/src/runtime/control-plane/facade/requirement-board.ts +6 -1
  458. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +48 -0
  459. package/src/runtime/control-plane/facade/semantic-admission.ts +8 -16
  460. package/src/runtime/control-plane/facade/suggested-actions.ts +4 -1
  461. package/src/runtime/control-plane/facade/types.ts +189 -532
  462. package/src/runtime/control-plane/facade/work-admission-policy.ts +84 -35
  463. package/src/runtime/control-plane/facade/work-contract-store.ts +2 -1043
  464. package/src/runtime/control-plane/facade/work-implementation-review.ts +2 -0
  465. package/src/runtime/control-plane/facade/work-state-machine.ts +2 -250
  466. package/src/runtime/control-plane/generated-cache-retention.ts +239 -18
  467. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +12 -1
  468. package/src/runtime/control-plane/global-scheduler/maintenance.ts +76 -13
  469. package/src/runtime/control-plane/global-scheduler/periodic-cleanup-entry.ts +55 -0
  470. package/src/runtime/control-plane/global-scheduler/periodic-cleanup-process.ts +98 -0
  471. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +1 -1
  472. package/src/runtime/control-plane/global-scheduler/scheduler-worker-entry.ts +10 -0
  473. package/src/runtime/control-plane/global-scheduler/scheduler.ts +173 -81
  474. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +18 -6
  475. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +397 -0
  476. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +2 -177
  477. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +301 -560
  478. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +20 -4
  479. package/src/runtime/control-plane/launcher/thin-launcher.ts +50 -4
  480. package/src/runtime/control-plane/lifecycle-retention-metrics.ts +60 -0
  481. package/src/runtime/control-plane/persistence/experience-store.ts +169 -0
  482. package/src/runtime/control-plane/persistence/operational-prior-store.ts +348 -0
  483. package/src/runtime/control-plane/persistence/requirement-store.ts +30 -22
  484. package/src/runtime/control-plane/persistence/sqlite-store.ts +545 -76
  485. package/src/runtime/control-plane/persistence/workflow-content-store.ts +98 -0
  486. package/src/runtime/control-plane/persistence/workflow-registry-store.ts +186 -0
  487. package/src/runtime/control-plane/persistence/workflow-run-store.ts +123 -0
  488. package/src/runtime/control-plane/release-retention.ts +56 -16
  489. package/src/runtime/control-plane/repository-namespace-retention.ts +208 -0
  490. package/src/runtime/control-plane/routing/route-policy.ts +19 -0
  491. package/src/runtime/control-plane/runtime-cleanup.ts +574 -37
  492. package/src/runtime/control-plane/runtime-generation.ts +6 -0
  493. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +465 -0
  494. package/src/runtime/control-plane/workspace/workspace-store.ts +80 -0
  495. package/src/runtime/diagnostics/incident-repair.ts +406 -0
  496. package/src/runtime/diagnostics/mcp-timing.ts +125 -6
  497. package/src/runtime/diagnostics/performance.ts +6 -14
  498. package/src/runtime/diagnostics/read-only-tool.ts +1 -1
  499. package/src/runtime/evidence/artifact-store.ts +65 -2
  500. package/src/runtime/evidence/operational-shadow.ts +38 -0
  501. package/src/runtime/evidence/process-check-receipt.ts +5 -43
  502. package/src/runtime/evidence/sensitive-output.ts +4 -4
  503. package/src/runtime/execution/jobs/receipt-recovery.ts +1 -1
  504. package/src/runtime/execution/jobs/store.ts +121 -2
  505. package/src/runtime/execution/managed-workspace.ts +55 -5
  506. package/src/runtime/execution/process-runtime/canary.ts +19 -5
  507. package/src/runtime/execution/process-runtime/check-classification.ts +48 -0
  508. package/src/runtime/execution/process-runtime/check-facade.ts +23 -9
  509. package/src/runtime/execution/process-runtime/check-receipt.ts +1 -1
  510. package/src/runtime/execution/process-runtime/check-result-retention.ts +132 -0
  511. package/src/runtime/execution/process-runtime/check-result.ts +73 -2
  512. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +42 -3
  513. package/src/runtime/execution/process-runtime/check-storage.ts +187 -0
  514. package/src/runtime/execution/process-runtime/command-facade.ts +38 -87
  515. package/src/runtime/execution/process-runtime/index.ts +1 -0
  516. package/src/runtime/execution/process-runtime/interactive-admission.ts +2 -1
  517. package/src/runtime/execution/process-runtime/lightweight-managed.ts +32 -1
  518. package/src/runtime/execution/process-runtime/persisted-check.ts +128 -21
  519. package/src/runtime/execution/process-runtime/resource-claims.ts +60 -3
  520. package/src/runtime/execution/process-runtime/runtime.ts +132 -15
  521. package/src/runtime/execution/process-runtime/types.ts +22 -0
  522. package/src/runtime/execution/workers/executor.ts +16 -13
  523. package/src/runtime/execution/workers/worker-entry.ts +1 -1
  524. package/src/runtime/gateway/mcp/execution-tools.ts +2 -207
  525. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +2 -61
  526. package/src/runtime/gateway/mcp/persisted-check-process.ts +2 -3
  527. package/src/runtime/gateway/mcp/process-tools.ts +2 -289
  528. package/src/runtime/gateway/mcp/router.ts +2 -1125
  529. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +2 -565
  530. package/src/runtime/gateway/mcp/runtime-tools.ts +2 -6655
  531. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +2 -1
  532. package/src/runtime/maintenance/cleanup.ts +38 -24
  533. package/src/runtime/platform/browser-product-discovery.ts +174 -0
  534. package/src/runtime/platform/computer-platform.ts +14 -0
  535. package/src/runtime/platform/executable-discovery.ts +54 -0
  536. package/src/runtime/platform/fetch-http-server.ts +90 -0
  537. package/src/runtime/platform/service-manager.ts +138 -0
  538. package/src/runtime/platform/windows-host-discovery.ts +118 -0
  539. package/src/runtime/platform/windows-recovery-deployment.ts +67 -0
  540. package/src/runtime/plugins/action-application.ts +135 -0
  541. package/src/runtime/plugins/app-store-connect-adapter.ts +9 -21
  542. package/src/runtime/plugins/browser-adapter.ts +140 -100
  543. package/src/runtime/plugins/browser-automation-service.ts +15 -36
  544. package/src/runtime/plugins/browser-macos-bridge.ts +69 -21
  545. package/src/runtime/plugins/browser-manifest-surface.ts +30 -6
  546. package/src/runtime/plugins/browser-native-session-service.ts +1 -1
  547. package/src/runtime/plugins/browser-provider-registry.ts +2 -109
  548. package/src/runtime/plugins/browser-registration.ts +16 -0
  549. package/src/runtime/plugins/browser-runtime-contract.ts +2 -154
  550. package/src/runtime/plugins/browser-runtime.ts +41 -9
  551. package/src/runtime/plugins/browser-session-authority.ts +101 -291
  552. package/src/runtime/plugins/browser-session-legacy-migration.ts +203 -0
  553. package/src/runtime/plugins/browser-session-store.ts +229 -36
  554. package/src/runtime/plugins/browser-session-types.ts +2 -98
  555. package/src/runtime/plugins/capability-authorization-grants.ts +17 -0
  556. package/src/runtime/plugins/catalog-trust.ts +82 -0
  557. package/src/runtime/plugins/computer-registration.ts +839 -0
  558. package/src/runtime/plugins/config-store.ts +119 -0
  559. package/src/runtime/plugins/desktop-operator-external-policy.ts +932 -0
  560. package/src/runtime/plugins/desktop-operator-registration.ts +111 -8
  561. package/src/runtime/plugins/errors.ts +8 -1
  562. package/src/runtime/plugins/external-adapter.ts +45 -322
  563. package/src/runtime/plugins/external-provider-policy.ts +48 -0
  564. package/src/runtime/plugins/external-registration.ts +9 -1
  565. package/src/runtime/plugins/external-unix-socket-probe.cjs +9 -3
  566. package/src/runtime/plugins/external-unix-socket.ts +64 -193
  567. package/src/runtime/plugins/first-party-external-registration.ts +163 -0
  568. package/src/runtime/plugins/first-party-registry.ts +3 -1
  569. package/src/runtime/plugins/github-adapter.ts +1 -2
  570. package/src/runtime/plugins/gmail-adapter.ts +6 -6
  571. package/src/runtime/plugins/google-calendar-adapter.ts +6 -6
  572. package/src/runtime/plugins/google-shared.ts +31 -46
  573. package/src/runtime/plugins/google-tasks-adapter.ts +6 -6
  574. package/src/runtime/plugins/ios-adapter.ts +1 -2
  575. package/src/runtime/plugins/local-system-adapter.ts +180 -0
  576. package/src/runtime/plugins/macos-capability-broker.ts +15 -105
  577. package/src/runtime/plugins/resend-adapter.ts +15 -24
  578. package/src/runtime/plugins/store.ts +493 -51
  579. package/src/runtime/plugins/types.ts +8 -1
  580. package/src/runtime/plugins/uu-remote-rescue-registration.ts +155 -0
  581. package/src/runtime/plugins/windows-host-recovery-install.ts +68 -0
  582. package/src/runtime/plugins/windows-host-recovery-registration.ts +85 -0
  583. package/src/runtime/plugins/xiaohongshu-publish.ts +86 -430
  584. package/src/runtime/projections/controller-context.ts +12 -6
  585. package/src/runtime/projections/git-status-sampler.ts +73 -22
  586. package/src/runtime/projections/materialized-view.ts +14 -8
  587. package/src/runtime/recovery/capability-action-application.ts +228 -0
  588. package/src/runtime/recovery/index.ts +3 -0
  589. package/src/runtime/recovery/lifecycle-inventory.ts +338 -0
  590. package/src/runtime/recovery/local-jobs-repair.ts +14 -14
  591. package/src/runtime/recovery/maintenance-executor.ts +358 -76
  592. package/src/runtime/recovery/quarantine-retention.ts +256 -0
  593. package/src/runtime/release/identity.ts +6 -0
  594. package/src/runtime/resources/leases/store.ts +1 -1
  595. package/src/runtime/root/active-execution-power-assertion.ts +139 -0
  596. package/src/runtime/root/assistant-learning-loop.ts +45 -0
  597. package/src/runtime/root/browser-session-composition.ts +59 -0
  598. package/src/runtime/root/computer-composition.ts +191 -0
  599. package/src/runtime/root/computer-target-composition.ts +16 -0
  600. package/src/runtime/root/computer-target-persistence.ts +39 -0
  601. package/src/runtime/root/controller-round-composition.ts +107 -0
  602. package/src/runtime/root/controller-services.ts +2 -0
  603. package/src/runtime/root/entry.ts +4 -3
  604. package/src/runtime/root/gateway-adapter.ts +3 -3
  605. package/src/runtime/root/local-bridge.ts +5 -2
  606. package/src/runtime/root/mcp-transport.ts +5 -5
  607. package/src/runtime/root/package-connector-service.ts +108 -56
  608. package/src/runtime/root/package-runtime-release.ts +85 -18
  609. package/src/runtime/root/package-runtime-service.ts +60 -97
  610. package/src/runtime/root/release-execution-canary.ts +71 -0
  611. package/src/runtime/root/release-loader.ts +68 -0
  612. package/src/runtime/root/release-manifest.ts +106 -2
  613. package/src/runtime/root/release-materialize.ts +103 -4
  614. package/src/runtime/root/release-store.ts +31 -2
  615. package/src/runtime/root/runtime.ts +240 -25
  616. package/src/runtime/root/scheduled-controller-composition.ts +51 -0
  617. package/src/runtime/root/scheduler.ts +12 -4
  618. package/src/runtime/root/service-runner.ts +1 -1
  619. package/src/runtime/root/service.ts +41 -16
  620. package/src/runtime/root/status.ts +1 -0
  621. package/src/runtime/root/types.ts +24 -1
  622. package/src/runtime/shared/local-bridge-surface.ts +1 -1
  623. package/src/runtime/shared/process-environment.ts +19 -4
  624. package/src/runtime/shared/storage-capacity.ts +68 -0
  625. package/src/runtime/standalone-recovery/controller-home-migration.ts +1116 -0
  626. package/src/runtime/standalone-recovery/core.ts +984 -230
  627. package/src/runtime/standalone-recovery/entry.ts +182 -51
  628. package/src/runtime/standalone-recovery/independent-host-rescue.ts +172 -0
  629. package/src/runtime/standalone-recovery/installer.ts +212 -104
  630. package/src/runtime/standalone-recovery/mcp-server.ts +243 -0
  631. package/src/runtime/standalone-recovery/mutation-identity-contract.ts +21 -0
  632. package/src/runtime/standalone-recovery/operation-lock.ts +160 -0
  633. package/src/runtime/standalone-recovery/performance.ts +135 -0
  634. package/src/runtime/standalone-recovery/release.ts +5 -0
  635. package/src/runtime/watchdog/workflow-watchdog.ts +1 -1
  636. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +1 -1
  637. package/src/runtime/workflow/schedules/engine.ts +191 -343
  638. package/src/runtime/workflow/schedules/pending-activation.ts +1 -1
  639. package/src/runtime/workflow/schedules/settlement.ts +2 -191
  640. package/src/runtime/workflow/schedules/store.ts +2 -607
  641. package/src/runtime/workflow/schedules/types.ts +2 -127
  642. package/src/runtime/workflow/schedules/work-continuation.ts +180 -15
  643. package/src/runtime/workflows/first-party/xiaohongshu.ts +122 -0
  644. package/src/runtime/workflows/runtime.ts +486 -0
  645. package/src/testing/test-governance.ts +90 -29
  646. package/assets/templates/helpers/archive-architecture-request.sh +0 -244
  647. package/docs/architecture/history/README.md +0 -7
  648. package/docs/architecture/history/chatgpt-handoff-facade.md +0 -397
  649. package/docs/architecture/history/global-hook-runtime.md +0 -166
  650. package/docs/architecture/history/ios-semantic-automation-provider-v2.md +0 -170
  651. package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  652. package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +0 -59
  653. package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +0 -59
  654. package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +0 -59
  655. package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +0 -59
  656. package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  657. package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  658. package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  659. package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  660. package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +0 -59
  661. package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  662. package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  663. package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  664. package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  665. package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  666. package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  667. package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  668. package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  669. package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  670. package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +0 -59
  671. package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +0 -59
  672. package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +0 -63
  673. package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
  674. package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
  675. package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
  676. package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
  677. package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +0 -60
  678. package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +0 -60
  679. package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +0 -68
  680. package/docs/architecture/requests/archive/2026/root.md +0 -68
  681. package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +0 -76
  682. package/docs/architecture/requests/archive/2026/verification-evals-checks.md +0 -68
  683. package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +0 -69
  684. package/scripts/archive-architecture-request.sh +0 -4
  685. package/scripts/run-skill-evals.ts +0 -1022
@@ -1,5 +1,5 @@
1
1
  import { createHash, randomBytes } from 'crypto';
2
- import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'fs';
2
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'fs';
3
3
  import { dirname, join, relative } from 'path';
4
4
  import { atomicWriteFile } from '../../effects/fs-transaction';
5
5
  import { runProcess } from '../../effects/process-runner';
@@ -13,6 +13,8 @@ import { globMatches, resolveMcpPath } from '../mcp/paths';
13
13
  import type { McpPolicy } from '../mcp/types';
14
14
  import type { ProcessCheckCompletionReceipt, ProcessCheckReceiptStatus } from '../../runtime/execution/process-runtime/check-receipt';
15
15
  import { invalidateRepositoryReadCaches } from '../repository/inspector';
16
+ import type { EditOperation } from './edit-operation-contract';
17
+ export type { EditOperation } from './edit-operation-contract';
16
18
 
17
19
  export type EditSessionStatus =
18
20
  | 'open'
@@ -129,6 +131,8 @@ export interface EditSession {
129
131
  export interface EditSessionSummary {
130
132
  sessionId: string;
131
133
  purpose: string;
134
+ /** Derived ownership identity for cheap lifecycle inventory; never a second Work authority. */
135
+ workId?: string;
132
136
  status: EditSessionStatus;
133
137
  issueId?: string;
134
138
  taskId?: string;
@@ -197,17 +201,39 @@ export class EditSessionPatchError extends Error {
197
201
  }
198
202
  }
199
203
 
200
- export type EditOperation =
201
- | { type: 'create'; path: string; content: string }
202
- | { type: 'write'; path: string; expectedSha256: string; content: string }
203
- | { type: 'replace'; path: string; expectedSha256: string; replacements: Array<{ oldText: string; newText: string; replaceAll?: boolean }> }
204
- | { type: 'insert_before' | 'insert_after'; path: string; expectedSha256: string; anchor: string; content: string; occurrence?: number }
205
- | { type: 'prepend' | 'append'; path: string; expectedSha256: string; content: string }
206
- | { type: 'delete'; path: string; expectedSha256: string };
207
-
208
204
  const SESSION_ROOT = '.ai/harness/edit-sessions';
205
+ const SESSION_OWNER_MARKER = '.forge-owner.json';
206
+
207
+ function hasDurableEditSessionStorageBinding(repoRoot: string, repoId: string): boolean {
208
+ const root = join(repoRoot, SESSION_ROOT);
209
+ try {
210
+ if (!lstatSync(root).isSymbolicLink()) return false;
211
+ const marker = JSON.parse(readFileSync(join(root, SESSION_OWNER_MARKER), 'utf-8')) as {
212
+ schemaVersion?: unknown;
213
+ repoId?: unknown;
214
+ binding?: unknown;
215
+ managedBy?: unknown;
216
+ };
217
+ return marker.schemaVersion === 1
218
+ && marker.repoId === repoId
219
+ && marker.binding === 'edit-sessions'
220
+ && marker.managedBy === 'forge';
221
+ } catch (_error) {
222
+ return false;
223
+ }
224
+ }
225
+
226
+ function assertDurableEditSessionStorageBound(repoRoot: string, repoId: string | undefined): void {
227
+ const normalizedRepoId = repoId?.trim();
228
+ if (!normalizedRepoId) return;
229
+ if (hasDurableEditSessionStorageBinding(repoRoot, normalizedRepoId)) return;
230
+ throw new Error(`EDIT_SESSION_STORAGE_NOT_BOUND: ${normalizedRepoId} requires Controller Home edit-sessions binding`);
231
+ }
232
+
209
233
  export const MAX_EDIT_PATCH_BATCH_OPERATIONS = 500;
210
234
  export const PREFERRED_EDIT_PATCH_BATCH_OPERATIONS = 100;
235
+ export const EDIT_SESSION_TERMINAL_RETENTION_MS = 7 * 24 * 60 * 60_000;
236
+ export const EDIT_SESSION_TERMINAL_MAX_RETAINED = 200;
211
237
 
212
238
  function hash(content: string): string {
213
239
  return createHash('sha256').update(content).digest('hex');
@@ -334,6 +360,7 @@ function revisionPatchPath(repoRoot: string, sessionId: string, revision: number
334
360
  }
335
361
 
336
362
  function writeSession(repoRoot: string, session: EditSession): void {
363
+ assertDurableEditSessionStorageBound(repoRoot, session.repoId);
337
364
  const path = sessionPath(repoRoot, session.sessionId);
338
365
  mkdirSync(dirname(path), { recursive: true });
339
366
  writeFileSync(path, `${JSON.stringify(session, null, 2)}\n`, 'utf-8');
@@ -617,6 +644,112 @@ function assertCurrentHashes(repoRoot: string, session: EditSession): void {
617
644
  if (path) throw new Error(`edited file changed outside the session after revision ${latestOperations(session).get(path)?.revision ?? session.currentRevision}: ${path}`);
618
645
  }
619
646
 
647
+ function committedChangedPathsBetween(repoRoot: string, baseRevision: string, targetRevision: string): string[] {
648
+ const ancestor = runProcess('git', ['merge-base', '--is-ancestor', baseRevision, targetRevision], {
649
+ cwd: repoRoot,
650
+ timeoutMs: 10_000,
651
+ maxOutputBytes: 64 * 1024,
652
+ });
653
+ if (!ancestor.ok) throw new Error('EDIT_SESSION_SUCCESSOR_HEAD_NOT_DESCENDANT');
654
+ const diff = runProcess('git', ['diff', '--name-status', '-z', '--find-renames', baseRevision, targetRevision, '--'], {
655
+ cwd: repoRoot,
656
+ timeoutMs: 10_000,
657
+ maxOutputBytes: 4 * 1024 * 1024,
658
+ });
659
+ if (!diff.ok) throw new Error(`EDIT_SESSION_SUCCESSOR_HEAD_DIFF_FAILED: ${diff.error || diff.stderr}`);
660
+ const tokens = diff.stdout.split('\0').filter(Boolean);
661
+ const paths = new Set<string>();
662
+ for (let index = 0; index < tokens.length;) {
663
+ const status = tokens[index++] ?? '';
664
+ const first = tokens[index++];
665
+ if (!first) break;
666
+ paths.add(first);
667
+ if (status.startsWith('R') || status.startsWith('C')) {
668
+ const second = tokens[index++];
669
+ if (second) paths.add(second);
670
+ }
671
+ }
672
+ return [...paths].sort((left, right) => left.localeCompare(right));
673
+ }
674
+
675
+ export function adoptEditSessionSuccessorHead(repoRoot: string, sessionId: string, input: {
676
+ binding?: EditSessionBinding;
677
+ reviewer?: string;
678
+ note?: string;
679
+ } = {}): EditSession {
680
+ let session = getEditSession(repoRoot, sessionId);
681
+ assertDurableEditSessionStorageBound(repoRoot, session.repoId);
682
+ if (!['dirty', 'checked', 'check_failed'].includes(session.status) || session.operations.length === 0) {
683
+ throw new Error(`EDIT_SESSION_SUCCESSOR_HEAD_NOT_ELIGIBLE: ${session.status}`);
684
+ }
685
+ assertEditSessionDurableBinding(session, input.binding, { requireBoundIdentity: true });
686
+ if (!session.workId || !session.repoId || !session.checkoutId || !session.principalId) {
687
+ throw new Error('EDIT_SESSION_SUCCESSOR_HEAD_WORK_BINDING_REQUIRED');
688
+ }
689
+ const previousBaseRevision = session.baseRevision?.trim();
690
+ const successorRevision = gitRevision(repoRoot)?.trim();
691
+ if (!previousBaseRevision || !successorRevision) throw new Error('EDIT_SESSION_SUCCESSOR_HEAD_REVISION_REQUIRED');
692
+ if (previousBaseRevision === successorRevision) return bindSessionControllerInstance(repoRoot, session, input.binding);
693
+
694
+ const committedPaths = committedChangedPathsBetween(repoRoot, previousBaseRevision, successorRevision);
695
+ const tracked = new Set(sessionTrackedPaths(session));
696
+ const overlaps = committedPaths.filter((path) => tracked.has(path));
697
+ if (overlaps.length > 0) {
698
+ throw new Error(`EDIT_SESSION_SUCCESSOR_HEAD_PATH_OVERLAP: ${overlaps.join(',')}`);
699
+ }
700
+ const mismatches = currentHashMismatches(repoRoot, session);
701
+ if (mismatches.length > 0) {
702
+ throw new Error(`EDIT_SESSION_SUCCESSOR_HEAD_CONTENT_DRIFT: ${mismatches.join(',')}`);
703
+ }
704
+
705
+ session = bindSessionControllerInstance(repoRoot, session, input.binding);
706
+ const revision = session.currentRevision + 1;
707
+ const revisionPatch = '';
708
+ const absoluteRevisionPatch = revisionPatchPath(repoRoot, session.sessionId, revision);
709
+ mkdirSync(dirname(absoluteRevisionPatch), { recursive: true });
710
+ writeFileSync(absoluteRevisionPatch, revisionPatch, 'utf-8');
711
+ const at = now();
712
+ session.revisions.push({
713
+ revision,
714
+ operations: [],
715
+ changedFiles: 0,
716
+ changedLines: 0,
717
+ patchPath: relative(repoRoot, absoluteRevisionPatch).replace(/\\/g, '/'),
718
+ patchSha256: hash(revisionPatch),
719
+ createdAt: at,
720
+ });
721
+ session.currentRevision = revision;
722
+ session.baseRevision = successorRevision;
723
+ session.status = 'dirty';
724
+ session.verifiedAt = undefined;
725
+ session.checkResults = [];
726
+ session.reviewer = undefined;
727
+ session.reviewNote = undefined;
728
+ session.assurance = calculateAssurance(session, at);
729
+ session.requestedChecks = session.assurance.requiredChecks;
730
+ session.workspaceFingerprint = workspaceFingerprint(repoRoot);
731
+ session.updatedAt = at;
732
+ writeSession(repoRoot, session);
733
+ tryAppendControllerWorklogEvent(repoRoot, {
734
+ category: 'edit',
735
+ action: 'edit_session_successor_head_adopted',
736
+ summary: `${session.purpose}: adopted non-overlapping successor HEAD`,
737
+ actor: input.reviewer?.trim() || undefined,
738
+ issueId: session.issueId,
739
+ taskId: session.taskId,
740
+ editSessionId: session.sessionId,
741
+ details: {
742
+ workId: session.workId,
743
+ previousBaseRevision,
744
+ successorRevision,
745
+ committedPaths,
746
+ revision,
747
+ note: input.note?.trim() || undefined,
748
+ },
749
+ });
750
+ return session;
751
+ }
752
+
620
753
  function markEditSessionSuperseded(repoRoot: string, session: EditSession, paths: string[], input: {
621
754
  reviewer?: string;
622
755
  note?: string;
@@ -999,6 +1132,7 @@ function sessionSummary(session: EditSession): EditSessionSummary {
999
1132
  return {
1000
1133
  sessionId: session.sessionId,
1001
1134
  purpose: session.purpose,
1135
+ workId: session.workId,
1002
1136
  status: session.status,
1003
1137
  issueId: session.issueId,
1004
1138
  taskId: session.taskId,
@@ -1060,6 +1194,7 @@ export function beginEditSession(repoRoot: string, input: {
1060
1194
  }): EditSession {
1061
1195
  const purpose = input.purpose.trim();
1062
1196
  if (!purpose) throw new Error('edit session purpose is required');
1197
+ assertDurableEditSessionStorageBound(repoRoot, input.binding?.repoId);
1063
1198
  const at = now();
1064
1199
  const session: EditSession = {
1065
1200
  schemaVersion: 3,
@@ -1125,6 +1260,135 @@ export function listEditSessions(repoRoot: string, limit = 100): EditSessionSumm
1125
1260
  .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
1126
1261
  }
1127
1262
 
1263
+
1264
+ export interface EditSessionRetentionResult {
1265
+ removedSessionIds: string[];
1266
+ reclaimedBytes: number;
1267
+ unknownReclaimedByteCount: number;
1268
+ inspected: number;
1269
+ eligible: number;
1270
+ attempted: number;
1271
+ retained: number;
1272
+ budgetExhausted: boolean;
1273
+ skippedByReason: Record<string, number>;
1274
+ errors: string[];
1275
+ }
1276
+
1277
+ function editSessionDirectoryBytes(path: string): { bytes: number; complete: boolean } {
1278
+ let bytes = 0;
1279
+ try {
1280
+ for (const entry of readdirSync(path, { withFileTypes: true })) {
1281
+ const entryPath = join(path, entry.name);
1282
+ if (entry.isDirectory()) {
1283
+ const nested = editSessionDirectoryBytes(entryPath);
1284
+ bytes += nested.bytes;
1285
+ if (!nested.complete) return { bytes, complete: false };
1286
+ } else if (entry.isFile()) {
1287
+ bytes += statSync(entryPath).size;
1288
+ }
1289
+ }
1290
+ return { bytes, complete: true };
1291
+ } catch {
1292
+ return { bytes, complete: false };
1293
+ }
1294
+ }
1295
+
1296
+ /**
1297
+ * Physically reclaim terminal EditSession artifacts after their Work no longer
1298
+ * owns live review/delivery authority. The repository-relative path may be the
1299
+ * runtime-storage compatibility link; deletion therefore follows the existing
1300
+ * Controller Home binding instead of creating a second persistence root.
1301
+ */
1302
+ export function cleanupTerminalEditSessionRecords(repoRoot: string, input: {
1303
+ nowMs?: number;
1304
+ retentionMs?: number;
1305
+ maxRetained?: number;
1306
+ maxEntries?: number;
1307
+ maxRemovals?: number;
1308
+ sequence?: number;
1309
+ protectedWorkIds?: Iterable<string>;
1310
+ } = {}): EditSessionRetentionResult {
1311
+ const root = join(repoRoot, SESSION_ROOT);
1312
+ const result: EditSessionRetentionResult = {
1313
+ removedSessionIds: [], reclaimedBytes: 0, unknownReclaimedByteCount: 0,
1314
+ inspected: 0, eligible: 0, attempted: 0, retained: 0, budgetExhausted: false,
1315
+ skippedByReason: {}, errors: [],
1316
+ };
1317
+ if (!existsSync(root)) return result;
1318
+ const nowMs = input.nowMs ?? Date.now();
1319
+ const retentionMs = Math.max(60_000, Math.trunc(input.retentionMs ?? EDIT_SESSION_TERMINAL_RETENTION_MS));
1320
+ const maxRetained = Math.max(0, Math.trunc(input.maxRetained ?? EDIT_SESSION_TERMINAL_MAX_RETAINED));
1321
+ const maxEntries = Math.max(1, Math.trunc(input.maxEntries ?? 2_000));
1322
+ const maxRemovals = Math.max(0, Math.trunc(input.maxRemovals ?? 50));
1323
+ const protectedWorkIds = new Set(Array.from(input.protectedWorkIds ?? [], (value) => String(value).trim()).filter(Boolean));
1324
+ const skip = (reason: string) => {
1325
+ result.retained += 1;
1326
+ result.skippedByReason[reason] = (result.skippedByReason[reason] ?? 0) + 1;
1327
+ };
1328
+ let entries;
1329
+ try {
1330
+ entries = readdirSync(root, { withFileTypes: true })
1331
+ .filter((entry) => entry.isDirectory() && existsSync(join(root, entry.name, 'session.json')))
1332
+ .sort((left, right) => right.name.localeCompare(left.name));
1333
+ } catch (error) {
1334
+ result.errors.push(`edit_session_root_unreadable:${error instanceof Error ? error.message : String(error)}`);
1335
+ return result;
1336
+ }
1337
+ if (entries.length === 0) return result;
1338
+ const rank = new Map(entries.map((entry, index) => [entry.name, index]));
1339
+ const start = (Math.max(0, Math.trunc(input.sequence ?? 0)) * maxEntries) % entries.length;
1340
+ const window = [...entries.slice(start), ...entries.slice(0, start)].slice(0, Math.min(maxEntries, entries.length));
1341
+ if (entries.length > window.length) result.budgetExhausted = true;
1342
+ for (const entry of window) {
1343
+ result.inspected += 1;
1344
+ let session: EditSession;
1345
+ try { session = getEditSession(repoRoot, entry.name); }
1346
+ catch (error) {
1347
+ result.errors.push(`edit_session_unreadable:${entry.name}:${error instanceof Error ? error.message : String(error)}`);
1348
+ skip('session_unreadable');
1349
+ continue;
1350
+ }
1351
+ if (!['finalized', 'superseded', 'rolled_back'].includes(session.status)) {
1352
+ skip('active_session');
1353
+ continue;
1354
+ }
1355
+ if (session.workId && protectedWorkIds.has(session.workId)) {
1356
+ skip('active_work');
1357
+ continue;
1358
+ }
1359
+ const updatedMs = Date.parse(session.updatedAt);
1360
+ if (!Number.isFinite(updatedMs)) {
1361
+ skip('terminal_timestamp_unknown');
1362
+ continue;
1363
+ }
1364
+ const beyondAge = nowMs - updatedMs >= retentionMs;
1365
+ const beyondCount = (rank.get(entry.name) ?? 0) >= maxRetained;
1366
+ if (!beyondAge && !beyondCount) {
1367
+ skip('within_retention');
1368
+ continue;
1369
+ }
1370
+ result.eligible += 1;
1371
+ if (result.attempted >= maxRemovals) {
1372
+ result.budgetExhausted = true;
1373
+ skip('cleanup_budget_exhausted');
1374
+ continue;
1375
+ }
1376
+ result.attempted += 1;
1377
+ const path = sessionDir(repoRoot, session.sessionId);
1378
+ const measurement = editSessionDirectoryBytes(path);
1379
+ if (measurement.complete) result.reclaimedBytes += measurement.bytes;
1380
+ else result.unknownReclaimedByteCount += 1;
1381
+ try {
1382
+ rmSync(path, { recursive: true, force: true });
1383
+ result.removedSessionIds.push(session.sessionId);
1384
+ } catch (error) {
1385
+ result.errors.push(`edit_session_remove_failed:${session.sessionId}:${error instanceof Error ? error.message : String(error)}`);
1386
+ }
1387
+ }
1388
+ result.removedSessionIds.sort();
1389
+ return result;
1390
+ }
1391
+
1128
1392
  export function getEditSessionDiff(repoRoot: string, sessionId: string): {
1129
1393
  sessionId: string;
1130
1394
  path?: string;
@@ -1144,6 +1408,7 @@ export function applyEditOperations(repoRoot: string, policy: McpPolicy, session
1144
1408
  binding?: EditSessionBinding;
1145
1409
  } = {}): EditSession {
1146
1410
  let session = getEditSession(repoRoot, sessionId);
1411
+ assertDurableEditSessionStorageBound(repoRoot, session.repoId);
1147
1412
  if (['finalized', 'rolled_back'].includes(session.status)) throw new Error(`edit session is closed: ${session.status}`);
1148
1413
  if (operations.length === 0) throw new Error('at least one edit operation is required');
1149
1414
  const maxBatchOperations = Math.max(1, Math.trunc(options.maxBatchOperations ?? MAX_EDIT_PATCH_BATCH_OPERATIONS));
@@ -1382,7 +1647,10 @@ export function applyEditOperations(repoRoot: string, policy: McpPolicy, session
1382
1647
  repoRoot,
1383
1648
  record.path,
1384
1649
  readFileSync(join(repoRoot, record.backupPath), 'utf-8'),
1385
- record.beforeMode === undefined ? {} : { mode: record.beforeMode },
1650
+ {
1651
+ backupRoot: `${SESSION_ROOT}/${session.sessionId}/atomic-backups/apply-rollback-r${revision}`,
1652
+ ...(record.beforeMode === undefined ? {} : { mode: record.beforeMode }),
1653
+ },
1386
1654
  );
1387
1655
  }
1388
1656
  const message = error instanceof Error ? error.message : String(error);
@@ -1531,7 +1799,7 @@ export async function verifyEditSessionAsync(repoRoot: string, sessionId: string
1531
1799
  });
1532
1800
  }
1533
1801
 
1534
- function restoreOperation(repoRoot: string, operation: EditSessionOperationRecord): void {
1802
+ function restoreOperation(repoRoot: string, operation: EditSessionOperationRecord, backupRoot: string): void {
1535
1803
  const absolute = join(repoRoot, operation.path);
1536
1804
  if (operation.type === 'create') {
1537
1805
  if (existsSync(absolute)) {
@@ -1554,7 +1822,10 @@ function restoreOperation(repoRoot: string, operation: EditSessionOperationRecor
1554
1822
  repoRoot,
1555
1823
  operation.path,
1556
1824
  readFileSync(join(repoRoot, operation.backupPath), 'utf-8'),
1557
- operation.beforeMode === undefined ? {} : { mode: operation.beforeMode },
1825
+ {
1826
+ backupRoot,
1827
+ ...(operation.beforeMode === undefined ? {} : { mode: operation.beforeMode }),
1828
+ },
1558
1829
  );
1559
1830
  }
1560
1831
 
@@ -1564,6 +1835,7 @@ export function rollbackEditSession(repoRoot: string, sessionId: string, input:
1564
1835
  allowFinalized?: boolean;
1565
1836
  } = {}): EditSession {
1566
1837
  const session = getEditSession(repoRoot, sessionId);
1838
+ assertDurableEditSessionStorageBound(repoRoot, session.repoId);
1567
1839
  if ((session.status === 'open' || (session.status === 'finalized' && input.allowFinalized)) && session.operations.length === 0) {
1568
1840
  const at = now();
1569
1841
  session.status = 'rolled_back';
@@ -1595,7 +1867,11 @@ export function rollbackEditSession(repoRoot: string, sessionId: string, input:
1595
1867
  try {
1596
1868
  for (const operation of reverted) {
1597
1869
  restoreAttempted = true;
1598
- restoreOperation(repoRoot, operation);
1870
+ restoreOperation(
1871
+ repoRoot,
1872
+ operation,
1873
+ `${SESSION_ROOT}/${session.sessionId}/atomic-backups/rollback-to-r${target}`,
1874
+ );
1599
1875
  }
1600
1876
  } finally {
1601
1877
  if (restoreAttempted) invalidateRepositoryReadCaches(repoRoot);
@@ -1,5 +1,5 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2
- import { dirname, join } from "path";
1
+ import { existsSync, readFileSync, rmSync } from "fs";
2
+ import { join } from "path";
3
3
  import { getGitHubStatus, publishIssueToGitHub, refreshGitHubIssue, closeGitHubIssue } from "./github";
4
4
  import type { ControllerIssue } from "../controller/types";
5
5
  import { tryAppendControllerWorklogEvent } from "../controller/worklog";
@@ -104,6 +104,10 @@ function loadLegacyGitHubPluginConfig(repoRoot: string): GitHubPluginConfig | un
104
104
  }
105
105
  }
106
106
 
107
+ function retireLegacyGitHubPluginConfig(repoRoot: string): void {
108
+ rmSync(join(repoRoot, CONFIG_PATH), { force: true });
109
+ }
110
+
107
111
  function findRepositoryRecord(repoRoot: string): RepositoryRecord | undefined {
108
112
  const controllerHome = resolveRepoPreferredControllerHome(repoRoot);
109
113
  return listRepositories(controllerHome).find((record) =>
@@ -127,18 +131,18 @@ function configFromRepository(record: RepositoryRecord | undefined): GitHubPlugi
127
131
  });
128
132
  }
129
133
 
130
- function syncRepositoryGitHubConfig(repoRoot: string, config: GitHubPluginConfig): void {
134
+ function syncRepositoryGitHubConfig(repoRoot: string, config: GitHubPluginConfig): boolean {
131
135
  const record = findRepositoryRecord(repoRoot);
132
- if (!record) return;
136
+ if (!record) return false;
133
137
  const controllerHome = resolveRepoPreferredControllerHome(repoRoot);
134
138
  const current = record.github;
135
139
  const repository = config.repository?.trim();
136
140
  const effectiveRepository = repository
137
141
  || current?.repository
138
142
  || (current?.owner && current?.repo ? `${current.owner}/${current.repo}` : undefined);
139
- if (!effectiveRepository) return;
143
+ if (!effectiveRepository) return false;
140
144
  const [owner, repo] = effectiveRepository.includes("/") ? effectiveRepository.split("/", 2) : [current?.owner, current?.repo];
141
- if (!owner || !repo) return;
145
+ if (!owner || !repo) return false;
142
146
  updateRepository(record.repoId, {
143
147
  github: {
144
148
  owner,
@@ -156,6 +160,7 @@ function syncRepositoryGitHubConfig(repoRoot: string, config: GitHubPluginConfig
156
160
  authenticationCapability: current?.authenticationCapability ?? "unknown",
157
161
  },
158
162
  }, controllerHome);
163
+ return true;
159
164
  }
160
165
 
161
166
  export function loadGitHubPluginConfig(repoRoot: string): GitHubPluginConfig {
@@ -173,12 +178,12 @@ export function loadGitHubPluginConfig(repoRoot: string): GitHubPluginConfig {
173
178
  projectNumber: legacyConfig.projectNumber ?? registryConfig.projectNumber,
174
179
  statusField: legacyConfig.statusField ?? registryConfig.statusField,
175
180
  });
176
- syncRepositoryGitHubConfig(repoRoot, merged);
181
+ if (syncRepositoryGitHubConfig(repoRoot, merged)) retireLegacyGitHubPluginConfig(repoRoot);
177
182
  return merged;
178
183
  }
179
184
  if (registryConfig) return registryConfig;
180
185
  if (legacyConfig) {
181
- syncRepositoryGitHubConfig(repoRoot, legacyConfig);
186
+ if (syncRepositoryGitHubConfig(repoRoot, legacyConfig)) retireLegacyGitHubPluginConfig(repoRoot);
182
187
  return legacyConfig;
183
188
  }
184
189
  return defaultGitHubPluginConfig();
@@ -224,10 +229,10 @@ export function saveGitHubPluginConfig(
224
229
  projectNumber,
225
230
  statusField,
226
231
  };
227
- syncRepositoryGitHubConfig(repoRoot, config);
228
- const path = join(repoRoot, CONFIG_PATH);
229
- mkdirSync(dirname(path), { recursive: true });
230
- writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
232
+ if (!syncRepositoryGitHubConfig(repoRoot, config)) {
233
+ throw new Error("GITHUB_PLUGIN_REPOSITORY_REGISTRATION_REQUIRED: configure GitHub only after the repository is registered in Controller Home");
234
+ }
235
+ retireLegacyGitHubPluginConfig(repoRoot);
231
236
  statusCache.set(repoRoot, {
232
237
  at: Date.now() - STATUS_CACHE_TTL_MS + CONFIG_STATUS_CACHE_TTL_MS,
233
238
  fingerprint: JSON.stringify(config),
@@ -6,11 +6,9 @@
6
6
  * names are an internal implementation detail — Phase 2 sealed hooks will
7
7
  * replace them with bundled implementations without changing the tuple.
8
8
  *
9
- * Derived from `.codex/hooks.json` reality verified Phase 0 canary
10
- * 2026-05-28 (see docs/architecture/global-hook-runtime.md and Codex consult
11
- * session 019e6df7-e7c9-70e2-8872-db9869420bd0). The matcher dimension was
12
- * the missing piece in the X (event-only) design — see
13
- * tasks/notes/hook-global-runtime.notes.md § Phase 1B Design Pivot.
9
+ * Derived from `.codex/hooks.json` reality verified by the Phase 0 canary on
10
+ * 2026-05-28. Historical rationale and verification evidence are preserved in
11
+ * Git history; the matcher-aware registry and its tests are the current contract.
14
12
  *
15
13
  * Order matters: it is the stable adapter entry order. Codex hashes adapter
16
14
  * entries by `(absolute-path, event-snake, i, j)`, so any reordering re-prompts
@@ -1,10 +1,14 @@
1
1
  import * as fs from 'fs';
2
+ import * as os from 'os';
2
3
  import * as path from 'path';
3
4
  import { fileURLToPath } from 'url';
4
5
  import { execFileSync, spawnSync, type StdioOptions } from 'child_process';
6
+ import { repositoryControllerRoot, resolveControllerHome } from '../repositories/controller-home';
7
+ import { findRegisteredRepositoryByCheckoutRoot } from '../repositories/registry';
5
8
  import { getRoute, type HookEvent, type RouteId } from './route-registry';
6
9
 
7
- const OPT_IN_MARKER = '.ai/harness/workflow-contract.json';
10
+ const OPT_IN_MARKER = 'forge.config.json';
11
+ const LEGACY_OPT_IN_MARKER = '.ai/harness/workflow-contract.json';
8
12
  const POLICY_FILE = '.ai/harness/policy.json';
9
13
  const PACKAGE_ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
10
14
 
@@ -83,7 +87,7 @@ export function resolveRepoRoot(cwd: string): string | null {
83
87
  }
84
88
 
85
89
  export function isOptIn(repoRoot: string): boolean {
86
- return fs.existsSync(path.join(repoRoot, OPT_IN_MARKER));
90
+ return fs.existsSync(path.join(repoRoot, OPT_IN_MARKER)) || fs.existsSync(path.join(repoRoot, LEGACY_OPT_IN_MARKER));
87
91
  }
88
92
 
89
93
  /**
@@ -108,6 +112,36 @@ export interface ResolvedHooksDir {
108
112
  source: HookSource;
109
113
  }
110
114
 
115
+ export interface ResolvedHookStateRoot {
116
+ root: string;
117
+ source: 'env' | 'controller-home' | 'ephemeral';
118
+ repoId?: string;
119
+ }
120
+
121
+ export function resolveHookStateRoot(
122
+ repoRoot: string,
123
+ env: NodeJS.ProcessEnv = process.env,
124
+ ): ResolvedHookStateRoot {
125
+ const explicit = env.FORGE_HOOK_STATE_ROOT?.trim();
126
+ if (explicit && path.isAbsolute(explicit)) {
127
+ fs.mkdirSync(explicit, { recursive: true });
128
+ return { root: explicit, source: 'env' };
129
+ }
130
+
131
+ const controllerHome = resolveControllerHome(env.FORGE_CONTROLLER_HOME);
132
+ const repository = findRegisteredRepositoryByCheckoutRoot(repoRoot, controllerHome);
133
+ if (repository) {
134
+ const root = path.join(repositoryControllerRoot(controllerHome, repository.repoId), 'hook-state');
135
+ fs.mkdirSync(root, { recursive: true });
136
+ return { root, source: 'controller-home', repoId: repository.repoId };
137
+ }
138
+
139
+ return {
140
+ root: fs.mkdtempSync(path.join(os.tmpdir(), 'forge-hook-state-')),
141
+ source: 'ephemeral',
142
+ };
143
+ }
144
+
111
145
  function repoPinsHookSource(repoRoot: string): boolean {
112
146
  try {
113
147
  const raw = fs.readFileSync(path.join(repoRoot, POLICY_FILE), 'utf-8');
@@ -173,6 +207,7 @@ export function runHook(opts: RunHookOptions): RunHookResult {
173
207
  return { exitCode: 2, reason: 'unknown-route', repoRoot, scriptsRun, skippedScripts };
174
208
  }
175
209
 
210
+ const hookState = resolveHookStateRoot(repoRoot);
176
211
  const resolved: ResolvedHooksDir = opts.hooksDir
177
212
  ? { dir: opts.hooksDir, source: 'env' }
178
213
  : resolveHooksDir(repoRoot);
@@ -202,6 +237,7 @@ export function runHook(opts: RunHookOptions): RunHookResult {
202
237
  ? ['inherit', 'pipe', 'inherit']
203
238
  : (opts.stdio ?? 'inherit');
204
239
 
240
+ try {
205
241
  for (const script of route.scripts) {
206
242
  const scriptPath = path.join(hooksDir, script);
207
243
  if (!fs.existsSync(scriptPath)) {
@@ -230,7 +266,12 @@ export function runHook(opts: RunHookOptions): RunHookResult {
230
266
  const child = spawnSync('bash', [scriptPath, ...(opts.args ?? [])], {
231
267
  cwd: repoRoot,
232
268
  stdio,
233
- env: { ...process.env, HOOK_REPO_ROOT: repoRoot },
269
+ env: {
270
+ ...process.env,
271
+ HOOK_REPO_ROOT: repoRoot,
272
+ FORGE_HOOK_STATE_ROOT: hookState.root,
273
+ FORGE_REPO_ID: hookState.repoId ?? '',
274
+ },
234
275
  });
235
276
 
236
277
  if (child.error) {
@@ -300,4 +341,9 @@ export function runHook(opts: RunHookOptions): RunHookResult {
300
341
  }
301
342
 
302
343
  return { exitCode: 0, reason: 'ok', repoRoot, scriptsRun, skippedScripts };
344
+ } finally {
345
+ if (hookState.source === 'ephemeral') {
346
+ fs.rmSync(hookState.root, { recursive: true, force: true });
347
+ }
348
+ }
303
349
  }
package/src/cli/index.ts CHANGED
@@ -17,6 +17,7 @@ import { buildSetupCommand, formatInitHook, runInitHook } from './commands/init-
17
17
  import { formatMigratePlan, runMigrate } from './commands/migrate';
18
18
  import { buildToolsCommand } from './commands/tools';
19
19
  import { buildPluginCommand } from './commands/plugin';
20
+ import { buildComputerCommand } from './commands/computer';
20
21
  import { buildBrainCommand } from './commands/brain';
21
22
  import { buildCapabilityContextCommand } from './commands/capability-context';
22
23
  import { buildDocsCommand } from './commands/docs';
@@ -53,6 +54,7 @@ export const SUBCOMMANDS = [
53
54
  'setup',
54
55
  'tools',
55
56
  'plugin',
57
+ 'computer',
56
58
  'brain',
57
59
  'capability-context',
58
60
  'docs',
@@ -509,6 +511,7 @@ export function buildProgram(): Command {
509
511
 
510
512
  program.addCommand(buildToolsCommand());
511
513
  program.addCommand(buildPluginCommand());
514
+ program.addCommand(buildComputerCommand());
512
515
  program.addCommand(buildBrainCommand(), { hidden: true });
513
516
  program.addCommand(buildCapabilityContextCommand(), { hidden: true });
514
517
  program.addCommand(buildDocsCommand());
@@ -18,8 +18,8 @@ import {
18
18
  import {
19
19
  loadMcpLocalConfig,
20
20
  loadMcpServiceLocalConfig,
21
- } from '../mcp/auth';
22
- import { PREFERRED_FACADE_TOOL_NAMES, DEFAULT_CONTROLLER_TOOL_NAMES } from '../mcp/toolset-names';
21
+ } from '../../../adapters/mcp/auth';
22
+ import { PREFERRED_FACADE_TOOL_NAMES, DEFAULT_CONTROLLER_TOOL_NAMES } from '../../../adapters/mcp/toolset-names';
23
23
  import { resolveRepoPreferredControllerHome } from '../repositories/controller-home';
24
24
  import type { PlainStatusTone } from './console-view-models';
25
25
 
@@ -1,8 +1,8 @@
1
1
  import type { RepositoryRecord } from '../repositories/types';
2
2
  import { getWorkContract } from '../../runtime/control-plane/facade';
3
3
  import { evaluateSchedule } from '../../runtime/workflow/schedules/engine';
4
- import { getSchedule, listOccurrences, listSchedules, saveSchedule } from '../../runtime/workflow/schedules/store';
5
- import type { RepositorySchedule, ScheduleOccurrence } from '../../runtime/workflow/schedules/types';
4
+ import { getSchedule, listOccurrences, listSchedules, saveSchedule } from '../../../packages/kernel/scheduler/api/index';
5
+ import type { RepositorySchedule, ScheduleOccurrence } from '../../../packages/kernel/scheduler/api/index';
6
6
 
7
7
  export type ConsoleAutomationMode = 'browser_watch' | 'browser_keepalive' | 'continuation' | 'schedule';
8
8