@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,4 +1,4 @@
1
- import { createHash, randomUUID } from 'crypto';
1
+ import { createHash } from 'crypto';
2
2
  import { execFile } from 'child_process';
3
3
  import { promisify } from 'util';
4
4
  import { getRepository } from '../../../cli/repositories/registry';
@@ -10,27 +10,35 @@ import {
10
10
  previewAutomaticRuntimeMaintenance,
11
11
  type RuntimeMaintenanceActionId,
12
12
  } from '../../recovery/maintenance-executor';
13
- import { appendWorkEvidence, controllerSessionBlocksRecovery, getControllerSession, getWorkContract, isTerminalWorkContractStatus, listHandoffItems } from '../../control-plane/facade';
14
- import { launchSuperController } from '../../control-plane/launcher/thin-launcher';
15
- import { getExternalControllerLaunchReservation } from '../../control-plane/launcher/launch-reservation-store';
16
- import { runStandaloneChatgptPrompt, runWorkChatgptContinuation } from '../../control-plane/launcher/chatgpt-work-continuation';
13
+ import { appendWorkEvidence, getWorkContract, isTerminalWorkContractStatus } from '../../../../packages/kernel/work/api/index';
17
14
  import {
18
- beginInitialControllerRoundDispatch,
19
- buildControllerRoundRelayPrompt,
20
- finishControllerRoundRelayDispatch,
21
- } from '../../control-plane/facade/controller-round-relay';
15
+ controllerSessionBlocksRecovery,
16
+ getControllerSession,
17
+ getControllerWorkBinding,
18
+ getRetainedControllerSession,
19
+ } from '../../../../packages/kernel/controller/api/index';
22
20
  import {
21
+ applyScheduleFailure,
22
+ applyScheduleRetryableFailure,
23
+ cronDue,
24
+ evaluateScheduleOccurrenceAdmission,
25
+ evaluateScheduleTriggerEligibility,
23
26
  getOccurrence,
24
27
  getSchedule,
25
28
  listActiveOccurrences,
26
29
  listOccurrences,
27
30
  recordScheduleOccurrenceHandoff,
31
+ resumeScheduledControllerContinuation,
28
32
  listSchedules,
29
33
  saveOccurrence,
30
34
  saveScheduleDecision,
31
35
  updateSchedule,
32
- } from './store';
33
- import { applyScheduleFailure, applyScheduleRetryableFailure } from './settlement';
36
+ } from '../../../../packages/kernel/scheduler/api/index';
37
+ export { cronDue };
38
+ import { ensureScheduledControllerBinding, controllerHostForScheduledBinding } from '../../root/scheduled-controller-composition';
39
+ import { listHandoffItems } from '../../control-plane/facade/handoff-inbox-store';
40
+ import { runStandaloneChatgptPrompt } from '../../control-plane/launcher/chatgpt-work-continuation';
41
+
34
42
  import { classifyScheduledBrowserObservation, executeScheduledBrowserProbe } from './browser-probe';
35
43
  import { executeScheduledGithubIssueWatch } from './github-issue-watch';
36
44
  import type {
@@ -38,7 +46,7 @@ import type {
38
46
  ScheduleDecisionType,
39
47
  ScheduleOccurrence,
40
48
  ScheduleTriggerContext,
41
- } from './types';
49
+ } from '../../../../packages/kernel/scheduler/api/index';
42
50
 
43
51
  const execFileAsync = promisify(execFile);
44
52
  const LIVE_MAINTENANCE_OPERATION = 'runtime_maintenance_apply';
@@ -65,128 +73,6 @@ function retiredScheduleReason(schedule: RepositorySchedule): string | undefined
65
73
  return undefined;
66
74
  }
67
75
 
68
- function normalizedWindow(minutes: number, at = Date.now()): string {
69
- return String(Math.floor(at / (Math.max(1, minutes) * 60_000)));
70
- }
71
-
72
- interface ZonedDateParts {
73
- year: number;
74
- month: number;
75
- day: number;
76
- hour: number;
77
- minute: number;
78
- weekday: number;
79
- }
80
-
81
- function zonedDateParts(at: number, timezone = 'UTC'): ZonedDateParts {
82
- let formatter: Intl.DateTimeFormat;
83
- try {
84
- formatter = new Intl.DateTimeFormat('en-US-u-ca-iso8601', {
85
- timeZone: timezone,
86
- year: 'numeric', month: '2-digit', day: '2-digit',
87
- hour: '2-digit', minute: '2-digit', weekday: 'short',
88
- hourCycle: 'h23',
89
- });
90
- } catch {
91
- throw new Error(`SCHEDULE_TIMEZONE_INVALID: ${timezone}`);
92
- }
93
- const values = Object.fromEntries(formatter.formatToParts(new Date(at)).map((entry) => [entry.type, entry.value]));
94
- const weekdays: Record<string, number> = { Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 };
95
- return {
96
- year: Number(values.year),
97
- month: Number(values.month),
98
- day: Number(values.day),
99
- hour: Number(values.hour),
100
- minute: Number(values.minute),
101
- weekday: weekdays[String(values.weekday)] ?? 0,
102
- };
103
- }
104
-
105
- function fixedCronTime(expression: string | undefined): { minute: number; hour: number; day: string; month: string; weekday: string } | undefined {
106
- if (!expression) return undefined;
107
- const fields = expression.trim().split(/\s+/);
108
- if (fields.length !== 5 || !/^\d+$/.test(fields[0]) || !/^\d+$/.test(fields[1])) return undefined;
109
- const minute = Number(fields[0]);
110
- const hour = Number(fields[1]);
111
- if (minute < 0 || minute > 59 || hour < 0 || hour > 23) return undefined;
112
- return { minute, hour, day: fields[2], month: fields[3], weekday: fields[4] };
113
- }
114
-
115
- function cronWindowKey(schedule: RepositorySchedule, at = Date.now()): string {
116
- const timezone = schedule.trigger.timezone ?? 'UTC';
117
- const parts = zonedDateParts(at, timezone);
118
- const fixed = fixedCronTime(schedule.trigger.cronExpression);
119
- if (fixed) {
120
- return `${parts.year}-${String(parts.month).padStart(2, '0')}-${String(parts.day).padStart(2, '0')}@${String(fixed.hour).padStart(2, '0')}:${String(fixed.minute).padStart(2, '0')}[${timezone}]`;
121
- }
122
- return `${parts.year}-${String(parts.month).padStart(2, '0')}-${String(parts.day).padStart(2, '0')}T${String(parts.hour).padStart(2, '0')}:${String(parts.minute).padStart(2, '0')}[${timezone}]`;
123
- }
124
-
125
- function triggerWindowKey(schedule: RepositorySchedule, context: ScheduleTriggerContext | undefined, at = Date.now()): string {
126
- // Explicit control-plane triggers use a separate identity namespace from timer/cron windows.
127
- // A caller-supplied event/request id is the stable retry key; otherwise each manual trigger is distinct.
128
- if (context?.source === 'manual' && schedule.trigger.type !== 'manual') {
129
- const stableManualKey = context.eventId?.trim();
130
- return `manual:${stableManualKey || randomUUID()}`;
131
- }
132
- switch (schedule.trigger.type) {
133
- case 'cron':
134
- return cronWindowKey(schedule, at);
135
- case 'calendar':
136
- return schedule.trigger.calendarAt ?? new Date(at).toISOString().slice(0, 16);
137
- case 'repository-event':
138
- return context?.eventId?.trim() || `${context?.eventName ?? schedule.trigger.eventName ?? 'event'}:${normalizedWindow(1, at)}`;
139
- case 'dependency-checkpoint':
140
- return createHash('sha256').update(JSON.stringify(schedule.trigger.dependencyJobIds ?? [])).digest('hex').slice(0, 20);
141
- case 'manual':
142
- return context?.eventId?.trim() || normalizedWindow(1, at);
143
- case 'condition':
144
- case 'interval':
145
- default:
146
- return normalizedWindow(schedule.trigger.everyMinutes ?? 60, at);
147
- }
148
- }
149
-
150
- function cronFieldMatches(value: number, field: string, min: number, max: number): boolean {
151
- return field.split(',').some((part) => {
152
- const trimmed = part.trim();
153
- if (trimmed === '*') return true;
154
- const stepMatch = trimmed.match(/^\*\/(\d+)$/);
155
- if (stepMatch) return value % Math.max(1, Number(stepMatch[1])) === 0;
156
- const rangeMatch = trimmed.match(/^(\d+)-(\d+)(?:\/(\d+))?$/);
157
- if (rangeMatch) {
158
- const start = Math.max(min, Number(rangeMatch[1]));
159
- const end = Math.min(max, Number(rangeMatch[2]));
160
- const step = Math.max(1, Number(rangeMatch[3] ?? 1));
161
- return value >= start && value <= end && (value - start) % step === 0;
162
- }
163
- const exact = Number(trimmed);
164
- return Number.isInteger(exact) && exact >= min && exact <= max && value === exact;
165
- });
166
- }
167
-
168
- export function cronDue(
169
- expression: string | undefined,
170
- at = Date.now(),
171
- timezone = 'UTC',
172
- catchUpMinutes = 0,
173
- ): boolean {
174
- if (!expression) return false;
175
- const fields = expression.trim().split(/\s+/);
176
- if (fields.length !== 5) throw new Error(`SCHEDULE_CRON_INVALID: expected five fields, received ${fields.length}`);
177
- const parts = zonedDateParts(at, timezone);
178
- const calendarMatches = cronFieldMatches(parts.day, fields[2], 1, 31)
179
- && cronFieldMatches(parts.month, fields[3], 1, 12)
180
- && cronFieldMatches(parts.weekday, fields[4], 0, 6);
181
- if (!calendarMatches) return false;
182
- if (cronFieldMatches(parts.minute, fields[0], 0, 59) && cronFieldMatches(parts.hour, fields[1], 0, 23)) return true;
183
- const fixed = fixedCronTime(expression);
184
- if (!fixed || catchUpMinutes <= 0) return false;
185
- const scheduledMinute = fixed.hour * 60 + fixed.minute;
186
- const currentMinute = parts.hour * 60 + parts.minute;
187
- return currentMinute >= scheduledMinute && currentMinute - scheduledMinute <= Math.min(24 * 60, catchUpMinutes);
188
- }
189
-
190
76
  async function workspaceDirty(controllerHome: string, repoId: string): Promise<boolean> {
191
77
  try {
192
78
  const repository = getRepository(repoId, controllerHome, { includeRemoved: true });
@@ -199,64 +85,6 @@ async function workspaceDirty(controllerHome: string, repoId: string): Promise<b
199
85
  }
200
86
  }
201
87
 
202
- async function triggerDue(
203
- controllerHome: string,
204
- schedule: RepositorySchedule,
205
- force: boolean,
206
- context?: ScheduleTriggerContext,
207
- ): Promise<{ due: boolean; reason?: string; evidence?: Record<string, unknown> }> {
208
- if (force && schedule.trigger.type !== 'repository-event') return { due: true };
209
- switch (schedule.trigger.type) {
210
- case 'manual':
211
- return { due: force, reason: force ? undefined : 'Manual Schedule requires an explicit trigger.' };
212
- case 'interval':
213
- return { due: true };
214
- case 'cron':
215
- return {
216
- due: cronDue(schedule.trigger.cronExpression, Date.now(), schedule.trigger.timezone ?? 'UTC', schedule.trigger.catchUpMinutes ?? 0),
217
- reason: `Cron expression is not due in the current ${schedule.trigger.timezone ?? 'UTC'} minute or catch-up window.`,
218
- };
219
- case 'calendar': {
220
- const at = Date.parse(schedule.trigger.calendarAt ?? '');
221
- if (!Number.isFinite(at)) throw new Error('SCHEDULE_CALENDAR_INVALID: calendarAt must be an ISO-8601 timestamp');
222
- return { due: Date.now() >= at, reason: 'Calendar trigger is not due yet.', evidence: { calendarAt: schedule.trigger.calendarAt } };
223
- }
224
- case 'repository-event': {
225
- const expected = schedule.trigger.eventName?.trim();
226
- const actual = context?.eventName?.trim();
227
- const due = context?.source === 'repository-event' && Boolean(actual) && (!expected || expected === actual);
228
- return { due, reason: due ? undefined : 'Repository event did not match this Schedule.', evidence: { expected, actual, eventId: context?.eventId } };
229
- }
230
- case 'dependency-checkpoint': {
231
- const dependencyJobIds = schedule.trigger.dependencyJobIds ?? [];
232
- if (dependencyJobIds.length === 0) throw new Error('SCHEDULE_DEPENDENCY_REQUIRED: dependency checkpoint has no Job ids');
233
- const jobs = dependencyJobIds.map((jobId) => findExecutionJob(controllerHome, jobId));
234
- const due = jobs.every((job) => job?.status === 'succeeded');
235
- return {
236
- due,
237
- reason: due ? undefined : 'Dependency checkpoint is not ready.',
238
- evidence: { dependencies: dependencyJobIds.map((jobId, index) => ({ jobId, status: jobs[index]?.status ?? 'missing' })) },
239
- };
240
- }
241
- case 'condition': {
242
- const condition = schedule.trigger.condition;
243
- if (!condition) throw new Error('SCHEDULE_CONDITION_REQUIRED');
244
- if (condition.kind === 'repository_clean') {
245
- const clean = !(await workspaceDirty(controllerHome, schedule.repoId));
246
- return { due: clean, reason: clean ? undefined : 'Repository is not clean.', evidence: { clean } };
247
- }
248
- if (condition.kind === 'job_succeeded' || condition.kind === 'job_terminal') {
249
- const job = condition.jobId ? findExecutionJob(controllerHome, condition.jobId) : undefined;
250
- const terminal = Boolean(job && ['succeeded', 'failed', 'timed_out', 'cancelled', 'orphaned', 'stale', 'human_attention_required'].includes(job.status));
251
- const due = condition.kind === 'job_succeeded' ? job?.status === 'succeeded' : terminal;
252
- return { due, reason: due ? undefined : `Condition ${condition.kind} is not met.`, evidence: { jobId: condition.jobId, status: job?.status ?? 'missing' } };
253
- }
254
- }
255
- default:
256
- return { due: false, reason: 'Unsupported Schedule trigger.' };
257
- }
258
- }
259
-
260
88
  function workBoundScheduleWorkId(schedule: RepositorySchedule): string | undefined {
261
89
  if (schedule.action.operation !== EXTERNAL_CONTROLLER_WAKE_OPERATION
262
90
  && schedule.action.operation !== BROWSER_PROBE_OPERATION) return undefined;
@@ -430,20 +258,6 @@ export function classifyChatgptWakeFailure(reason: string): ChatgptWakeFailureCl
430
258
  return 'ordinary_failure';
431
259
  }
432
260
 
433
- function externalControllerLaunchArgs(args: Record<string, unknown>, controllerType: string): string[] {
434
- const launchArgs = Array.isArray(args.launch_args) ? args.launch_args.map(String) : [];
435
- if (controllerType !== 'chatgpt') return launchArgs;
436
- const explicit = new Set(launchArgs.filter((value) => value.startsWith('--')).map((value) => value.split('=', 1)[0]));
437
- const add = (flag: string, value: unknown) => {
438
- if (explicit.has(flag) || typeof value !== 'string' || !value.trim()) return;
439
- launchArgs.push(flag, value.trim());
440
- };
441
- add('--model', args.model);
442
- add('--reasoning', args.reasoning);
443
- add('--tab-policy', args.tab_policy);
444
- return launchArgs;
445
- }
446
-
447
261
  async function executeExternalControllerWake(
448
262
  controllerHome: string,
449
263
  schedule: RepositorySchedule,
@@ -454,13 +268,9 @@ async function executeExternalControllerWake(
454
268
  options: { transientWakeFailure?: boolean } = {},
455
269
  ): Promise<ScheduleOccurrence> {
456
270
  const workId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
457
- const controllerType = typeof args.controller_type === 'string' ? args.controller_type.trim() : 'chatgpt';
458
271
  if (!workId) {
459
272
  return decideOccurrence(controllerHome, schedule, occurrence, 'operation_blocked', 'skipped', 'EXTERNAL_CONTROLLER_WAKE_WORK_ID_REQUIRED');
460
273
  }
461
- if (!['chatgpt', 'codex', 'claude', 'grok'].includes(controllerType)) {
462
- return decideOccurrence(controllerHome, schedule, occurrence, 'operation_blocked', 'skipped', 'EXTERNAL_CONTROLLER_WAKE_TYPE_INVALID');
463
- }
464
274
  const workStore = { controllerHome, repoId: schedule.repoId };
465
275
  const work = getWorkContract(workStore, workId);
466
276
  if (!work) {
@@ -471,136 +281,144 @@ async function executeExternalControllerWake(
471
281
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ enabled: false, pausedReason: `Work ${workId} is terminal (${work.status}).`, lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
472
282
  return decideOccurrence(controllerHome, schedule, occurrence, 'nothing_to_do', 'skipped', `Work ${workId} is terminal (${work.status}); automatic continuation stopped.`);
473
283
  }
474
- const existingOwner = getControllerSession(workStore, workId);
284
+
285
+ const retainedSession = getRetainedControllerSession(workStore, workId);
286
+ if (!retainedSession) {
287
+ return decideOccurrence(controllerHome, schedule, occurrence, 'operation_blocked', 'skipped', `SCHEDULE_CONTINUATION_CONTROLLER_SESSION_REQUIRED:${workId}`);
288
+ }
289
+ const requestedControllerType = typeof args.controller_type === 'string' ? args.controller_type.trim() : '';
290
+ if (requestedControllerType && requestedControllerType !== retainedSession.controllerType) {
291
+ return decideOccurrence(
292
+ controllerHome,
293
+ schedule,
294
+ occurrence,
295
+ 'operation_blocked',
296
+ 'skipped',
297
+ `SCHEDULE_CONTINUATION_CONTROLLER_TYPE_MISMATCH:${workId}:expected=${retainedSession.controllerType}:requested=${requestedControllerType}`,
298
+ );
299
+ }
475
300
  const occurrenceNowMs = Date.parse(timestamp);
476
301
  const nowMs = Number.isFinite(occurrenceNowMs) ? occurrenceNowMs : Date.now();
477
302
  if (workHasActiveExecution(controllerHome, schedule.repoId, workId)) {
478
303
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
479
304
  return decideOccurrence(controllerHome, schedule, occurrence, 'nothing_to_do', 'skipped', `Work ${workId} has active execution; duplicate Controller wake suppressed.`);
480
305
  }
306
+ const existingOwner = getControllerSession(workStore, workId);
481
307
  if (existingOwner && controllerSessionBlocksRecovery(workStore, workId, { nowMs })) {
482
308
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
483
309
  return decideOccurrence(controllerHome, schedule, occurrence, 'nothing_to_do', 'skipped', `Work ${workId} has a recently active Controller ${existingOwner.controllerId}.`);
484
310
  }
485
- const launchReservation = getExternalControllerLaunchReservation(workStore, workId);
486
- if (launchReservation) {
487
- updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
488
- return decideOccurrence(controllerHome, schedule, occurrence, 'nothing_to_do', 'skipped', `Work ${workId} already has a pending external Controller launch ${launchReservation.reservationId}.`);
311
+
312
+ const repository = getRepository(schedule.repoId, controllerHome, { includeRemoved: true });
313
+ let bindingId = typeof args.controller_binding_id === 'string' ? args.controller_binding_id.trim() : '';
314
+ let bindingRecord = getControllerWorkBinding(workStore, workId);
315
+ if (bindingRecord && bindingRecord.binding.bindingId !== bindingId) {
316
+ return decideOccurrence(
317
+ controllerHome,
318
+ schedule,
319
+ occurrence,
320
+ 'operation_blocked',
321
+ 'skipped',
322
+ `SCHEDULE_CONTINUATION_BINDING_DRIFT:${workId}:expected=${bindingId}:actual=${bindingRecord.binding.bindingId}`,
323
+ );
489
324
  }
325
+
326
+ const hadLegacySessionIdentity = typeof args.controller_session_id === 'string' && args.controller_session_id.trim().length > 0;
327
+
328
+ // Explicit compatibility migration for schedules written before Kernel V2 B4.
329
+ // Provider metadata is copied once into the adapter-owned binding and the
330
+ // Schedule is rewritten to exact Work/ControllerSession/ControllerBinding ids.
331
+ if (!bindingRecord) {
332
+ const binding = ensureScheduledControllerBinding(
333
+ { controllerHome, repoId: schedule.repoId },
334
+ { workId, session: retainedSession, scheduleName: schedule.name, args },
335
+ );
336
+ bindingId = binding.bindingId;
337
+ bindingRecord = getControllerWorkBinding(workStore, workId);
338
+ if (!bindingRecord || bindingRecord.binding.bindingId !== bindingId) {
339
+ throw new Error(`SCHEDULE_CONTINUATION_BINDING_MIGRATION_FAILED:${workId}`);
340
+ }
341
+ }
342
+
343
+ const continuationHintForMigration = typeof args.continuation_hint === 'string'
344
+ ? args.continuation_hint
345
+ : typeof args.continuation_prompt === 'string'
346
+ ? args.continuation_prompt
347
+ : undefined;
348
+ const relayScopeIdForMigration = typeof args.relay_scope_id === 'string' ? args.relay_scope_id.trim() : undefined;
349
+ if (hadLegacySessionIdentity || bindingId !== bindingRecord.binding.bindingId) {
350
+ bindingId = bindingRecord.binding.bindingId;
351
+ schedule = updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, (current) => ({
352
+ action: {
353
+ ...current.action,
354
+ arguments: {
355
+ work_id: workId,
356
+ controller_type: retainedSession.controllerType,
357
+ controller_binding_id: bindingId,
358
+ ...(relayScopeIdForMigration ? { relay_scope_id: relayScopeIdForMigration } : {}),
359
+ ...(continuationHintForMigration?.trim() ? { continuation_hint: continuationHintForMigration.trim() } : {}),
360
+ },
361
+ },
362
+ }));
363
+ }
364
+
365
+ const controllerType = retainedSession.controllerType;
366
+ const continuationHint = typeof schedule.action.arguments?.continuation_hint === 'string'
367
+ ? schedule.action.arguments.continuation_hint
368
+ : undefined;
369
+ const relayScopeId = typeof schedule.action.arguments?.relay_scope_id === 'string'
370
+ ? schedule.action.arguments.relay_scope_id
371
+ : undefined;
490
372
  const wakeDecision = decideOccurrence(
491
373
  controllerHome,
492
374
  schedule,
493
375
  occurrence,
494
376
  'execute',
495
377
  'running',
496
- 'Deterministic external Controller wake is starting through Thin Launcher.',
378
+ 'Deterministic Controller continuation is starting through Kernel Scheduler and ControllerHost.',
497
379
  occurrenceDecisionEvidence({
498
380
  operation: schedule.action.operation,
499
381
  workId,
500
382
  controllerType,
501
- ...(controllerType === 'chatgpt' ? {
502
- model: typeof args.model === 'string' ? args.model : 'gpt-5.6',
503
- reasoning: typeof args.reasoning === 'string' ? args.reasoning : 'high',
504
- tabPolicy: typeof args.tab_policy === 'string' ? args.tab_policy : 'auto',
505
- } : {}),
383
+ controllerSessionId: retainedSession.sessionId,
384
+ controllerBindingId: bindingRecord.binding.bindingId,
506
385
  ...extraEvidence,
507
386
  }),
508
387
  );
388
+
509
389
  try {
510
- const repository = getRepository(schedule.repoId, controllerHome, { includeRemoved: true });
511
- const continuationPrompt = typeof args.continuation_prompt === 'string'
512
- ? args.continuation_prompt
513
- : `Scheduled continuation ${occurrence.occurrenceId} from ${schedule.scheduleId}. Read current Forge state and continue only the bounded Work objective.`;
514
- if (controllerType === 'chatgpt') {
515
- const reasoning = args.reasoning === 'medium' || args.reasoning === 'xhigh' ? args.reasoning : 'high';
516
- const tabPolicy = args.tab_policy === 'reuse' || args.tab_policy === 'new' ? args.tab_policy : 'auto';
517
- const timeoutMs = externalControllerWakeTimeoutMs(args.timeout_ms);
518
- let relay;
519
- try {
520
- relay = beginInitialControllerRoundDispatch(workStore, {
521
- workId,
522
- identity: {
523
- controllerId: `schedule:${schedule.scheduleId}`,
524
- principalId: 'forge-scheduler',
525
- controllerInstanceId: 'forge-runtime-scheduler',
526
- sessionId: occurrence.occurrenceId,
527
- },
528
- requirementId: work.requirementId,
529
- browserSessionId: typeof args.browser_session_id === 'string' ? args.browser_session_id : undefined,
530
- conversationUrl: typeof args.conversation_url === 'string' ? args.conversation_url : undefined,
531
- });
532
- if (relay.status === 'blocked') throw new Error(`CONTROLLER_RELAY_LAUNCH_BLOCKED: ${relay.blockedReason ?? relay.relayScopeId}`);
533
- const relayPrompt = `${buildControllerRoundRelayPrompt(workStore, relay, { exactOriginWork: true })}\n\nScheduled continuation hint: ${continuationPrompt}`;
534
- const dispatched = await awaitExternalControllerWake(runWorkChatgptContinuation({
535
- controllerHome,
536
- repoId: schedule.repoId,
537
- repoRoot: repository.canonicalRoot,
538
- workId,
539
- prompt: relayPrompt,
540
- title: schedule.name,
541
- browserSessionId: typeof args.browser_session_id === 'string' ? args.browser_session_id : undefined,
542
- conversationUrl: typeof args.conversation_url === 'string' ? args.conversation_url : undefined,
543
- model: typeof args.model === 'string' ? args.model : 'gpt-5.6',
544
- reasoning,
545
- tabPolicy,
546
- timeoutMs,
547
- }), timeoutMs);
548
- if (dispatched.status === 'failed') throw new Error(dispatched.error?.message ?? 'CHATGPT_WORK_CONTINUATION_FAILED');
549
- const completedRelay = finishControllerRoundRelayDispatch(workStore, {
550
- workId,
551
- ok: true,
552
- browserSessionId: dispatched.browserSessionId,
553
- conversationUrl: dispatched.conversationUrl,
554
- });
555
- updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, (current) => ({
556
- lastTriggeredAt: timestamp,
557
- lastOccurrenceId: occurrence.occurrenceId,
558
- consecutiveFailures: 0,
559
- nextEligibleAt: undefined,
560
- ...(current.enabled ? { pausedReason: undefined } : {}),
561
- }));
562
- const succeededOccurrence = saveOccurrence(controllerHome, {
563
- ...wakeDecision,
564
- status: 'succeeded',
565
- reason: `ChatGPT dispatch action succeeded via ${dispatched.browserSessionId}; relay ${completedRelay?.relayScopeId ?? relay.relayScopeId} remains dispatched until the new Controller claims Work ${workId}.`,
566
- });
567
- appendWorkEvidence(workStore, workId, {
568
- evidenceId: succeededOccurrence.occurrenceId,
569
- title: 'scheduled ChatGPT continuation dispatched',
570
- summary: `Schedule ${schedule.scheduleId} timer occurrence ${succeededOccurrence.occurrenceId} dispatched the Work-bound ChatGPT continuation successfully.`,
571
- detailLevel: 'summary',
572
- });
573
- return succeededOccurrence;
574
- } catch (error) {
575
- if (relay) {
576
- finishControllerRoundRelayDispatch(workStore, {
577
- workId,
578
- ok: false,
579
- error: error instanceof Error ? error.message : String(error),
580
- });
581
- }
582
- if (error instanceof Error && error.message.startsWith('CONTROLLER_RELAY_ROUND_ALREADY_OPEN:')) {
583
- updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
584
- return decideOccurrence(controllerHome, schedule, wakeDecision, 'nothing_to_do', 'skipped', `Work ${workId} already has an open ChatGPT controller round awaiting claim or disposition.`);
585
- }
586
- throw error;
587
- }
390
+ const host = controllerHostForScheduledBinding(
391
+ { controllerHome, repoId: schedule.repoId, repoRoot: repository.canonicalRoot },
392
+ bindingRecord.binding,
393
+ );
394
+ const resumed = await resumeScheduledControllerContinuation(
395
+ workStore,
396
+ {
397
+ scheduleId: schedule.scheduleId,
398
+ occurrenceId: occurrence.occurrenceId,
399
+ workId,
400
+ controllerBindingId: bindingRecord.binding.bindingId,
401
+ relayScopeId,
402
+ continuationHint,
403
+ },
404
+ host,
405
+ );
406
+ if (resumed.dispatch.status === 'semantic_wait') {
407
+ updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({
408
+ lastTriggeredAt: timestamp,
409
+ lastOccurrenceId: occurrence.occurrenceId,
410
+ }));
411
+ return saveOccurrence(controllerHome, {
412
+ ...wakeDecision,
413
+ status: 'skipped',
414
+ decision: 'nothing_to_do',
415
+ reason: resumed.dispatch.reason ?? `Work ${workId} remains in unchanged semantic wait; provider dispatch suppressed.`,
416
+ });
417
+ }
418
+ if (resumed.dispatch.status === 'rejected') {
419
+ throw new Error(resumed.dispatch.reason ?? 'CONTROLLER_HOST_RESUME_REJECTED');
420
+
588
421
  }
589
- const launched = await launchSuperController({
590
- work: { controllerHome, repoId: schedule.repoId },
591
- handoff: { controllerHome, repoId: schedule.repoId },
592
- }, {
593
- controllerType: controllerType as 'codex' | 'claude' | 'grok',
594
- executable: typeof args.executable === 'string' ? args.executable : undefined,
595
- args: externalControllerLaunchArgs(args, controllerType),
596
- workId,
597
- handoffId: typeof args.handoff_id === 'string' ? args.handoff_id : undefined,
598
- browserSessionId: typeof args.browser_session_id === 'string' ? args.browser_session_id : undefined,
599
- conversationUrl: typeof args.conversation_url === 'string' ? args.conversation_url : undefined,
600
- launchReservationMs: typeof args.launch_reservation_ms === 'number' ? args.launch_reservation_ms : typeof args.lease_ms === 'number' ? args.lease_ms : undefined,
601
- continuationPrompt,
602
- cwd: repository.canonicalRoot,
603
- });
604
422
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, (current) => ({
605
423
  lastTriggeredAt: timestamp,
606
424
  lastOccurrenceId: occurrence.occurrenceId,
@@ -608,13 +426,26 @@ async function executeExternalControllerWake(
608
426
  nextEligibleAt: undefined,
609
427
  ...(current.enabled ? { pausedReason: undefined } : {}),
610
428
  }));
611
- return saveOccurrence(controllerHome, {
429
+ const dispatchedOccurrence = saveOccurrence(controllerHome, {
612
430
  ...wakeDecision,
613
- status: 'succeeded',
614
- reason: `External Controller wake started ${launched.controllerType} pid=${String(launched.pid ?? 'unknown')} for Work ${workId}.`,
431
+ status: 'dispatched',
432
+ reason: resumed.reused
433
+ ? `Controller continuation occurrence ${occurrence.occurrenceId} was already durably dispatched; external replay suppressed and semantic round closure is still pending.`
434
+ : `ControllerHost accepted durable binding ${bindingRecord.binding.bindingId} for Work ${workId}; dispatch ${resumed.dispatch.hostDispatchId ?? resumed.dispatch.relayScopeId}; semantic round closure is still pending.`,
435
+ });
436
+ appendWorkEvidence(workStore, workId, {
437
+ evidenceId: dispatchedOccurrence.occurrenceId,
438
+ title: 'scheduled Controller continuation dispatched',
439
+ summary: `Schedule ${schedule.scheduleId} occurrence ${dispatchedOccurrence.occurrenceId} resumed the exact Work-bound ControllerSession through ControllerHost.`,
440
+ detailLevel: 'summary',
615
441
  });
442
+ return dispatchedOccurrence;
616
443
  } catch (error) {
617
444
  const reason = error instanceof Error ? error.message : String(error);
445
+ if (reason.startsWith('SCHEDULE_CONTINUATION_ROUND_ALREADY_OPEN:')) {
446
+ updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
447
+ return decideOccurrence(controllerHome, schedule, wakeDecision, 'nothing_to_do', 'skipped', `Work ${workId} already has an open Controller round awaiting claim or disposition.`);
448
+ }
618
449
  const failureClass = controllerType === 'chatgpt' ? classifyChatgptWakeFailure(reason) : 'ordinary_failure';
619
450
  if (options.transientWakeFailure || failureClass === 'retryable_readiness' || failureClass === 'semantic_wait') {
620
451
  const semanticWait = failureClass === 'semantic_wait';
@@ -644,15 +475,17 @@ async function executeExternalControllerWake(
644
475
  ...(failureClass === 'user_action_required' ? { pauseReason: reason } : {}),
645
476
  handoff: {
646
477
  title: `External Controller wake ${occurrence.occurrenceId} failed`,
647
- summary: 'Forge recorded the schedule trigger but could not wake the configured external Controller.',
478
+ summary: 'Forge recorded the schedule trigger but could not resume the exact configured ControllerSession through ControllerHost.',
648
479
  reason,
649
480
  creationReason: 'repeated_infrastructure_failure',
650
- blockingDecision: 'Repair the external Controller/browser launch path or update the saved session reference.',
651
- recommendedDecision: 'Inspect launcher/browser readiness, then retrigger this bounded continuation.',
652
- recommendedPrompt: `Resume Work ${workId} manually, inspect failed wake occurrence ${occurrence.occurrenceId}, and repair the configured external Controller launch path before unattended continuation resumes.`,
653
- statusSummary: 'Scheduled external Controller wake failed.',
481
+ blockingDecision: reason.startsWith('SCHEDULE_CONTINUATION_OUTCOME_UNKNOWN:')
482
+ ? 'Inspect the durable ControllerHost dispatch outcome before any retry; automatic replay is fenced.'
483
+ : 'Repair the ControllerHost adapter/binding or update the retained ControllerSession.',
484
+ recommendedDecision: 'Inspect the exact Scheduler continuation dispatch, ControllerSession, and adapter binding, then retrigger only when the outcome is known.',
485
+ recommendedPrompt: `Resume Work ${workId} manually, inspect failed wake occurrence ${occurrence.occurrenceId}, and repair the exact ControllerHost continuation path before unattended continuation resumes.`,
486
+ statusSummary: 'Scheduled ControllerHost continuation failed.',
654
487
  blockedBy: ['external_controller_wake_failed'],
655
- attemptedActions: [`schedule:${schedule.scheduleId}`, `work:${workId}`, `controller:${controllerType}`],
488
+ attemptedActions: [`schedule:${schedule.scheduleId}`, `work:${workId}`, `controller:${controllerType}`, `session:${retainedSession.sessionId}`, `binding:${bindingRecord.binding.bindingId}`],
656
489
  },
657
490
  });
658
491
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
@@ -673,11 +506,23 @@ export async function evaluateSchedule(
673
506
  // Preserve retired schedule records as evidence, but do not create a new
674
507
  // occurrence or resume a controller/external action from their old payload.
675
508
  if (retiredScheduleReason(schedule)) return undefined;
676
- if (!schedule.enabled && !force) return undefined;
677
- const due = await triggerDue(controllerHome, schedule, force, triggerContext);
678
- if (!due.due) return undefined;
509
+ const eligibilityNowMs = Date.now();
510
+ const triggerJobIds = new Set<string>(schedule.trigger.dependencyJobIds ?? []);
511
+ if (schedule.trigger.condition?.jobId) triggerJobIds.add(schedule.trigger.condition.jobId);
512
+ const jobStatuses = Object.fromEntries([...triggerJobIds].map((jobId) => [jobId, findExecutionJob(controllerHome, jobId)?.status]));
513
+ const repositoryClean = schedule.trigger.condition?.kind === 'repository_clean'
514
+ ? !(await workspaceDirty(controllerHome, schedule.repoId))
515
+ : undefined;
516
+ const due = evaluateScheduleTriggerEligibility(schedule, {
517
+ nowMs: eligibilityNowMs,
518
+ force,
519
+ context: triggerContext,
520
+ repositoryClean,
521
+ jobStatuses,
522
+ });
523
+ if (!due.due || !due.windowKey) return undefined;
679
524
 
680
- const key = triggerWindowKey(schedule, triggerContext);
525
+ const key = due.windowKey;
681
526
  const occurrenceId = `OCC-${schedule.scheduleId}-${createHash('sha256').update(key).digest('hex').slice(0, 20)}`;
682
527
  const existing = getOccurrence(controllerHome, schedule.repoId, occurrenceId);
683
528
  if (existing) return existing;
@@ -729,8 +574,17 @@ export async function evaluateSchedule(
729
574
  }
730
575
 
731
576
  const recent = listOccurrences(controllerHome, schedule.repoId, schedule.scheduleId, 1000);
732
- const stop = await stopReason(controllerHome, schedule);
733
- if (stop) {
577
+ const active = listActiveOccurrences(controllerHome, schedule.repoId, schedule.scheduleId)
578
+ .filter((entry) => entry.occurrenceId !== occurrence.occurrenceId);
579
+ const admission = evaluateScheduleOccurrenceAdmission(schedule, {
580
+ nowMs: Date.now(),
581
+ force,
582
+ stopReason: await stopReason(controllerHome, schedule),
583
+ activeOccurrenceCount: active.length,
584
+ dailyRuntimeMinutes: dailyRuntimeMinutes(controllerHome, recent),
585
+ });
586
+ if (admission.kind === 'stop_condition') {
587
+ const stop = admission.reason ?? 'Schedule stop condition is active.';
734
588
  const stopped = decideOccurrence(controllerHome, schedule, occurrence, 'stopped', 'skipped', stop);
735
589
  if (!isLiveMaintenanceSchedule(schedule)) return stopped;
736
590
  const failed = applyScheduleFailure(controllerHome, schedule.scheduleId, schedule.repoId, occurrence.occurrenceId, {
@@ -754,27 +608,21 @@ export async function evaluateSchedule(
754
608
  });
755
609
  return failed.occurrence ?? stopped;
756
610
  }
757
-
758
- const active = listActiveOccurrences(controllerHome, schedule.repoId, schedule.scheduleId)
759
- .filter((entry) => entry.occurrenceId !== occurrence.occurrenceId);
760
- if (active.length >= schedule.policy.maxActiveOccurrences) {
761
- return decideOccurrence(controllerHome, schedule, occurrence, 'active_occurrence', 'skipped', 'Maximum active occurrences reached.');
611
+ if (admission.kind === 'active_occurrence') {
612
+ return decideOccurrence(controllerHome, schedule, occurrence, 'active_occurrence', 'skipped', admission.reason);
762
613
  }
763
- if (schedule.consecutiveFailures >= schedule.policy.maxFailures) {
614
+ if (admission.kind === 'failure_limit') {
764
615
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, (current) => ({
765
616
  enabled: false,
766
617
  pausedReason: current.enabled ? 'Maximum consecutive failures reached.' : current.pausedReason,
767
618
  }));
768
- return decideOccurrence(controllerHome, schedule, occurrence, 'stopped', 'skipped', 'Schedule paused after repeated failures.');
769
- }
770
- if (schedule.nextEligibleAt && Date.parse(schedule.nextEligibleAt) > Date.now() && !force) {
771
- return decideOccurrence(controllerHome, schedule, occurrence, 'cooldown', 'skipped', `Schedule backoff remains active until ${schedule.nextEligibleAt}.`);
619
+ return decideOccurrence(controllerHome, schedule, occurrence, 'stopped', 'skipped', admission.reason);
772
620
  }
773
- if (schedule.lastTriggeredAt && Date.now() - Date.parse(schedule.lastTriggeredAt) < schedule.policy.cooldownMinutes * 60_000 && !force) {
774
- return decideOccurrence(controllerHome, schedule, occurrence, 'cooldown', 'skipped', 'Schedule is cooling down.');
621
+ if (admission.kind === 'cooldown') {
622
+ return decideOccurrence(controllerHome, schedule, occurrence, 'cooldown', 'skipped', admission.reason);
775
623
  }
776
- if (dailyRuntimeMinutes(controllerHome, recent) >= schedule.policy.dailyBudgetMinutes) {
777
- return decideOccurrence(controllerHome, schedule, occurrence, 'budget_exhausted', 'skipped', 'Daily schedule budget exhausted.');
624
+ if (admission.kind === 'budget_exhausted') {
625
+ return decideOccurrence(controllerHome, schedule, occurrence, 'budget_exhausted', 'skipped', admission.reason);
778
626
  }
779
627
  if (schedule.policy.shadowMode) {
780
628
  if (isLiveMaintenanceSchedule(schedule)) {