@moretea-labs/forge 1.6.0 → 1.7.1

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 (469) hide show
  1. package/AGENTS.md +4 -0
  2. package/CHANGELOG.md +39 -0
  3. package/CLAUDE.md +4 -0
  4. package/README.md +2 -2
  5. package/README.zh-CN.md +1 -1
  6. package/SKILL.md +2 -2
  7. package/THIRD_PARTY_NOTICES.md +1 -1
  8. package/agents/openai.yaml +1 -1
  9. package/assets/hooks/hook-input.sh +11 -8
  10. package/assets/hooks/lib/session-state.sh +10 -7
  11. package/assets/hooks/lib/workflow-state.sh +13 -177
  12. package/assets/hooks/post-tool-observer.sh +8 -2
  13. package/assets/hooks/prompt-guard.sh +5 -81
  14. package/assets/hooks/session-start-context.sh +56 -1
  15. package/assets/partials/05-workflow.partial.md +1 -1
  16. package/assets/partials-agents/02-operating-mode.partial.md +2 -0
  17. package/assets/partials-agents/03-orchestration.partial.md +1 -1
  18. package/assets/plugin-registry.v1.json +3 -3
  19. package/assets/reference-configs/document-generation.md +1 -1
  20. package/assets/reference-configs/harness-overview.md +1 -1
  21. package/assets/reference-configs/sprint-contracts.md +3 -3
  22. package/assets/skill-version.json +2 -2
  23. package/assets/templates/contract.template.md +2 -7
  24. package/assets/templates/helpers/capture-plan.sh +2 -2
  25. package/assets/templates/helpers/check-architecture-sync.sh +17 -0
  26. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  27. package/assets/templates/helpers/contract-worktree.sh +1 -21
  28. package/assets/templates/helpers/ensure-task-workflow.sh +11 -36
  29. package/assets/templates/helpers/inspect-project-state.ts +8 -6
  30. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  31. package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
  32. package/assets/templates/helpers/new-plan.sh +1 -1
  33. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  34. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  35. package/assets/templates/helpers/verify-contract.sh +1 -111
  36. package/assets/templates/helpers/verify-sprint.sh +3 -180
  37. package/assets/templates/helpers/workflow-contract.ts +5 -1
  38. package/assets/templates/plan.template.md +1 -1
  39. package/assets/templates/review.template.md +9 -34
  40. package/assets/workflow-contract.v1.json +10 -19
  41. package/docs/README.md +10 -10
  42. package/docs/architecture/CURRENT.md +178 -0
  43. package/docs/architecture/EVOLUTION.md +42 -0
  44. package/docs/architecture/current/README.md +4 -156
  45. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  46. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  47. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  48. package/docs/architecture/history/README.md +7 -0
  49. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  50. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  51. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  52. package/docs/architecture/history.md +3 -34
  53. package/docs/architecture/index.md +15 -98
  54. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  55. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  56. package/docs/architecture/versions/1.6.md +38 -0
  57. package/docs/architecture/versions/1.7.md +41 -0
  58. package/docs/forge-chatgpt-browser-engine.md +2 -2
  59. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  60. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  61. package/docs/forge-github-issue-launcher.md +1 -1
  62. package/docs/forge-plugin-management.md +1 -1
  63. package/docs/forge-runtime-self-healing-loop.md +1 -1
  64. package/docs/operations/controller-browser-plugin.md +26 -6
  65. package/docs/operations/controller-performance-and-502.md +143 -0
  66. package/docs/operations/controller-reliability-runbook.md +1 -1
  67. package/docs/operations/features.md +2 -2
  68. package/docs/operations/github-repository.md +1 -1
  69. package/docs/operations/homebrew.md +2 -2
  70. package/docs/operations/mcp-tool-exposure.md +5 -3
  71. package/docs/wiki/Architecture.md +6 -6
  72. package/docs/wiki/Implementation.md +2 -2
  73. package/docs/wiki/Integrations.md +2 -2
  74. package/docs/wiki/Work-Lifecycle.md +1 -1
  75. package/package.json +33 -11
  76. package/scripts/activate-source-baseline.ts +17 -13
  77. package/scripts/architecture-event.ts +2 -820
  78. package/scripts/architecture-queue.sh +2 -645
  79. package/scripts/archive-architecture-request.sh +2 -242
  80. package/scripts/archive-workflow.sh +1 -291
  81. package/scripts/benchmark-background-check-overlap.ts +228 -0
  82. package/scripts/benchmark-mcp-host.sh +117 -0
  83. package/scripts/benchmark-mcp-transport.ts +170 -0
  84. package/scripts/benchmark-quality-harness.ts +146 -0
  85. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  86. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  87. package/scripts/benchmark-typescript-navigation.ts +186 -0
  88. package/scripts/benchmark-work-efficiency.ts +334 -0
  89. package/scripts/capability-config.ts +2 -392
  90. package/scripts/capability-resolver.ts +2 -503
  91. package/scripts/capture-plan.sh +1 -332
  92. package/scripts/check-agent-tooling.sh +2 -1558
  93. package/scripts/check-architecture-sync.sh +2 -371
  94. package/scripts/check-brain-manifest.sh +2 -253
  95. package/scripts/check-context-files.sh +2 -47
  96. package/scripts/check-deploy-sql-order.sh +2 -115
  97. package/scripts/check-mcp-compatibility.ts +14 -0
  98. package/scripts/check-runtime-architecture.mjs +349 -79
  99. package/scripts/check-skill-version.ts +3 -191
  100. package/scripts/check-source-duplication.mjs +61 -0
  101. package/scripts/check-stable-baseline.ts +92 -0
  102. package/scripts/check-task-sync.sh +2 -63
  103. package/scripts/check-task-workflow.sh +2 -1000
  104. package/scripts/codex-handoff-resume.sh +2 -267
  105. package/scripts/context-contract-sync.sh +2 -514
  106. package/scripts/contract-run.ts +2 -463
  107. package/scripts/contract-worktree.sh +1 -722
  108. package/scripts/ensure-task-workflow.sh +1 -1225
  109. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  110. package/scripts/inspect-project-state.ts +4 -279
  111. package/scripts/install-standalone-recovery.ts +24 -0
  112. package/scripts/lib/project-init-lib.sh +22 -46
  113. package/scripts/lib/run-forge-helper.sh +19 -0
  114. package/scripts/lib/run-forge-helper.ts +26 -0
  115. package/scripts/migrate-project-template.sh +1 -1189
  116. package/scripts/migrate-workflow-docs.ts +4 -412
  117. package/scripts/new-plan.sh +1 -180
  118. package/scripts/new-spec.sh +1 -47
  119. package/scripts/new-sprint.sh +1 -46
  120. package/scripts/plan-to-todo.sh +1 -796
  121. package/scripts/prepare-codex-handoff.sh +2 -201
  122. package/scripts/prepare-handoff.sh +1 -78
  123. package/scripts/refresh-current-status.sh +2 -467
  124. package/scripts/run-governed-gate.ts +5 -1
  125. package/scripts/select-agent-context-blocks.sh +2 -64
  126. package/scripts/ship-worktrees.sh +1 -558
  127. package/scripts/smoke-ios-physical-device.ts +4 -2
  128. package/scripts/smoke-runtime-recovery.ts +1 -35
  129. package/scripts/smoke-schedule-engine.ts +1 -20
  130. package/scripts/sprint-backlog.sh +1 -834
  131. package/scripts/stage-runtime-release.ts +2 -1
  132. package/scripts/summarize-failures.sh +2 -123
  133. package/scripts/switch-plan.sh +1 -150
  134. package/scripts/sync-brain-docs.sh +2 -379
  135. package/scripts/sync-generated-authority.mjs +175 -0
  136. package/scripts/verify-contract.sh +2 -703
  137. package/scripts/verify-forge-runtime.sh +0 -1
  138. package/scripts/verify-sprint.sh +1 -677
  139. package/scripts/workflow-contract.ts +4 -205
  140. package/scripts/workstream-sync.sh +2 -261
  141. package/src/cli/agent-jobs/executor-health.ts +1 -1
  142. package/src/cli/commands/init-hook.ts +3 -3
  143. package/src/cli/commands/mcp.ts +9 -5
  144. package/src/cli/commands/plugin.ts +12 -3
  145. package/src/cli/commands/recovery.ts +25 -3
  146. package/src/cli/commands/runtime.ts +55 -3
  147. package/src/cli/commands/security.ts +12 -1
  148. package/src/cli/commands/setup-profile.ts +31 -21
  149. package/src/cli/controller/check-runner.ts +113 -5
  150. package/src/cli/controller/composite-result.ts +1 -1
  151. package/src/cli/controller/context/focus.ts +51 -0
  152. package/src/cli/controller/context/instruction-context.ts +114 -0
  153. package/src/cli/controller/context/known-paths.ts +76 -0
  154. package/src/cli/controller/context/query-planning.ts +110 -0
  155. package/src/cli/controller/context/rule-resolution.ts +532 -0
  156. package/src/cli/controller/context/source-materializer.ts +278 -0
  157. package/src/cli/controller/context/structural.ts +16 -0
  158. package/src/cli/controller/context/types.ts +286 -0
  159. package/src/cli/controller/context-pack.ts +828 -487
  160. package/src/cli/controller/launch-agents.ts +77 -2
  161. package/src/cli/controller/operational-plan.ts +2 -2
  162. package/src/cli/controller/work-mode.ts +6 -4
  163. package/src/cli/editing/edit-session.ts +60 -7
  164. package/src/cli/github/contracts.ts +16 -0
  165. package/src/cli/github/github.ts +135 -16
  166. package/src/cli/github/session.ts +2 -1
  167. package/src/cli/installer/managed-entries.ts +15 -1
  168. package/src/cli/local-bridge/console-automations.ts +54 -78
  169. package/src/cli/local-bridge/console-view-models.ts +1 -35
  170. package/src/cli/local-bridge/facade-api.ts +37 -264
  171. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  172. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
  173. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  174. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
  175. package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
  176. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  177. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
  178. package/src/cli/local-bridge/frontend/src/styles.css +1 -1
  179. package/src/cli/local-bridge/frontend/src/types.ts +5 -8
  180. package/src/cli/local-bridge/job-store.ts +1 -490
  181. package/src/cli/local-bridge/server.ts +2 -515
  182. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  183. package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
  184. package/src/cli/mcp/auth.ts +5 -5
  185. package/src/cli/mcp/instructions.ts +3 -2
  186. package/src/cli/mcp/legacy-tool-service.ts +10 -222
  187. package/src/cli/mcp/multi-repository.ts +16 -5
  188. package/src/cli/mcp/oauth.ts +175 -26
  189. package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
  190. package/src/cli/mcp/repository-tools.ts +282 -146
  191. package/src/cli/mcp/server.ts +586 -116
  192. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  193. package/src/cli/mcp/tool-contract.ts +14 -0
  194. package/src/cli/mcp/toolset-selection.ts +1 -1
  195. package/src/cli/mcp/toolset.ts +44 -7
  196. package/src/cli/mcp/transports/http.ts +124 -14
  197. package/src/cli/mcp/transports/session-registry.ts +43 -5
  198. package/src/cli/mcp/types.ts +3 -3
  199. package/src/cli/repositories/command-classifier.ts +103 -21
  200. package/src/cli/repositories/command-executor.ts +78 -526
  201. package/src/cli/repositories/command-process.ts +108 -0
  202. package/src/cli/repositories/command-scope.ts +99 -41
  203. package/src/cli/repositories/controller-home.ts +7 -8
  204. package/src/cli/repositories/git-command-executor.ts +2 -0
  205. package/src/cli/repositories/locks.ts +53 -16
  206. package/src/cli/repositories/repository-snapshot.ts +124 -0
  207. package/src/cli/repositories/selected-path-actions.ts +17 -9
  208. package/src/cli/repositories/structured-git.ts +118 -6
  209. package/src/cli/repository/inspector.ts +563 -65
  210. package/src/cli/repository/session-cache.ts +58 -17
  211. package/src/cli/v81-entry.ts +1 -4
  212. package/src/effects/fs-transaction.ts +85 -17
  213. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  214. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  215. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  216. package/src/runtime/context/lsp-client.ts +283 -0
  217. package/src/runtime/context/semantic-navigation-contract.ts +61 -0
  218. package/src/runtime/context/semantic-navigation.ts +223 -0
  219. package/src/runtime/context/swift-navigation.ts +565 -0
  220. package/src/runtime/context/typescript-navigation.ts +226 -0
  221. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  222. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +48 -16
  223. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  224. package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
  225. package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
  226. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  227. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  228. package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
  229. package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
  230. package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
  231. package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
  232. package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
  233. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  234. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  235. package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
  236. package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
  237. package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
  238. package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
  239. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  240. package/src/runtime/control-plane/execution/work-task-receipt.ts +22 -18
  241. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +156 -11
  242. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
  243. package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
  244. package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
  245. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +90 -9
  246. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  247. package/src/runtime/control-plane/facade/controller-round-relay.ts +1118 -0
  248. package/src/runtime/control-plane/facade/controller-session-store.ts +302 -12
  249. package/src/runtime/control-plane/facade/goal-workloop-access.ts +17 -1
  250. package/src/runtime/control-plane/facade/goal-workloop.ts +928 -190
  251. package/src/runtime/control-plane/facade/index.ts +3 -0
  252. package/src/runtime/control-plane/facade/plan-contract-store.ts +275 -42
  253. package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
  254. package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
  255. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  256. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  257. package/src/runtime/control-plane/facade/types.ts +90 -10
  258. package/src/runtime/control-plane/facade/work-contract-store.ts +157 -261
  259. package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
  260. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  261. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  262. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  263. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  264. package/src/runtime/control-plane/global-scheduler/maintenance.ts +152 -0
  265. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  266. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  267. package/src/runtime/control-plane/global-scheduler/scheduler.ts +278 -543
  268. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  269. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  270. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  271. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  272. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  273. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  274. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  275. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  276. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  277. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  278. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +63 -0
  279. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +365 -117
  280. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +89 -0
  281. package/src/runtime/control-plane/launcher/thin-launcher.ts +244 -11
  282. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  283. package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
  284. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  285. package/src/runtime/control-plane/release-retention.ts +62 -2
  286. package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
  287. package/src/runtime/control-plane/routing/route-policy.ts +24 -21
  288. package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
  289. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  290. package/src/runtime/diagnostics/mcp-timing.ts +13 -0
  291. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  292. package/src/runtime/diagnostics/performance.ts +24 -1
  293. package/src/runtime/evidence/event-ledger.ts +1 -1
  294. package/src/runtime/evidence/process-check-execution.ts +18 -0
  295. package/src/runtime/execution/jobs/child-reference.ts +6 -2
  296. package/src/runtime/execution/jobs/store.ts +58 -4
  297. package/src/runtime/execution/jobs/types.ts +1 -1
  298. package/src/runtime/execution/managed-workspace.ts +203 -1
  299. package/src/runtime/execution/process-runtime/check-facade.ts +51 -4
  300. package/src/runtime/execution/process-runtime/check-result.ts +88 -0
  301. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
  302. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  303. package/src/runtime/execution/process-runtime/command-facade.ts +367 -40
  304. package/src/runtime/execution/process-runtime/gc.ts +38 -6
  305. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1201 -0
  306. package/src/runtime/execution/process-runtime/persisted-check.ts +51 -5
  307. package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
  308. package/src/runtime/execution/process-runtime/runtime.ts +53 -3
  309. package/src/runtime/execution/process-runtime/store.ts +1 -0
  310. package/src/runtime/execution/process-runtime/types.ts +4 -12
  311. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  312. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  313. package/src/runtime/execution/work-activity.ts +21 -0
  314. package/src/runtime/execution/workers/executor.ts +18 -61
  315. package/src/runtime/gateway/mcp/execution-tools.ts +35 -1852
  316. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
  317. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  318. package/src/runtime/gateway/mcp/router.ts +186 -84
  319. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +565 -0
  320. package/src/runtime/gateway/mcp/runtime-tools.ts +2378 -1947
  321. package/src/runtime/plugins/app-store-connect-adapter.ts +216 -47
  322. package/src/runtime/plugins/browser-adapter.ts +2662 -829
  323. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  324. package/src/runtime/plugins/browser-handoff-host.ts +2 -25
  325. package/src/runtime/plugins/browser-handoff.ts +110 -5
  326. package/src/runtime/plugins/browser-macos-bridge.ts +701 -63
  327. package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
  328. package/src/runtime/plugins/browser-native-session-service.ts +222 -0
  329. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  330. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  331. package/src/runtime/plugins/browser-runtime-contract.ts +154 -0
  332. package/src/runtime/plugins/browser-runtime.ts +193 -0
  333. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  334. package/src/runtime/plugins/browser-session-store.ts +121 -0
  335. package/src/runtime/plugins/browser-session-types.ts +98 -0
  336. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  337. package/src/runtime/plugins/desktop-operator-registration.ts +10 -4
  338. package/src/runtime/plugins/external-adapter.ts +358 -3
  339. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  340. package/src/runtime/plugins/first-party-registry.ts +2 -0
  341. package/src/runtime/plugins/github-adapter.ts +125 -0
  342. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  343. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  344. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  345. package/src/runtime/plugins/ios-adapter.ts +106 -16
  346. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  347. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  348. package/src/runtime/plugins/lightweight-action.ts +153 -0
  349. package/src/runtime/plugins/local-system-adapter.ts +123 -6
  350. package/src/runtime/plugins/macos-capability-broker.ts +47 -9
  351. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  352. package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
  353. package/src/runtime/plugins/resend-adapter.ts +1 -1
  354. package/src/runtime/plugins/store.ts +330 -33
  355. package/src/runtime/plugins/types.ts +38 -3
  356. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  357. package/src/runtime/projections/git-status-sampler.ts +16 -16
  358. package/src/runtime/projections/materialized-view.ts +28 -10
  359. package/src/runtime/recovery/maintenance-executor.ts +426 -25
  360. package/src/runtime/root/mcp-transport.ts +180 -10
  361. package/src/runtime/root/package-connector-service.ts +230 -10
  362. package/src/runtime/root/package-runtime-release.ts +143 -17
  363. package/src/runtime/root/package-runtime-service.ts +461 -22
  364. package/src/runtime/root/release-manifest.ts +144 -18
  365. package/src/runtime/root/release-materialize.ts +125 -32
  366. package/src/runtime/root/release-store.ts +48 -11
  367. package/src/runtime/root/runtime.ts +23 -5
  368. package/src/runtime/root/service.ts +100 -29
  369. package/src/runtime/root/types.ts +12 -0
  370. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  371. package/src/runtime/shared/trusted-executable.ts +62 -0
  372. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  373. package/src/runtime/standalone-recovery/core.ts +1079 -240
  374. package/src/runtime/standalone-recovery/entry.ts +100 -24
  375. package/src/runtime/standalone-recovery/installer.ts +20 -4
  376. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  377. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  378. package/src/runtime/workflow/schedules/browser-probe.ts +81 -3
  379. package/src/runtime/workflow/schedules/engine.ts +364 -202
  380. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  381. package/src/runtime/workflow/schedules/settlement.ts +64 -17
  382. package/src/runtime/workflow/schedules/store.ts +209 -19
  383. package/src/runtime/workflow/schedules/types.ts +2 -4
  384. package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
  385. package/src/testing/test-governance.ts +8 -40
  386. package/assets/reference-configs/heartbeat-triage.md +0 -57
  387. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  388. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  389. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  390. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  391. package/docs/architecture/current/architecture-invariants.md +0 -331
  392. package/docs/architecture/current/automation-and-schedule-engine.md +0 -459
  393. package/docs/architecture/current/codegraph-context-provider.md +0 -238
  394. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  395. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  396. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -373
  397. package/docs/architecture/current/entity-model.md +0 -612
  398. package/docs/architecture/current/external-plugin-governance.md +0 -396
  399. package/docs/architecture/current/failure-recovery.md +0 -447
  400. package/docs/architecture/current/governance.md +0 -213
  401. package/docs/architecture/current/human-interaction-plane.md +0 -87
  402. package/docs/architecture/current/implementation-status.md +0 -128
  403. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  404. package/docs/architecture/current/legacy-governance.md +0 -58
  405. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  406. package/docs/architecture/current/migration-roadmap.md +0 -105
  407. package/docs/architecture/current/multi-repository-execution.md +0 -371
  408. package/docs/architecture/current/operations-runbook.md +0 -45
  409. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  410. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  411. package/docs/architecture/current/repository-access-modes.md +0 -102
  412. package/docs/architecture/current/route-policy.md +0 -15
  413. package/docs/architecture/current/route-session-concurrency.md +0 -85
  414. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  415. package/docs/architecture/current/runtime-directory-map.md +0 -49
  416. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  417. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  418. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  419. package/docs/architecture/current/system-overview.md +0 -169
  420. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  421. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  422. package/docs/architecture/current/thin-harness-v1.md +0 -321
  423. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  424. package/docs/forge-autonomous-goal-loop.md +0 -9
  425. package/docs/forge-provider-configuration.md +0 -7
  426. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -93
  427. package/docs/operations/gmail-assistant-routines.md +0 -186
  428. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  429. package/docs/operations/provider-configuration.md +0 -31
  430. package/scripts/harness-trace-grade.sh +0 -150
  431. package/scripts/heartbeat-triage.sh +0 -361
  432. package/scripts/maintenance-triage.sh +0 -167
  433. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  434. package/src/cli/repositories/goal-registry.ts +0 -239
  435. package/src/runtime/assistant/action-proposals.ts +0 -279
  436. package/src/runtime/assistant/intent.ts +0 -395
  437. package/src/runtime/assistant/model-provider.ts +0 -460
  438. package/src/runtime/assistant/openapi.ts +0 -223
  439. package/src/runtime/assistant/policy.ts +0 -89
  440. package/src/runtime/assistant/readiness.ts +0 -258
  441. package/src/runtime/assistant/routine-runtime.ts +0 -477
  442. package/src/runtime/assistant/schedule-binding.ts +0 -171
  443. package/src/runtime/assistant/standing-grants.ts +0 -375
  444. package/src/runtime/assistant/store.ts +0 -243
  445. package/src/runtime/assistant/types.ts +0 -135
  446. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  447. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  448. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  449. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  450. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  451. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  452. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  453. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  454. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  455. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  456. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  457. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  458. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  459. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  460. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  461. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  462. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  463. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  464. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  465. package/src/runtime/workflow/findings/store.ts +0 -204
  466. package/src/runtime/workflow/findings/types.ts +0 -58
  467. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  468. package/src/runtime/workflow/portfolio/store.ts +0 -185
  469. package/src/runtime/workflow/portfolio/types.ts +0 -29
@@ -1,11 +1,12 @@
1
1
  import { randomUUID } from 'crypto';
2
2
  import { existsSync, mkdirSync, realpathSync } from 'fs';
3
- import { isAbsolute, join } from 'path';
3
+ import { delimiter, dirname, isAbsolute, join } from 'path';
4
4
  import { spawnSync } from 'child_process';
5
5
  import { performance } from 'perf_hooks';
6
6
  import { repositoryControllerRoot } from '../../cli/repositories/controller-home';
7
7
  import { runBoundedProcess } from '../execution/thin-harness/async-process';
8
8
  import { readJsonFile, writeJsonAtomic } from '../shared/json-files';
9
+ import { resolveTrustedNodeExecutable } from '../shared/trusted-node-executable';
9
10
  import { AssistantPluginError, toAssistantPluginError } from './errors';
10
11
  import {
11
12
  interactionAutomationEngine,
@@ -169,16 +170,35 @@ export function resetIosAgentDeviceRuntimeHooksForTest(): void {
169
170
  interactionCommandTails.clear();
170
171
  }
171
172
 
172
- function executable(): string {
173
- return process.env.FORGE_AGENT_DEVICE_EXECUTABLE?.trim() || 'agent-device';
173
+ function configuredExecutable(): string | undefined {
174
+ return process.env.FORGE_AGENT_DEVICE_EXECUTABLE?.trim() || undefined;
174
175
  }
175
176
 
176
- function resolvedExecutable(): string {
177
- const configured = executable();
177
+ function repoLocalExecutable(repoRoot?: string): string | undefined {
178
+ if (!repoRoot) return undefined;
179
+ const candidates = [
180
+ join(repoRoot, 'node_modules', '.bin', 'agent-device'),
181
+ join(repoRoot, 'node_modules', 'agent-device', 'bin', 'agent-device.mjs'),
182
+ ];
183
+ for (const candidate of candidates) {
184
+ if (!existsSync(candidate)) continue;
185
+ try { return realpathSync(candidate); } catch { return candidate; }
186
+ }
187
+ return undefined;
188
+ }
189
+
190
+ function executable(repoRoot?: string): string {
191
+ const configured = configuredExecutable();
192
+ if (configured) return configured;
193
+ return repoLocalExecutable(repoRoot) ?? 'agent-device';
194
+ }
195
+
196
+ function resolvedExecutable(repoRoot?: string): string {
197
+ const configured = executable(repoRoot);
178
198
  if (isAbsolute(configured)) {
179
199
  try { return realpathSync(configured); } catch { return configured; }
180
200
  }
181
- for (const directory of (process.env.PATH ?? '').split(':').filter(Boolean)) {
201
+ for (const directory of (process.env.PATH ?? '').split(delimiter).filter(Boolean)) {
182
202
  const candidate = join(directory, configured);
183
203
  if (!existsSync(candidate)) continue;
184
204
  try { return realpathSync(candidate); } catch { return candidate; }
@@ -186,6 +206,13 @@ function resolvedExecutable(): string {
186
206
  return configured;
187
207
  }
188
208
 
209
+ function withTrustedNodePath(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
210
+ const node = resolveTrustedNodeExecutable(env).executable;
211
+ if (!node) return env;
212
+ const path = [dirname(node), env.PATH].filter((value): value is string => Boolean(value)).join(delimiter);
213
+ return { ...env, PATH: path };
214
+ }
215
+
189
216
  function timestamp(): string {
190
217
  return hooks.now().toISOString();
191
218
  }
@@ -194,28 +221,29 @@ function sanitize(value: string): string {
194
221
  return value.replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'ios-agent-device';
195
222
  }
196
223
 
197
- function statusProbeCacheKey(): string {
224
+ function statusProbeCacheKey(repoRoot?: string): string {
198
225
  return [
199
226
  hooks.platform(),
200
- executable(),
201
- resolvedExecutable(),
227
+ repoRoot ?? '',
228
+ executable(repoRoot),
229
+ resolvedExecutable(repoRoot),
202
230
  configuredAgentDeviceBackendMode(),
203
231
  process.versions.node,
204
232
  process.env.PATH ?? '',
205
233
  ].join('|');
206
234
  }
207
235
 
208
- function probeStatus() {
236
+ function probeStatus(repoRoot?: string) {
209
237
  const backendMode = configuredAgentDeviceBackendMode();
210
- const typedClient = typedAgentDeviceIdentity();
238
+ const typedClient = typedAgentDeviceIdentity({ repoRoot });
211
239
  if (hooks.platform() !== 'darwin') {
212
240
  return {
213
241
  available: false,
214
242
  expectedVersion: IOS_AGENT_DEVICE_VERSION,
215
243
  supportedVersionPolicy: '>=0.19.3 <0.21.0 with reviewed command contract',
216
244
  detectedVersion: undefined,
217
- executable: executable(),
218
- resolvedExecutable: resolvedExecutable(),
245
+ executable: executable(repoRoot),
246
+ resolvedExecutable: resolvedExecutable(repoRoot),
219
247
  platform: hooks.platform(),
220
248
  capabilityProfile: detectAgentDeviceCapabilities('', {}),
221
249
  backendMode,
@@ -223,14 +251,15 @@ function probeStatus() {
223
251
  reason: 'agent-device iOS support requires macOS.',
224
252
  };
225
253
  }
226
- const result = hooks.runCommand(executable(), ['--version'], { timeoutMs: 3_000 });
254
+ const runtimeEnv = withTrustedNodePath({ ...process.env });
255
+ const result = hooks.runCommand(executable(repoRoot), ['--version'], { cwd: repoRoot, env: runtimeEnv, timeoutMs: 3_000 });
227
256
  const detectedVersion = result.ok ? result.stdout.trim() : undefined;
228
257
  const help: AgentDeviceHelpContract = {};
229
258
  if (result.ok && detectedVersion) {
230
- const rootHelp = hooks.runCommand(executable(), ['help'], { timeoutMs: 3_000 });
259
+ const rootHelp = hooks.runCommand(executable(repoRoot), ['help'], { cwd: repoRoot, env: runtimeEnv, timeoutMs: 3_000 });
231
260
  if (rootHelp.ok) help.root = rootHelp.stdout || rootHelp.stderr;
232
261
  for (const topic of ['snapshot', 'press', 'fill', 'batch', 'keyboard'] as const) {
233
- const topicResult = hooks.runCommand(executable(), ['help', topic], { timeoutMs: 3_000 });
262
+ const topicResult = hooks.runCommand(executable(repoRoot), ['help', topic], { cwd: repoRoot, env: runtimeEnv, timeoutMs: 3_000 });
234
263
  if (topicResult.ok) help[topic] = topicResult.stdout || topicResult.stderr;
235
264
  }
236
265
  }
@@ -251,8 +280,8 @@ function probeStatus() {
251
280
  expectedVersion: IOS_AGENT_DEVICE_VERSION,
252
281
  supportedVersionPolicy: '>=0.19.3 <0.21.0 with reviewed command contract',
253
282
  detectedVersion,
254
- executable: executable(),
255
- resolvedExecutable: resolvedExecutable(),
283
+ executable: executable(repoRoot),
284
+ resolvedExecutable: resolvedExecutable(repoRoot),
256
285
  platform: hooks.platform(),
257
286
  capabilityProfile,
258
287
  backendMode,
@@ -267,20 +296,105 @@ function probeStatus() {
267
296
  };
268
297
  }
269
298
 
270
- export function iosAgentDeviceStatus(options: { forceRefresh?: boolean } = {}) {
299
+ function unprobedAgentDeviceStatus(repoRoot?: string): ReturnType<typeof probeStatus> {
300
+ const backendMode = configuredAgentDeviceBackendMode();
301
+ const typedClient = typedAgentDeviceIdentity({ repoRoot });
302
+ return {
303
+ available: false,
304
+ expectedVersion: IOS_AGENT_DEVICE_VERSION,
305
+ supportedVersionPolicy: '>=0.19.3 <0.21.0 with reviewed command contract',
306
+ detectedVersion: undefined,
307
+ executable: executable(repoRoot),
308
+ resolvedExecutable: resolvedExecutable(repoRoot),
309
+ platform: hooks.platform(),
310
+ capabilityProfile: detectAgentDeviceCapabilities('', {}),
311
+ backendMode,
312
+ typedClient: { ...typedClient, cliVersion: undefined, cliVersionCompatible: false },
313
+ reason: 'agent-device readiness has not been probed by an explicit asynchronous action in this runtime yet.',
314
+ };
315
+ }
316
+
317
+ export function iosAgentDeviceStatus(options: { forceRefresh?: boolean; repoRoot?: string } = {}) {
271
318
  const nowMs = hooks.now().getTime();
272
- const cacheKey = statusProbeCacheKey();
319
+ const cacheKey = statusProbeCacheKey(options.repoRoot);
273
320
  if (!options.forceRefresh
274
321
  && statusCache
275
322
  && statusCache.cacheKey === cacheKey
276
323
  && statusCache.expiresAt > nowMs) return statusCache.value;
277
- const value = probeStatus();
324
+ if (hooks.platform() !== 'darwin') return probeStatus(options.repoRoot);
325
+ return unprobedAgentDeviceStatus(options.repoRoot);
326
+ }
327
+
328
+ async function probeStatusAsync(input: Pick<AssistantPluginActionExecutionInput, 'repoRoot' | 'signal'>): Promise<ReturnType<typeof probeStatus>> {
329
+ const repoRoot = input.repoRoot;
330
+ const backendMode = configuredAgentDeviceBackendMode();
331
+ const typedClient = typedAgentDeviceIdentity({ repoRoot });
332
+ if (hooks.platform() !== 'darwin') return probeStatus(repoRoot);
333
+ const runtimeEnv = withTrustedNodePath({ ...process.env });
334
+ const result = await hooks.runCommandAsync(executable(repoRoot), ['--version'], {
335
+ cwd: repoRoot,
336
+ env: runtimeEnv,
337
+ timeoutMs: 3_000,
338
+ signal: input.signal,
339
+ });
340
+ const detectedVersion = result.ok ? result.stdout.trim() : undefined;
341
+ const help: AgentDeviceHelpContract = {};
342
+ if (result.ok && detectedVersion) {
343
+ const rootHelp = await hooks.runCommandAsync(executable(repoRoot), ['help'], {
344
+ cwd: repoRoot, env: runtimeEnv, timeoutMs: 3_000, signal: input.signal,
345
+ });
346
+ if (rootHelp.ok) help.root = rootHelp.stdout || rootHelp.stderr;
347
+ for (const topic of ['snapshot', 'press', 'fill', 'batch', 'keyboard'] as const) {
348
+ const topicResult = await hooks.runCommandAsync(executable(repoRoot), ['help', topic], {
349
+ cwd: repoRoot, env: runtimeEnv, timeoutMs: 3_000, signal: input.signal,
350
+ });
351
+ if (topicResult.ok) help[topic] = topicResult.stdout || topicResult.stderr;
352
+ }
353
+ }
354
+ const capabilityProfile = detectAgentDeviceCapabilities(detectedVersion ?? '', help);
355
+ const typedClientWithCompatibility = {
356
+ ...typedClient,
357
+ cliVersion: detectedVersion,
358
+ cliVersionCompatible: agentDeviceProviderVersionsMatch(typedClient.version, detectedVersion),
359
+ };
360
+ const available = result.ok
361
+ && capabilityProfile.versionSupported
362
+ && Boolean(capabilityProfile.snapshot.interactiveFlag)
363
+ && capabilityProfile.press.supported
364
+ && capabilityProfile.fill.supported
365
+ && capabilityProfile.batch.supported;
366
+ return {
367
+ available,
368
+ expectedVersion: IOS_AGENT_DEVICE_VERSION,
369
+ supportedVersionPolicy: '>=0.19.3 <0.21.0 with reviewed command contract',
370
+ detectedVersion,
371
+ executable: executable(repoRoot),
372
+ resolvedExecutable: resolvedExecutable(repoRoot),
373
+ platform: hooks.platform(),
374
+ capabilityProfile,
375
+ backendMode,
376
+ typedClient: typedClientWithCompatibility,
377
+ reason: !result.ok
378
+ ? (result.stderr || result.stdout || 'agent-device is not installed.')
379
+ : !capabilityProfile.versionSupported
380
+ ? `Unsupported agent-device version ${detectedVersion || 'unknown'}; expected the reviewed >=0.19.3 <0.21.0 contract.`
381
+ : !available
382
+ ? 'The installed agent-device command contract is missing required snapshot, press, fill, or batch capabilities.'
383
+ : undefined,
384
+ };
385
+ }
386
+
387
+ async function iosAgentDeviceActionStatus(input: AssistantPluginActionExecutionInput): Promise<ReturnType<typeof probeStatus>> {
388
+ const nowMs = hooks.now().getTime();
389
+ const cacheKey = statusProbeCacheKey(input.repoRoot);
390
+ if (statusCache && statusCache.cacheKey === cacheKey && statusCache.expiresAt > nowMs) return statusCache.value;
391
+ const value = await probeStatusAsync(input);
278
392
  statusCache = { cacheKey, expiresAt: nowMs + STATUS_TTL_MS, value };
279
393
  return value;
280
394
  }
281
395
 
282
- function requireDependency(): ReturnType<typeof probeStatus> {
283
- const status = iosAgentDeviceStatus();
396
+ function requireDependency(repoRoot?: string): ReturnType<typeof probeStatus> {
397
+ const status = iosAgentDeviceStatus({ repoRoot });
284
398
  if (!status.available) {
285
399
  throw new AssistantPluginError('PLUGIN_DEPENDENCY_MISSING', status.reason ?? 'A compatible agent-device provider is unavailable.', {
286
400
  retryable: false,
@@ -290,8 +404,19 @@ function requireDependency(): ReturnType<typeof probeStatus> {
290
404
  return status;
291
405
  }
292
406
 
293
- function capabilityProfile(): AgentDeviceCapabilityProfile {
294
- return requireDependency().capabilityProfile;
407
+ async function requireDependencyAsync(input: AssistantPluginActionExecutionInput): Promise<ReturnType<typeof probeStatus>> {
408
+ const status = await iosAgentDeviceActionStatus(input);
409
+ if (!status.available) {
410
+ throw new AssistantPluginError('PLUGIN_DEPENDENCY_MISSING', status.reason ?? 'A compatible agent-device provider is unavailable.', {
411
+ retryable: false,
412
+ details: status,
413
+ });
414
+ }
415
+ return status;
416
+ }
417
+
418
+ function capabilityProfile(repoRoot?: string): AgentDeviceCapabilityProfile {
419
+ return requireDependency(repoRoot).capabilityProfile;
295
420
  }
296
421
 
297
422
  function controllerRoot(input: AssistantPluginActionExecutionInput): string {
@@ -308,6 +433,37 @@ function stateDir(input: AssistantPluginActionExecutionInput, interactionId: str
308
433
  return path;
309
434
  }
310
435
 
436
+ function physicalDeviceRuntimeRoot(input: AssistantPluginActionExecutionInput, targetId: string): string {
437
+ const path = join(
438
+ controllerRoot(input),
439
+ 'interactions',
440
+ 'ios-agent-device',
441
+ 'device-runtime',
442
+ sanitize(targetId),
443
+ );
444
+ mkdirSync(path, { recursive: true });
445
+ return path;
446
+ }
447
+
448
+ function physicalDeviceRuntimeStateDir(input: AssistantPluginActionExecutionInput, targetId: string): string {
449
+ const path = join(physicalDeviceRuntimeRoot(input, targetId), 'state');
450
+ mkdirSync(path, { recursive: true });
451
+ return path;
452
+ }
453
+
454
+ function runtimeStateDir(input: AssistantPluginActionExecutionInput, record: InteractionSessionRecord): string {
455
+ // A real iPhone must not get a fresh daemon/Runner cache for every logical
456
+ // interaction. One stable per-device runtime owns provider metadata and any
457
+ // explicitly prepared semantic Runner. Simulator sessions remain isolated.
458
+ return record.provider === DEVICE_PROVIDER
459
+ ? physicalDeviceRuntimeStateDir(input, record.targetId)
460
+ : stateDir(input, record.interactionId);
461
+ }
462
+
463
+ function targetRuntimeStateDir(input: AssistantPluginActionExecutionInput, target: AgentDeviceEntry): string | undefined {
464
+ return target.kind === 'device' ? physicalDeviceRuntimeStateDir(input, target.id) : undefined;
465
+ }
466
+
311
467
  function signingConfigPath(input: AssistantPluginActionExecutionInput, interactionId: string): string {
312
468
  return join(interactionRoot(input, interactionId), 'signing.json');
313
469
  }
@@ -344,27 +500,31 @@ function artifactDir(input: AssistantPluginActionExecutionInput, interactionId:
344
500
 
345
501
  function sessionEnv(input: AssistantPluginActionExecutionInput, record: InteractionSessionRecord): NodeJS.ProcessEnv {
346
502
  const config = readSigningConfig(input, record.interactionId);
347
- return {
503
+ return withTrustedNodePath({
348
504
  ...process.env,
349
505
  ...signingEnv(config),
350
- AGENT_DEVICE_STATE_DIR: stateDir(input, record.interactionId),
506
+ AGENT_DEVICE_STATE_DIR: runtimeStateDir(input, record),
351
507
  AGENT_DEVICE_SESSION: record.sessionId,
352
508
  AGENT_DEVICE_PLATFORM: 'ios',
353
509
  AGENT_DEVICE_SESSION_LOCK: 'reject',
354
- // Keep the per-interaction daemon and a healthy XCTest runner warm between
355
- // commands. The previous five-second/zero-retention policy forced repeated
356
- // cold starts during ordinary multi-step device workflows.
510
+ // Keep the daemon and an explicitly prepared Runner warm. Physical devices
511
+ // share one stable runtime state directory across logical interactions;
512
+ // Simulator interactions remain isolated.
357
513
  AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS:
358
514
  process.env.FORGE_AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS?.trim() || DEFAULT_AGENT_DEVICE_IDLE_MS,
359
515
  AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS:
360
516
  process.env.FORGE_AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS?.trim() || DEFAULT_AGENT_DEVICE_IDLE_MS,
361
- };
517
+ });
362
518
  }
363
519
 
364
- function probeEnv(input: AssistantPluginActionExecutionInput, config?: AgentDeviceSigningConfig): NodeJS.ProcessEnv {
365
- const path = join(controllerRoot(input), 'interactions', 'ios-agent-device', 'probe-state');
520
+ function probeEnv(
521
+ input: AssistantPluginActionExecutionInput,
522
+ config?: AgentDeviceSigningConfig,
523
+ requestedStateDir?: string,
524
+ ): NodeJS.ProcessEnv {
525
+ const path = requestedStateDir ?? join(controllerRoot(input), 'interactions', 'ios-agent-device', 'probe-state');
366
526
  mkdirSync(path, { recursive: true });
367
- return {
527
+ return withTrustedNodePath({
368
528
  ...process.env,
369
529
  ...signingEnv(config),
370
530
  AGENT_DEVICE_STATE_DIR: path,
@@ -373,7 +533,7 @@ function probeEnv(input: AssistantPluginActionExecutionInput, config?: AgentDevi
373
533
  process.env.FORGE_AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS?.trim() || DEFAULT_AGENT_DEVICE_IDLE_MS,
374
534
  AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS:
375
535
  process.env.FORGE_AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS?.trim() || DEFAULT_AGENT_DEVICE_IDLE_MS,
376
- };
536
+ });
377
537
  }
378
538
 
379
539
  function bounded(value: unknown): unknown {
@@ -488,14 +648,15 @@ function runJson(
488
648
  options: {
489
649
  record?: InteractionSessionRecord;
490
650
  signing?: AgentDeviceSigningConfig;
651
+ stateDir?: string;
491
652
  timeoutMs?: number;
492
653
  failureCode: string;
493
654
  },
494
655
  ): Record<string, unknown> {
495
- const result = hooks.runCommand(executable(), args, {
656
+ const result = hooks.runCommand(executable(input.repoRoot), args, {
496
657
  cwd: input.repoRoot,
497
658
  timeoutMs: effectiveCommandTimeout(input, options.timeoutMs),
498
- env: options.record ? sessionEnv(input, options.record) : probeEnv(input, options.signing),
659
+ env: options.record ? sessionEnv(input, options.record) : probeEnv(input, options.signing, options.stateDir),
499
660
  signal: input.signal,
500
661
  });
501
662
  return parseJsonResult(result, options.failureCode);
@@ -507,14 +668,15 @@ async function runJsonAsync(
507
668
  options: {
508
669
  record?: InteractionSessionRecord;
509
670
  signing?: AgentDeviceSigningConfig;
671
+ stateDir?: string;
510
672
  timeoutMs?: number;
511
673
  failureCode: string;
512
674
  },
513
675
  ): Promise<Record<string, unknown>> {
514
- const result = await hooks.runCommandAsync(executable(), args, {
676
+ const result = await hooks.runCommandAsync(executable(input.repoRoot), args, {
515
677
  cwd: input.repoRoot,
516
678
  timeoutMs: effectiveCommandTimeout(input, options.timeoutMs),
517
- env: options.record ? sessionEnv(input, options.record) : probeEnv(input, options.signing),
679
+ env: options.record ? sessionEnv(input, options.record) : probeEnv(input, options.signing, options.stateDir),
518
680
  signal: input.signal,
519
681
  });
520
682
  return parseJsonResult(result, options.failureCode);
@@ -696,7 +858,7 @@ function providerSessionAlreadyAbsent(result: CommandResult): boolean {
696
858
  }
697
859
 
698
860
  function bestEffortClose(input: AssistantPluginActionExecutionInput, record: InteractionSessionRecord): boolean {
699
- const result = hooks.runCommand(executable(), ['close', '--session', record.sessionId, '--platform', 'ios', '--json'], {
861
+ const result = hooks.runCommand(executable(input.repoRoot), ['close', '--session', record.sessionId, '--platform', 'ios', '--json'], {
700
862
  cwd: input.repoRoot,
701
863
  timeoutMs: 30_000,
702
864
  env: sessionEnv(input, record),
@@ -716,7 +878,7 @@ async function closeProviderSession(
716
878
  record: InteractionSessionRecord,
717
879
  args: string[],
718
880
  ): Promise<{ result: Record<string, unknown>; providerAlreadyAbsent: boolean }> {
719
- const commandResult = await hooks.runCommandAsync(executable(), [
881
+ const commandResult = await hooks.runCommandAsync(executable(input.repoRoot), [
720
882
  ...args,
721
883
  '--session', record.sessionId,
722
884
  '--platform', 'ios',
@@ -985,8 +1147,8 @@ async function executeSessionSnapshotBackend(
985
1147
  let fallbackTypedVersion: string | undefined;
986
1148
  let fallbackCliVersion: string | undefined;
987
1149
  if (mode !== 'cli') {
988
- const dependency = requireDependency();
989
- const typed = new TypedAgentDeviceReadProvider();
1150
+ const dependency = requireDependency(input.repoRoot);
1151
+ const typed = new TypedAgentDeviceReadProvider(typedAgentDeviceIdentity({ repoRoot: input.repoRoot }));
990
1152
  const versionsMatch = agentDeviceProviderVersionsMatch(
991
1153
  typed.identity.version,
992
1154
  dependency.detectedVersion,
@@ -1013,9 +1175,8 @@ async function executeSessionSnapshotBackend(
1013
1175
  } else if (typed.identity.available || mode === 'typed') {
1014
1176
  try {
1015
1177
  return await typed.snapshot({
1016
- stateDir: stateDir(input, record.interactionId),
1178
+ stateDir: runtimeStateDir(input, record),
1017
1179
  session: record.sessionId,
1018
- device: record.targetId,
1019
1180
  platform: 'ios',
1020
1181
  requestId: input.requestId,
1021
1182
  cwd: input.repoRoot,
@@ -1052,7 +1213,7 @@ async function executeSessionSnapshotBackend(
1052
1213
  }
1053
1214
  }
1054
1215
 
1055
- const args = compileSnapshotCommand(capabilityProfile(), request);
1216
+ const args = compileSnapshotCommand(capabilityProfile(input.repoRoot), request);
1056
1217
  const result = await runJsonAsync(
1057
1218
  input,
1058
1219
  [...args, '--session', record.sessionId, '--platform', 'ios', '--json'],
@@ -1378,7 +1539,7 @@ async function runSessionBatch(
1378
1539
  let result: unknown = await runSessionCommand(
1379
1540
  input,
1380
1541
  record,
1381
- compileBatchCommand(capabilityProfile(), prepared.nativeSteps, MAX_BATCH_STEPS, { includeCost: true }),
1542
+ compileBatchCommand(capabilityProfile(input.repoRoot), prepared.nativeSteps, MAX_BATCH_STEPS, { includeCost: true }),
1382
1543
  'AGENT_DEVICE_BATCH_FAILED',
1383
1544
  timeoutMs,
1384
1545
  );
@@ -1395,7 +1556,7 @@ async function runSessionBatchAttempt(
1395
1556
  let result: unknown = await runSessionCommandAttempt(
1396
1557
  input,
1397
1558
  record,
1398
- compileBatchCommand(capabilityProfile(), prepared.nativeSteps, MAX_BATCH_STEPS, { includeCost: true }),
1559
+ compileBatchCommand(capabilityProfile(input.repoRoot), prepared.nativeSteps, MAX_BATCH_STEPS, { includeCost: true }),
1399
1560
  'AGENT_DEVICE_BATCH_FAILED',
1400
1561
  timeoutMs,
1401
1562
  );
@@ -1817,7 +1978,7 @@ async function executeJdSearch(input: AssistantPluginActionExecutionInput): Prom
1817
1978
  // The current batch schema supports only status/dismiss, so Return stays
1818
1979
  // a separate provider command, but only when the negotiated contract
1819
1980
  // explicitly advertises it.
1820
- if (!capabilityProfile().keyboard.returnSupported) {
1981
+ if (!capabilityProfile(input.repoRoot).keyboard.returnSupported) {
1821
1982
  return failWorkflowSession(input, record, new AssistantPluginError(
1822
1983
  'PLUGIN_ACTION_NOT_SUPPORTED',
1823
1984
  'The detected agent-device contract does not support keyboard Return.',
@@ -1921,7 +2082,7 @@ export function iosAgentDeviceCapabilities(): AssistantPluginCapability[] {
1921
2082
  {
1922
2083
  capabilityId: 'ios-agent-device-physical',
1923
2084
  title: 'agent-device physical iPhone',
1924
- description: 'Optional signed, capability-negotiated agent-device XCTest sessions for one exact connected physical iPhone.',
2085
+ description: 'Opt-in XCTest accessibility fallback for one exact physical iPhone. CoreDevice/RemoteXPC is the default physical-device path. Do not use agent-device for ordinary profile/form editing, Unicode text entry, screenshots, or known-coordinate interaction; use the physical-device provider and its batch fast path instead. Prepare XCTest only when semantic AX inspection is genuinely required.',
1925
2086
  scopes: ['ios.discover', 'ios.device'],
1926
2087
  actions,
1927
2088
  },
@@ -1935,7 +2096,7 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
1935
2096
  { resource: 'repo-state' as const, mode: 'write' as const },
1936
2097
  ];
1937
2098
  const interactionProperty = { interaction_id: { type: 'string' } };
1938
- return [
2099
+ const actions: AssistantPluginActionDescriptor[] = [
1939
2100
  {
1940
2101
  actionId: 'agent_device_status', title: 'agent-device status',
1941
2102
  description: 'Resolve the exact executable and verify a reviewed agent-device command contract.',
@@ -1950,8 +2111,8 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
1950
2111
  argumentsSchema: { type: 'object', properties: { app: { type: 'string' }, device: { type: 'string' }, team_id: { type: 'string' }, runner_bundle_id: { type: 'string' }, developer_dir: { type: 'string' } }, additionalProperties: false },
1951
2112
  },
1952
2113
  {
1953
- actionId: 'agent_device_prepare', title: 'Prepare signed iOS Runner',
1954
- description: 'Build, sign, install and health-check the agent-device XCTest Runner for one exact iOS target.',
2114
+ actionId: 'agent_device_prepare', title: 'Prepare semantic XCTest fallback',
2115
+ description: 'Explicitly build, sign, install and health-check the agent-device XCTest Runner. This is a heavy semantic fallback, not the normal physical-iPhone form-edit path. Physical-device preparation uses one stable per-device runtime so repeated semantic interactions can reuse it.',
1955
2116
  readOnly: false, risk: 'workspace_write', confirmation: 'authorization', defaultTimeoutMs: 10 * 60_000, cancellable: true, idempotent: false,
1956
2117
  scopes: ['ios.discover', 'ios.simulator', 'ios.device'], resourceClaims: write,
1957
2118
  argumentsSchema: {
@@ -1961,7 +2122,7 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
1961
2122
  },
1962
2123
  {
1963
2124
  actionId: 'agent_device_open', title: 'Open agent-device iOS session',
1964
- description: 'Open an app on one exact connected physical iPhone or already-booted iOS Simulator.',
2125
+ description: 'Open an agent-device semantic session on one exact physical iPhone or booted Simulator. On physical iPhone this may start/reconnect an XCTest Runner; prefer physical_device_open plus physical_device_batch for ordinary app navigation and profile/form edits.',
1965
2126
  readOnly: false, risk: 'workspace_write', confirmation: 'authorization', defaultTimeoutMs: 4 * 60_000, cancellable: true, idempotent: false,
1966
2127
  scopes: ['ios.simulator', 'ios.device'], resourceClaims: write,
1967
2128
  argumentsSchema: {
@@ -1971,7 +2132,7 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
1971
2132
  },
1972
2133
  {
1973
2134
  actionId: 'agent_device_batch', title: 'Run fast typed iOS action batch',
1974
- description: `Run up to ${MAX_BATCH_STEPS} allowlisted session steps in one agent-device process and one daemon request. Mutating steps always settle before the next step.`,
2135
+ description: `Run up to ${MAX_BATCH_STEPS} semantic AX steps in one agent-device process and one daemon request. Mutating steps settle before the next step. On a physical iPhone, use this only when accessibility semantics are required; known-coordinate/form workflows should use physical_device_batch to avoid XCTest lifecycle cost.`,
1975
2136
  readOnly: false, risk: 'workspace_write', confirmation: 'authorization', defaultTimeoutMs: 2 * 60_000, cancellable: true, idempotent: false,
1976
2137
  scopes: ['ios.simulator', 'ios.device'], resourceClaims: write,
1977
2138
  argumentsSchema: {
@@ -2023,7 +2184,7 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
2023
2184
  },
2024
2185
  {
2025
2186
  actionId: 'agent_device_press', title: 'Press agent-device target',
2026
- description: 'Press one ref, selector, or explicit coordinate pair and return a settled bounded diff.',
2187
+ description: 'Press one ref, selector, or explicit coordinate pair. Semantic targets return a settled bounded diff; explicit coordinates bypass accessibility settle for heavy-screen recovery.',
2027
2188
  readOnly: false, risk: 'workspace_write', confirmation: 'authorization', defaultTimeoutMs: 60_000, cancellable: true, idempotent: false,
2028
2189
  scopes: ['ios.simulator', 'ios.device'], resourceClaims: write,
2029
2190
  argumentsSchema: { type: 'object', properties: { ...interactionProperty, target: { type: 'string' }, x: { type: 'number' }, y: { type: 'number' } }, required: ['interaction_id'], additionalProperties: false },
@@ -2064,13 +2225,16 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
2064
2225
  argumentsSchema: { type: 'object', properties: { ...interactionProperty, shutdown_simulator: { type: 'boolean' } }, required: ['interaction_id'], additionalProperties: false },
2065
2226
  },
2066
2227
  ];
2228
+ return actions.map((action) => action.readOnly
2229
+ ? action
2230
+ : { ...action, executionMode: 'lightweight_process' });
2067
2231
  }
2068
2232
 
2069
2233
  export async function executeIosAgentDeviceAction(input: AssistantPluginActionExecutionInput): Promise<Record<string, unknown>> {
2070
2234
  if (input.deadlineAtMs === undefined && typeof input.timeoutMs === 'number' && Number.isFinite(input.timeoutMs)) {
2071
2235
  input = { ...input, deadlineAtMs: Date.now() + Math.max(1, Math.trunc(input.timeoutMs)) };
2072
2236
  }
2073
- if (input.actionId === 'agent_device_status') return { provider: 'agent-device', ...iosAgentDeviceStatus() };
2237
+ if (input.actionId === 'agent_device_status') return { provider: 'agent-device', ...await iosAgentDeviceActionStatus(input) };
2074
2238
  if (input.actionId === 'agent_device_close') {
2075
2239
  const interactionId = requireString(input.args.interaction_id, 'interaction_id');
2076
2240
  const existing = readAgentDeviceInteraction(input.repoRoot, interactionId);
@@ -2078,7 +2242,7 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
2078
2242
  return { provider: 'agent-device', interaction: existing, alreadyClosed: true };
2079
2243
  }
2080
2244
  }
2081
- const dependency = requireDependency();
2245
+ const dependency = await requireDependencyAsync(input);
2082
2246
 
2083
2247
  if (input.actionId === 'agent_device_jd_search') return executeJdSearch(input);
2084
2248
 
@@ -2096,6 +2260,7 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
2096
2260
  physicalDeviceSupported: selected.kind === 'device',
2097
2261
  result: bounded(await runJsonAsync(input, args, {
2098
2262
  signing: signingFromArgs(input.args),
2263
+ stateDir: targetRuntimeStateDir(input, selected),
2099
2264
  failureCode: 'AGENT_DEVICE_DOCTOR_FAILED',
2100
2265
  timeoutMs: 4 * 60_000,
2101
2266
  })),
@@ -2115,6 +2280,7 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
2115
2280
  'prepare', 'ios-runner', '--platform', 'ios', '--device', selected.name, '--timeout', '600000', '--json',
2116
2281
  ], {
2117
2282
  signing,
2283
+ stateDir: targetRuntimeStateDir(input, selected),
2118
2284
  failureCode: 'AGENT_DEVICE_PREPARE_FAILED',
2119
2285
  timeoutMs: 10 * 60_000,
2120
2286
  })),
@@ -2223,11 +2389,15 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
2223
2389
  if (record.provider === DEVICE_PROVIDER && target && SENSITIVE_SEMANTICS.test(target)) {
2224
2390
  throw new AssistantPluginError('IOS_DEVICE_SENSITIVE_ACTION_BLOCKED', 'Press targets involving credentials, verification, biometrics, checkout, purchase or payment require human interaction.', { retryable: false });
2225
2391
  }
2226
- const args = appendSettleFlag(
2227
- capabilityProfile(),
2228
- ['press', ...(target ? [target] : [String(input.args.x), String(input.args.y)])],
2229
- 'press',
2230
- );
2392
+ const baseArgs = ['press', ...(target ? [target] : [String(input.args.x), String(input.args.y)])];
2393
+ // Explicit coordinate presses are the bounded fallback for screens whose
2394
+ // accessibility tree is too heavy or animated to snapshot reliably.
2395
+ // Settling forces an AX snapshot after the mutation, defeating that
2396
+ // fallback and can recycle/wedge the XCTest runner. Keep semantic target
2397
+ // presses settled, but let explicit points complete without AX capture.
2398
+ const args = target
2399
+ ? appendSettleFlag(capabilityProfile(input.repoRoot), baseArgs, 'press')
2400
+ : baseArgs;
2231
2401
  return { provider: 'agent-device', interaction: record, result: bounded(await runSessionCommand(input, record, args, 'AGENT_DEVICE_PRESS_FAILED')) };
2232
2402
  }
2233
2403
  case 'agent_device_fill': {
@@ -2237,7 +2407,7 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
2237
2407
  if (record.provider === DEVICE_PROVIDER && (SENSITIVE_SEMANTICS.test(target) || SENSITIVE_SEMANTICS.test(text))) {
2238
2408
  throw new AssistantPluginError('IOS_DEVICE_SENSITIVE_ACTION_BLOCKED', 'Sensitive text and credential, verification, checkout, purchase or payment targets require human interaction.', { retryable: false });
2239
2409
  }
2240
- const profile = capabilityProfile();
2410
+ const profile = capabilityProfile(input.repoRoot);
2241
2411
  const args = appendSettleFlag(profile, ['fill', target, text]);
2242
2412
  if (typeof input.args.delay_ms === 'number') {
2243
2413
  if (!profile.fill.delayFlag) {