@moretea-labs/forge 1.5.1 → 1.7.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 (434) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +46 -0
  3. package/CLAUDE.md +2 -0
  4. package/DESIGN.md +7 -2
  5. package/README.md +4 -4
  6. package/README.zh-CN.md +2 -2
  7. package/SKILL.md +2 -2
  8. package/THIRD_PARTY_NOTICES.md +1 -1
  9. package/agents/openai.yaml +1 -1
  10. package/assets/hooks/hook-input.sh +11 -8
  11. package/assets/hooks/lib/session-state.sh +10 -7
  12. package/assets/hooks/lib/workflow-state.sh +13 -177
  13. package/assets/hooks/post-tool-observer.sh +8 -2
  14. package/assets/hooks/pre-edit-guard.sh +8 -39
  15. package/assets/hooks/prompt-guard.sh +7 -83
  16. package/assets/hooks/session-start-context.sh +56 -1
  17. package/assets/partials/05-workflow.partial.md +1 -1
  18. package/assets/partials-agents/03-orchestration.partial.md +1 -1
  19. package/assets/plugin-registry.v1.json +54 -3
  20. package/assets/reference-configs/document-generation.md +1 -1
  21. package/assets/reference-configs/harness-overview.md +1 -1
  22. package/assets/reference-configs/hook-operations.md +1 -1
  23. package/assets/reference-configs/sprint-contracts.md +3 -3
  24. package/assets/skill-version.json +2 -2
  25. package/assets/templates/contract.template.md +2 -7
  26. package/assets/templates/helpers/capture-plan.sh +2 -2
  27. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  28. package/assets/templates/helpers/contract-worktree.sh +1 -21
  29. package/assets/templates/helpers/ensure-task-workflow.sh +13 -38
  30. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  31. package/assets/templates/helpers/new-plan.sh +1 -1
  32. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  33. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  34. package/assets/templates/helpers/sprint-backlog.sh +6 -6
  35. package/assets/templates/helpers/verify-contract.sh +1 -111
  36. package/assets/templates/helpers/verify-sprint.sh +3 -180
  37. package/assets/templates/plan.template.md +1 -1
  38. package/assets/templates/review.template.md +9 -34
  39. package/assets/workflow-contract.v1.json +10 -19
  40. package/docs/README.md +10 -10
  41. package/docs/architecture/CURRENT.md +170 -0
  42. package/docs/architecture/EVOLUTION.md +42 -0
  43. package/docs/architecture/current/README.md +4 -156
  44. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  45. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  46. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  47. package/docs/architecture/history/README.md +7 -0
  48. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  49. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  50. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  51. package/docs/architecture/history.md +3 -34
  52. package/docs/architecture/index.md +15 -98
  53. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  54. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  55. package/docs/architecture/versions/1.6.md +38 -0
  56. package/docs/architecture/versions/1.7.md +41 -0
  57. package/docs/forge-chatgpt-browser-engine.md +2 -2
  58. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  59. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  60. package/docs/forge-github-issue-launcher.md +1 -1
  61. package/docs/forge-runtime-self-healing-loop.md +1 -1
  62. package/docs/operations/controller-browser-plugin.md +38 -22
  63. package/docs/operations/controller-performance-and-502.md +124 -0
  64. package/docs/operations/controller-reliability-runbook.md +1 -1
  65. package/docs/operations/features.md +3 -3
  66. package/docs/operations/github-repository.md +1 -1
  67. package/docs/operations/homebrew.md +2 -2
  68. package/docs/operations/mcp-tool-exposure.md +5 -3
  69. package/docs/tutorials/01-install-and-start.md +1 -1
  70. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  71. package/docs/wiki/Architecture.md +6 -6
  72. package/docs/wiki/Implementation.md +2 -2
  73. package/docs/wiki/Installation.md +1 -1
  74. package/docs/wiki/Integrations.md +2 -2
  75. package/docs/wiki/Quick-Start.md +1 -1
  76. package/docs/wiki/Work-Lifecycle.md +1 -1
  77. package/package.json +29 -10
  78. package/scripts/activate-source-baseline.ts +17 -13
  79. package/scripts/benchmark-background-check-overlap.ts +228 -0
  80. package/scripts/benchmark-mcp-host.sh +117 -0
  81. package/scripts/benchmark-mcp-transport.ts +170 -0
  82. package/scripts/benchmark-quality-harness.ts +146 -0
  83. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  84. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  85. package/scripts/benchmark-typescript-navigation.ts +186 -0
  86. package/scripts/benchmark-work-efficiency.ts +334 -0
  87. package/scripts/capture-plan.sh +3 -3
  88. package/scripts/check-agent-tooling.sh +8 -35
  89. package/scripts/check-architecture-sync.sh +17 -86
  90. package/scripts/check-mcp-compatibility.ts +14 -0
  91. package/scripts/check-public-docs.sh +14 -1
  92. package/scripts/check-runtime-architecture.mjs +107 -64
  93. package/scripts/check-stable-baseline.ts +92 -0
  94. package/scripts/check-task-workflow.sh +4 -4
  95. package/scripts/contract-worktree.sh +1 -21
  96. package/scripts/ensure-task-workflow.sh +22 -55
  97. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  98. package/scripts/install-standalone-recovery.ts +24 -0
  99. package/scripts/lib/project-init-lib.sh +15 -44
  100. package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
  101. package/scripts/migrate-project-template.sh +23 -1179
  102. package/scripts/new-plan.sh +1 -1
  103. package/scripts/plan-to-todo.sh +11 -36
  104. package/scripts/run-governed-gate.ts +2 -1
  105. package/scripts/ship-worktrees.sh +2 -29
  106. package/scripts/smoke-ios-physical-device.ts +4 -2
  107. package/scripts/smoke-runtime-recovery.ts +1 -35
  108. package/scripts/smoke-schedule-engine.ts +1 -20
  109. package/scripts/sprint-backlog.sh +1 -1
  110. package/scripts/verify-contract.sh +1 -111
  111. package/scripts/verify-forge-runtime.sh +0 -1
  112. package/scripts/verify-sprint.sh +3 -180
  113. package/scripts/workflow-contract.ts +1 -5
  114. package/src/cli/commands/chatgpt.ts +31 -2
  115. package/src/cli/commands/init-hook.ts +3 -3
  116. package/src/cli/commands/mcp.ts +9 -5
  117. package/src/cli/commands/plugin.ts +37 -10
  118. package/src/cli/commands/recovery.ts +25 -3
  119. package/src/cli/commands/runtime.ts +55 -3
  120. package/src/cli/commands/security.ts +12 -1
  121. package/src/cli/commands/setup-profile.ts +31 -21
  122. package/src/cli/controller/check-runner.ts +106 -3
  123. package/src/cli/controller/composite-result.ts +1 -1
  124. package/src/cli/controller/context/focus.ts +51 -0
  125. package/src/cli/controller/context/instruction-context.ts +114 -0
  126. package/src/cli/controller/context/known-paths.ts +76 -0
  127. package/src/cli/controller/context/query-planning.ts +110 -0
  128. package/src/cli/controller/context/rule-resolution.ts +532 -0
  129. package/src/cli/controller/context/source-materializer.ts +278 -0
  130. package/src/cli/controller/context/structural.ts +16 -0
  131. package/src/cli/controller/context/types.ts +286 -0
  132. package/src/cli/controller/context-pack.ts +898 -430
  133. package/src/cli/controller/launch-agents.ts +77 -2
  134. package/src/cli/controller/operational-plan.ts +2 -2
  135. package/src/cli/controller/work-mode.ts +6 -4
  136. package/src/cli/editing/edit-session.ts +60 -7
  137. package/src/cli/github/github.ts +133 -0
  138. package/src/cli/hook/prompt-guard-decision.ts +17 -18
  139. package/src/cli/hook/prompt-intents.ts +1 -1
  140. package/src/cli/installer/managed-entries.ts +15 -1
  141. package/src/cli/local-bridge/console-automations.ts +225 -67
  142. package/src/cli/local-bridge/console-view-models.ts +3 -35
  143. package/src/cli/local-bridge/facade-api.ts +2 -217
  144. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  145. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
  146. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  147. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
  148. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
  149. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
  150. package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
  151. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  152. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
  153. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
  154. package/src/cli/local-bridge/frontend/src/styles.css +27 -11
  155. package/src/cli/local-bridge/frontend/src/types.ts +8 -7
  156. package/src/cli/local-bridge/job-store.ts +1 -490
  157. package/src/cli/local-bridge/server.ts +29 -532
  158. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  159. package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
  160. package/src/cli/mcp/auth.ts +5 -5
  161. package/src/cli/mcp/instructions.ts +3 -2
  162. package/src/cli/mcp/legacy-tool-service.ts +0 -189
  163. package/src/cli/mcp/multi-repository.ts +16 -5
  164. package/src/cli/mcp/oauth.ts +175 -26
  165. package/src/cli/mcp/paths.ts +8 -2
  166. package/src/cli/mcp/repository-tools.ts +356 -101
  167. package/src/cli/mcp/server.ts +625 -54
  168. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  169. package/src/cli/mcp/toolset-selection.ts +1 -1
  170. package/src/cli/mcp/toolset.ts +42 -5
  171. package/src/cli/mcp/transports/http.ts +125 -15
  172. package/src/cli/mcp/transports/session-registry.ts +67 -5
  173. package/src/cli/mcp/types.ts +3 -3
  174. package/src/cli/repositories/command-classifier.ts +209 -14
  175. package/src/cli/repositories/command-executor.ts +55 -521
  176. package/src/cli/repositories/command-process.ts +108 -0
  177. package/src/cli/repositories/command-scope.ts +99 -41
  178. package/src/cli/repositories/controller-home.ts +7 -8
  179. package/src/cli/repositories/git-command-executor.ts +2 -0
  180. package/src/cli/repositories/locks.ts +53 -16
  181. package/src/cli/repositories/repository-snapshot.ts +121 -0
  182. package/src/cli/repositories/safe-patch.ts +6 -4
  183. package/src/cli/repositories/selected-path-actions.ts +17 -9
  184. package/src/cli/repositories/structured-git.ts +110 -10
  185. package/src/cli/repository/inspector.ts +565 -62
  186. package/src/cli/repository/session-cache.ts +58 -17
  187. package/src/cli/v81-entry.ts +1 -4
  188. package/src/effects/fs-transaction.ts +85 -17
  189. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  190. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  191. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  192. package/src/runtime/context/lsp-client.ts +283 -0
  193. package/src/runtime/context/semantic-navigation.ts +275 -0
  194. package/src/runtime/context/swift-navigation.ts +565 -0
  195. package/src/runtime/context/typescript-navigation.ts +226 -0
  196. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  197. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +196 -2
  198. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  199. package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
  200. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  201. package/src/runtime/control-plane/execution/validation.ts +15 -2
  202. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  203. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  204. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  205. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  206. package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
  207. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +175 -8
  208. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
  209. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
  210. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  211. package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
  212. package/src/runtime/control-plane/facade/controller-session-store.ts +144 -14
  213. package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
  214. package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
  215. package/src/runtime/control-plane/facade/index.ts +1 -0
  216. package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
  217. package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
  218. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  219. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  220. package/src/runtime/control-plane/facade/types.ts +55 -11
  221. package/src/runtime/control-plane/facade/work-contract-store.ts +204 -73
  222. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  223. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  224. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  225. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  226. package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
  227. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  228. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  229. package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
  230. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  231. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  232. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  233. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  234. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  235. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  236. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  237. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  238. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  239. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  240. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
  241. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +642 -51
  242. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
  243. package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
  244. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  245. package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
  246. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  247. package/src/runtime/control-plane/release-retention.ts +62 -2
  248. package/src/runtime/control-plane/routing/route-policy.ts +7 -16
  249. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  250. package/src/runtime/diagnostics/mcp-timing.ts +19 -0
  251. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  252. package/src/runtime/diagnostics/performance.ts +24 -1
  253. package/src/runtime/evidence/event-ledger.ts +1 -1
  254. package/src/runtime/execution/jobs/store.ts +58 -4
  255. package/src/runtime/execution/jobs/types.ts +1 -1
  256. package/src/runtime/execution/managed-workspace.ts +203 -1
  257. package/src/runtime/execution/process-runtime/check-facade.ts +52 -14
  258. package/src/runtime/execution/process-runtime/check-result.ts +63 -2
  259. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  260. package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
  261. package/src/runtime/execution/process-runtime/gc.ts +98 -12
  262. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
  263. package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
  264. package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
  265. package/src/runtime/execution/process-runtime/runtime.ts +59 -4
  266. package/src/runtime/execution/process-runtime/store.ts +7 -0
  267. package/src/runtime/execution/process-runtime/types.ts +2 -0
  268. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  269. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  270. package/src/runtime/execution/workers/executor.ts +0 -48
  271. package/src/runtime/gateway/mcp/execution-tools.ts +1219 -126
  272. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  273. package/src/runtime/gateway/mcp/router.ts +185 -83
  274. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
  275. package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
  276. package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
  277. package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
  278. package/src/runtime/plugins/browser-adapter.ts +2925 -318
  279. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  280. package/src/runtime/plugins/browser-handoff-host.ts +6 -31
  281. package/src/runtime/plugins/browser-handoff.ts +92 -5
  282. package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
  283. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  284. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  285. package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
  286. package/src/runtime/plugins/browser-runtime.ts +183 -0
  287. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  288. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  289. package/src/runtime/plugins/desktop-operator-registration.ts +15 -12
  290. package/src/runtime/plugins/external-adapter.ts +324 -3
  291. package/src/runtime/plugins/external-registration.ts +84 -5
  292. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  293. package/src/runtime/plugins/first-party-registry.ts +4 -2
  294. package/src/runtime/plugins/github-adapter.ts +125 -0
  295. package/src/runtime/plugins/gmail-adapter.ts +28 -2
  296. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  297. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  298. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  299. package/src/runtime/plugins/ios-adapter.ts +106 -16
  300. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  301. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  302. package/src/runtime/plugins/lightweight-action.ts +153 -0
  303. package/src/runtime/plugins/local-system-adapter.ts +125 -8
  304. package/src/runtime/plugins/macos-capability-broker.ts +55 -9
  305. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  306. package/src/runtime/plugins/plugin-management-adapter.ts +181 -0
  307. package/src/runtime/plugins/resend-adapter.ts +1 -1
  308. package/src/runtime/plugins/store.ts +366 -24
  309. package/src/runtime/plugins/types.ts +39 -2
  310. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  311. package/src/runtime/projections/git-status-sampler.ts +16 -16
  312. package/src/runtime/projections/materialized-view.ts +28 -10
  313. package/src/runtime/recovery/actions.ts +0 -10
  314. package/src/runtime/recovery/classifier.ts +0 -9
  315. package/src/runtime/recovery/maintenance-executor.ts +415 -18
  316. package/src/runtime/recovery/probe.ts +0 -1
  317. package/src/runtime/recovery/types.ts +0 -1
  318. package/src/runtime/root/mcp-transport.ts +180 -10
  319. package/src/runtime/root/package-connector-service.ts +186 -8
  320. package/src/runtime/root/package-runtime-release.ts +143 -17
  321. package/src/runtime/root/package-runtime-service.ts +430 -22
  322. package/src/runtime/root/release-manifest.ts +7 -2
  323. package/src/runtime/root/release-materialize.ts +162 -19
  324. package/src/runtime/root/release-store.ts +48 -11
  325. package/src/runtime/root/runtime.ts +23 -5
  326. package/src/runtime/root/service.ts +100 -27
  327. package/src/runtime/root/types.ts +2 -0
  328. package/src/runtime/safe-tooling/index.ts +0 -1
  329. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  330. package/src/runtime/safe-tooling/types.ts +0 -30
  331. package/src/runtime/shared/trusted-executable.ts +62 -0
  332. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  333. package/src/runtime/standalone-recovery/core.ts +702 -94
  334. package/src/runtime/standalone-recovery/entry.ts +99 -23
  335. package/src/runtime/standalone-recovery/installer.ts +19 -3
  336. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  337. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  338. package/src/runtime/workflow/schedules/browser-probe.ts +258 -0
  339. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
  340. package/src/runtime/workflow/schedules/engine.ts +509 -80
  341. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  342. package/src/runtime/workflow/schedules/settlement.ts +48 -4
  343. package/src/runtime/workflow/schedules/store.ts +131 -10
  344. package/src/runtime/workflow/schedules/types.ts +6 -3
  345. package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
  346. package/src/testing/test-governance.ts +8 -40
  347. package/assets/reference-configs/heartbeat-triage.md +0 -57
  348. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  349. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  350. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  351. package/bin/forge-desktop-helper.mjs +0 -204
  352. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  353. package/docs/architecture/current/architecture-invariants.md +0 -331
  354. package/docs/architecture/current/automation-and-schedule-engine.md +0 -453
  355. package/docs/architecture/current/codegraph-context-provider.md +0 -226
  356. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  357. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  358. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -354
  359. package/docs/architecture/current/entity-model.md +0 -592
  360. package/docs/architecture/current/external-plugin-governance.md +0 -396
  361. package/docs/architecture/current/failure-recovery.md +0 -447
  362. package/docs/architecture/current/governance.md +0 -213
  363. package/docs/architecture/current/human-interaction-plane.md +0 -87
  364. package/docs/architecture/current/implementation-status.md +0 -128
  365. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  366. package/docs/architecture/current/legacy-governance.md +0 -58
  367. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  368. package/docs/architecture/current/migration-roadmap.md +0 -105
  369. package/docs/architecture/current/multi-repository-execution.md +0 -371
  370. package/docs/architecture/current/operations-runbook.md +0 -45
  371. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  372. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  373. package/docs/architecture/current/repository-access-modes.md +0 -102
  374. package/docs/architecture/current/route-policy.md +0 -15
  375. package/docs/architecture/current/route-session-concurrency.md +0 -85
  376. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  377. package/docs/architecture/current/runtime-directory-map.md +0 -49
  378. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  379. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  380. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  381. package/docs/architecture/current/system-overview.md +0 -144
  382. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  383. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  384. package/docs/architecture/current/thin-harness-v1.md +0 -311
  385. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  386. package/docs/forge-autonomous-goal-loop.md +0 -9
  387. package/docs/forge-provider-configuration.md +0 -7
  388. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -83
  389. package/docs/operations/controller-desktop-plugin.md +0 -112
  390. package/docs/operations/gmail-assistant-routines.md +0 -186
  391. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  392. package/docs/operations/provider-configuration.md +0 -31
  393. package/scripts/harness-trace-grade.sh +0 -150
  394. package/scripts/heartbeat-triage.sh +0 -361
  395. package/scripts/maintenance-triage.sh +0 -167
  396. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  397. package/src/cli/repositories/goal-registry.ts +0 -239
  398. package/src/runtime/assistant/action-proposals.ts +0 -279
  399. package/src/runtime/assistant/intent.ts +0 -395
  400. package/src/runtime/assistant/model-provider.ts +0 -460
  401. package/src/runtime/assistant/openapi.ts +0 -223
  402. package/src/runtime/assistant/policy.ts +0 -89
  403. package/src/runtime/assistant/readiness.ts +0 -258
  404. package/src/runtime/assistant/routine-runtime.ts +0 -477
  405. package/src/runtime/assistant/schedule-binding.ts +0 -171
  406. package/src/runtime/assistant/standing-grants.ts +0 -375
  407. package/src/runtime/assistant/store.ts +0 -243
  408. package/src/runtime/assistant/types.ts +0 -135
  409. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  410. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  411. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  412. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  413. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  414. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  415. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  416. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  417. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  418. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  419. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  420. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  421. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  422. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  423. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  424. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  425. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  426. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  427. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  428. package/src/runtime/plugins/desktop-adapter.ts +0 -374
  429. package/src/runtime/safe-tooling/browser-safe.ts +0 -133
  430. package/src/runtime/workflow/findings/store.ts +0 -204
  431. package/src/runtime/workflow/findings/types.ts +0 -58
  432. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  433. package/src/runtime/workflow/portfolio/store.ts +0 -185
  434. package/src/runtime/workflow/portfolio/types.ts +0 -29
@@ -5,7 +5,9 @@ import {
5
5
  lstatSync,
6
6
  mkdirSync,
7
7
  mkdtempSync,
8
+ readFileSync,
8
9
  readdirSync,
10
+ rmdirSync,
9
11
  rmSync,
10
12
  statSync,
11
13
  symlinkSync,
@@ -18,7 +20,7 @@ import { globMatches, normalizeMcpRelativePath } from '../../../cli/mcp/paths';
18
20
  import { sanitizeFileComponent } from '../../shared/json-files';
19
21
 
20
22
  const STALE_SNAPSHOT_MS = 6 * 60 * 60_000;
21
- const SNAPSHOT_MARKER = '.forge-work-verification-snapshot.json';
23
+ const SNAPSHOT_MARKER = '.ai/harness/controller/work-verification-snapshot.json';
22
24
 
23
25
  export interface WorkVerificationSnapshotScope {
24
26
  workId: string;
@@ -91,11 +93,28 @@ function cloneHead(sourceRoot: string, targetRoot: string, head: string): void {
91
93
  git(targetRoot, ['checkout', '--detach', '--quiet', head]);
92
94
  }
93
95
 
96
+ function pruneEmptySnapshotParents(targetRoot: string, targetPath: string): void {
97
+ const boundary = resolve(targetRoot);
98
+ let current = dirname(resolve(targetPath));
99
+ while (current !== boundary) {
100
+ try {
101
+ if (readdirSync(current).length > 0) return;
102
+ rmdirSync(current);
103
+ } catch {
104
+ return;
105
+ }
106
+ current = dirname(current);
107
+ }
108
+ }
109
+
94
110
  function overlayPath(sourceRoot: string, targetRoot: string, relativePath: string): void {
95
111
  const source = resolve(sourceRoot, relativePath);
96
112
  const target = resolve(targetRoot, relativePath);
97
113
  rmSync(target, { recursive: true, force: true });
98
- if (!existsSync(source)) return;
114
+ if (!existsSync(source)) {
115
+ pruneEmptySnapshotParents(targetRoot, target);
116
+ return;
117
+ }
99
118
  mkdirSync(dirname(target), { recursive: true });
100
119
  const stat = lstatSync(source);
101
120
  if (stat.isSymbolicLink()) {
@@ -105,11 +124,69 @@ function overlayPath(sourceRoot: string, targetRoot: string, relativePath: strin
105
124
  cpSync(source, target, { recursive: stat.isDirectory(), dereference: false, force: true, preserveTimestamps: true });
106
125
  }
107
126
 
108
- function linkIgnoredNodeModules(sourceRoot: string, targetRoot: string): void {
109
- const source = join(sourceRoot, 'node_modules');
127
+ const DEPENDENCY_LOCK_FILES = ['bun.lock', 'bun.lockb', 'pnpm-lock.yaml', 'package-lock.json', 'yarn.lock'] as const;
128
+ const DEPENDENCY_CONFIG_FILES = ['pnpm-workspace.yaml', 'bunfig.toml', '.npmrc', '.yarnrc.yml'] as const;
129
+ const DEPENDENCY_METADATA_NAMES = ['package.json', ...DEPENDENCY_LOCK_FILES, ...DEPENDENCY_CONFIG_FILES] as const;
130
+
131
+ function isDependencyMetadataPath(path: string): boolean {
132
+ const name = path.split('/').pop() ?? path;
133
+ return DEPENDENCY_METADATA_NAMES.some((candidate) => candidate === name);
134
+ }
135
+
136
+ function hasUntrackedDependencyMetadata(root: string): boolean {
137
+ return nulPaths(git(root, ['ls-files', '--others', '--exclude-standard', '-z'])).some(isDependencyMetadataPath);
138
+ }
139
+
140
+ function dependencyMetadataDigest(root: string): string | undefined {
141
+ if (!existsSync(join(root, 'package.json'))) return undefined;
142
+ const rootLock = DEPENDENCY_LOCK_FILES.find((name) => existsSync(join(root, name)));
143
+ if (!rootLock) return undefined;
144
+ const pathspecs = DEPENDENCY_METADATA_NAMES.flatMap((name) => [name, `:(glob)**/${name}`]);
145
+ const tracked = nulPaths(git(root, ['ls-files', '-z', '--', ...pathspecs]));
146
+ const files = [...new Set(tracked)].sort();
147
+ if (!files.includes('package.json') || !files.includes(rootLock)) return undefined;
148
+ const hash = createHash('sha256');
149
+ for (const path of files) {
150
+ hash.update(path);
151
+ hash.update('\0');
152
+ hash.update(readFileSync(join(root, path)));
153
+ hash.update('\0');
154
+ }
155
+ return hash.digest('hex');
156
+ }
157
+
158
+ function primaryWorktreeRoot(sourceRoot: string): string | undefined {
159
+ const commonDirValue = git(sourceRoot, ['rev-parse', '--git-common-dir']).toString('utf8').trim();
160
+ if (!commonDirValue) return undefined;
161
+ const commonDir = resolve(sourceRoot, commonDirValue);
162
+ const candidate = dirname(commonDir);
163
+ if (resolve(candidate) === resolve(sourceRoot)) return undefined;
164
+ if (!existsSync(join(candidate, '.git'))) return undefined;
165
+ return candidate;
166
+ }
167
+
168
+ function linkIgnoredNodeModules(sourceRoot: string, targetRoot: string, dirtyPaths: readonly string[]): void {
169
+ let source = join(sourceRoot, 'node_modules');
110
170
  const target = join(targetRoot, 'node_modules');
111
- if (!existsSync(source) || existsSync(target)) return;
112
- const ignored = spawnSync('git', ['-C', sourceRoot, 'check-ignore', '--quiet', '--', 'node_modules'], { stdio: 'ignore', timeout: 10_000 });
171
+ if (existsSync(target)) return;
172
+ if (!existsSync(source)) {
173
+ if (dirtyPaths.some(isDependencyMetadataPath)) return;
174
+ const primaryRoot = primaryWorktreeRoot(sourceRoot);
175
+ if (!primaryRoot) return;
176
+ const primaryNodeModules = join(primaryRoot, 'node_modules');
177
+ if (!existsSync(primaryNodeModules) || hasUntrackedDependencyMetadata(primaryRoot)) return;
178
+ const sourceDigest = dependencyMetadataDigest(sourceRoot);
179
+ const primaryDigest = dependencyMetadataDigest(primaryRoot);
180
+ if (!sourceDigest || sourceDigest !== primaryDigest) return;
181
+ source = primaryNodeModules;
182
+ }
183
+ // An existing managed-worktree node_modules may itself be a symlink. Git
184
+ // rejects child pathspecs through symlinks, while an absent node_modules
185
+ // needs a virtual child path so directory-only ignore rules still match.
186
+ const ignoreProbe = existsSync(join(sourceRoot, 'node_modules'))
187
+ ? 'node_modules'
188
+ : 'node_modules/.forge-verification-probe';
189
+ const ignored = spawnSync('git', ['-C', sourceRoot, 'check-ignore', '--quiet', '--', ignoreProbe], { stdio: 'ignore', timeout: 10_000 });
113
190
  if (ignored.status !== 0) return;
114
191
  try {
115
192
  symlinkSync(source, target, process.platform === 'win32' ? 'junction' : 'dir');
@@ -136,18 +213,18 @@ export function materializeWorkVerificationSnapshot(input: {
136
213
  excludedPaths.push(path);
137
214
  continue;
138
215
  }
139
- if (input.scope.allowedPaths.length > 0 && matchesAny(input.scope.allowedPaths, path)) {
216
+ if (input.scope.allowedPaths.length === 0 || matchesAny(input.scope.allowedPaths, path)) {
140
217
  includedPaths.push(path);
141
218
  continue;
142
219
  }
143
- throw new Error(`WORK_VERIFICATION_PATH_OWNERSHIP_AMBIGUOUS: ${path} is dirty but is neither allowed nor forbidden for ${input.scope.workId}`);
220
+ throw new Error(`WORK_VERIFICATION_PATH_OWNERSHIP_AMBIGUOUS: ${path} is dirty but is outside the allowed path fence for ${input.scope.workId}`);
144
221
  }
145
222
 
146
223
  const root = snapshotRoot(input.controllerHome, input.repoId, input.scope.workId);
147
224
  try {
148
225
  cloneHead(input.sourceRoot, root, sourceHead);
149
226
  for (const path of includedPaths) overlayPath(input.sourceRoot, root, path);
150
- linkIgnoredNodeModules(input.sourceRoot, root);
227
+ linkIgnoredNodeModules(input.sourceRoot, root, dirtyPaths);
151
228
  const ownershipDigest = createHash('sha256').update(JSON.stringify({
152
229
  sourceHead,
153
230
  workId: input.scope.workId,
@@ -156,6 +233,7 @@ export function materializeWorkVerificationSnapshot(input: {
156
233
  allowedPaths: [...input.scope.allowedPaths].sort(),
157
234
  forbiddenPaths: [...input.scope.forbiddenPaths].sort(),
158
235
  })).digest('hex');
236
+ mkdirSync(dirname(join(root, SNAPSHOT_MARKER)), { recursive: true });
159
237
  writeFileSync(join(root, SNAPSHOT_MARKER), `${JSON.stringify({ schemaVersion: 1, ...input.scope, sourceHead, includedPaths, excludedPaths, ownershipDigest }, null, 2)}\n`);
160
238
  return { root, sourceHead, includedPaths, excludedPaths, ownershipDigest };
161
239
  } catch (error) {
@@ -1,5 +1,5 @@
1
1
  import type { AssistantPluginManifest } from '../../plugins/types';
2
- import type { CapabilityDescriptor, CapabilityDomain, CapabilityGroupSummary, CapabilityOperationClass, CapabilityRisk, FacadeTool } from './types';
2
+ import type { CapabilityDescriptor, CapabilityDomain, CapabilityExecutionSurface, CapabilityGroupSummary, CapabilityOperationClass, CapabilityRisk, FacadeTool } from './types';
3
3
 
4
4
  const CORE_CAPABILITIES: CapabilityDescriptor[] = [
5
5
  {
@@ -83,24 +83,14 @@ const CORE_CAPABILITIES: CapabilityDescriptor[] = [
83
83
  summary: 'Diagnose and dry-run repair stuck jobs, stale projections, invalid check pollution, and worker unavailability without treating infrastructure failure as acceptance failure.',
84
84
  },
85
85
  {
86
- capabilityId: 'controller.codex_delegation',
86
+ capabilityId: 'controller.external_controller',
87
87
  domain: 'controller',
88
88
  group: 'controller',
89
89
  operationClass: 'execute',
90
90
  risk: 'workspace_write',
91
91
  exposedVia: 'rh_work',
92
92
  schemaExposure: 'stable_static',
93
- summary: 'Delegate bounded implementation work to Codex or Claude with context packs; workers return evidence and proposals but do not own final acceptance.',
94
- },
95
- {
96
- capabilityId: 'controller.autonomous_goal_loop',
97
- domain: 'controller',
98
- group: 'controller',
99
- operationClass: 'execute',
100
- risk: 'workspace_write',
101
- exposedVia: 'rh_work',
102
- schemaExposure: 'stable_static',
103
- summary: 'Advance daemon-owned goal contracts through deterministic policy, executor routing, verification, repair, and handoff.',
93
+ summary: 'Claim Work ownership and start an external Codex, Claude, or ChatGPT controller through controller_claim and launcher_start, with handoff decisions coordinated through rh_inbox; deprecated delegate is not an execution path.',
104
94
  },
105
95
  {
106
96
  capabilityId: 'controller.work_contract',
@@ -148,9 +138,9 @@ const CORE_CAPABILITIES: CapabilityDescriptor[] = [
148
138
  group: 'browser',
149
139
  operationClass: 'execute',
150
140
  risk: 'unknown',
151
- exposedVia: 'rh_work',
141
+ exposedVia: 'plugin_action_execute',
152
142
  schemaExposure: 'stable_static',
153
- summary: 'Use typed browser target, snapshot, domain grant, and plugin actions when browser capability is configured.',
143
+ summary: 'Use typed HTTP(S) browser navigation, snapshot, and interaction actions through plugin_action_execute when browser capability is configured.',
154
144
  },
155
145
  {
156
146
  capabilityId: 'platform.ios',
@@ -158,9 +148,9 @@ const CORE_CAPABILITIES: CapabilityDescriptor[] = [
158
148
  group: 'ios',
159
149
  operationClass: 'execute',
160
150
  risk: 'workspace_write',
161
- exposedVia: 'rh_work',
151
+ exposedVia: 'plugin_action_execute',
162
152
  schemaExposure: 'stable_static',
163
- summary: 'Use typed Xcode, simulator launch, screenshot, log, and smoke-test handlers when the local iOS toolchain is ready.',
153
+ summary: 'Use typed Xcode, simulator, screenshot, log, and smoke-review actions through plugin_action_execute when the local iOS toolchain is ready.',
164
154
  },
165
155
  ];
166
156
 
@@ -185,13 +175,16 @@ function domainFromPlugin(pluginId: string): CapabilityDomain {
185
175
  return 'plugin';
186
176
  }
187
177
 
188
- function exposedViaFromPluginAction(readOnly: boolean, risk: string): FacadeTool {
189
- if (readOnly || risk === 'readonly') return 'rh_context';
190
- return 'rh_work';
178
+ function exposedViaFromPluginAction(_readOnly: boolean, _risk: string): CapabilityExecutionSurface {
179
+ // rh_context exposes schema/policy. plugin_action_execute is the sole action executor.
180
+ return 'plugin_action_execute';
191
181
  }
192
182
 
193
- export function pluginCapabilities(manifests: readonly AssistantPluginManifest[] = []): CapabilityDescriptor[] {
194
- return manifests.flatMap((manifest) => manifest.actions.map((action) => ({
183
+ function pluginCapabilityDescriptor(
184
+ manifest: AssistantPluginManifest,
185
+ action: AssistantPluginManifest['actions'][number],
186
+ ): CapabilityDescriptor {
187
+ return {
195
188
  capabilityId: `plugin.${manifest.pluginId}.${action.actionId}`,
196
189
  domain: domainFromPlugin(manifest.pluginId),
197
190
  group: manifest.pluginId === 'browser' ? 'browser' : 'plugin',
@@ -200,7 +193,11 @@ export function pluginCapabilities(manifests: readonly AssistantPluginManifest[]
200
193
  exposedVia: exposedViaFromPluginAction(action.readOnly, action.risk),
201
194
  schemaExposure: 'plugin_manifest',
202
195
  summary: `${manifest.displayName}: ${action.title}. ${action.description}`,
203
- } satisfies CapabilityDescriptor)));
196
+ } satisfies CapabilityDescriptor;
197
+ }
198
+
199
+ export function pluginCapabilities(manifests: readonly AssistantPluginManifest[] = []): CapabilityDescriptor[] {
200
+ return manifests.flatMap((manifest) => manifest.actions.map((action) => pluginCapabilityDescriptor(manifest, action)));
204
201
  }
205
202
 
206
203
  export function listCapabilityDescriptors(manifests: readonly AssistantPluginManifest[] = []): CapabilityDescriptor[] {
@@ -209,6 +206,97 @@ export function listCapabilityDescriptors(manifests: readonly AssistantPluginMan
209
206
  return [...byId.values()].sort((a, b) => a.capabilityId.localeCompare(b.capabilityId));
210
207
  }
211
208
 
209
+ export interface CapabilitySearchMatch {
210
+ capabilityId: string;
211
+ score: number;
212
+ matchedTerms: string[];
213
+ descriptor: CapabilityDescriptor;
214
+ }
215
+
216
+ function normalizedCapabilityText(value: string): string {
217
+ return value
218
+ .toLowerCase()
219
+ .replace(/[_./:-]+/g, ' ')
220
+ .replace(/[^a-z0-9]+/g, ' ')
221
+ .trim();
222
+ }
223
+
224
+ function capabilityIntentTokens(query: string): string[] {
225
+ return [...new Set(normalizedCapabilityText(query).split(' ').filter((token) => token.length >= 2))];
226
+ }
227
+
228
+ function intentBoosts(query: string, capabilityId: string): Array<{ label: string; score: number }> {
229
+ const normalized = normalizedCapabilityText(query);
230
+ const boosts: Array<{ label: string; score: number }> = [];
231
+ const appleDevelopmentIntent = /\b(xcode|provision|provisioning|signing|developer account|apple developer)\b/.test(normalized);
232
+ if (appleDevelopmentIntent) {
233
+ if (capabilityId === 'platform.ios') boosts.push({ label: 'apple-development', score: 90 });
234
+ if (capabilityId.startsWith('plugin.ios.')) boosts.push({ label: 'apple-development', score: 72 });
235
+ if (capabilityId === 'plugin.app_store_connect.auth_status') boosts.push({ label: 'apple-development', score: 88 });
236
+ else if (capabilityId === 'plugin.app_store_connect.configure') boosts.push({ label: 'apple-development', score: 82 });
237
+ else if (capabilityId.startsWith('plugin.app_store_connect.')) boosts.push({ label: 'apple-development', score: 28 });
238
+ if (capabilityId === 'plugin.desktop_operator.desktop_session_open') boosts.push({ label: 'xcode-desktop-fallback', score: 86 });
239
+ else if (capabilityId === 'plugin.desktop_operator.desktop_observe') boosts.push({ label: 'xcode-desktop-fallback', score: 78 });
240
+ else if (capabilityId === 'plugin.desktop_operator.desktop_press') boosts.push({ label: 'xcode-desktop-fallback', score: 74 });
241
+ else if (capabilityId.startsWith('plugin.desktop_operator.')) boosts.push({ label: 'xcode-desktop-fallback', score: 22 });
242
+ }
243
+
244
+ const browserLoginIntent = normalized.includes('browser')
245
+ && /\b(login|log in|signin|sign in|auth|authentication|session)\b/.test(normalized);
246
+ if (browserLoginIntent) {
247
+ if (capabilityId === 'plugin.browser') boosts.push({ label: 'browser-auth', score: 90 });
248
+ else if (capabilityId.startsWith('plugin.browser.')) boosts.push({ label: 'browser-auth', score: 62 });
249
+ if (capabilityId === 'plugin.desktop_operator.desktop_session_open') boosts.push({ label: 'browser-desktop-fallback', score: 70 });
250
+ else if (capabilityId === 'plugin.desktop_operator.desktop_observe') boosts.push({ label: 'browser-desktop-fallback', score: 62 });
251
+ else if (capabilityId.startsWith('plugin.desktop_operator.')) boosts.push({ label: 'browser-desktop-fallback', score: 18 });
252
+ }
253
+ return boosts;
254
+ }
255
+
256
+ export function searchCapabilityDescriptors(
257
+ query: string,
258
+ manifests: readonly AssistantPluginManifest[] = [],
259
+ limit = 12,
260
+ ): CapabilitySearchMatch[] {
261
+ const normalizedQuery = normalizedCapabilityText(query);
262
+ if (!normalizedQuery) return [];
263
+ const tokens = capabilityIntentTokens(query);
264
+ const boundedLimit = Math.max(1, Math.min(24, Math.floor(limit)));
265
+
266
+ return listCapabilityDescriptors(manifests)
267
+ .map((descriptor): CapabilitySearchMatch | undefined => {
268
+ const haystack = normalizedCapabilityText([
269
+ descriptor.capabilityId,
270
+ descriptor.summary,
271
+ descriptor.group,
272
+ descriptor.domain,
273
+ descriptor.operationClass,
274
+ descriptor.exposedVia,
275
+ ].join(' '));
276
+ let score = haystack.includes(normalizedQuery) ? 48 : 0;
277
+ const matchedTerms = new Set<string>();
278
+ for (const token of tokens) {
279
+ if (!haystack.includes(token)) continue;
280
+ matchedTerms.add(token);
281
+ score += descriptor.capabilityId.toLowerCase().includes(token) ? 12 : 5;
282
+ }
283
+ for (const boost of intentBoosts(query, descriptor.capabilityId)) {
284
+ score += boost.score;
285
+ matchedTerms.add(boost.label);
286
+ }
287
+ if (score <= 0) return undefined;
288
+ return {
289
+ capabilityId: descriptor.capabilityId,
290
+ score,
291
+ matchedTerms: [...matchedTerms].sort(),
292
+ descriptor,
293
+ };
294
+ })
295
+ .filter((entry): entry is CapabilitySearchMatch => Boolean(entry))
296
+ .sort((a, b) => b.score - a.score || a.capabilityId.localeCompare(b.capabilityId))
297
+ .slice(0, boundedLimit);
298
+ }
299
+
212
300
  export function summarizeCapabilityGroups(manifests: readonly AssistantPluginManifest[] = []): CapabilityGroupSummary[] {
213
301
  const grouped = new Map<CapabilityDescriptor['group'], CapabilityDescriptor[]>();
214
302
  for (const descriptor of listCapabilityDescriptors(manifests)) {
@@ -222,7 +310,8 @@ export function summarizeCapabilityGroups(manifests: readonly AssistantPluginMan
222
310
  group,
223
311
  capabilityCount: entries.length,
224
312
  domains: [...new Set(entries.map((entry) => entry.domain))].sort(),
225
- facadeTools: [...new Set(entries.map((entry) => entry.exposedVia))].sort(),
313
+ executionSurfaces: [...new Set(entries.map((entry) => entry.exposedVia))].sort(),
314
+ facadeTools: [...new Set(entries.map((entry) => entry.exposedVia).filter((surface): surface is FacadeTool => surface.startsWith('rh_')))].sort(),
226
315
  operationClasses: [...new Set(entries.map((entry) => entry.operationClass))].sort(),
227
316
  risks: [...new Set(entries.map((entry) => entry.risk))].sort(),
228
317
  schemaExposures: [...new Set(entries.map((entry) => entry.schemaExposure))].sort(),
@@ -257,6 +346,12 @@ export function getPluginActionCapabilitySchema(
257
346
  scopes: [...action.scopes],
258
347
  resourceClaims: structuredClone(action.resourceClaims),
259
348
  argumentsSchema: structuredClone(action.argumentsSchema),
349
+ authorizationReuse: action.confirmation === 'authorization'
350
+ ? {
351
+ mode: 'exact_target_persistent_when_adapter_supported',
352
+ hostPermissionBoundary: 'Tool invocation permission remains host-managed; reusable Forge grants never bypass strong_confirmation or destructive gates.',
353
+ }
354
+ : { mode: 'not_reusable' },
260
355
  executeWith: 'plugin_action_execute',
261
356
  };
262
357
  }
@@ -265,5 +360,14 @@ export function getPluginActionCapabilitySchema(
265
360
  }
266
361
 
267
362
  export function getCapabilityDescriptor(capabilityId: string, manifests: readonly AssistantPluginManifest[] = []): CapabilityDescriptor | undefined {
268
- return listCapabilityDescriptors(manifests).find((descriptor) => descriptor.capabilityId === capabilityId);
363
+ const core = CORE_CAPABILITIES.find((descriptor) => descriptor.capabilityId === capabilityId);
364
+ if (core) return core;
365
+ for (const manifest of manifests) {
366
+ for (const action of manifest.actions) {
367
+ if (`plugin.${manifest.pluginId}.${action.actionId}` === capabilityId) {
368
+ return pluginCapabilityDescriptor(manifest, action);
369
+ }
370
+ }
371
+ }
372
+ return undefined;
269
373
  }