@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,224 +1,50 @@
1
- import { AsyncLocalStorage } from 'node:async_hooks';
2
- import { createHash } from 'crypto';
3
- import { readdirSync, readFileSync } from 'fs';
4
- import { join, resolve } from 'path';
1
+ /** @deprecated Compatibility facade. Durable Browser interaction identity belongs to Computer SurfaceTarget authority. */
2
+ import type {
3
+ BrowserSessionAuthorityPage,
4
+ BrowserSessionAuthoritySession,
5
+ BrowserSessionLegacyCutoverRepository,
6
+ BrowserSessionLegacyCutoverReport,
7
+ BrowserSessionTombstoneCleanupReport,
8
+ } from '../../../packages/plugin-runtime/browser/session-authority';
5
9
  import {
6
- listControlPlaneRecords,
7
- readControlPlaneRecord,
8
- readControlPlaneRecordWithinTransaction,
9
- withControlPlaneTransaction,
10
- writeControlPlaneRecordWithinTransaction,
11
- } from '../control-plane/persistence/sqlite-store';
12
-
13
- const SESSION_NAMESPACE = 'browser_session';
14
- const SESSION_SCOPE = 'controller';
15
- const IMPORT_NAMESPACE = 'browser_session_legacy_import';
16
- const MAX_AUTHORITY_RECORDS = 5_000;
17
- export const DEFAULT_BROWSER_SESSION_LIST_LIMIT = 50;
18
- export const MAX_BROWSER_SESSION_LIST_LIMIT = 200;
19
-
20
- export interface BrowserSessionAuthorityContext {
21
- controllerHome: string;
22
- repoId: string;
23
- }
24
-
25
- export interface BrowserSessionAuthoritySession {
26
- schemaVersion: 1;
27
- sessionId: string;
28
- url: string;
29
- title?: string;
30
- createdAt: string;
31
- updatedAt: string;
32
- browser?: {
33
- provider?: string;
34
- browserProduct?: string;
35
- tab?: {
36
- windowId?: string;
37
- tabId?: string;
38
- ownership?: string;
39
- };
40
- };
41
- }
42
-
43
- interface BrowserSessionAuthorityEntry<T extends BrowserSessionAuthoritySession = BrowserSessionAuthoritySession> {
44
- schemaVersion: 1;
45
- status: 'active' | 'tombstoned';
46
- session: T;
47
- aliases: string[];
48
- repositoryIds: string[];
49
- nativeIdentity?: string;
50
- tombstonedAt?: string;
51
- importedFromLegacy?: boolean;
52
- }
53
-
54
- interface LegacyImportMarker {
55
- schemaVersion: 1;
56
- repoId: string;
57
- repoRootFingerprint: string;
58
- importedAt: string;
59
- importedRecordCount: number;
60
- }
61
-
62
- export interface BrowserSessionAuthorityPage<T extends BrowserSessionAuthoritySession = BrowserSessionAuthoritySession> {
63
- sessions: T[];
64
- limit: number;
65
- totalCount: number;
66
- nextCursor?: string;
67
- }
68
-
69
- const authorityContextStorage = new AsyncLocalStorage<BrowserSessionAuthorityContext>();
70
-
71
- export function withBrowserSessionAuthorityContext<T>(
72
- context: BrowserSessionAuthorityContext,
73
- operation: () => T,
74
- ): T {
75
- return authorityContextStorage.run(context, operation);
76
- }
77
-
78
- export function currentBrowserSessionAuthorityContext(): BrowserSessionAuthorityContext | undefined {
79
- return authorityContextStorage.getStore();
80
- }
81
-
82
- function digest(value: string): string {
83
- return createHash('sha256').update(value).digest('hex');
84
- }
85
-
86
- function nativeIdentity(session: BrowserSessionAuthoritySession): string | undefined {
87
- const browser = session.browser;
88
- const tab = browser?.tab;
89
- if (browser?.provider !== 'macos-apple-events' || !browser.browserProduct || !tab?.windowId || !tab.tabId) return undefined;
90
- return `${browser.provider}:${browser.browserProduct}:${tab.windowId}:${tab.tabId}`;
91
- }
92
-
93
- function recordKey(repoId: string, session: BrowserSessionAuthoritySession): string {
94
- const native = nativeIdentity(session);
95
- return native ? `native-${digest(native).slice(0, 40)}` : `session-${digest(`${repoId}:${session.sessionId}`).slice(0, 40)}`;
96
- }
97
-
98
- function importMarkerKey(repoRoot: string): string {
99
- return digest(resolve(repoRoot)).slice(0, 40);
100
- }
101
-
102
- function unique(values: string[]): string[] {
103
- return [...new Set(values.filter(Boolean))].sort();
104
- }
105
-
106
- function parseLegacySession(path: string): BrowserSessionAuthoritySession {
107
- let parsed: unknown;
108
- try {
109
- parsed = JSON.parse(readFileSync(path, 'utf8'));
110
- } catch (error) {
111
- throw new Error(`PLUGIN_BROWSER_SESSION_STATE_CORRUPT: ${path}: ${error instanceof Error ? error.message : String(error)}`);
112
- }
113
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
114
- throw new Error(`PLUGIN_BROWSER_SESSION_STATE_CORRUPT: ${path}: expected object`);
115
- }
116
- const session = parsed as Partial<BrowserSessionAuthoritySession>;
117
- if (session.schemaVersion !== 1 || typeof session.sessionId !== 'string' || typeof session.url !== 'string'
118
- || typeof session.createdAt !== 'string' || typeof session.updatedAt !== 'string') {
119
- throw new Error(`PLUGIN_BROWSER_SESSION_STATE_CORRUPT: ${path}: required session fields are missing`);
120
- }
121
- return session as BrowserSessionAuthoritySession;
122
- }
123
-
124
- function legacySessions(repoRoot: string): BrowserSessionAuthoritySession[] {
125
- const root = join(repoRoot, '.forge', 'browser', 'sessions');
126
- let names: string[];
127
- try {
128
- names = readdirSync(root);
129
- } catch (error) {
130
- if ((error as NodeJS.ErrnoException)?.code === 'ENOENT') return [];
131
- throw error;
132
- }
133
- return names.filter((name) => name.endsWith('.json')).sort().map((name) => parseLegacySession(join(root, name)));
134
- }
135
-
136
- function mergeEntry<T extends BrowserSessionAuthoritySession>(
137
- existing: BrowserSessionAuthorityEntry<T> | undefined,
138
- repoId: string,
139
- session: T,
140
- options: { importedFromLegacy?: boolean } = {},
141
- ): BrowserSessionAuthorityEntry<T> {
142
- const canonicalSessionId = existing?.session.sessionId ?? session.sessionId;
143
- const canonicalCreatedAt = existing?.session.createdAt ?? session.createdAt;
144
- const normalizedSession = {
145
- ...session,
146
- sessionId: canonicalSessionId,
147
- createdAt: canonicalCreatedAt,
148
- } as T;
149
- return {
150
- schemaVersion: 1,
151
- status: 'active',
152
- session: normalizedSession,
153
- aliases: unique([...(existing?.aliases ?? []), existing?.session.sessionId ?? '', session.sessionId, canonicalSessionId]),
154
- repositoryIds: unique([...(existing?.repositoryIds ?? []), repoId]),
155
- nativeIdentity: nativeIdentity(session) ?? existing?.nativeIdentity,
156
- importedFromLegacy: options.importedFromLegacy === true || existing?.importedFromLegacy === true,
157
- };
10
+ DEFAULT_BROWSER_SESSION_LIST_LIMIT,
11
+ MAX_BROWSER_SESSION_LIST_LIMIT,
12
+ } from '../../../packages/plugin-runtime/browser/session-authority';
13
+ import {
14
+ currentRuntimeBrowserSessionExecutionContext,
15
+ withRuntimeBrowserSessionExecutionContext,
16
+ } from '../root/browser-session-composition';
17
+ import {
18
+ ensureBrowserSessionsMigratedToComputer,
19
+ findBrowserSession as findComputerBackedBrowserSession,
20
+ listSavedBrowserSessions,
21
+ removeBrowserSession,
22
+ saveBrowserSession as saveComputerBackedBrowserSession,
23
+ } from './browser-session-store';
24
+
25
+ export {
26
+ DEFAULT_BROWSER_SESSION_LIST_LIMIT,
27
+ MAX_BROWSER_SESSION_LIST_LIMIT,
28
+ type BrowserSessionAuthorityContext,
29
+ type BrowserSessionExecutionContext,
30
+ type BrowserSessionAuthorityPage,
31
+ type BrowserSessionAuthoritySession,
32
+ type BrowserSessionLegacyCutoverRepository,
33
+ type BrowserSessionLegacyCutoverReport,
34
+ type BrowserSessionTombstoneCleanupReport,
35
+ } from '../../../packages/plugin-runtime/browser/session-authority';
36
+
37
+ export {
38
+ currentRuntimeBrowserSessionExecutionContext as currentBrowserSessionAuthorityContext,
39
+ withRuntimeBrowserSessionExecutionContext as withBrowserSessionAuthorityContext,
40
+ } from '../root/browser-session-composition';
41
+
42
+ function withContext<T>(controllerHome: string, repoId: string, operation: () => T): T {
43
+ return withRuntimeBrowserSessionExecutionContext({ controllerHome, repoId }, operation);
158
44
  }
159
45
 
160
46
  export function ensureLegacyBrowserSessionsImported(controllerHome: string, repoId: string, repoRoot: string): number {
161
- const markerKey = importMarkerKey(repoRoot);
162
- if (readControlPlaneRecord<LegacyImportMarker>(controllerHome, IMPORT_NAMESPACE, repoId, markerKey)) return 0;
163
- const sessions = legacySessions(repoRoot);
164
- return withControlPlaneTransaction(controllerHome, (database) => {
165
- const marker = readControlPlaneRecordWithinTransaction<LegacyImportMarker>(database, IMPORT_NAMESPACE, repoId, markerKey);
166
- if (marker) return 0;
167
- let imported = 0;
168
- for (const session of sessions) {
169
- const key = recordKey(repoId, session);
170
- const current = readControlPlaneRecordWithinTransaction<BrowserSessionAuthorityEntry>(database, SESSION_NAMESPACE, SESSION_SCOPE, key);
171
- const next = mergeEntry(current?.value, repoId, session, { importedFromLegacy: true });
172
- writeControlPlaneRecordWithinTransaction(database, {
173
- namespace: SESSION_NAMESPACE,
174
- scope: SESSION_SCOPE,
175
- key,
176
- schemaVersion: 1,
177
- value: next,
178
- expectedRevision: current?.revision ?? null,
179
- action: current ? 'legacy_merge' : 'legacy_import',
180
- });
181
- imported += 1;
182
- }
183
- writeControlPlaneRecordWithinTransaction(database, {
184
- namespace: IMPORT_NAMESPACE,
185
- scope: repoId,
186
- key: markerKey,
187
- schemaVersion: 1,
188
- value: {
189
- schemaVersion: 1,
190
- repoId,
191
- repoRootFingerprint: markerKey,
192
- importedAt: new Date().toISOString(),
193
- importedRecordCount: imported,
194
- } satisfies LegacyImportMarker,
195
- expectedRevision: null,
196
- action: 'legacy_import_complete',
197
- });
198
- return imported;
199
- });
200
- }
201
-
202
- function authorityEntries(controllerHome: string): BrowserSessionAuthorityEntry[] {
203
- return listControlPlaneRecords<BrowserSessionAuthorityEntry>(controllerHome, {
204
- namespace: SESSION_NAMESPACE,
205
- scope: SESSION_SCOPE,
206
- limit: MAX_AUTHORITY_RECORDS,
207
- }).map((record) => record.value);
208
- }
209
-
210
- function visibleToRepository(entry: BrowserSessionAuthorityEntry, repoId: string): boolean {
211
- return Boolean(entry.nativeIdentity) || entry.repositoryIds.includes(repoId);
212
- }
213
-
214
- function activeEntries(controllerHome: string, repoId: string, repoRoot: string): BrowserSessionAuthorityEntry[] {
215
- ensureLegacyBrowserSessionsImported(controllerHome, repoId, repoRoot);
216
- return authorityEntries(controllerHome)
217
- .filter((entry) => entry.status === 'active' && visibleToRepository(entry, repoId))
218
- .sort((left, right) => {
219
- const updated = right.session.updatedAt.localeCompare(left.session.updatedAt);
220
- return updated !== 0 ? updated : left.session.sessionId.localeCompare(right.session.sessionId);
221
- });
47
+ return withContext(controllerHome, repoId, () => ensureBrowserSessionsMigratedToComputer(repoRoot));
222
48
  }
223
49
 
224
50
  export function saveBrowserSession<T extends BrowserSessionAuthoritySession>(
@@ -227,22 +53,7 @@ export function saveBrowserSession<T extends BrowserSessionAuthoritySession>(
227
53
  repoRoot: string,
228
54
  session: T,
229
55
  ): T {
230
- ensureLegacyBrowserSessionsImported(controllerHome, repoId, repoRoot);
231
- const key = recordKey(repoId, session);
232
- return withControlPlaneTransaction(controllerHome, (database) => {
233
- const current = readControlPlaneRecordWithinTransaction<BrowserSessionAuthorityEntry<T>>(database, SESSION_NAMESPACE, SESSION_SCOPE, key);
234
- const next = mergeEntry(current?.value, repoId, session);
235
- const written = writeControlPlaneRecordWithinTransaction(database, {
236
- namespace: SESSION_NAMESPACE,
237
- scope: SESSION_SCOPE,
238
- key,
239
- schemaVersion: 1,
240
- value: next,
241
- expectedRevision: current?.revision ?? null,
242
- action: current ? 'save' : 'create',
243
- });
244
- return written.value.session;
245
- });
56
+ return withContext(controllerHome, repoId, () => saveComputerBackedBrowserSession(repoRoot, session as never) as unknown as T);
246
57
  }
247
58
 
248
59
  export function findBrowserSession<T extends BrowserSessionAuthoritySession>(
@@ -251,8 +62,7 @@ export function findBrowserSession<T extends BrowserSessionAuthoritySession>(
251
62
  repoRoot: string,
252
63
  sessionId: string,
253
64
  ): T | undefined {
254
- return activeEntries(controllerHome, repoId, repoRoot)
255
- .find((entry) => entry.session.sessionId === sessionId || entry.aliases.includes(sessionId))?.session as T | undefined;
65
+ return withContext(controllerHome, repoId, () => findComputerBackedBrowserSession(repoRoot, sessionId) as unknown as T | undefined);
256
66
  }
257
67
 
258
68
  export function listBrowserSessions<T extends BrowserSessionAuthoritySession>(
@@ -261,29 +71,30 @@ export function listBrowserSessions<T extends BrowserSessionAuthoritySession>(
261
71
  repoRoot: string,
262
72
  options: { limit?: number; cursor?: string } = {},
263
73
  ): BrowserSessionAuthorityPage<T> {
264
- const entries = activeEntries(controllerHome, repoId, repoRoot);
265
- const limit = Math.max(1, Math.min(Math.trunc(options.limit ?? DEFAULT_BROWSER_SESSION_LIST_LIMIT), MAX_BROWSER_SESSION_LIST_LIMIT));
266
- let offset = 0;
267
- if (options.cursor) {
268
- try {
269
- const parsed = JSON.parse(Buffer.from(options.cursor, 'base64url').toString('utf8')) as { offset?: unknown };
270
- if (!Number.isInteger(parsed.offset) || Number(parsed.offset) < 0) throw new Error('invalid offset');
271
- offset = Number(parsed.offset);
272
- } catch {
273
- throw new Error('PLUGIN_BROWSER_SESSION_CURSOR_INVALID: cursor is invalid or expired');
74
+ return withContext(controllerHome, repoId, () => {
75
+ const sessions = listSavedBrowserSessions(repoRoot) as unknown as T[];
76
+ const limit = Math.max(1, Math.min(Math.trunc(options.limit ?? DEFAULT_BROWSER_SESSION_LIST_LIMIT), MAX_BROWSER_SESSION_LIST_LIMIT));
77
+ let offset = 0;
78
+ if (options.cursor) {
79
+ try {
80
+ const parsed = JSON.parse(Buffer.from(options.cursor, 'base64url').toString('utf8')) as { offset?: unknown };
81
+ if (!Number.isInteger(parsed.offset) || Number(parsed.offset) < 0) throw new Error('invalid offset');
82
+ offset = Number(parsed.offset);
83
+ } catch {
84
+ throw new Error('PLUGIN_BROWSER_SESSION_CURSOR_INVALID: cursor is invalid or expired');
85
+ }
274
86
  }
275
- }
276
- const page = entries.slice(offset, offset + limit);
277
- const nextOffset = offset + page.length;
278
- const nextCursor = nextOffset < entries.length
279
- ? Buffer.from(JSON.stringify({ offset: nextOffset }), 'utf8').toString('base64url')
280
- : undefined;
281
- return {
282
- sessions: page.map((entry) => entry.session as T),
283
- limit,
284
- totalCount: entries.length,
285
- nextCursor,
286
- };
87
+ const page = sessions.slice(offset, offset + limit);
88
+ const nextOffset = offset + page.length;
89
+ return {
90
+ sessions: page,
91
+ limit,
92
+ totalCount: sessions.length,
93
+ nextCursor: nextOffset < sessions.length
94
+ ? Buffer.from(JSON.stringify({ offset: nextOffset }), 'utf8').toString('base64url')
95
+ : undefined,
96
+ };
97
+ });
287
98
  }
288
99
 
289
100
  export function listAllBrowserSessionsForRepository<T extends BrowserSessionAuthoritySession>(
@@ -291,42 +102,41 @@ export function listAllBrowserSessionsForRepository<T extends BrowserSessionAuth
291
102
  repoId: string,
292
103
  repoRoot: string,
293
104
  ): T[] {
294
- return activeEntries(controllerHome, repoId, repoRoot).map((entry) => entry.session as T);
105
+ return withContext(controllerHome, repoId, () => listSavedBrowserSessions(repoRoot) as unknown as T[]);
295
106
  }
296
107
 
297
- export function tombstoneBrowserSession(
298
- controllerHome: string,
299
- repoId: string,
300
- repoRoot: string,
301
- sessionId: string,
302
- ): boolean {
303
- ensureLegacyBrowserSessionsImported(controllerHome, repoId, repoRoot);
304
- const record = listControlPlaneRecords<BrowserSessionAuthorityEntry>(controllerHome, {
305
- namespace: SESSION_NAMESPACE,
306
- scope: SESSION_SCOPE,
307
- limit: MAX_AUTHORITY_RECORDS,
308
- }).find((candidate) => {
309
- const entry = candidate.value;
310
- return entry.status === 'active' && visibleToRepository(entry, repoId)
311
- && (entry.session.sessionId === sessionId || entry.aliases.includes(sessionId));
312
- });
313
- if (!record) return false;
314
- return withControlPlaneTransaction(controllerHome, (database) => {
315
- const current = readControlPlaneRecordWithinTransaction<BrowserSessionAuthorityEntry>(database, SESSION_NAMESPACE, SESSION_SCOPE, record.key);
316
- if (!current || current.value.status !== 'active') return false;
317
- writeControlPlaneRecordWithinTransaction(database, {
318
- namespace: SESSION_NAMESPACE,
319
- scope: SESSION_SCOPE,
320
- key: record.key,
321
- schemaVersion: 1,
322
- value: {
323
- ...current.value,
324
- status: 'tombstoned',
325
- tombstonedAt: new Date().toISOString(),
326
- },
327
- expectedRevision: current.revision,
328
- action: 'tombstone',
329
- });
108
+ export function tombstoneBrowserSession(controllerHome: string, repoId: string, repoRoot: string, sessionId: string): boolean {
109
+ return withContext(controllerHome, repoId, () => {
110
+ const existing = findComputerBackedBrowserSession(repoRoot, sessionId);
111
+ if (!existing) return false;
112
+ removeBrowserSession(repoRoot, sessionId);
330
113
  return true;
331
114
  });
332
115
  }
116
+
117
+ /** Browser-owned legacy cutover authority is retired; Computer migration markers own cutover state. */
118
+ export function closeLegacyBrowserSessionImportCutover(
119
+ _controllerHome: string,
120
+ repositories: readonly BrowserSessionLegacyCutoverRepository[],
121
+ ): BrowserSessionLegacyCutoverReport {
122
+ return { closed: true, alreadyClosed: true, repositoryCount: repositories.length, migratedRecordCount: 0 };
123
+ }
124
+
125
+ /** Browser-owned tombstone retention is retired; Computer target retention is authoritative. */
126
+ export function cleanupBrowserSessionTombstones(
127
+ _controllerHome: string,
128
+ _options?: { nowMs?: number; ttlMs?: number; maxTombstones?: number; maxRemovals?: number },
129
+ ): BrowserSessionTombstoneCleanupReport {
130
+ return {
131
+ policyVersion: 'browser-session-tombstone-retention-v1',
132
+ cutoverClosed: true,
133
+ inspected: 0,
134
+ eligible: 0,
135
+ removed: 0,
136
+ retained: 0,
137
+ blockers: [],
138
+ budgetExhausted: false,
139
+ };
140
+ }
141
+
142
+ void currentRuntimeBrowserSessionExecutionContext;
@@ -0,0 +1,203 @@
1
+ import { createHash } from 'crypto';
2
+ import { readdirSync, readFileSync, rmSync } from 'fs';
3
+ import { join, resolve } from 'path';
4
+ import type { BrowserSessionState } from '../../../packages/protocols/browser/index';
5
+ import {
6
+ listAllControlPlaneRecords,
7
+ readControlPlaneRecord,
8
+ } from '../control-plane/persistence/sqlite-store';
9
+ import { AssistantPluginError } from './errors';
10
+
11
+ const LEGACY_SESSION_NAMESPACE = 'browser_session';
12
+ const LEGACY_SESSION_SCOPE = 'controller';
13
+ const LEGACY_IMPORT_NAMESPACE = 'browser_session_legacy_import';
14
+ const LEGACY_IMPORT_CUTOVER_SCOPE = 'controller';
15
+ const LEGACY_IMPORT_CUTOVER_KEY = 'v2-browser-session-import-cutover';
16
+
17
+ export interface LegacyBrowserSessionMigrationEntry {
18
+ schemaVersion: 1;
19
+ status: 'active' | 'tombstoned';
20
+ session: BrowserSessionState;
21
+ aliases: string[];
22
+ repositoryIds: string[];
23
+ nativeIdentity?: string;
24
+ tombstonedAt?: string;
25
+ importedFromLegacy?: boolean;
26
+ }
27
+
28
+ function digest40(value: string): string {
29
+ return createHash('sha256').update(value).digest('hex').slice(0, 40);
30
+ }
31
+
32
+ function unique(values: readonly string[]): string[] {
33
+ return [...new Set(values.map((value) => value.trim()).filter(Boolean))].sort();
34
+ }
35
+
36
+ function nativeIdentity(session: BrowserSessionState): string | undefined {
37
+ const browser = session.browser;
38
+ const tab = browser?.tab;
39
+ if (browser?.provider !== 'macos-apple-events' || !browser.browserProduct || !tab?.windowId || !tab.tabId) return undefined;
40
+ return `${browser.provider}:${browser.browserProduct}:${tab.windowId}:${tab.tabId}`;
41
+ }
42
+
43
+ function corruptSession(source: string, message: string, field?: string): never {
44
+ throw new AssistantPluginError('PLUGIN_BROWSER_SESSION_STATE_CORRUPT', message, {
45
+ retryable: false,
46
+ details: { source, ...(field ? { field } : {}) },
47
+ });
48
+ }
49
+
50
+ function legacyNativeBrowserId(value: unknown, source: string, field: 'windowId' | 'tabId'): string | undefined {
51
+ if (value === undefined) return undefined;
52
+ if (typeof value === 'string') {
53
+ const normalized = value.trim();
54
+ if (normalized) return normalized;
55
+ }
56
+ // Before the Browser runtime-contract extraction, macOS native ids were
57
+ // persisted as integers. Accept only that exact retired representation.
58
+ if (typeof value === 'number' && Number.isSafeInteger(value)) return String(value);
59
+ return corruptSession(source, 'Legacy Browser native tab identity is malformed; migration stopped fail-closed.', `browser.tab.${field}`);
60
+ }
61
+
62
+ function assertSession(value: unknown, source: string): BrowserSessionState {
63
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
64
+ return corruptSession(source, 'Legacy Browser session metadata is malformed; migration stopped fail-closed.');
65
+ }
66
+ const session = structuredClone(value) as Record<string, unknown>;
67
+ if (session.schemaVersion !== 1 || typeof session.sessionId !== 'string' || typeof session.url !== 'string'
68
+ || typeof session.createdAt !== 'string' || typeof session.updatedAt !== 'string') {
69
+ return corruptSession(source, 'Legacy Browser session metadata is missing required fields; migration stopped fail-closed.');
70
+ }
71
+ const browser = session.browser;
72
+ if (browser !== undefined) {
73
+ if (!browser || typeof browser !== 'object' || Array.isArray(browser)) {
74
+ return corruptSession(source, 'Legacy Browser connection metadata is malformed; migration stopped fail-closed.', 'browser');
75
+ }
76
+ const browserRecord = browser as Record<string, unknown>;
77
+ const tab = browserRecord.tab;
78
+ if (tab !== undefined) {
79
+ if (!tab || typeof tab !== 'object' || Array.isArray(tab)) {
80
+ return corruptSession(source, 'Legacy Browser tab metadata is malformed; migration stopped fail-closed.', 'browser.tab');
81
+ }
82
+ const tabRecord = tab as Record<string, unknown>;
83
+ const windowId = legacyNativeBrowserId(tabRecord.windowId, source, 'windowId');
84
+ const tabId = legacyNativeBrowserId(tabRecord.tabId, source, 'tabId');
85
+ if (windowId === undefined) delete tabRecord.windowId; else tabRecord.windowId = windowId;
86
+ if (tabId === undefined) delete tabRecord.tabId; else tabRecord.tabId = tabId;
87
+ }
88
+ }
89
+ return session as unknown as BrowserSessionState;
90
+ }
91
+
92
+ function assertEntry(value: unknown): LegacyBrowserSessionMigrationEntry {
93
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('LEGACY_BROWSER_SESSION_ENTRY_INVALID');
94
+ const entry = value as Partial<LegacyBrowserSessionMigrationEntry>;
95
+ if (entry.schemaVersion !== 1 || (entry.status !== 'active' && entry.status !== 'tombstoned')
96
+ || !Array.isArray(entry.aliases) || !Array.isArray(entry.repositoryIds)) throw new Error('LEGACY_BROWSER_SESSION_ENTRY_INVALID');
97
+ return {
98
+ ...(entry as LegacyBrowserSessionMigrationEntry),
99
+ session: assertSession(entry.session, 'controller-home:sqlite/browser_session'),
100
+ aliases: unique(entry.aliases),
101
+ repositoryIds: unique(entry.repositoryIds),
102
+ };
103
+ }
104
+
105
+ function legacySessionDirectories(controllerHome: string, repoId: string, repoRoot: string): string[] {
106
+ return [...new Set([
107
+ join(repoRoot, '.forge', 'browser', 'sessions'),
108
+ join(controllerHome, 'repositories', repoId, 'browser', 'sessions'),
109
+ ].map((path) => resolve(path)))];
110
+ }
111
+
112
+ function readJsonSessions(controllerHome: string, repoId: string, repoRoot: string): BrowserSessionState[] {
113
+ const sessions: BrowserSessionState[] = [];
114
+ for (const root of legacySessionDirectories(controllerHome, repoId, repoRoot)) {
115
+ let names: string[];
116
+ try { names = readdirSync(root); } catch (error) {
117
+ if ((error as NodeJS.ErrnoException)?.code === 'ENOENT') continue;
118
+ throw error;
119
+ }
120
+ for (const name of names.filter((entry) => entry.endsWith('.json')).sort()) {
121
+ let parsed: unknown;
122
+ try { parsed = JSON.parse(readFileSync(join(root, name), 'utf8')); } catch (error) {
123
+ throw new AssistantPluginError('PLUGIN_BROWSER_SESSION_STATE_CORRUPT', 'Legacy Browser session JSON is malformed; migration stopped fail-closed.', {
124
+ retryable: false,
125
+ details: { fileName: name, cause: error instanceof Error ? error.message : String(error) },
126
+ });
127
+ }
128
+ sessions.push(assertSession(parsed, name));
129
+ }
130
+ }
131
+ return sessions;
132
+ }
133
+
134
+ function legacyJsonImportAllowed(controllerHome: string, repoId: string, repoRoot: string): boolean {
135
+ const globalCutover = readControlPlaneRecord<{ status?: string }>(
136
+ controllerHome,
137
+ LEGACY_IMPORT_NAMESPACE,
138
+ LEGACY_IMPORT_CUTOVER_SCOPE,
139
+ LEGACY_IMPORT_CUTOVER_KEY,
140
+ );
141
+ if (globalCutover?.value.status === 'closed') return false;
142
+ const markerKey = digest40(resolve(repoRoot));
143
+ return !readControlPlaneRecord(controllerHome, LEGACY_IMPORT_NAMESPACE, repoId, markerKey);
144
+ }
145
+
146
+ function mergeLegacyJson(entries: LegacyBrowserSessionMigrationEntry[], repoId: string, session: BrowserSessionState): void {
147
+ const native = nativeIdentity(session);
148
+ const index = entries.findIndex((entry) => native
149
+ ? entry.nativeIdentity === native
150
+ : !entry.nativeIdentity && entry.repositoryIds.includes(repoId)
151
+ && (entry.session.sessionId === session.sessionId || entry.aliases.includes(session.sessionId)));
152
+ const current = index >= 0 ? entries[index] : undefined;
153
+ if (current?.status === 'tombstoned') return;
154
+ if (current) {
155
+ entries[index] = {
156
+ ...current,
157
+ status: 'active',
158
+ session: { ...session, sessionId: current.session.sessionId, createdAt: current.session.createdAt },
159
+ aliases: unique([...current.aliases, current.session.sessionId, session.sessionId]),
160
+ repositoryIds: unique([...current.repositoryIds, repoId]),
161
+ nativeIdentity: native ?? current.nativeIdentity,
162
+ importedFromLegacy: true,
163
+ };
164
+ return;
165
+ }
166
+ entries.push({
167
+ schemaVersion: 1,
168
+ status: 'active',
169
+ session,
170
+ aliases: [session.sessionId],
171
+ repositoryIds: [repoId],
172
+ ...(native ? { nativeIdentity: native } : {}),
173
+ importedFromLegacy: true,
174
+ });
175
+ }
176
+
177
+ /** Read-only compatibility reader. It can consume retired Browser state but cannot mutate that authority. */
178
+ export function readLegacyBrowserSessionMigrationEntries(input: {
179
+ controllerHome: string;
180
+ repoId: string;
181
+ repoRoot: string;
182
+ }): LegacyBrowserSessionMigrationEntry[] {
183
+ const entries = listAllControlPlaneRecords<LegacyBrowserSessionMigrationEntry>(input.controllerHome, {
184
+ namespace: LEGACY_SESSION_NAMESPACE,
185
+ scope: LEGACY_SESSION_SCOPE,
186
+ }).map((record) => assertEntry(record.value));
187
+ if (legacyJsonImportAllowed(input.controllerHome, input.repoId, input.repoRoot)) {
188
+ for (const session of readJsonSessions(input.controllerHome, input.repoId, input.repoRoot)) mergeLegacyJson(entries, input.repoId, session);
189
+ }
190
+ return entries;
191
+ }
192
+
193
+ /** Repo-local/controller-home JSON is import-only. Removal after Computer migration is best-effort and idempotent. */
194
+ export function cleanupLegacyBrowserSessionJson(controllerHome: string, repoId: string, repoRoot: string): void {
195
+ for (const root of legacySessionDirectories(controllerHome, repoId, repoRoot)) {
196
+ let names: string[];
197
+ try { names = readdirSync(root); } catch { continue; }
198
+ for (const name of names) {
199
+ if (!name.endsWith('.json')) continue;
200
+ try { rmSync(join(root, name), { force: true }); } catch { /* retry on a later Browser access */ }
201
+ }
202
+ }
203
+ }