@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
@@ -2,28 +2,34 @@ import { createHash } from 'crypto';
2
2
  import { join } from 'path';
3
3
  import type { RepositoryRecord } from '../../cli/repositories/types';
4
4
  import { CONTROLLER_SCOPE_REPO_ID, controllerSystemRoot, ensureControllerHome, repositoryControllerRoot } from '../../cli/repositories/controller-home';
5
- import { existsSync, mkdirSync, readdirSync, rmSync } from 'fs';
5
+ import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, rmSync } from 'fs';
6
6
  import type { ExecutionJob, ResourceClaimSpec } from '../execution/jobs/types';
7
7
  import { appendRuntimeEvent } from '../evidence/event-ledger';
8
8
  import { readJsonFile, sanitizeFileComponent, writeJsonAtomic } from '../shared/json-files';
9
9
  import { createFirstPartyPluginAdapterMap } from './first-party-registry';
10
+ import { reconcileFirstPartyExternalPluginRegistration, reconcileFirstPartyExternalPluginRegistrations } from './first-party-external-registration';
11
+ import { REPOSITORY_PLUGIN_CONFIG_IDS, repositoryPluginConfigFileName, repositoryPluginConfigPath } from './config-store';
10
12
  import { getExternalPluginAdapter, listExternalPluginAdapters } from './external-adapter';
11
- import { AssistantPluginError, toAssistantPluginError } from './errors';
13
+ import { AssistantPluginError, isAssistantPluginError, toAssistantPluginError, type AssistantPluginEffectOutcome } from './errors';
12
14
  import {
15
+ findActivePluginCapabilityAuthorizationById,
13
16
  findActivePluginCapabilityAuthorization,
14
17
  pluginCapabilityAuthorizationOwnerScope,
15
18
  recordPluginCapabilityAuthorization,
16
19
  type PluginCapabilityAuthorizationGrant,
17
20
  } from './capability-authorization-grants';
18
21
  import { markControllerContextProjectionDirty } from '../projections/controller-context';
22
+ import { acquireExecutionLeases, releaseExactExecutionLeases } from '../resources/leases/store';
19
23
  import { classifyRepositoryCommand } from '../../cli/repositories/command-classifier';
20
24
  import {
21
25
  acceptSubmittedWorkContract,
26
+ activateWorkContract,
22
27
  appendWorkEvidence,
28
+ failWorkContract,
23
29
  getWorkContract,
24
30
  recordWorkCompletionReceipt,
25
31
  updateWorkContract,
26
- } from '../control-plane/facade/work-contract-store';
32
+ } from '../../../packages/kernel/work/api/index';
27
33
  import { isTerminalWorkContractStatus, type LocalEffectCompletionReceipt, type RemoteEffectCompletionReceipt, type WorkContract, type WorkRisk } from '../control-plane/facade/types';
28
34
  import type {
29
35
  AssistantPluginAdapter,
@@ -43,8 +49,10 @@ function resolvePluginAdapter(controllerHome: string, pluginId: string): Assista
43
49
  }
44
50
 
45
51
  function listPluginAdapters(controllerHome: string): AssistantPluginAdapter[] {
46
- const external = listExternalPluginAdapters(controllerHome).filter((adapter) => !PLUGIN_ADAPTERS.has(adapter.pluginId));
47
- return [...PLUGIN_ADAPTERS.values(), ...external];
52
+ const firstParty = [...PLUGIN_ADAPTERS.values()].filter((adapter) => adapter.exposure !== 'internal');
53
+ const external = listExternalPluginAdapters(controllerHome)
54
+ .filter((adapter) => !PLUGIN_ADAPTERS.has(adapter.pluginId) && adapter.exposure !== 'internal');
55
+ return [...firstParty, ...external];
48
56
  }
49
57
 
50
58
  export function assistantPluginScope(pluginId: string, controllerHome?: string): AssistantPluginAdapter['scope'] | undefined {
@@ -89,6 +97,39 @@ export function controllerPluginRepository(controllerHome: string): RepositoryRe
89
97
  };
90
98
  }
91
99
 
100
+ /**
101
+ * Controller-scoped product facade. The synthetic RepositoryRecord remains an
102
+ * internal storage/projection compatibility shape only; callers need no repo.
103
+ */
104
+ export function readControllerStoredPluginManifest(controllerHome: string, pluginId: string): AssistantPluginManifest | undefined {
105
+ return readStoredAssistantPluginManifest(controllerHome, controllerPluginRepository(controllerHome), pluginId);
106
+ }
107
+
108
+ export function listControllerPluginManifests(
109
+ controllerHome: string,
110
+ options: ListAssistantPluginManifestsOptions = {},
111
+ ): AssistantPluginManifest[] {
112
+ return listAssistantPluginManifests(controllerHome, controllerPluginRepository(controllerHome), options);
113
+ }
114
+
115
+ export function getControllerPluginManifest(controllerHome: string, pluginId: string): AssistantPluginManifest {
116
+ return getAssistantPluginManifest(controllerHome, controllerPluginRepository(controllerHome), pluginId);
117
+ }
118
+
119
+ export function syncControllerPluginRegistry(controllerHome: string) {
120
+ reconcileFirstPartyExternalPluginRegistrations(controllerHome);
121
+ return syncAssistantPluginRegistry(controllerHome, controllerPluginRepository(controllerHome));
122
+ }
123
+
124
+ export function syncControllerPluginManifest(controllerHome: string, pluginId: string) {
125
+ reconcileFirstPartyExternalPluginRegistration(controllerHome, pluginId);
126
+ return syncAssistantPluginManifest(controllerHome, controllerPluginRepository(controllerHome), pluginId);
127
+ }
128
+
129
+ export function removeControllerPluginManifestProjection(controllerHome: string, pluginId: string) {
130
+ return removeAssistantPluginManifestProjection(controllerHome, controllerPluginRepository(controllerHome), pluginId);
131
+ }
132
+
92
133
  function adapterMatchesRepository(adapter: AssistantPluginAdapter, repository: RepositoryRecord): boolean {
93
134
  const scope = adapter.scope ?? 'repository';
94
135
  if (scope === 'controller_with_repository_overlay') return true;
@@ -99,8 +140,9 @@ function cloneCacheValue<T>(value: T): T {
99
140
  return structuredClone(value);
100
141
  }
101
142
 
102
- function listCacheKey(controllerHome: string, repoId: string, preferStored: boolean): string {
103
- return `${controllerHome}::${repoId}::list::${preferStored ? 'stored' : 'live'}`;
143
+ function listCacheKey(controllerHome: string, repoId: string, preferStored: boolean, fallbackToLive: boolean): string {
144
+ const mode = preferStored ? (fallbackToLive ? 'stored-with-live-fallback' : 'stored-only') : 'live';
145
+ return `${controllerHome}::${repoId}::list::${mode}`;
104
146
  }
105
147
 
106
148
  function itemCacheKey(controllerHome: string, repoId: string, pluginId: string, preferStored: boolean): string {
@@ -236,6 +278,15 @@ function readStoredManifest(controllerHome: string, repoId: string, pluginId: st
236
278
  }
237
279
  }
238
280
 
281
+ /** Read-only persisted plugin projection. This never probes or rebuilds a provider manifest. */
282
+ export function readStoredAssistantPluginManifest(
283
+ controllerHome: string,
284
+ repository: RepositoryRecord,
285
+ pluginId: string,
286
+ ): AssistantPluginManifest | undefined {
287
+ return readStoredManifest(controllerHome, repository.repoId, pluginId);
288
+ }
289
+
239
290
  function cachedManifestForRepository(
240
291
  controllerHome: string,
241
292
  repoId: string,
@@ -248,12 +299,48 @@ function cachedManifestForRepository(
248
299
  ) ?? readPluginManifestCache(pluginManifestItemCache, itemCacheKey(controllerHome, repoId, pluginId, false));
249
300
  }
250
301
 
302
+ export function migrateRepositoryPluginConfigLegacyFiles(
303
+ controllerHome: string,
304
+ repository: Pick<RepositoryRecord, 'repoId' | 'canonicalRoot'>,
305
+ ): string {
306
+ const targetRoot = join(repositoryControllerRoot(controllerHome, repository.repoId), 'plugins', 'config');
307
+ const legacyRoots = [
308
+ join(repository.canonicalRoot, '.forge', 'plugins'),
309
+ join(repository.canonicalRoot, '.repo-harness', 'plugins'),
310
+ ];
311
+ mkdirSync(targetRoot, { recursive: true });
312
+ for (const legacyRoot of legacyRoots) {
313
+ if (!existsSync(legacyRoot)) continue;
314
+ const stat = lstatSync(legacyRoot);
315
+ // Historical compatibility symlinks may point at another Controller Home.
316
+ // Never traverse them; unlink only the retired repository-local compatibility entry.
317
+ if (stat.isSymbolicLink()) {
318
+ rmSync(legacyRoot, { force: true });
319
+ continue;
320
+ }
321
+ if (!stat.isDirectory()) throw new Error(`PLUGIN_CONFIG_LEGACY_PATH_INVALID: ${legacyRoot}`);
322
+ for (const pluginId of REPOSITORY_PLUGIN_CONFIG_IDS) {
323
+ const fileName = repositoryPluginConfigFileName(pluginId);
324
+ const source = join(legacyRoot, fileName);
325
+ if (!existsSync(source)) continue;
326
+ const sourceStat = lstatSync(source);
327
+ if (sourceStat.isSymbolicLink() || !sourceStat.isFile()) continue;
328
+ const target = repositoryPluginConfigPath({ controllerHome, repoId: repository.repoId }, pluginId);
329
+ if (!existsSync(target)) cpSync(source, target, { force: false, errorOnExist: false });
330
+ rmSync(source, { force: true });
331
+ }
332
+ if (readdirSync(legacyRoot).length === 0) rmSync(legacyRoot, { recursive: true, force: true });
333
+ }
334
+ return targetRoot;
335
+ }
336
+
251
337
  function computeManifest(
252
338
  controllerHome: string,
253
339
  repository: RepositoryRecord,
254
340
  pluginId: string,
255
341
  resolvedAdapter?: AssistantPluginAdapter,
256
342
  ): AssistantPluginManifest {
343
+ migrateRepositoryPluginConfigLegacyFiles(controllerHome, repository);
257
344
  const adapter = resolvedAdapter ?? resolvePluginAdapter(controllerHome, pluginId);
258
345
  if (!adapter || !adapterMatchesRepository(adapter, repository)) throw new Error(`PLUGIN_NOT_FOUND: ${pluginId}`);
259
346
  const previous = readStoredManifest(controllerHome, repository.repoId, pluginId);
@@ -307,6 +394,71 @@ export function claimsForAssistantPluginAction(
307
394
  }));
308
395
  }
309
396
 
397
+ async function withAssistantPluginResourceLeases<T>(
398
+ controllerHome: string,
399
+ repository: RepositoryRecord,
400
+ action: AssistantPluginActionDescriptor,
401
+ request: AssistantPluginActionRequest,
402
+ operation: () => Promise<T>,
403
+ ): Promise<T> {
404
+ const claims = claimsForAssistantPluginAction(action, repository, request.pluginId).map((claim) => ({
405
+ ...claim,
406
+ repoId: repository.repoId,
407
+ checkoutId: repository.activeCheckoutId,
408
+ }));
409
+ if (claims.length === 0) return operation();
410
+
411
+ const ownerJobId = `plugin:${request.requestId}`;
412
+ const timeoutMs = Math.max(5_000, Math.min(10 * 60_000, request.timeoutMs ?? action.defaultTimeoutMs));
413
+ const acquisition = acquireExecutionLeases(controllerHome, repository.repoId, ownerJobId, claims, {
414
+ ttlMs: timeoutMs + 60_000,
415
+ ownerIdentity: {
416
+ repositoryId: repository.repoId,
417
+ checkoutId: repository.activeCheckoutId,
418
+ worktreeId: repository.activeCheckoutId,
419
+ branch: 'workflow-plugin-action',
420
+ principalId: request.origin.actor?.trim() || 'workflow-plugin-action',
421
+ controllerInstanceId: process.env.FORGE_RUNTIME_INSTANCE_ID?.trim()
422
+ || process.env.FORGE_WRITER_INSTANCE_ID?.trim()
423
+ || process.env.FORGE_DAEMON_INSTANCE_ID?.trim()
424
+ || `process:${process.pid}`,
425
+ controllerGeneration: process.env.FORGE_WRITER_GENERATION?.trim()
426
+ || process.env.FORGE_ACTIVE_RUNTIME_REVISION?.trim()
427
+ || 'unbound',
428
+ },
429
+ });
430
+ if (!acquisition.acquired) {
431
+ throw new AssistantPluginError(
432
+ 'PLUGIN_RESOURCE_CONTENTION',
433
+ `${request.pluginId}/${request.actionId} could not acquire its declared resource claims before dispatch.`,
434
+ { retryable: true, details: { blockers: acquisition.blockers } },
435
+ );
436
+ }
437
+ const expected = acquisition.leases.map((lease) => ({
438
+ leaseId: lease.leaseId,
439
+ fencingToken: lease.fencingToken,
440
+ repoId: lease.repoId,
441
+ checkoutId: lease.checkoutId,
442
+ resourceKey: lease.resourceKey,
443
+ ownerIdentityDigest: lease.ownerIdentityDigest,
444
+ }));
445
+ let retainForReconciliation = false;
446
+ try {
447
+ const result = await operation();
448
+ const nestedResult = result && typeof result === 'object' && !Array.isArray(result)
449
+ ? (result as Record<string, unknown>).result
450
+ : undefined;
451
+ retainForReconciliation = Boolean(nestedResult && typeof nestedResult === 'object' && !Array.isArray(nestedResult)
452
+ && (nestedResult as Record<string, unknown>).outcome === 'outcome_unknown');
453
+ return result;
454
+ } catch (error) {
455
+ retainForReconciliation = isAssistantPluginError(error) && error.effectOutcome === 'outcome_unknown';
456
+ throw error;
457
+ } finally {
458
+ if (!retainForReconciliation) releaseExactExecutionLeases(controllerHome, repository.repoId, ownerJobId, expected);
459
+ }
460
+ }
461
+
310
462
  function semanticKey(repository: RepositoryRecord, pluginId: string, actionId: string, args: Record<string, unknown>): string {
311
463
  const digest = createHash('sha256').update(JSON.stringify(canonical(args))).digest('hex').slice(0, 20);
312
464
  return `plugin-action:${repository.repoId}:${pluginId}:${actionId}:${digest}`;
@@ -408,6 +560,92 @@ function originMayEstablishCapabilityAuthorization(origin: AssistantPluginAction
408
560
  return INTERACTIVE_PLUGIN_AUTHORIZATION_SURFACES.has(origin.surface);
409
561
  }
410
562
 
563
+ function requiresAutomatedWriteAuthorization(origin: AssistantPluginActionExecutionInput['origin']): boolean {
564
+ return ['schedule', 'reconciliation', 'system'].includes(origin.surface);
565
+ }
566
+
567
+ const AUTHORIZATION_RISK_RANK: Record<AssistantPluginActionDescriptor['risk'], number> = {
568
+ readonly: 0,
569
+ workspace_write: 1,
570
+ remote_write: 2,
571
+ destructive: 3,
572
+ };
573
+
574
+ function authorizationTargetMatches(
575
+ left: PluginCapabilityAuthorizationGrant['target'],
576
+ right: PluginCapabilityAuthorizationGrant['target'],
577
+ ): boolean {
578
+ return left.kind === right.kind
579
+ && left.id === right.id
580
+ && (left.identityFingerprint ?? '') === (right.identityFingerprint ?? '');
581
+ }
582
+
583
+ async function resolveAutomatedWriteAuthorization(input: {
584
+ controllerHome: string;
585
+ repository: RepositoryRecord;
586
+ adapter: AssistantPluginAdapter;
587
+ manifest: AssistantPluginManifest;
588
+ action: AssistantPluginActionDescriptor;
589
+ args: Record<string, unknown>;
590
+ origin: AssistantPluginActionExecutionInput['origin'];
591
+ requestId: string;
592
+ jobId?: string;
593
+ authorizationGrantRefs?: readonly string[];
594
+ }): Promise<PluginCapabilityAuthorizationGrant | undefined> {
595
+ if (input.action.readOnly) return undefined;
596
+ if (input.action.confirmation === 'strong_confirmation') {
597
+ throw new AssistantPluginError(
598
+ 'EXTERNAL_EFFECT_AUTHORIZATION_REQUIRED',
599
+ `${input.manifest.pluginId}/${input.action.actionId} requires an interactive strong confirmation.`,
600
+ { retryable: false },
601
+ );
602
+ }
603
+ const refs = [...new Set((input.authorizationGrantRefs ?? []).map((ref) => ref.trim()).filter(Boolean))];
604
+ if (refs.length === 0 || !input.adapter.resolveAuthorizationContext) {
605
+ throw new AssistantPluginError(
606
+ 'EXTERNAL_EFFECT_AUTHORIZATION_REQUIRED',
607
+ `${input.manifest.pluginId}/${input.action.actionId} requires an active Workflow capability grant.`,
608
+ { retryable: false },
609
+ );
610
+ }
611
+ const targetContext = await input.adapter.resolveAuthorizationContext({
612
+ controllerHome: input.controllerHome,
613
+ repoId: input.repository.repoId,
614
+ repoRoot: input.repository.canonicalRoot,
615
+ pluginId: input.manifest.pluginId,
616
+ actionId: input.action.actionId,
617
+ requestId: input.requestId,
618
+ args: input.args,
619
+ origin: input.origin,
620
+ jobId: input.jobId,
621
+ });
622
+ if (!targetContext) {
623
+ throw new AssistantPluginError(
624
+ 'PLUGIN_CAPABILITY_GRANT_TARGET_UNAVAILABLE',
625
+ `${input.manifest.pluginId}/${input.action.actionId} did not resolve an exact authorization target.`,
626
+ { retryable: false },
627
+ );
628
+ }
629
+ const capabilityId = reusableCapabilityId(input.manifest, input.action);
630
+ const grant = refs
631
+ .map((ref) => findActivePluginCapabilityAuthorizationById(input.controllerHome, ref))
632
+ .find((candidate) => candidate
633
+ && candidate.repoId === input.repository.repoId
634
+ && candidate.pluginId === input.manifest.pluginId
635
+ && candidate.capabilityId === capabilityId
636
+ && authorizationTargetMatches(candidate.target, targetContext.target)
637
+ && input.action.scopes.every((scope) => candidate.scopes.includes(scope))
638
+ && AUTHORIZATION_RISK_RANK[candidate.riskCeiling] >= AUTHORIZATION_RISK_RANK[input.action.risk]);
639
+ if (!grant) {
640
+ throw new AssistantPluginError(
641
+ 'PLUGIN_CAPABILITY_GRANT_NOT_FOUND',
642
+ `${input.manifest.pluginId}/${input.action.actionId} has no active grant for this exact target.`,
643
+ { retryable: false },
644
+ );
645
+ }
646
+ return grant;
647
+ }
648
+
411
649
  function authorizationTargetSummary(context: AssistantPluginAuthorizationContext): { kind: string; id: string } {
412
650
  return { kind: context.target.kind, id: context.target.id };
413
651
  }
@@ -429,19 +667,15 @@ function initialAuthorizationEvidence(
429
667
  return { source: 'host_permission_model', reusable: false, capabilityId };
430
668
  }
431
669
 
432
- function denyAutomatedWrite(manifest: AssistantPluginManifest, action: AssistantPluginActionDescriptor, origin: AssistantPluginActionExecutionInput['origin']): void {
433
- if (!['schedule', 'reconciliation', 'system'].includes(origin.surface)) return;
434
- if (action.readOnly) return;
435
- throw new Error(`EXTERNAL_EFFECT_AUTHORIZATION_REQUIRED: ${manifest.pluginId}/${action.actionId} cannot run from ${origin.surface}`);
436
- }
437
-
438
670
  export type ListAssistantPluginManifestsOptions = {
439
671
  /**
440
672
  * Prefer previously persisted manifests for connector/status hot paths.
441
673
  * Live adapter rebuild (including host probes such as Xcode) runs only when
442
- * no stored manifest exists, or when forceRefresh is true.
674
+ * no stored manifest exists, unless fallbackToLive=false, or when forceRefresh is true.
443
675
  */
444
676
  preferStored?: boolean;
677
+ /** Materialized projections set this false so a cold summary never synchronously probes providers. */
678
+ fallbackToLive?: boolean;
445
679
  forceRefresh?: boolean;
446
680
  };
447
681
 
@@ -458,7 +692,8 @@ export function listAssistantPluginManifests(
458
692
  options: ListAssistantPluginManifestsOptions = {},
459
693
  ): AssistantPluginManifest[] {
460
694
  const preferStored = options.preferStored === true && options.forceRefresh !== true;
461
- const cacheKey = listCacheKey(controllerHome, repository.repoId, preferStored);
695
+ const fallbackToLive = options.fallbackToLive !== false || !preferStored;
696
+ const cacheKey = listCacheKey(controllerHome, repository.repoId, preferStored, fallbackToLive);
462
697
  if (options.forceRefresh !== true) {
463
698
  // Stored manifests are persisted snapshots. Their freshness is governed by
464
699
  // explicit registry/config mutation invalidation, not a wall-clock trust
@@ -475,9 +710,11 @@ export function listAssistantPluginManifests(
475
710
  if (preferStored) {
476
711
  const stored = readStoredManifest(controllerHome, repository.repoId, pluginId);
477
712
  if (stored) return stored;
713
+ if (!fallbackToLive) return undefined;
478
714
  }
479
715
  return computeManifest(controllerHome, repository, pluginId);
480
716
  })
717
+ .filter((manifest): manifest is AssistantPluginManifest => Boolean(manifest))
481
718
  .sort((left, right) => left.pluginId.localeCompare(right.pluginId));
482
719
  primePluginManifestItemCache(controllerHome, repository.repoId, manifests, preferStored);
483
720
  return writePluginManifestCache(pluginManifestListCache, cacheKey, manifests);
@@ -533,7 +770,7 @@ export function syncAssistantPluginRegistry(
533
770
  };
534
771
  }
535
772
 
536
- function syncAssistantPluginManifest(
773
+ export function syncAssistantPluginManifest(
537
774
  controllerHome: string,
538
775
  repository: RepositoryRecord,
539
776
  pluginId: string,
@@ -558,6 +795,29 @@ function syncAssistantPluginManifest(
558
795
  };
559
796
  }
560
797
 
798
+ /** Remove one persisted plugin projection without probing or rebuilding unrelated providers. */
799
+ export function removeAssistantPluginManifestProjection(
800
+ controllerHome: string,
801
+ repository: RepositoryRecord,
802
+ pluginId: string,
803
+ ): AssistantPluginRegistryIndex {
804
+ invalidateAssistantPluginManifestCache(controllerHome, repository.repoId, pluginId);
805
+ rmSync(manifestPath(controllerHome, repository.repoId, pluginId), { force: true });
806
+ const current = readJsonFile<AssistantPluginRegistryIndex>(indexPath(controllerHome, repository.repoId), {
807
+ schemaVersion: 1,
808
+ updatedAt: now(),
809
+ plugins: [],
810
+ });
811
+ const next: AssistantPluginRegistryIndex = {
812
+ ...current,
813
+ updatedAt: now(),
814
+ plugins: current.plugins.filter((entry) => entry.pluginId !== pluginId),
815
+ };
816
+ writeJsonAtomic(indexPath(controllerHome, repository.repoId), next);
817
+ markControllerContextProjectionDirty(repository.canonicalRoot, `plugin:${pluginId}:removed`);
818
+ return next;
819
+ }
820
+
561
821
  export function isDirectPluginReadAction(action: AssistantPluginActionDescriptor): boolean {
562
822
  return action.readOnly === true
563
823
  && action.risk === 'readonly'
@@ -565,6 +825,76 @@ export function isDirectPluginReadAction(action: AssistantPluginActionDescriptor
565
825
  && action.idempotent === true;
566
826
  }
567
827
 
828
+ export function isDirectNonPersistentPluginAction(action: AssistantPluginActionDescriptor): boolean {
829
+ return action.executionMode === 'direct_non_persistent'
830
+ && action.readOnly === false
831
+ && action.risk === 'workspace_write'
832
+ && action.confirmation === 'authorization'
833
+ && action.idempotent === false
834
+ && action.remoteEffectWorkCompletion === undefined
835
+ && action.resourceClaims.length === 0;
836
+ }
837
+
838
+ export async function executeAssistantPluginDirectNonPersistent(
839
+ controllerHome: string,
840
+ repository: RepositoryRecord,
841
+ request: AssistantPluginActionRequest,
842
+ ): Promise<{ manifest: AssistantPluginManifest; action: AssistantPluginActionDescriptor; result: Record<string, unknown> }> {
843
+ const adapter = resolvePluginAdapter(controllerHome, request.pluginId);
844
+ if (!adapter) throw new Error(`PLUGIN_NOT_FOUND: ${request.pluginId}`);
845
+ if (PLUGIN_ADAPTERS.get(request.pluginId) !== adapter) {
846
+ throw new Error(`PLUGIN_DIRECT_NON_PERSISTENT_FIRST_PARTY_REQUIRED: ${request.pluginId}/${request.actionId}`);
847
+ }
848
+ const manifestLookup = getAssistantPluginManifestForExecution(controllerHome, repository, request.pluginId, adapter);
849
+ const manifest = manifestLookup.manifest;
850
+ const action = actionForManifest(manifest, request.actionId);
851
+ if (!manifest.enabled && action.actionId !== 'configure') {
852
+ throw new Error(`PLUGIN_DISABLED: ${request.pluginId} is disabled`);
853
+ }
854
+ if (action.executionMode !== 'direct_non_persistent') {
855
+ throw new Error(`PLUGIN_DIRECT_NON_PERSISTENT_NOT_ALLOWED: ${request.pluginId}/${request.actionId}`);
856
+ }
857
+ if (!isDirectNonPersistentPluginAction(action)) {
858
+ throw new Error(`PLUGIN_DIRECT_NON_PERSISTENT_CONTRACT_INVALID: ${request.pluginId}/${request.actionId}`);
859
+ }
860
+ if (request.workId || request.workRepoId) {
861
+ throw new Error(`PLUGIN_DIRECT_NON_PERSISTENT_WORK_ATTRIBUTION_FORBIDDEN: ${request.pluginId}/${request.actionId}`);
862
+ }
863
+ if (request.confirmAuthorization !== true) {
864
+ throw new Error(`PLUGIN_DIRECT_NON_PERSISTENT_AUTHORIZATION_REQUIRED: ${request.pluginId}/${request.actionId} requires confirm_authorization=true for this invocation`);
865
+ }
866
+ const normalizedArgs = validateActionArguments(action, request.args ?? {});
867
+ enforceConfirmation(action, { ...request, args: normalizedArgs });
868
+ if (requiresAutomatedWriteAuthorization(request.origin)) {
869
+ await resolveAutomatedWriteAuthorization({
870
+ controllerHome,
871
+ repository,
872
+ adapter,
873
+ manifest,
874
+ action,
875
+ args: normalizedArgs,
876
+ origin: request.origin,
877
+ requestId: request.requestId,
878
+ authorizationGrantRefs: request.authorizationGrantRefs,
879
+ });
880
+ }
881
+ const result = await adapter.executeAction({
882
+ controllerHome,
883
+ repoId: repository.repoId,
884
+ repoRoot: repository.canonicalRoot,
885
+ pluginId: request.pluginId,
886
+ actionId: request.actionId,
887
+ requestId: request.requestId,
888
+ args: normalizedArgs,
889
+ origin: request.origin,
890
+ timeoutMs: request.timeoutMs,
891
+ signal: request.signal,
892
+ authorizationGrantRefs: request.authorizationGrantRefs,
893
+ providerIdentityPrevalidated: manifestLookup.providerIdentityPrevalidated,
894
+ });
895
+ return { manifest, action, result };
896
+ }
897
+
568
898
  export async function executeAssistantPluginReadDirect(
569
899
  controllerHome: string,
570
900
  repository: RepositoryRecord,
@@ -604,6 +934,8 @@ export interface PluginActionReceipt {
604
934
  actionId: string;
605
935
  semanticKey: string;
606
936
  status: 'succeeded' | 'failed';
937
+ /** Durable semantic disposition for an attempted external/local effect. */
938
+ effectOutcome?: AssistantPluginEffectOutcome;
607
939
  createdAt: string;
608
940
  workId?: string;
609
941
  origin?: { surface: string; actor?: string; correlationId?: string };
@@ -661,6 +993,17 @@ export function findPluginActionReceipt(
661
993
  return undefined;
662
994
  }
663
995
 
996
+ /** Exact request lookup for subordinate Workflow recovery; never dispatches an action. */
997
+ export function readPluginActionReceiptForRequest(controllerHome: string, requestId: string): PluginActionReceipt | undefined {
998
+ const path = pluginActionRequestPath(controllerHome, requestId);
999
+ if (!existsSync(path)) return undefined;
1000
+ const index = readJsonFile<PluginActionRequestIndex>(path);
1001
+ if (index.requestId !== requestId) throw new Error('PLUGIN_RECEIPT_REQUEST_MISMATCH');
1002
+ const receipt = readPluginActionReceipt(controllerHome, index.repoId, index.receiptId);
1003
+ if (!receipt || receipt.requestId !== requestId || receipt.semanticKey !== index.semanticKey) throw new Error('PLUGIN_RECEIPT_LOST');
1004
+ return receipt;
1005
+ }
1006
+
664
1007
  export function compatibilityPluginJobFromReceipt(
665
1008
  receipt: PluginActionReceipt,
666
1009
  checkoutId = 'unknown',
@@ -914,7 +1257,9 @@ function compatibilityJobFromReceipt(receipt: PluginActionReceipt, checkoutId: s
914
1257
  repoId: receipt.repoId,
915
1258
  checkoutId,
916
1259
  type: 'plugin-action',
917
- status: receipt.status === 'succeeded' ? 'succeeded' : 'failed',
1260
+ status: receipt.effectOutcome === 'outcome_unknown'
1261
+ ? 'human_attention_required'
1262
+ : receipt.status === 'succeeded' ? 'succeeded' : 'failed',
918
1263
  priority: 'P2',
919
1264
  requestId: receipt.requestId,
920
1265
  semanticKey: receipt.semanticKey,
@@ -962,6 +1307,9 @@ export async function submitAssistantPluginAction(
962
1307
  if (!manifest.enabled && action.actionId !== 'configure') {
963
1308
  throw new Error(`PLUGIN_DISABLED: ${request.pluginId} is disabled`);
964
1309
  }
1310
+ if (action.executionMode === 'direct_non_persistent') {
1311
+ throw new Error(`PLUGIN_DIRECT_NON_PERSISTENT_RECEIPT_PATH_FORBIDDEN: ${request.pluginId}/${request.actionId}`);
1312
+ }
965
1313
  const normalizedArgs = validateActionArguments(action, request.args ?? {});
966
1314
  enforceConfirmation(action, { ...request, args: normalizedArgs });
967
1315
 
@@ -1009,6 +1357,29 @@ export async function submitAssistantPluginAction(
1009
1357
  let authorization = initialAuthorizationEvidence(manifest, action);
1010
1358
  let authorizationContext: AssistantPluginAuthorizationContext | undefined;
1011
1359
  let activeAuthorizationGrant: PluginCapabilityAuthorizationGrant | undefined;
1360
+ if (requiresAutomatedWriteAuthorization(request.origin)) {
1361
+ activeAuthorizationGrant = await resolveAutomatedWriteAuthorization({
1362
+ controllerHome,
1363
+ repository,
1364
+ adapter,
1365
+ manifest,
1366
+ action,
1367
+ args: normalizedArgs,
1368
+ origin: request.origin,
1369
+ requestId: request.requestId,
1370
+ jobId: receiptId,
1371
+ authorizationGrantRefs: request.authorizationGrantRefs,
1372
+ });
1373
+ if (activeAuthorizationGrant) {
1374
+ authorization = {
1375
+ source: 'capability_grant',
1376
+ reusable: true,
1377
+ capabilityId,
1378
+ target: activeAuthorizationGrant.target,
1379
+ grantId: activeAuthorizationGrant.grantId,
1380
+ };
1381
+ }
1382
+ }
1012
1383
  const requiresLocalEffectWork = localSystemActionRequiresWork(
1013
1384
  repository,
1014
1385
  request.pluginId,
@@ -1054,12 +1425,15 @@ export async function submitAssistantPluginAction(
1054
1425
  }).contract
1055
1426
  : undefined;
1056
1427
  if (acceptedWork) {
1057
- updateWorkContract({ controllerHome, repoId: repository.repoId }, acceptedWork.workId, {
1058
- status: 'running',
1059
- workKind: 'local_effect',
1060
- dispatchState: 'running',
1061
- evidenceState: 'partial',
1062
- });
1428
+ activateWorkContract(
1429
+ { controllerHome, repoId: repository.repoId },
1430
+ acceptedWork.workId,
1431
+ {
1432
+ phase: 'implementation',
1433
+ summary: `Controller-local plugin action ${request.pluginId}/${request.actionId} started.`,
1434
+ evidenceState: 'partial',
1435
+ },
1436
+ );
1063
1437
  }
1064
1438
  appendRuntimeEvent(controllerHome, {
1065
1439
  repoId: repository.repoId,
@@ -1130,22 +1504,29 @@ export async function submitAssistantPluginAction(
1130
1504
  }
1131
1505
  }
1132
1506
 
1133
- const result = await executeAssistantPluginAction({
1507
+ const result = await withAssistantPluginResourceLeases(
1134
1508
  controllerHome,
1135
- repoId: repository.repoId,
1136
- repoRoot: repository.canonicalRoot,
1137
- pluginId: request.pluginId,
1138
- actionId: request.actionId,
1139
- requestId: request.requestId,
1140
- args: normalizedArgs,
1141
- origin: request.origin,
1142
- jobId: receiptId,
1143
- timeoutMs: request.timeoutMs,
1144
- signal: request.signal,
1145
- deadlineAtMs: typeof request.timeoutMs === 'number'
1146
- ? Date.now() + Math.max(1, Math.trunc(request.timeoutMs))
1147
- : undefined,
1148
- });
1509
+ repository,
1510
+ action,
1511
+ request,
1512
+ () => executeAssistantPluginAction({
1513
+ controllerHome,
1514
+ repoId: repository.repoId,
1515
+ repoRoot: repository.canonicalRoot,
1516
+ pluginId: request.pluginId,
1517
+ actionId: request.actionId,
1518
+ requestId: request.requestId,
1519
+ args: normalizedArgs,
1520
+ origin: request.origin,
1521
+ jobId: receiptId,
1522
+ timeoutMs: request.timeoutMs,
1523
+ signal: request.signal,
1524
+ authorizationGrantRefs: request.authorizationGrantRefs,
1525
+ deadlineAtMs: typeof request.timeoutMs === 'number'
1526
+ ? Date.now() + Math.max(1, Math.trunc(request.timeoutMs))
1527
+ : undefined,
1528
+ }),
1529
+ );
1149
1530
  if (action.confirmation === 'authorization'
1150
1531
  && authorizationContext
1151
1532
  && !activeAuthorizationGrant
@@ -1275,27 +1656,46 @@ export async function submitAssistantPluginAction(
1275
1656
  };
1276
1657
  } catch (error) {
1277
1658
  const message = error instanceof Error ? error.message : String(error);
1278
- const code = /^([A-Z][A-Z0-9_]+)/.exec(message)?.[1] ?? 'PLUGIN_ACTION_FAILED';
1659
+ const code = isAssistantPluginError(error)
1660
+ ? error.code
1661
+ : /^([A-Z][A-Z0-9_]+)/.exec(message)?.[1] ?? 'PLUGIN_ACTION_FAILED';
1662
+ const effectOutcome: AssistantPluginEffectOutcome = isAssistantPluginError(error)
1663
+ ? error.effectOutcome
1664
+ : 'failed';
1665
+ const outcomeUnknown = effectOutcome === 'outcome_unknown';
1666
+ const outcomeResult = outcomeUnknown
1667
+ ? { outcome: 'outcome_unknown', error: { code, message } }
1668
+ : undefined;
1279
1669
  if (boundRemoteWork) {
1280
1670
  appendWorkEvidence({ controllerHome, repoId: workAttributionRepoId(repository, request) }, boundRemoteWork.workId, {
1281
- title: 'typed remote plugin effect failed',
1671
+ title: outcomeUnknown ? 'typed remote plugin effect outcome unknown' : 'typed remote plugin effect failed',
1282
1672
  summary: `${request.pluginId}/${request.actionId}: ${message}`.slice(0, 1_000),
1283
1673
  detailLevel: 'summary',
1284
1674
  });
1285
1675
  }
1286
1676
  if (acceptedWork) {
1287
- const current = getWorkContract({ controllerHome, repoId: repository.repoId }, acceptedWork.workId);
1288
- updateWorkContract({ controllerHome, repoId: repository.repoId }, acceptedWork.workId, {
1289
- status: 'failed',
1290
- workKind: 'local_effect',
1291
- dispatchState: 'terminal',
1292
- evidenceState: 'failed',
1293
- evidenceRefs: [{
1294
- title: 'controller-local effect failed',
1677
+ if (outcomeUnknown) {
1678
+ appendWorkEvidence({ controllerHome, repoId: repository.repoId }, acceptedWork.workId, {
1679
+ title: 'controller-local effect outcome unknown',
1295
1680
  summary: `${request.pluginId}/${request.actionId}: ${message}`.slice(0, 1_000),
1296
1681
  detailLevel: 'summary',
1297
- }, ...(current?.evidenceRefs ?? [])],
1298
- });
1682
+ });
1683
+ } else {
1684
+ const current = getWorkContract({ controllerHome, repoId: repository.repoId }, acceptedWork.workId);
1685
+ failWorkContract(
1686
+ { controllerHome, repoId: repository.repoId },
1687
+ acceptedWork.workId,
1688
+ {
1689
+ phase: current?.phase ?? 'implementation',
1690
+ summary: `Controller-local plugin action failed: ${request.pluginId}/${request.actionId}: ${message}`.slice(0, 1_000),
1691
+ evidenceRefs: [{
1692
+ title: 'controller-local effect failed',
1693
+ summary: `${request.pluginId}/${request.actionId}: ${message}`.slice(0, 1_000),
1694
+ detailLevel: 'summary',
1695
+ }, ...(current?.evidenceRefs ?? [])],
1696
+ },
1697
+ );
1698
+ }
1299
1699
  }
1300
1700
  const receipt: PluginActionReceipt = {
1301
1701
  schemaVersion: 1,
@@ -1307,6 +1707,7 @@ export async function submitAssistantPluginAction(
1307
1707
  actionId: request.actionId,
1308
1708
  semanticKey: key,
1309
1709
  status: 'failed',
1710
+ effectOutcome,
1310
1711
  createdAt,
1311
1712
  ...(acceptedWork
1312
1713
  ? { workId: acceptedWork.workId }
@@ -1317,20 +1718,45 @@ export async function submitAssistantPluginAction(
1317
1718
  : {}),
1318
1719
  origin: request.origin,
1319
1720
  authorization,
1721
+ ...(outcomeResult ? { result: outcomeResult } : {}),
1320
1722
  error: { code, message },
1321
1723
  };
1322
1724
  writeJsonAtomic(pluginActionReceiptPath(controllerHome, repository.repoId, receiptId), receipt);
1323
1725
  writeJsonAtomic(requestPath, {
1324
1726
  requestId: request.requestId,
1325
1727
  repoId: repository.repoId,
1728
+ ...(request.workId ? { workRepoId: workAttributionRepoId(repository, request) } : {}),
1326
1729
  receiptId,
1327
1730
  semanticKey: key,
1328
1731
  createdAt,
1329
1732
  } satisfies PluginActionRequestIndex);
1733
+ if (outcomeUnknown) {
1734
+ return {
1735
+ manifest,
1736
+ action,
1737
+ job: compatibilityJobFromReceipt(receipt, repository.activeCheckoutId),
1738
+ deduplicated: false,
1739
+ result: outcomeResult,
1740
+ receipt,
1741
+ authorization,
1742
+ workId: acceptedWork?.workId ?? boundRemoteWork?.workId ?? attributedWork?.workId,
1743
+ };
1744
+ }
1330
1745
  throw error;
1331
1746
  }
1332
1747
  }
1333
1748
 
1749
+ export async function executeControllerScopedPluginAction(
1750
+ input: Omit<AssistantPluginActionExecutionInput, 'repoId' | 'repoRoot'>,
1751
+ ): Promise<Record<string, unknown>> {
1752
+ const repository = controllerPluginRepository(input.controllerHome);
1753
+ return executeAssistantPluginAction({
1754
+ ...input,
1755
+ repoId: repository.repoId,
1756
+ repoRoot: repository.canonicalRoot,
1757
+ });
1758
+ }
1759
+
1334
1760
  export async function executeAssistantPluginAction(
1335
1761
  input: AssistantPluginActionExecutionInput,
1336
1762
  ): Promise<Record<string, unknown>> {
@@ -1344,8 +1770,24 @@ export async function executeAssistantPluginAction(
1344
1770
  const manifestLookup = getAssistantPluginManifestForExecution(input.controllerHome, repository, input.pluginId, adapter);
1345
1771
  const manifest = manifestLookup.manifest;
1346
1772
  const action = actionForManifest(manifest, input.actionId);
1347
- denyAutomatedWrite(manifest, action, input.origin);
1773
+ if (action.executionMode === 'direct_non_persistent') {
1774
+ throw new Error(`PLUGIN_DIRECT_NON_PERSISTENT_APPLICATION_PATH_REQUIRED: ${input.pluginId}/${input.actionId}`);
1775
+ }
1348
1776
  const normalizedArgs = validateActionArguments(action, input.args);
1777
+ if (requiresAutomatedWriteAuthorization(input.origin)) {
1778
+ await resolveAutomatedWriteAuthorization({
1779
+ controllerHome: input.controllerHome,
1780
+ repository,
1781
+ adapter,
1782
+ manifest,
1783
+ action,
1784
+ args: normalizedArgs,
1785
+ origin: input.origin,
1786
+ requestId: input.requestId,
1787
+ jobId: input.jobId,
1788
+ authorizationGrantRefs: input.authorizationGrantRefs,
1789
+ });
1790
+ }
1349
1791
  try {
1350
1792
  const result = await adapter.executeAction({
1351
1793
  ...input,