@moretea-labs/forge 1.7.1 → 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 +39 -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 -1585
  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 +417 -100
  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 +267 -16
  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 -6651
  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 +86 -18
  609. package/src/runtime/root/package-runtime-service.ts +63 -86
  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 +1,2 @@
1
- export * from '../../control-plane/execution/work-validation-reconciler';
1
+ /** @deprecated Kernel V2 compatibility shim. MCP gateway mapping authority lives in adapters/mcp. */
2
+ export * from '../../../../adapters/mcp/runtime-gateway/work-validation-reconciler';
@@ -1,6 +1,6 @@
1
1
  import { execFileSync } from 'child_process';
2
- import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'fs';
3
- import { basename, dirname, join, relative, resolve } from 'path';
2
+ import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'fs';
3
+ import { basename, dirname, isAbsolute, join, relative, resolve } from 'path';
4
4
  import { tmpdir } from 'os';
5
5
  import type { CleanupCycleSummary } from '../control-plane/runtime-cleanup';
6
6
  import { assertRuntimeMayWrite } from '../root/write-fence';
@@ -131,6 +131,22 @@ function readJson(path: string): unknown {
131
131
  try { return JSON.parse(readFileSync(path, 'utf8')); } catch { return undefined; }
132
132
  }
133
133
 
134
+ function pathInside(root: string, candidate: string): boolean {
135
+ const rel = relative(resolve(root), resolve(candidate));
136
+ return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
137
+ }
138
+
139
+ function relocatedRuntimeStorageRoot(repoRoot: string, name: 'local-jobs' | 'jobs'): string | undefined {
140
+ const repositoryPath = join(repoRoot, '.ai', 'harness', name);
141
+ try {
142
+ if (!lstatSync(repositoryPath).isSymbolicLink()) return undefined;
143
+ const target = realpathSync(repositoryPath);
144
+ return pathInside(repoRoot, target) ? undefined : target;
145
+ } catch {
146
+ return undefined;
147
+ }
148
+ }
149
+
134
150
  function terminalStatus(status: unknown): boolean {
135
151
  return ['succeeded', 'failed', 'cancelled', 'timed_out', 'rejected'].includes(String(status));
136
152
  }
@@ -139,6 +155,7 @@ function scanTerminalLocalJobs(repoRoot: string, minAgeMinutes: number, limit: n
139
155
  const root = join(repoRoot, '.ai/harness/local-jobs');
140
156
  if (!existsSync(root)) return [];
141
157
  const at = Date.now();
158
+ const relocated = Boolean(relocatedRuntimeStorageRoot(repoRoot, 'local-jobs'));
142
159
  const candidates: RuntimeCleanupCandidate[] = [];
143
160
  for (const name of readdirSync(root).slice(0, limit * 3)) {
144
161
  const path = join(root, name);
@@ -147,20 +164,23 @@ function scanTerminalLocalJobs(repoRoot: string, minAgeMinutes: number, limit: n
147
164
  if (!stat.isDirectory()) continue;
148
165
  const jobJson = readJson(join(path, 'job.json')) as Record<string, unknown> | undefined;
149
166
  const ageMinutes = Math.max(0, Math.round((at - stat.mtimeMs) / 60_000));
150
- const safe = ageMinutes >= minAgeMinutes && terminalStatus(jobJson?.status);
167
+ const safe = relocated && ageMinutes >= minAgeMinutes && terminalStatus(jobJson?.status);
151
168
  candidates.push({
152
169
  kind: 'local_job',
153
170
  path,
154
171
  id: typeof jobJson?.jobId === 'string' ? jobJson.jobId : name,
155
- reason: safe ? 'Terminal local job is old enough to archive.' : 'Local job is not terminal or is too new.',
172
+ reason: !relocated
173
+ ? 'Repository-local Local Job storage must be relocated to Controller Home before cleanup.'
174
+ : safe ? 'Terminal Local Job is old enough to remove from Controller runtime storage.' : 'Local Job is not terminal or is too new.',
156
175
  ageMinutes,
157
176
  safe,
177
+ ownershipStatus: relocated ? 'explicit' : 'unknown',
158
178
  });
159
179
  } catch {
160
180
  // Ignore malformed entries.
161
181
  }
162
182
  }
163
- return candidates.filter((candidate) => candidate.safe).slice(0, limit);
183
+ return candidates.slice(0, limit);
164
184
  }
165
185
 
166
186
  function textIncludesNoOpIntegrate(value: unknown): boolean {
@@ -190,6 +210,7 @@ function scanLegacyRuns(repoRoot: string, minAgeMinutes: number, limit: number):
190
210
  if (!existsSync(root)) return [];
191
211
  const processes = processCommands();
192
212
  const at = Date.now();
213
+ const relocated = Boolean(relocatedRuntimeStorageRoot(repoRoot, 'jobs'));
193
214
  const candidates: RuntimeCleanupCandidate[] = [];
194
215
  for (const name of readdirSync(root).filter((entry) => entry.startsWith('RUN-')).slice(0, limit * 3)) {
195
216
  const path = join(root, name);
@@ -200,17 +221,20 @@ function scanLegacyRuns(repoRoot: string, minAgeMinutes: number, limit: number):
200
221
  const occupied = processes.find((process) => process.command.includes(name) || process.command.includes(path));
201
222
  const status = String(state?.status ?? 'unknown');
202
223
  const ageMinutes = Math.max(0, Math.round((at - stat.mtimeMs) / 60_000));
203
- const safe = !occupied && ageMinutes >= minAgeMinutes && status === 'waiting_for_user' && textIncludesNoOpIntegrate(state);
224
+ const safe = relocated && !occupied && ageMinutes >= minAgeMinutes && status === 'waiting_for_user' && textIncludesNoOpIntegrate(state);
204
225
  candidates.push({
205
226
  kind: 'legacy_run',
206
227
  path,
207
228
  id: typeof state?.runId === 'string' ? state.runId : name,
208
- reason: safe
209
- ? 'Legacy task run is waiting_for_user only because its worktree has no changes to integrate; it is safe to archive.'
210
- : `Legacy task run is not a proven no-op waiting_for_user run. status=${status}`,
229
+ reason: !relocated
230
+ ? 'Repository-local legacy Run storage must be relocated to Controller Home before cleanup.'
231
+ : safe
232
+ ? 'Legacy no-op Run is old enough to remove from Controller runtime storage.'
233
+ : `Legacy task run is not a proven no-op waiting_for_user run. status=${status}`,
211
234
  ageMinutes,
212
235
  occupiedByPid: occupied?.pid,
213
236
  safe,
237
+ ownershipStatus: relocated ? 'explicit' : 'unknown',
214
238
  });
215
239
  } catch {
216
240
  candidates.push({
@@ -284,7 +308,7 @@ export function previewRuntimeCleanup(repoRoot: string, options: RuntimeCleanupO
284
308
  summary: summarize(candidates),
285
309
  warnings: [
286
310
  'Preview is non-destructive. Apply requires confirmCleanup=true.',
287
- 'Legacy run cleanup only archives directories proven to be old no-op waiting_for_user runs with no matching process.',
311
+ 'Legacy runtime cleanup removes only relocated Controller Home records proven terminal/no-op and old enough; repository-local storage is never archived in the source tree.',
288
312
  'Historical attention cleanup is intentionally represented as acknowledgement guidance unless an explicit reconciler is added.',
289
313
  ],
290
314
  cycle: {
@@ -306,18 +330,6 @@ export function previewRuntimeCleanup(repoRoot: string, options: RuntimeCleanupO
306
330
  };
307
331
  }
308
332
 
309
- function archiveLocalJob(path: string, repoRoot: string): void {
310
- const archiveRoot = join(repoRoot, '.ai/harness/local-jobs-archive');
311
- mkdirSync(archiveRoot, { recursive: true });
312
- renameSync(path, join(archiveRoot, basename(path)));
313
- }
314
-
315
- function archiveLegacyRun(path: string, repoRoot: string): void {
316
- const archiveRoot = join(repoRoot, '.ai/harness/jobs-archive/legacy-noop');
317
- mkdirSync(archiveRoot, { recursive: true });
318
- renameSync(path, join(archiveRoot, basename(path)));
319
- }
320
-
321
333
  export function applyRuntimeCleanup(repoRoot: string, options: RuntimeCleanupOptions = {}): RuntimeCleanupApplyResult {
322
334
  // Passive / fenced runtimes must not run cleanup.
323
335
  try {
@@ -362,14 +374,16 @@ export function applyRuntimeCleanup(repoRoot: string, options: RuntimeCleanupOpt
362
374
  if (candidate.kind === 'local_job' && candidate.path) {
363
375
  const relativePath = relative(join(repoRoot, '.ai/harness/local-jobs'), candidate.path);
364
376
  if (relativePath && !relativePath.startsWith('..')) {
365
- archiveLocalJob(candidate.path, repoRoot);
377
+ if (!relocatedRuntimeStorageRoot(repoRoot, 'local-jobs')) throw new Error('RUNTIME_CLEANUP_STORAGE_NOT_RELOCATED');
378
+ rmSync(candidate.path, { recursive: true, force: true });
366
379
  return { ...candidate, applied: true };
367
380
  }
368
381
  }
369
382
  if (candidate.kind === 'legacy_run' && candidate.path) {
370
383
  const relativePath = relative(join(repoRoot, '.ai/harness/jobs'), candidate.path);
371
384
  if (relativePath && !relativePath.startsWith('..') && basename(candidate.path).startsWith('RUN-')) {
372
- archiveLegacyRun(candidate.path, repoRoot);
385
+ if (!relocatedRuntimeStorageRoot(repoRoot, 'jobs')) throw new Error('RUNTIME_CLEANUP_STORAGE_NOT_RELOCATED');
386
+ rmSync(candidate.path, { recursive: true, force: true });
373
387
  return { ...candidate, applied: true };
374
388
  }
375
389
  }
@@ -0,0 +1,174 @@
1
+ import { existsSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join, win32 as windowsPath } from 'path';
4
+ import { discoverExecutable } from './executable-discovery';
5
+ import type { NativeBrowserChannel } from '../../cli/chatgpt-browser/types';
6
+
7
+ export type BrowserProductDiscoverySource = 'explicit' | 'path' | 'fallback';
8
+
9
+ export interface NativeBrowserProduct {
10
+ channel: NativeBrowserChannel;
11
+ appName: string;
12
+ executable: string;
13
+ source: BrowserProductDiscoverySource;
14
+ defaultUserDataDir?: string;
15
+ }
16
+
17
+ export interface NativeBrowserProductDescriptor {
18
+ appName: string;
19
+ defaultUserDataDir?: string;
20
+ }
21
+
22
+ interface BrowserProductFallback extends NativeBrowserProductDescriptor {
23
+ appName: string;
24
+ pathNames: string[];
25
+ executableFallbacks: string[];
26
+ defaultUserDataDir?: string;
27
+ }
28
+
29
+ function channelSuffix(channel: NativeBrowserChannel): { mac: string; win: string; linux: string; profile: string } {
30
+ if (channel === 'chrome') return { mac: '', win: '', linux: '', profile: 'Chrome' };
31
+ if (channel === 'chrome-beta') return { mac: ' Beta', win: ' Beta', linux: '-beta', profile: 'Chrome Beta' };
32
+ if (channel === 'chrome-dev') return { mac: ' Dev', win: ' Dev', linux: '-unstable', profile: 'Chrome Dev' };
33
+ return { mac: ' Canary', win: ' SxS', linux: '-unstable', profile: 'Chrome Canary' };
34
+ }
35
+
36
+ function fallbackFor(channel: NativeBrowserChannel, platform: NodeJS.Platform, env: NodeJS.ProcessEnv): BrowserProductFallback | undefined {
37
+ const suffix = channelSuffix(channel);
38
+ if (platform === 'darwin') {
39
+ const appName = `Google Chrome${suffix.mac}`;
40
+ return {
41
+ appName,
42
+ pathNames: channel === 'chrome' ? ['google-chrome', 'chrome'] : [`google-chrome${suffix.linux}`],
43
+ executableFallbacks: [`/Applications/${appName}.app/Contents/MacOS/${appName}`],
44
+ defaultUserDataDir: join(env.HOME ?? homedir(), 'Library', 'Application Support', 'Google', suffix.profile),
45
+ };
46
+ }
47
+ if (platform === 'win32') {
48
+ const productRoot = channel === 'chrome-canary' ? 'Chrome SxS' : suffix.profile;
49
+ const relativeExecutable = windowsPath.join('Google', productRoot, 'Application', 'chrome.exe');
50
+ const programRoots = [env.ProgramFiles, env['ProgramFiles(x86)']].map((value) => value?.trim()).filter((value): value is string => Boolean(value));
51
+ const localAppData = env.LOCALAPPDATA?.trim() || windowsPath.join(env.USERPROFILE?.trim() || homedir(), 'AppData', 'Local');
52
+ const profileFolder = channel === 'chrome-canary' ? 'Chrome SxS' : suffix.profile;
53
+ return {
54
+ appName: channel === 'chrome' ? 'Google Chrome' : `Google Chrome${suffix.mac}`,
55
+ pathNames: ['chrome.exe', 'chrome'],
56
+ executableFallbacks: programRoots.map((root) => windowsPath.join(root, relativeExecutable)),
57
+ defaultUserDataDir: windowsPath.join(localAppData, 'Google', profileFolder, 'User Data'),
58
+ };
59
+ }
60
+ if (platform === 'linux') {
61
+ const command = channel === 'chrome' ? 'google-chrome' : `google-chrome${suffix.linux}`;
62
+ const configRoot = env.XDG_CONFIG_HOME?.trim() || join(env.HOME ?? homedir(), '.config');
63
+ return {
64
+ appName: channel === 'chrome' ? 'Google Chrome' : `Google Chrome${suffix.mac}`,
65
+ pathNames: channel === 'chrome' ? ['google-chrome', 'google-chrome-stable'] : [command],
66
+ executableFallbacks: [],
67
+ defaultUserDataDir: join(configRoot, command),
68
+ };
69
+ }
70
+ return undefined;
71
+ }
72
+
73
+
74
+ export function describeNativeBrowserProduct(input: {
75
+ channel: NativeBrowserChannel;
76
+ platform?: NodeJS.Platform;
77
+ env?: NodeJS.ProcessEnv;
78
+ }): NativeBrowserProductDescriptor | undefined {
79
+ const fallback = fallbackFor(input.channel, input.platform ?? process.platform, input.env ?? process.env);
80
+ return fallback ? { appName: fallback.appName, defaultUserDataDir: fallback.defaultUserDataDir } : undefined;
81
+ }
82
+
83
+ export function discoverNativeBrowserProduct(input: {
84
+ channel: NativeBrowserChannel;
85
+ platform?: NodeJS.Platform;
86
+ env?: NodeJS.ProcessEnv;
87
+ explicitExecutable?: string;
88
+ explicitUserDataDir?: string;
89
+ fileExists?: (path: string) => boolean;
90
+ }): NativeBrowserProduct | undefined {
91
+ const platform = input.platform ?? process.platform;
92
+ const env = input.env ?? process.env;
93
+ const fallback = fallbackFor(input.channel, platform, env);
94
+ if (!fallback) return undefined;
95
+ const explicitExecutable = input.explicitExecutable?.trim() || env.FORGE_BROWSER_EXECUTABLE?.trim();
96
+ const explicitUserDataDir = input.explicitUserDataDir?.trim() || env.FORGE_BROWSER_USER_DATA_DIR?.trim();
97
+ const fileExists = input.fileExists ?? existsSync;
98
+ if (explicitExecutable) {
99
+ const resolution = discoverExecutable({ id: `browser:${input.channel}`, candidates: [], platform, env, explicitPath: explicitExecutable, fileExists });
100
+ if (resolution.status !== 'ready' || !resolution.executable) return undefined;
101
+ return { channel: input.channel, appName: fallback.appName, executable: resolution.executable, source: 'explicit', defaultUserDataDir: explicitUserDataDir || fallback.defaultUserDataDir };
102
+ }
103
+ const onPath = discoverExecutable({ id: `browser:${input.channel}`, candidates: fallback.pathNames, platform, env, fileExists });
104
+ if (onPath.status === 'ready' && onPath.executable) {
105
+ return { channel: input.channel, appName: fallback.appName, executable: onPath.executable, source: 'path', defaultUserDataDir: explicitUserDataDir || fallback.defaultUserDataDir };
106
+ }
107
+ const executable = fallback.executableFallbacks.find((candidate) => fileExists(candidate));
108
+ if (!executable) return undefined;
109
+ return { channel: input.channel, appName: fallback.appName, executable, source: 'fallback', defaultUserDataDir: explicitUserDataDir || fallback.defaultUserDataDir };
110
+ }
111
+
112
+ export type SupportedNativeBrowserProductId = 'chrome' | 'vivaldi';
113
+
114
+ export interface SupportedNativeBrowserProduct extends NativeBrowserProduct {
115
+ product: SupportedNativeBrowserProductId;
116
+ }
117
+
118
+ function discoverVivaldiProduct(input: {
119
+ platform: NodeJS.Platform;
120
+ env: NodeJS.ProcessEnv;
121
+ fileExists: (path: string) => boolean;
122
+ }): SupportedNativeBrowserProduct | undefined {
123
+ const { platform, env, fileExists } = input;
124
+ let pathNames: string[] = [];
125
+ let executableFallbacks: string[] = [];
126
+ let defaultUserDataDir: string | undefined;
127
+ if (platform === 'darwin') {
128
+ pathNames = ['vivaldi'];
129
+ executableFallbacks = ['/Applications/Vivaldi.app/Contents/MacOS/Vivaldi'];
130
+ defaultUserDataDir = join(env.HOME ?? homedir(), 'Library', 'Application Support', 'Vivaldi');
131
+ } else if (platform === 'win32') {
132
+ pathNames = ['vivaldi.exe', 'vivaldi'];
133
+ const localAppData = env.LOCALAPPDATA?.trim() || windowsPath.join(env.USERPROFILE?.trim() || homedir(), 'AppData', 'Local');
134
+ const roots = [localAppData, env.ProgramFiles, env['ProgramFiles(x86)']].map((value) => value?.trim()).filter((value): value is string => Boolean(value));
135
+ executableFallbacks = roots.map((root) => windowsPath.join(root, 'Vivaldi', 'Application', 'vivaldi.exe'));
136
+ defaultUserDataDir = windowsPath.join(localAppData, 'Vivaldi', 'User Data');
137
+ } else if (platform === 'linux') {
138
+ pathNames = ['vivaldi', 'vivaldi-stable'];
139
+ defaultUserDataDir = join(env.XDG_CONFIG_HOME?.trim() || join(env.HOME ?? homedir(), '.config'), 'vivaldi');
140
+ } else {
141
+ return undefined;
142
+ }
143
+ const onPath = discoverExecutable({ id: 'browser:vivaldi', candidates: pathNames, platform, env, fileExists });
144
+ if (onPath.status === 'ready' && onPath.executable) {
145
+ return { product: 'vivaldi', channel: 'chrome', appName: 'Vivaldi', executable: onPath.executable, source: 'path', defaultUserDataDir };
146
+ }
147
+ const executable = executableFallbacks.find((candidate) => fileExists(candidate));
148
+ return executable
149
+ ? { product: 'vivaldi', channel: 'chrome', appName: 'Vivaldi', executable, source: 'fallback', defaultUserDataDir }
150
+ : undefined;
151
+ }
152
+
153
+ /** Discover a usable supported Chromium-family product without binding product readiness to one developer browser. */
154
+ export function discoverPreferredNativeBrowserProduct(input: {
155
+ platform?: NodeJS.Platform;
156
+ env?: NodeJS.ProcessEnv;
157
+ explicitExecutable?: string;
158
+ explicitUserDataDir?: string;
159
+ fileExists?: (path: string) => boolean;
160
+ } = {}): SupportedNativeBrowserProduct | undefined {
161
+ const platform = input.platform ?? process.platform;
162
+ const env = input.env ?? process.env;
163
+ const fileExists = input.fileExists ?? existsSync;
164
+ const channels: NativeBrowserChannel[] = ['chrome', 'chrome-beta', 'chrome-dev', 'chrome-canary'];
165
+ for (const channel of channels) {
166
+ const chrome = discoverNativeBrowserProduct({
167
+ channel, platform, env, fileExists,
168
+ explicitExecutable: channel === 'chrome' ? input.explicitExecutable : undefined,
169
+ explicitUserDataDir: input.explicitUserDataDir,
170
+ });
171
+ if (chrome) return { ...chrome, product: 'chrome' };
172
+ }
173
+ return discoverVivaldiProduct({ platform, env, fileExists });
174
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Platform resolution for Computer composition. Keeping this behind one seam
3
+ * makes native-provider policy deterministic in contract tests without
4
+ * weakening the production platform fence.
5
+ */
6
+ let platformOverrideForTest: NodeJS.Platform | undefined;
7
+
8
+ export function currentComputerPlatform(): NodeJS.Platform {
9
+ return platformOverrideForTest ?? process.platform;
10
+ }
11
+
12
+ export function setComputerPlatformForTest(platform: NodeJS.Platform | undefined): void {
13
+ platformOverrideForTest = platform;
14
+ }
@@ -0,0 +1,54 @@
1
+ import { existsSync } from 'fs';
2
+ import { delimiter, isAbsolute, join } from 'path';
3
+
4
+ export type ExecutableDiscoveryStatus = 'ready' | 'missing' | 'unsupported';
5
+ export interface ExecutableDiscoveryResult {
6
+ id: string;
7
+ status: ExecutableDiscoveryStatus;
8
+ executable?: string;
9
+ source?: 'explicit' | 'path';
10
+ recovery?: string;
11
+ }
12
+
13
+ function executableNames(name: string, platform: NodeJS.Platform, env: NodeJS.ProcessEnv): string[] {
14
+ if (platform !== 'win32' || /\.[A-Za-z0-9]+$/.test(name)) return [name];
15
+ const extensions = (env.PATHEXT || '.COM;.EXE;.BAT;.CMD').split(';').map((value) => value.trim()).filter(Boolean);
16
+ return [name, ...extensions.map((extension) => `${name}${extension.toLowerCase()}`), ...extensions.map((extension) => `${name}${extension.toUpperCase()}`)];
17
+ }
18
+
19
+ export function discoverExecutable(input: {
20
+ id: string;
21
+ candidates: readonly string[];
22
+ platform?: NodeJS.Platform;
23
+ env?: NodeJS.ProcessEnv;
24
+ explicitPath?: string;
25
+ supportedPlatforms?: readonly NodeJS.Platform[];
26
+ fileExists?: (path: string) => boolean;
27
+ recovery?: string;
28
+ }): ExecutableDiscoveryResult {
29
+ const platform = input.platform ?? process.platform;
30
+ const env = input.env ?? process.env;
31
+ const fileExists = input.fileExists ?? existsSync;
32
+ if (input.supportedPlatforms && !input.supportedPlatforms.includes(platform)) {
33
+ return { id: input.id, status: 'unsupported', recovery: input.recovery };
34
+ }
35
+ const explicit = input.explicitPath?.trim();
36
+ if (explicit) {
37
+ if (isAbsolute(explicit) && fileExists(explicit)) return { id: input.id, status: 'ready', executable: explicit, source: 'explicit' };
38
+ return { id: input.id, status: 'missing', recovery: input.recovery };
39
+ }
40
+ const pathEntries = (env.PATH ?? '').split(delimiter).map((entry) => entry.trim()).filter(Boolean);
41
+ for (const candidate of input.candidates) {
42
+ if (isAbsolute(candidate)) {
43
+ if (fileExists(candidate)) return { id: input.id, status: 'ready', executable: candidate, source: 'path' };
44
+ continue;
45
+ }
46
+ for (const directory of pathEntries) {
47
+ for (const name of executableNames(candidate, platform, env)) {
48
+ const executable = join(directory, name);
49
+ if (fileExists(executable)) return { id: input.id, status: 'ready', executable, source: 'path' };
50
+ }
51
+ }
52
+ }
53
+ return { id: input.id, status: 'missing', recovery: input.recovery };
54
+ }
@@ -0,0 +1,90 @@
1
+ import { createServer, type IncomingMessage, type ServerResponse } from 'http';
2
+
3
+ export interface FetchHttpServer {
4
+ readonly port: number;
5
+ stop(force?: boolean): void;
6
+ }
7
+
8
+ export interface FetchHttpServerOptions {
9
+ hostname?: string;
10
+ port?: number;
11
+ maxRequestBytes?: number;
12
+ fetch(request: Request): Response | Promise<Response>;
13
+ }
14
+
15
+ async function requestBody(request: IncomingMessage, maxRequestBytes: number): Promise<ArrayBuffer | undefined> {
16
+ if (request.method === 'GET' || request.method === 'HEAD') return undefined;
17
+ const declaredLength = Number(request.headers['content-length'] ?? 0);
18
+ if (Number.isFinite(declaredLength) && declaredLength > maxRequestBytes) throw new Error('FETCH_HTTP_REQUEST_TOO_LARGE');
19
+ const chunks: Buffer[] = [];
20
+ let bytes = 0;
21
+ for await (const chunk of request) {
22
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
23
+ bytes += buffer.byteLength;
24
+ if (bytes > maxRequestBytes) throw new Error('FETCH_HTTP_REQUEST_TOO_LARGE');
25
+ chunks.push(buffer);
26
+ }
27
+ if (!chunks.length) return undefined;
28
+ const combined = Buffer.concat(chunks);
29
+ const copy = new Uint8Array(combined.byteLength);
30
+ copy.set(combined);
31
+ return copy.buffer;
32
+ }
33
+
34
+ async function toFetchRequest(request: IncomingMessage, hostname: string, maxRequestBytes: number): Promise<Request> {
35
+ const authority = request.headers.host?.trim() || hostname;
36
+ const url = new URL(request.url || '/', `http://${authority}`);
37
+ const headers = new Headers();
38
+ for (const [name, raw] of Object.entries(request.headers)) {
39
+ if (raw === undefined) continue;
40
+ if (Array.isArray(raw)) for (const value of raw) headers.append(name, value);
41
+ else headers.set(name, raw);
42
+ }
43
+ const requestBodyBuffer = await requestBody(request, maxRequestBytes);
44
+ return new Request(url, {
45
+ method: request.method || 'GET',
46
+ headers,
47
+ ...(requestBodyBuffer ? { body: requestBodyBuffer } : {}),
48
+ });
49
+ }
50
+
51
+ async function writeFetchResponse(response: Response, target: ServerResponse): Promise<void> {
52
+ target.statusCode = response.status;
53
+ response.headers.forEach((value, name) => target.setHeader(name, value));
54
+ if (!response.body) { target.end(); return; }
55
+ const body = Buffer.from(await response.arrayBuffer());
56
+ target.end(body);
57
+ }
58
+
59
+ export async function serveFetchHttp(input: FetchHttpServerOptions): Promise<FetchHttpServer> {
60
+ const hostname = input.hostname ?? '127.0.0.1';
61
+ const maxRequestBytes = Math.max(1_024, Math.min(input.maxRequestBytes ?? 1_048_576, 16_777_216));
62
+ const server = createServer(async (nodeRequest, nodeResponse) => {
63
+ try {
64
+ const request = await toFetchRequest(nodeRequest, hostname, maxRequestBytes);
65
+ await writeFetchResponse(await input.fetch(request), nodeResponse);
66
+ } catch (error) {
67
+ if (nodeResponse.headersSent) { nodeResponse.destroy(); return; }
68
+ const tooLarge = error instanceof Error && error.message === 'FETCH_HTTP_REQUEST_TOO_LARGE';
69
+ nodeResponse.statusCode = tooLarge ? 413 : 500;
70
+ nodeResponse.setHeader('content-type', 'application/json; charset=utf-8');
71
+ nodeResponse.end(JSON.stringify({ error: { code: tooLarge ? 'REQUEST_TOO_LARGE' : 'LOCAL_HTTP_HANDLER_FAILED' } }));
72
+ }
73
+ });
74
+ await new Promise<void>((resolve, reject) => {
75
+ const onError = (error: Error) => { server.off('listening', onListening); reject(error); };
76
+ const onListening = () => { server.off('error', onError); resolve(); };
77
+ server.once('error', onError);
78
+ server.once('listening', onListening);
79
+ server.listen(input.port ?? 0, hostname);
80
+ });
81
+ const address = server.address();
82
+ if (!address || typeof address === 'string') { server.close(); throw new Error('FETCH_HTTP_LISTENER_ADDRESS_UNAVAILABLE'); }
83
+ return {
84
+ port: address.port,
85
+ stop(force = false): void {
86
+ if (force && typeof server.closeAllConnections === 'function') server.closeAllConnections();
87
+ server.close();
88
+ },
89
+ };
90
+ }
@@ -0,0 +1,138 @@
1
+ import { spawn, spawnSync } from 'child_process';
2
+ import { closeSync, mkdirSync, openSync } from 'fs';
3
+ import { dirname } from 'path';
4
+ import {
5
+ bootstrapLaunchAgentWithRetryV2,
6
+ bootoutLaunchAgentWithRetryV2,
7
+ currentUserLaunchdDomain,
8
+ installLaunchAgent,
9
+ launchAgentPath,
10
+ retireConflictingForgeLaunchAgents,
11
+ } from '../../cli/controller/launch-agents';
12
+ import {
13
+ installSystemdUserUnit,
14
+ renderSystemdUserUnit,
15
+ systemdUserAvailable,
16
+ writeSystemdUserUnit,
17
+ systemdUserInstallCommands,
18
+ type SystemdUserUnitInput,
19
+ } from '../../cli/controller/systemd-user';
20
+
21
+ export type { SystemdUserUnitInput } from '../../cli/controller/systemd-user';
22
+
23
+ export type PlatformServiceManagerKind = 'launchd' | 'systemd-user' | 'portable';
24
+
25
+ export interface PlatformServiceManagerSelection {
26
+ kind: PlatformServiceManagerKind;
27
+ persistent: boolean;
28
+ reason: string;
29
+ }
30
+
31
+ export interface PlatformDetachedProcessInput {
32
+ executable: string;
33
+ args: string[];
34
+ environment: NodeJS.ProcessEnv;
35
+ stdoutPath: string;
36
+ stderrPath: string;
37
+ errorCode: string;
38
+ }
39
+
40
+ export interface PlatformServiceManagerHost {
41
+ selection: PlatformServiceManagerSelection;
42
+ renderSystemdUserUnit(input: SystemdUserUnitInput): string;
43
+ installSystemdUserUnit(input: { unitName: string; unit: SystemdUserUnitInput; env?: NodeJS.ProcessEnv; errorPrefix: string }): string;
44
+ writeSystemdUserUnit(unitName: string, unit: SystemdUserUnitInput, env?: NodeJS.ProcessEnv): string;
45
+ systemdUserInstallCommands(unitName: string): string[][];
46
+ launchdInstalledPath(label: string, accountHome?: string): string;
47
+ installLaunchd(sourcePath: string, label: string): void;
48
+ bootstrapLaunchd(input: { label: string; plistPath: string }): Promise<{ ok: boolean; diagnostics: string[] }>;
49
+ bootoutLaunchd(input: { label: string; plistPath: string }): Promise<{ ok: boolean; diagnostics: string[] }>;
50
+ retireConflictingLaunchd(input: Parameters<typeof retireConflictingForgeLaunchAgents>[0]): ReturnType<typeof retireConflictingForgeLaunchAgents>;
51
+ launchdDomain(): string;
52
+ detachLaunchdBootout(label: string): void;
53
+ startDetached(input: PlatformDetachedProcessInput): number;
54
+ }
55
+
56
+ /** Pure product-level selection. Platform adapters own probing/install mechanics. */
57
+ export function resolvePlatformServiceManager(input: {
58
+ platform: NodeJS.Platform;
59
+ forcePortable?: boolean;
60
+ systemdUserAvailable?: boolean;
61
+ }): PlatformServiceManagerSelection {
62
+ if (input.forcePortable === true) {
63
+ return { kind: 'portable', persistent: false, reason: 'portable_explicitly_requested' };
64
+ }
65
+ if (input.platform === 'darwin') {
66
+ return { kind: 'launchd', persistent: true, reason: 'macos_launchd_available' };
67
+ }
68
+ if (input.platform === 'linux' && input.systemdUserAvailable === true) {
69
+ return { kind: 'systemd-user', persistent: true, reason: 'linux_systemd_user_available' };
70
+ }
71
+ if (input.platform === 'linux') {
72
+ return { kind: 'portable', persistent: false, reason: 'linux_systemd_user_unavailable' };
73
+ }
74
+ if (input.platform === 'win32') {
75
+ return { kind: 'portable', persistent: false, reason: 'windows_native_persistence_preview' };
76
+ }
77
+ return { kind: 'portable', persistent: false, reason: 'platform_service_manager_unsupported' };
78
+ }
79
+
80
+ export function createPlatformServiceManagerHost(input: {
81
+ platform?: NodeJS.Platform;
82
+ env?: NodeJS.ProcessEnv;
83
+ forcePortable?: boolean;
84
+ systemdUserAvailable?: boolean;
85
+ } = {}): PlatformServiceManagerHost {
86
+ const platform = input.platform ?? process.platform;
87
+ const env = input.env ?? process.env;
88
+ const systemdAvailable = input.systemdUserAvailable ?? (platform === 'linux' ? systemdUserAvailable(env) : false);
89
+ const selection = resolvePlatformServiceManager({ platform, forcePortable: input.forcePortable, systemdUserAvailable: systemdAvailable });
90
+ return {
91
+ selection,
92
+ renderSystemdUserUnit,
93
+ installSystemdUserUnit,
94
+ writeSystemdUserUnit,
95
+ systemdUserInstallCommands,
96
+ launchdInstalledPath: launchAgentPath,
97
+ installLaunchd: installLaunchAgent,
98
+ bootstrapLaunchd: bootstrapLaunchAgentWithRetryV2,
99
+ bootoutLaunchd: bootoutLaunchAgentWithRetryV2,
100
+ retireConflictingLaunchd: retireConflictingForgeLaunchAgents,
101
+ launchdDomain: currentUserLaunchdDomain,
102
+ detachLaunchdBootout(label: string): void {
103
+ if (platform !== 'darwin') return;
104
+ const child = spawn('/bin/launchctl', ['bootout', `${currentUserLaunchdDomain()}/${label}`], {
105
+ detached: true, stdio: 'ignore', env: { PATH: '/usr/bin:/bin:/usr/sbin:/sbin' },
106
+ });
107
+ child.unref();
108
+ },
109
+ startDetached(processInput: PlatformDetachedProcessInput): number {
110
+ mkdirSync(dirname(processInput.stdoutPath), { recursive: true, mode: 0o700 });
111
+ const stdout = openSync(processInput.stdoutPath, 'a', 0o600);
112
+ const stderr = openSync(processInput.stderrPath, 'a', 0o600);
113
+ try {
114
+ const child = spawn(processInput.executable, processInput.args, {
115
+ detached: true, stdio: ['ignore', stdout, stderr], env: processInput.environment,
116
+ });
117
+ if (!child.pid) throw new Error(`${processInput.errorCode}: child pid unavailable`);
118
+ child.unref();
119
+ return child.pid;
120
+ } finally {
121
+ closeSync(stdout);
122
+ closeSync(stderr);
123
+ }
124
+ },
125
+ };
126
+ }
127
+
128
+ export function platformLaunchdInstalledPath(label: string, accountHome?: string): string {
129
+ return launchAgentPath(label, accountHome);
130
+ }
131
+
132
+ export function probeSystemdUserAvailable(env: NodeJS.ProcessEnv = process.env): boolean {
133
+ return systemdUserAvailable(env);
134
+ }
135
+
136
+ export function probeSystemdUserAvailableDirect(env: NodeJS.ProcessEnv = process.env): boolean {
137
+ return spawnSync('systemctl', ['--user', 'show-environment'], { encoding: 'utf8', env, timeout: 30_000 }).status === 0;
138
+ }