@moretea-labs/forge 1.8.0 → 1.8.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 (528) hide show
  1. package/AGENTS.md +70 -7
  2. package/CHANGELOG.md +14 -0
  3. package/CLAUDE.md +17 -2
  4. package/CONTRIBUTING.md +3 -2
  5. package/THIRD_PARTY_NOTICES.md +1 -1
  6. package/adapters/chatgpt/browser-delivery-host.ts +7 -1
  7. package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
  8. package/adapters/chatgpt/controller-binding-store.ts +101 -22
  9. package/adapters/chatgpt/controller-round-host.ts +15 -25
  10. package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
  11. package/adapters/chatgpt/provider-delivery.ts +228 -1
  12. package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
  13. package/adapters/computer/chatgpt-extension-target.ts +463 -0
  14. package/adapters/computer/chatgpt-target-router.ts +103 -0
  15. package/adapters/computer/chrome-extension/background.js +385 -0
  16. package/adapters/computer/chrome-extension/content.js +378 -0
  17. package/adapters/computer/chrome-extension/core.js +24 -0
  18. package/adapters/computer/chrome-extension/manifest.json +30 -0
  19. package/adapters/computer/desktop-operator-discovery.ts +11 -31
  20. package/adapters/computer/interaction-target-authority.ts +142 -18
  21. package/adapters/mcp/auth.ts +0 -1
  22. package/adapters/mcp/instructions.ts +5 -4
  23. package/adapters/mcp/multi-repository.ts +3 -19
  24. package/adapters/mcp/oauth.ts +73 -0
  25. package/adapters/mcp/paths.ts +4 -1
  26. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
  27. package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
  28. package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
  29. package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
  30. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
  31. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
  32. package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
  33. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
  34. package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
  35. package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
  36. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
  37. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
  38. package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
  39. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
  40. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
  41. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
  42. package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
  43. package/adapters/mcp/runtime-gateway/router.ts +18 -504
  44. package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
  45. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
  46. package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
  47. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
  48. package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
  49. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
  50. package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
  51. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
  52. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
  53. package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
  54. package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
  55. package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
  56. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
  57. package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
  58. package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
  59. package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
  60. package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
  61. package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
  62. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
  63. package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
  64. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
  65. package/adapters/mcp/server.ts +67 -23
  66. package/adapters/mcp/setup.ts +1 -3
  67. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
  68. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
  69. package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
  70. package/adapters/mcp/toolset-names.ts +5 -0
  71. package/adapters/mcp/toolset.ts +6 -5
  72. package/adapters/mcp/transports/http-observation.ts +365 -0
  73. package/adapters/mcp/transports/http.ts +154 -677
  74. package/adapters/mcp/transports/oauth-http.ts +322 -0
  75. package/adapters/mcp/transports/session-registry.ts +6 -0
  76. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
  77. package/assets/plugin-registry.v1.json +6 -4
  78. package/assets/reference-configs/agentic-development-flow.md +25 -0
  79. package/assets/reference-configs/global-working-rules.md +19 -0
  80. package/assets/skill-version.json +2 -2
  81. package/docs/architecture/CURRENT.md +111 -41
  82. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
  83. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
  84. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
  85. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
  86. package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
  87. package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
  88. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
  89. package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
  90. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
  91. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
  92. package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
  93. package/docs/architecture/domains/verification.md +1 -0
  94. package/docs/architecture/domains/workflow-engine.md +6 -0
  95. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  96. package/docs/forge-plugin-management.md +2 -2
  97. package/docs/operations/controller-performance-and-502.md +17 -0
  98. package/docs/operations/controller-reliability-runbook.md +2 -2
  99. package/docs/operations/features.md +1 -1
  100. package/docs/operations/features.zh-CN.md +1 -1
  101. package/docs/operations/homebrew.md +2 -2
  102. package/docs/operations/mcp-tool-exposure.md +2 -0
  103. package/docs/operations/releasing.md +2 -0
  104. package/docs/operations/standalone-disaster-recovery.md +14 -6
  105. package/docs/wiki/Implementation.md +1 -1
  106. package/package.json +25 -14
  107. package/packages/kernel/cognition/api/index.ts +6 -0
  108. package/packages/kernel/cognition/application/activation-service.ts +451 -0
  109. package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
  110. package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
  111. package/packages/kernel/cognition/application/memory-service.ts +64 -0
  112. package/packages/kernel/cognition/domain/learning.ts +106 -0
  113. package/packages/kernel/cognition/domain/memory.ts +254 -0
  114. package/packages/kernel/controller/api/index.ts +1 -0
  115. package/packages/kernel/controller/application/continuation-service.ts +281 -0
  116. package/packages/kernel/controller/application/controller-round-service.ts +12 -0
  117. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
  118. package/packages/kernel/controller/domain/controller-round.ts +4 -1
  119. package/packages/kernel/controller/domain/execution-quality.ts +3 -1
  120. package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
  121. package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
  122. package/packages/kernel/controller/ports/controller-host.ts +2 -0
  123. package/packages/kernel/identity/api/index.ts +10 -0
  124. package/packages/kernel/identity/domain/activity-projection.ts +43 -0
  125. package/packages/kernel/identity/domain/capability-broker.ts +60 -0
  126. package/packages/kernel/identity/domain/grant.ts +72 -0
  127. package/packages/kernel/identity/domain/owned-resource.ts +116 -0
  128. package/packages/kernel/identity/domain/user-request.ts +93 -0
  129. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
  130. package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
  131. package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
  132. package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
  133. package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
  134. package/packages/kernel/scheduler/api/index.ts +0 -2
  135. package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
  136. package/packages/kernel/scheduler/application/settlement.ts +0 -15
  137. package/packages/kernel/scheduler/domain/schedule.ts +87 -0
  138. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
  139. package/packages/kernel/work/api/index.ts +3 -2
  140. package/packages/kernel/work/application/work-service.ts +17 -42
  141. package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
  142. package/packages/kernel/work/domain/engineering-design.ts +10 -5
  143. package/packages/kernel/work/domain/engineering-profile.ts +8 -12
  144. package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
  145. package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
  146. package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
  147. package/packages/kernel/work/domain/implementation-review.ts +14 -331
  148. package/packages/kernel/work/domain/objective-graph.ts +119 -0
  149. package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
  150. package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
  151. package/packages/kernel/work/domain/state-machine.ts +25 -63
  152. package/packages/kernel/work/domain/types.ts +57 -51
  153. package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
  154. package/packages/kernel/work/ports/work-contract-store.ts +5 -2
  155. package/packages/plugin-runtime/browser/session-authority.ts +2 -1
  156. package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
  157. package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
  158. package/packages/plugin-runtime/computer/index.ts +2 -0
  159. package/packages/plugin-runtime/computer/target-authority.ts +26 -1
  160. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
  161. package/packages/protocols/computer/contract.ts +27 -1
  162. package/scripts/activate-source-baseline.ts +7 -9
  163. package/scripts/canary-controller-semantic-wait.ts +12 -24
  164. package/scripts/check-mcp-compatibility.ts +48 -136
  165. package/scripts/check-runtime-architecture.mjs +622 -217
  166. package/scripts/forge-local-recovery-helper.mjs +93 -15
  167. package/scripts/lib/project-init-lib.sh +3 -0
  168. package/scripts/open-source-audit-allowlist.txt +1 -2
  169. package/scripts/run-bounded-command.mjs +5 -0
  170. package/scripts/run-governed-gate.ts +0 -1
  171. package/scripts/run-mobile-monitor-bridge.ts +0 -1
  172. package/scripts/smoke-control-plane-failure-domain.ts +94 -0
  173. package/scripts/smoke-mcp-http-runtime.ts +5 -0
  174. package/scripts/smoke-runtime-recovery.ts +12 -43
  175. package/scripts/smoke-schedule-engine.ts +23 -15
  176. package/scripts/smoke-unattended-transport-recovery.ts +223 -0
  177. package/scripts/smoke-user-request-continuation-restart.ts +232 -0
  178. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
  179. package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
  180. package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
  181. package/scripts/smoke-workflow-supervisor.ts +103 -0
  182. package/scripts/verify-forge-runtime.sh +2 -1
  183. package/src/cli/agent-jobs/executor-health.ts +11 -34
  184. package/src/cli/agent-jobs/integration.ts +18 -49
  185. package/src/cli/agent-jobs/job-manager.ts +7 -3
  186. package/src/cli/commands/brain-assistant.ts +27 -13
  187. package/src/cli/commands/brain.ts +13 -15
  188. package/src/cli/commands/chatgpt.ts +1 -163
  189. package/src/cli/commands/recovery.ts +135 -121
  190. package/src/cli/commands/runtime.ts +3 -3
  191. package/src/cli/commands/setup-profile.ts +8 -0
  192. package/src/cli/controller/check-runner.ts +13 -2
  193. package/src/cli/controller/completion-backlog.ts +3 -3
  194. package/src/cli/controller/completion-orchestrator.ts +4 -43
  195. package/src/cli/controller/completion-target.ts +3 -72
  196. package/src/cli/controller/context/source-materializer.ts +81 -100
  197. package/src/cli/controller/context-pack.ts +10 -8
  198. package/src/cli/controller/execution-completion.ts +4 -7
  199. package/src/cli/controller/execution-policy.ts +36 -153
  200. package/src/cli/controller/governance.ts +2 -3
  201. package/src/cli/controller/issue-store.ts +4 -99
  202. package/src/cli/controller/launch-agents.ts +59 -18
  203. package/src/cli/controller/operational-plan.ts +24 -51
  204. package/src/cli/controller/runtime-config.ts +5 -1
  205. package/src/cli/controller/stuck-state-migration.ts +2 -3
  206. package/src/cli/controller/systemd-user.ts +39 -1
  207. package/src/cli/editing/edit-session.ts +1 -7
  208. package/src/cli/local-bridge/console-automations.ts +18 -13
  209. package/src/cli/local-bridge/console-view-models.ts +3 -12
  210. package/src/cli/local-bridge/facade-api.ts +64 -191
  211. package/src/cli/local-bridge/server.ts +24 -147
  212. package/src/cli/local-bridge/types.ts +0 -1
  213. package/src/cli/mcp/oauth-client-retirement.ts +74 -0
  214. package/src/cli/repositories/command-executor.ts +29 -23
  215. package/src/cli/repositories/command-scope.ts +35 -16
  216. package/src/cli/repositories/controller-home.ts +48 -0
  217. package/src/cli/repositories/ephemeral-workspace.ts +20 -30
  218. package/src/cli/repositories/git-command-executor.ts +2 -2
  219. package/src/cli/repositories/registry.ts +77 -11
  220. package/src/cli/repositories/structured-git.ts +62 -2
  221. package/src/cli/repository/session-cache.ts +92 -6
  222. package/src/runtime/context/assistant-context.ts +20 -7
  223. package/src/runtime/context/assistant-work-context.ts +89 -27
  224. package/src/runtime/context/automatic-learning.ts +565 -0
  225. package/src/runtime/context/cognitive-attention.ts +173 -0
  226. package/src/runtime/context/cognitive-skill-canary.ts +158 -0
  227. package/src/runtime/context/context-closure.ts +46 -9
  228. package/src/runtime/context/context-pack-process.ts +103 -0
  229. package/src/runtime/context/context-plane.ts +1 -9
  230. package/src/runtime/context/direct-controller-learning.ts +298 -0
  231. package/src/runtime/context/semantic-navigation-contract.ts +9 -0
  232. package/src/runtime/context/semantic-navigation.ts +6 -34
  233. package/src/runtime/context/typescript-navigation-process.ts +145 -0
  234. package/src/runtime/context/typescript-navigation.ts +89 -3
  235. package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
  236. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
  237. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
  238. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
  239. package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
  240. package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
  241. package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
  242. package/src/runtime/control-plane/execution/session-store.ts +31 -1
  243. package/src/runtime/control-plane/execution/validation.ts +6 -8
  244. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
  245. package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
  246. package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
  247. package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
  248. package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
  249. package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
  250. package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
  251. package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
  252. package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
  253. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
  254. package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
  255. package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
  256. package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
  257. package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
  258. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
  259. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
  260. package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
  261. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
  262. package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
  263. package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
  264. package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
  265. package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
  266. package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
  267. package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
  268. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
  269. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
  270. package/src/runtime/control-plane/facade/index.ts +0 -1
  271. package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
  272. package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
  273. package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
  274. package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
  275. package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
  276. package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
  277. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
  278. package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
  279. package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
  280. package/src/runtime/control-plane/facade/types.ts +49 -108
  281. package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
  282. package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
  283. package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
  284. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
  285. package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
  286. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
  287. package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
  288. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
  289. package/src/runtime/control-plane/governance/access-policy.ts +19 -2
  290. package/src/runtime/control-plane/governance/authorization.ts +20 -3
  291. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
  292. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
  293. package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
  294. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
  295. package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
  296. package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
  297. package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
  298. package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
  299. package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
  300. package/src/runtime/control-plane/release-retention.ts +135 -47
  301. package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
  302. package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
  303. package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
  304. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
  305. package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
  306. package/src/runtime/diagnostics/incident-repair.ts +313 -146
  307. package/src/runtime/diagnostics/mcp-timing.ts +114 -0
  308. package/src/runtime/evidence/artifact-store.ts +158 -40
  309. package/src/runtime/evidence/evidence-store.ts +112 -8
  310. package/src/runtime/evidence/output-handle-index.ts +225 -0
  311. package/src/runtime/evidence/result-store.ts +158 -44
  312. package/src/runtime/execution/jobs/store.ts +3 -4
  313. package/src/runtime/execution/managed-workspace.ts +57 -0
  314. package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
  315. package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
  316. package/src/runtime/execution/process-runtime/check-result.ts +105 -1
  317. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
  318. package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
  319. package/src/runtime/execution/process-runtime/gc.ts +15 -2
  320. package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
  321. package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
  322. package/src/runtime/execution/process-runtime/index.ts +3 -0
  323. package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
  324. package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
  325. package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
  326. package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
  327. package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
  328. package/src/runtime/execution/process-runtime/runtime.ts +35 -2
  329. package/src/runtime/execution/process-runtime/store.ts +30 -2
  330. package/src/runtime/execution/process-runtime/types.ts +6 -1
  331. package/src/runtime/execution/workers/executor.ts +2 -6
  332. package/src/runtime/platform/service-inventory.ts +130 -0
  333. package/src/runtime/platform/service-manager.ts +8 -0
  334. package/src/runtime/plugins/action-application.ts +85 -28
  335. package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
  336. package/src/runtime/plugins/browser-adapter.ts +757 -34
  337. package/src/runtime/plugins/browser-automation-service.ts +23 -3
  338. package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
  339. package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
  340. package/src/runtime/plugins/browser-native-session-service.ts +63 -13
  341. package/src/runtime/plugins/browser-registration.ts +16 -0
  342. package/src/runtime/plugins/browser-runtime.ts +14 -1
  343. package/src/runtime/plugins/browser-session-authority.ts +2 -2
  344. package/src/runtime/plugins/browser-session-store.ts +46 -76
  345. package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
  346. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
  347. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
  348. package/src/runtime/plugins/computer-registration.ts +222 -11
  349. package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
  350. package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
  351. package/src/runtime/plugins/external-adapter.ts +42 -6
  352. package/src/runtime/plugins/external-registration.ts +21 -1
  353. package/src/runtime/plugins/gmail-adapter.ts +23 -2
  354. package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
  355. package/src/runtime/plugins/google-shared.ts +14 -7
  356. package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
  357. package/src/runtime/plugins/ios-adapter.ts +1 -1
  358. package/src/runtime/plugins/lightweight-action.ts +208 -2
  359. package/src/runtime/plugins/local-system-adapter.ts +12 -2
  360. package/src/runtime/plugins/managed-process-adapter.ts +12 -5
  361. package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
  362. package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
  363. package/src/runtime/plugins/store.ts +602 -428
  364. package/src/runtime/plugins/types.ts +20 -0
  365. package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
  366. package/src/runtime/projections/invalidation.ts +7 -3
  367. package/src/runtime/projections/materialized-view.ts +80 -36
  368. package/src/runtime/recovery/actions.ts +3 -3
  369. package/src/runtime/recovery/capability-action-application.ts +46 -45
  370. package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
  371. package/src/runtime/recovery/maintenance-executor.ts +374 -123
  372. package/src/runtime/recovery/store.ts +29 -11
  373. package/src/runtime/release/release-coordinator.ts +296 -0
  374. package/src/runtime/release/release-session.ts +716 -0
  375. package/src/runtime/release/release-state-migration.ts +25 -0
  376. package/src/runtime/resources/leases/store.ts +56 -25
  377. package/src/runtime/root/computer-composition.ts +191 -6
  378. package/src/runtime/root/controller-progression-composition.ts +192 -0
  379. package/src/runtime/root/controller-round-composition.ts +20 -1
  380. package/src/runtime/root/deployment-topology.ts +106 -0
  381. package/src/runtime/root/entry.ts +4 -3
  382. package/src/runtime/root/known-good-recovery.ts +184 -0
  383. package/src/runtime/root/local-bridge.ts +0 -1
  384. package/src/runtime/root/mcp-transport.ts +111 -18
  385. package/src/runtime/root/ownership.ts +261 -9
  386. package/src/runtime/root/package-connector-service.ts +105 -19
  387. package/src/runtime/root/package-runtime-release.ts +117 -18
  388. package/src/runtime/root/package-runtime-service.ts +17 -11
  389. package/src/runtime/root/release-execution-canary.ts +44 -12
  390. package/src/runtime/root/release-loader.ts +90 -8
  391. package/src/runtime/root/release-manifest.ts +80 -6
  392. package/src/runtime/root/release-materialize.ts +372 -28
  393. package/src/runtime/root/release-store.ts +395 -36
  394. package/src/runtime/root/runtime-lane.ts +191 -0
  395. package/src/runtime/root/runtime.ts +159 -27
  396. package/src/runtime/root/scheduled-controller-composition.ts +28 -3
  397. package/src/runtime/root/service-runner.ts +2 -2
  398. package/src/runtime/root/service.ts +36 -33
  399. package/src/runtime/root/status.ts +48 -0
  400. package/src/runtime/root/types.ts +32 -3
  401. package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
  402. package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
  403. package/src/runtime/root/write-fence.ts +50 -2
  404. package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
  405. package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
  406. package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
  407. package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
  408. package/src/runtime/shared/process-environment.ts +20 -9
  409. package/src/runtime/shared/response-budget.ts +1 -3
  410. package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
  411. package/src/runtime/standalone-recovery/core.ts +3702 -342
  412. package/src/runtime/standalone-recovery/entry.ts +469 -39
  413. package/src/runtime/standalone-recovery/installer.ts +262 -148
  414. package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
  415. package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
  416. package/src/runtime/standalone-recovery/performance.ts +54 -16
  417. package/src/runtime/standalone-recovery/release.ts +53 -5
  418. package/src/runtime/standalone-recovery/service-labels.ts +5 -2
  419. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
  420. package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
  421. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
  422. package/src/runtime/workflow/schedules/engine.ts +138 -172
  423. package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
  424. package/src/runtime/workflows/runtime.ts +15 -19
  425. package/src/testing/test-governance.ts +5 -1
  426. package/supervisor/chatgpt-conversation.ts +23 -0
  427. package/supervisor/client.ts +201 -0
  428. package/supervisor/control-plane.ts +868 -0
  429. package/supervisor/entry.ts +15 -0
  430. package/supervisor/forge-validators.ts +80 -0
  431. package/supervisor/index.ts +5 -0
  432. package/supervisor/native-browser-adapter.ts +786 -0
  433. package/supervisor/native-messaging/host.ts +39 -0
  434. package/supervisor/native-messaging/manifest.ts +26 -0
  435. package/supervisor/native-messaging/protocol.ts +27 -0
  436. package/supervisor/paths.ts +18 -0
  437. package/supervisor/protocol.ts +202 -0
  438. package/supervisor/server.ts +404 -0
  439. package/supervisor/store.ts +1451 -0
  440. package/supervisor/tsconfig.json +8 -0
  441. package/supervisor/types.ts +255 -0
  442. package/adapters/chatgpt/controller-host.ts +0 -119
  443. package/adapters/mcp/controller-round-compatibility.ts +0 -184
  444. package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
  445. package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
  446. package/packages/kernel/progression/api/index.ts +0 -2
  447. package/packages/kernel/progression/application/projector.ts +0 -211
  448. package/packages/kernel/progression/domain/types.ts +0 -116
  449. package/packages/kernel/progression/index.ts +0 -1
  450. package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
  451. package/packages/kernel/scheduler/domain/continuation.ts +0 -38
  452. package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
  453. package/packages/kernel/work/domain/admission-policy.ts +0 -34
  454. package/scripts/benchmark-background-check-overlap.ts +0 -228
  455. package/scripts/benchmark-computer-hotpath.ts +0 -255
  456. package/scripts/benchmark-controller-hotpath.ts +0 -212
  457. package/scripts/benchmark-controller-round2.ts +0 -191
  458. package/scripts/benchmark-ios-agent-device.ts +0 -511
  459. package/scripts/benchmark-mcp-host.sh +0 -117
  460. package/scripts/benchmark-mcp-transport.ts +0 -169
  461. package/scripts/benchmark-operational-memory-activation.ts +0 -235
  462. package/scripts/benchmark-operational-shadow.ts +0 -28
  463. package/scripts/benchmark-quality-harness.ts +0 -146
  464. package/scripts/benchmark-route-session-concurrency.ts +0 -915
  465. package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
  466. package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
  467. package/scripts/benchmark-thin-harness.ts +0 -251
  468. package/scripts/benchmark-typescript-navigation.ts +0 -186
  469. package/scripts/benchmark-work-efficiency.ts +0 -334
  470. package/scripts/build-controller-ui.ts +0 -28
  471. package/scripts/check-npm-release.sh +0 -32
  472. package/scripts/check-public-release-surface.sh +0 -19
  473. package/scripts/check-release-published.sh +0 -57
  474. package/scripts/check-release-readiness.sh +0 -37
  475. package/scripts/check-release-version.mjs +0 -74
  476. package/scripts/check-tarball-install-smoke.sh +0 -150
  477. package/scripts/package-source-archive.sh +0 -147
  478. package/scripts/public-release-files.txt +0 -39
  479. package/scripts/public-release.ts +0 -174
  480. package/scripts/publish-release-tarball.sh +0 -27
  481. package/scripts/route-nl-vs-ts-eval.ts +0 -679
  482. package/scripts/stage-runtime-release.ts +0 -44
  483. package/src/cli/controller/progress.ts +0 -656
  484. package/src/cli/controller/work-mode.ts +0 -181
  485. package/src/cli/local-bridge/console-assets.ts +0 -17
  486. package/src/cli/local-bridge/dashboard.ts +0 -17
  487. package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
  488. package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
  489. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
  490. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
  491. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
  492. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
  493. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
  494. package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
  495. package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
  496. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
  497. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
  498. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
  499. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
  500. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
  501. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
  502. package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
  503. package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
  504. package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
  505. package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
  506. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
  507. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
  508. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
  509. package/src/cli/local-bridge/frontend/src/styles.css +0 -28
  510. package/src/cli/local-bridge/frontend/src/types.ts +0 -15
  511. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
  512. package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
  513. package/src/cli/local-bridge/ui-dist/app.css +0 -1
  514. package/src/cli/local-bridge/ui-dist/app.js +0 -11228
  515. package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
  516. package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
  517. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
  518. package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
  519. package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
  520. package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
  521. package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
  522. package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
  523. package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
  524. package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
  525. package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
  526. package/src/runtime/control-plane/routing/index.ts +0 -1
  527. package/src/runtime/control-plane/routing/route-policy.ts +0 -401
  528. package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
@@ -1,5 +1,6 @@
1
1
  import { createHash, randomUUID } from 'crypto';
2
2
  import type {
3
+ ComputerApplicationLaunchProvenance,
3
4
  ComputerApplicationTarget,
4
5
  ComputerApplicationStableIdentity,
5
6
  ComputerApplicationTargetLease,
@@ -11,6 +12,7 @@ import {
11
12
  COMPUTER_ELEMENT_OBSERVE_CAPABILITY,
12
13
  COMPUTER_INPUT_CAPABILITY,
13
14
  COMPUTER_OBSERVE_CAPABILITY,
15
+ type ComputerConsoleUnlockCommandRequest,
14
16
  type ComputerConsoleUnlockPrepareRequest,
15
17
  type ComputerConsoleUnlockRequest,
16
18
  type ComputerElementSemanticAction,
@@ -48,6 +50,10 @@ const DESKTOP_ELEMENT_OBSERVE_ACTION = 'desktop_element_observe';
48
50
  const DESKTOP_ELEMENT_ACTION_ACTION = 'desktop_element_action';
49
51
  export const COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION = 'console_unlock_prepare';
50
52
  export const COMPUTER_CONSOLE_UNLOCK_ACTION = 'console_unlock';
53
+ export const COMPUTER_CONSOLE_UNLOCK_ENROLL_ACTION = 'console_unlock_enroll';
54
+ export const COMPUTER_CONSOLE_UNLOCK_STATUS_ACTION = 'console_unlock_status';
55
+ export const COMPUTER_CONSOLE_UNLOCK_RECOVER_ACTION = 'console_unlock_recover';
56
+ export const COMPUTER_CONSOLE_UNLOCK_REVOKE_ACTION = 'console_unlock_revoke';
51
57
  const DEFAULT_CONSOLE_UNLOCK_TIMEOUT_MS = 15_000;
52
58
  const MAX_CONSOLE_UNLOCK_TIMEOUT_MS = 30_000;
53
59
  const CONSOLE_CREDENTIAL_HANDLE_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@@ -69,6 +75,10 @@ const DESKTOP_PRODUCT_ACTION_IDS = new Set([
69
75
  DESKTOP_ELEMENT_ACTION_ACTION,
70
76
  COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION,
71
77
  COMPUTER_CONSOLE_UNLOCK_ACTION,
78
+ COMPUTER_CONSOLE_UNLOCK_ENROLL_ACTION,
79
+ COMPUTER_CONSOLE_UNLOCK_STATUS_ACTION,
80
+ COMPUTER_CONSOLE_UNLOCK_RECOVER_ACTION,
81
+ COMPUTER_CONSOLE_UNLOCK_REVOKE_ACTION,
72
82
  ]);
73
83
 
74
84
  function providerActionDescriptor(actionId: string): AssistantPluginActionDescriptor {
@@ -178,6 +188,31 @@ export async function executeProtectedConsoleUnlockInvocation(
178
188
  };
179
189
  }
180
190
 
191
+ export async function executeProtectedConsoleUnlockLifecycle(
192
+ action: 'console_unlock_enroll' | 'console_unlock_status' | 'console_unlock_recover' | 'console_unlock_revoke',
193
+ input: ProtectedConsoleUnlockPreparationInput,
194
+ controllerHome: string,
195
+ ): Promise<Record<string, unknown>> {
196
+ requireConsoleUnlockAuthorization(input.confirmAuthorization);
197
+ const invocationId = randomUUID();
198
+ const request: ComputerConsoleUnlockCommandRequest = {
199
+ capability: COMPUTER_CONSOLE_UNLOCK_CAPABILITY,
200
+ action,
201
+ };
202
+ const providerResult = await executeRuntimeComputerConsoleUnlock(
203
+ request,
204
+ { kind: 'explicit_single_use', confirmed: true, invocationId },
205
+ boundedConsoleUnlockTimeoutMs(input.timeoutMs),
206
+ controllerHome,
207
+ );
208
+ return {
209
+ capability: COMPUTER_CONSOLE_UNLOCK_CAPABILITY,
210
+ action,
211
+ invocationId,
212
+ ...providerResult,
213
+ };
214
+ }
215
+
181
216
  function desktopProductActions(): AssistantPluginActionDescriptor[] {
182
217
  const open = providerActionDescriptor('desktop_session_open');
183
218
  const close = providerActionDescriptor('desktop_session_close');
@@ -240,6 +275,70 @@ function desktopProductActions(): AssistantPluginActionDescriptor[] {
240
275
  additionalProperties: false,
241
276
  },
242
277
  },
278
+ {
279
+ actionId: COMPUTER_CONSOLE_UNLOCK_ENROLL_ACTION,
280
+ title: 'Enable unattended console recovery',
281
+ description: 'Enroll provider-local unattended console recovery. Credential collection and Keychain persistence remain entirely inside the native provider.',
282
+ readOnly: false,
283
+ risk: 'workspace_write',
284
+ confirmation: 'authorization',
285
+ defaultTimeoutMs: DEFAULT_CONSOLE_UNLOCK_TIMEOUT_MS,
286
+ cancellable: true,
287
+ idempotent: false,
288
+ executionMode: 'direct_non_persistent',
289
+ foregroundEffect: 'required',
290
+ scopes: ['console.unlock'],
291
+ resourceClaims: [],
292
+ argumentsSchema: { type: 'object', properties: {}, additionalProperties: false },
293
+ },
294
+ {
295
+ actionId: COMPUTER_CONSOLE_UNLOCK_STATUS_ACTION,
296
+ title: 'Read unattended console recovery status',
297
+ description: 'Read whether provider-local unattended console recovery is enrolled and available without exposing credential material.',
298
+ readOnly: true,
299
+ risk: 'readonly',
300
+ confirmation: 'authorization',
301
+ defaultTimeoutMs: DEFAULT_CONSOLE_UNLOCK_TIMEOUT_MS,
302
+ cancellable: true,
303
+ idempotent: true,
304
+ executionMode: 'direct_non_persistent',
305
+ foregroundEffect: 'none',
306
+ scopes: ['console.unlock'],
307
+ resourceClaims: [],
308
+ argumentsSchema: { type: 'object', properties: {}, additionalProperties: false },
309
+ },
310
+ {
311
+ actionId: COMPUTER_CONSOLE_UNLOCK_RECOVER_ACTION,
312
+ title: 'Recover locked macOS console',
313
+ description: 'Recover an already-locked console using only the provider-local enrolled credential. No password or credential handle enters Forge.',
314
+ readOnly: false,
315
+ risk: 'workspace_write',
316
+ confirmation: 'authorization',
317
+ defaultTimeoutMs: DEFAULT_CONSOLE_UNLOCK_TIMEOUT_MS,
318
+ cancellable: true,
319
+ idempotent: false,
320
+ executionMode: 'direct_non_persistent',
321
+ foregroundEffect: 'required',
322
+ scopes: ['console.unlock'],
323
+ resourceClaims: [],
324
+ argumentsSchema: { type: 'object', properties: {}, additionalProperties: false },
325
+ },
326
+ {
327
+ actionId: COMPUTER_CONSOLE_UNLOCK_REVOKE_ACTION,
328
+ title: 'Disable unattended console recovery',
329
+ description: 'Delete the provider-local unattended console recovery credential and disable future recovery.',
330
+ readOnly: false,
331
+ risk: 'workspace_write',
332
+ confirmation: 'authorization',
333
+ defaultTimeoutMs: DEFAULT_CONSOLE_UNLOCK_TIMEOUT_MS,
334
+ cancellable: true,
335
+ idempotent: true,
336
+ executionMode: 'direct_non_persistent',
337
+ foregroundEffect: 'none',
338
+ scopes: ['console.unlock'],
339
+ resourceClaims: [],
340
+ argumentsSchema: { type: 'object', properties: {}, additionalProperties: false },
341
+ },
243
342
  {
244
343
  actionId: DESKTOP_ELEMENT_OBSERVE_ACTION,
245
344
  title: 'Observe Computer elements',
@@ -318,7 +417,7 @@ function desktopProductPermissions(ready: boolean): AssistantPluginPermissionSco
318
417
  { scope: 'desktop.observe', mode: 'read', description: 'Observe bounded desktop accessibility state.', granted: ready, required: false },
319
418
  { scope: 'desktop.interact', mode: 'write', description: 'Perform bounded semantic desktop interaction.', granted: ready, required: false },
320
419
  { scope: 'desktop.capture', mode: 'read', description: 'Capture an authorized desktop target.', granted: ready, required: false },
321
- { scope: 'console.unlock', mode: 'write', description: 'Prepare and consume a provider-local console unlock handle.', granted: ready, required: false },
420
+ { scope: 'console.unlock', mode: 'write', description: 'Use provider-local temporary unlock or explicitly enrolled unattended console recovery.', granted: ready, required: false },
322
421
  ];
323
422
  }
324
423
 
@@ -330,7 +429,7 @@ function desktopProductCapabilities(): AssistantPluginCapability[] {
330
429
  { capabilityId: 'computer.capture.v1', title: 'Computer capture', description: 'Capture authorized desktop state.', scopes: ['desktop.capture'], actions: ['desktop_screenshot'] },
331
430
  { capabilityId: COMPUTER_ELEMENT_OBSERVE_CAPABILITY, title: 'Computer element observation', description: 'Observe exact provider-neutral semantic element snapshots for a Forge-owned target.', scopes: ['desktop.observe'], actions: [DESKTOP_ELEMENT_OBSERVE_ACTION] },
332
431
  { capabilityId: COMPUTER_ELEMENT_ACTION_CAPABILITY, title: 'Computer element action', description: 'Act on exact observed element refs with observation-epoch fencing.', scopes: ['desktop.interact'], actions: [DESKTOP_ELEMENT_ACTION_ACTION] },
333
- { capabilityId: COMPUTER_CONSOLE_UNLOCK_CAPABILITY, title: 'Protected console unlock', description: 'Collect console credential material only inside the native provider and consume an opaque one-shot handle without durable replay state.', scopes: ['console.unlock'], actions: [COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION, COMPUTER_CONSOLE_UNLOCK_ACTION] },
432
+ { capabilityId: COMPUTER_CONSOLE_UNLOCK_CAPABILITY, title: 'Protected console unlock', description: 'Keep console credential material provider-local while supporting temporary one-shot unlock and opt-in unattended recovery.', scopes: ['console.unlock'], actions: [COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION, COMPUTER_CONSOLE_UNLOCK_ACTION, COMPUTER_CONSOLE_UNLOCK_ENROLL_ACTION, COMPUTER_CONSOLE_UNLOCK_STATUS_ACTION, COMPUTER_CONSOLE_UNLOCK_RECOVER_ACTION, COMPUTER_CONSOLE_UNLOCK_REVOKE_ACTION] },
334
433
  ];
335
434
  }
336
435
 
@@ -367,7 +466,6 @@ function buildComputerManifest(
367
466
  sourceOfTruth: [
368
467
  ...browser.authority.sourceOfTruth,
369
468
  'controllerHome:sqlite/computer_interaction_target',
370
- 'controllerHome:system/plugins/external/registrations/desktop_operator.json',
371
469
  ],
372
470
  },
373
471
  enabled: browser.enabled || desktop?.enabled === true,
@@ -384,15 +482,20 @@ function buildComputerManifest(
384
482
  checkedAt,
385
483
  ready,
386
484
  probed: browser.health.probed || desktop?.health.probed === true,
387
- errors: ready ? [] : [...browser.health.errors, ...(desktopSupported ? (desktop?.health.errors ?? (desktop ? [] : ['Native Computer provider is not installed.'])) : [])],
485
+ errors: ready ? [] : [
486
+ ...browser.health.errors,
487
+ ...(desktopSupported && !desktopReady ? ['Native Computer capabilities are unavailable or not ready.'] : []),
488
+ ],
388
489
  warnings: [
389
490
  ...browser.health.warnings,
390
- ...(desktopSupported ? (desktop?.health.warnings ?? []) : [`Native Desktop Computer capabilities are unsupported on ${platform}.`]),
491
+ ...(desktopSupported
492
+ ? (desktopReady ? [] : ['Native Computer capability diagnostics are available through the internal platform provider.'])
493
+ : [`Native Desktop Computer capabilities are unsupported on ${platform}.`]),
391
494
  ],
392
495
  details: {
393
496
  partial: !ready && partial,
394
497
  browser: { ready: browserReady, state: browser.health.state },
395
- desktop: { supported: desktopSupported, ready: desktopReady, state: desktop?.health.state ?? (desktopSupported ? 'not_installed' : 'unsupported'), provider: DESKTOP_PROVIDER_ID },
498
+ desktop: { supported: desktopSupported, ready: desktopReady, state: desktop?.health.state ?? (desktopSupported ? 'not_installed' : 'unsupported') },
396
499
  },
397
500
  },
398
501
  permissions: [...browser.permissions, ...desktopProductPermissions(desktopReady)],
@@ -618,10 +721,12 @@ async function rebindProviderSession(
618
721
  { retryable: false, details: { targetId: target.targetId, stableIdentity: target.stableIdentity } },
619
722
  );
620
723
  }
724
+ const processId = providerProcessId(rebound);
621
725
  lease.bind({
622
726
  providerId: DESKTOP_PROVIDER_ID,
623
727
  providerSessionId: interactionId,
624
728
  observedAt: new Date().toISOString(),
729
+ ...(processId !== undefined ? { processId } : {}),
625
730
  });
626
731
  return interactionId;
627
732
  }
@@ -638,6 +743,55 @@ async function ensureProviderBinding(
638
743
  return rebindProviderSession(input, lease, provider);
639
744
  }
640
745
 
746
+ function providerProcessId(result: Record<string, unknown>): number | undefined {
747
+ const value = result.pid ?? result.process_id;
748
+ if (value === undefined) return undefined;
749
+ if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0 || value > 2_147_483_647) {
750
+ throw new AssistantPluginError(
751
+ 'PLUGIN_COMPUTER_TARGET_PROCESS_ID_INVALID',
752
+ 'Native Computer provider returned an invalid application process identifier.',
753
+ { retryable: false, details: { processId: value } },
754
+ );
755
+ }
756
+ return value;
757
+ }
758
+
759
+ function explicitLaunchProvenanceFromProviderResult(
760
+ result: Record<string, unknown>,
761
+ processId: number | undefined,
762
+ ): ComputerApplicationLaunchProvenance | undefined {
763
+ const rawOwnership = result.applicationOwnership ?? result.application_ownership;
764
+ const rawOwnedPid = result.ownedProcessIdentifier ?? result.owned_process_identifier;
765
+ if (rawOwnership === undefined && rawOwnedPid === undefined) return undefined;
766
+ if (rawOwnership === 'preexisting' && rawOwnedPid === undefined) return { kind: 'preexisting' };
767
+ if (rawOwnership === 'provider_launched'
768
+ && typeof rawOwnedPid === 'number'
769
+ && Number.isInteger(rawOwnedPid)
770
+ && rawOwnedPid > 0
771
+ && rawOwnedPid <= 2_147_483_647
772
+ && processId === rawOwnedPid) {
773
+ return { kind: 'provider_launched', processId: rawOwnedPid };
774
+ }
775
+ throw new AssistantPluginError(
776
+ 'PLUGIN_COMPUTER_TARGET_LAUNCH_PROVENANCE_INVALID',
777
+ 'Native Computer provider returned inconsistent application launch provenance.',
778
+ { retryable: false, details: { applicationOwnership: rawOwnership, ownedProcessIdentifier: rawOwnedPid, processId } },
779
+ );
780
+ }
781
+
782
+ function inheritedLaunchProvenance(
783
+ controllerHome: string,
784
+ processId: number | undefined,
785
+ ): ComputerApplicationLaunchProvenance | undefined {
786
+ if (processId === undefined) return undefined;
787
+ const owner = computerTargetAuthority.listAllApplications(controllerHome).find((target) =>
788
+ target.launchProvenance?.kind === 'provider_launched'
789
+ && target.launchProvenance.processId === processId
790
+ && target.providerBinding?.processId === processId,
791
+ );
792
+ return owner ? { kind: 'provider_launched', processId } : undefined;
793
+ }
794
+
641
795
  function stableIdentityFromProviderResult(
642
796
  result: Record<string, unknown>,
643
797
  requested: ComputerApplicationStableIdentity,
@@ -689,10 +843,35 @@ async function openDesktopTarget(
689
843
  }
690
844
  throw error;
691
845
  }
846
+ let processId: number | undefined;
847
+ let explicitProvenance: ComputerApplicationLaunchProvenance | undefined;
692
848
  try {
849
+ processId = providerProcessId(opened);
850
+ explicitProvenance = explicitLaunchProvenanceFromProviderResult(opened, processId);
851
+ } catch (error) {
852
+ try {
853
+ await provider.executeAction(providerInput(input, 'desktop_session_close', { interaction_id: interactionId }, 'target-open-provenance-compensate'));
854
+ } catch (cleanupError) {
855
+ throw new AssistantPluginError('PLUGIN_COMPUTER_TARGET_LAUNCH_PROVENANCE_CLEANUP_UNKNOWN', 'Computer target launch provenance was invalid and provider-session cleanup could not be confirmed.', {
856
+ retryable: false,
857
+ details: { cause: error instanceof Error ? error.message : String(error), cleanupCause: cleanupError instanceof Error ? cleanupError.message : String(cleanupError) },
858
+ });
859
+ }
860
+ throw error;
861
+ }
862
+ try {
863
+ const launchProvenance = explicitProvenance?.kind === 'provider_launched'
864
+ ? explicitProvenance
865
+ : inheritedLaunchProvenance(input.controllerHome, processId) ?? explicitProvenance;
693
866
  const target = computerTargetAuthority.create(input.controllerHome, {
694
867
  stableIdentity,
695
- providerBinding: { providerId: DESKTOP_PROVIDER_ID, providerSessionId: interactionId, observedAt: new Date().toISOString() },
868
+ ...(launchProvenance ? { launchProvenance } : {}),
869
+ providerBinding: {
870
+ providerId: DESKTOP_PROVIDER_ID,
871
+ providerSessionId: interactionId,
872
+ observedAt: new Date().toISOString(),
873
+ ...(processId !== undefined ? { processId } : {}),
874
+ },
696
875
  });
697
876
  return {
698
877
  targetId: target.targetId,
@@ -730,7 +909,27 @@ async function closeDesktopTarget(
730
909
  );
731
910
  }
732
911
  if (provider) {
733
- await provider.executeAction(providerInput(input, 'desktop_session_close', { interaction_id: target.providerBinding.providerSessionId }, 'target-close-provider'));
912
+ const activeTargets = computerTargetAuthority.listAllApplications(input.controllerHome);
913
+ const anotherActiveTargetUsesBinding = activeTargets.some((candidate) =>
914
+ candidate.targetId !== target.targetId
915
+ && candidate.providerBinding?.providerId === target.providerBinding?.providerId
916
+ && candidate.providerBinding?.providerSessionId === target.providerBinding?.providerSessionId,
917
+ );
918
+ if (!anotherActiveTargetUsesBinding) {
919
+ const ownedProcessId = target.launchProvenance?.kind === 'provider_launched'
920
+ ? target.launchProvenance.processId
921
+ : undefined;
922
+ const anotherActiveTargetUsesOwnedProcess = ownedProcessId !== undefined
923
+ && activeTargets.some((candidate) =>
924
+ candidate.targetId !== target.targetId && candidate.providerBinding?.processId === ownedProcessId,
925
+ );
926
+ await provider.executeAction(providerInput(input, 'desktop_session_close', {
927
+ interaction_id: target.providerBinding.providerSessionId,
928
+ ...(ownedProcessId !== undefined && !anotherActiveTargetUsesOwnedProcess
929
+ ? { terminate_owned_pid: ownedProcessId }
930
+ : {}),
931
+ }, 'target-close-provider'));
932
+ }
734
933
  }
735
934
  // A missing registration is authoritative absence only because provider uninstall
736
935
  // must stop/remove its native lifecycle before the registration is deleted.
@@ -796,7 +995,7 @@ function targetAuthorization(identity: ComputerApplicationStableIdentity): Assis
796
995
  }
797
996
 
798
997
  async function resolveDesktopAuthorizationContext(input: AssistantPluginActionExecutionInput): Promise<AssistantPluginAuthorizationContext | undefined> {
799
- if (input.actionId === COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION || input.actionId === COMPUTER_CONSOLE_UNLOCK_ACTION) return undefined;
998
+ if ([COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION, COMPUTER_CONSOLE_UNLOCK_ACTION, COMPUTER_CONSOLE_UNLOCK_ENROLL_ACTION, COMPUTER_CONSOLE_UNLOCK_STATUS_ACTION, COMPUTER_CONSOLE_UNLOCK_RECOVER_ACTION, COMPUTER_CONSOLE_UNLOCK_REVOKE_ACTION].includes(input.actionId)) return undefined;
800
999
  if (input.actionId === DESKTOP_TARGET_OPEN_ACTION) return targetAuthorization(stableIdentityFromArgs(input.args));
801
1000
  const targetId = typeof input.args.target_id === 'string' ? input.args.target_id.trim() : '';
802
1001
  if (targetId) return targetAuthorization(computerTargetAuthority.require(input.controllerHome, targetId).stableIdentity);
@@ -819,15 +1018,27 @@ export const computerPluginAdapter: AssistantPluginAdapter = {
819
1018
  return executeBrowserPluginAction({ ...input, pluginId: 'browser' });
820
1019
  }
821
1020
  if (input.actionId === COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION) {
822
- return executeProtectedConsoleUnlockPreparation({ confirmAuthorization: true, timeoutMs: input.timeoutMs }, input.controllerHome);
1021
+ return executeProtectedConsoleUnlockPreparation({ confirmAuthorization: input.confirmAuthorization === true, timeoutMs: input.timeoutMs }, input.controllerHome);
823
1022
  }
824
1023
  if (input.actionId === COMPUTER_CONSOLE_UNLOCK_ACTION) {
825
1024
  return executeProtectedConsoleUnlockInvocation({
826
1025
  credentialHandle: typeof input.args.credential_handle === 'string' ? input.args.credential_handle : '',
827
- confirmAuthorization: true,
1026
+ confirmAuthorization: input.confirmAuthorization === true,
828
1027
  timeoutMs: input.timeoutMs,
829
1028
  }, input.controllerHome);
830
1029
  }
1030
+ if (input.actionId === COMPUTER_CONSOLE_UNLOCK_ENROLL_ACTION) {
1031
+ return executeProtectedConsoleUnlockLifecycle('console_unlock_enroll', { confirmAuthorization: input.confirmAuthorization === true, timeoutMs: input.timeoutMs }, input.controllerHome);
1032
+ }
1033
+ if (input.actionId === COMPUTER_CONSOLE_UNLOCK_STATUS_ACTION) {
1034
+ return executeProtectedConsoleUnlockLifecycle('console_unlock_status', { confirmAuthorization: input.confirmAuthorization === true, timeoutMs: input.timeoutMs }, input.controllerHome);
1035
+ }
1036
+ if (input.actionId === COMPUTER_CONSOLE_UNLOCK_RECOVER_ACTION) {
1037
+ return executeProtectedConsoleUnlockLifecycle('console_unlock_recover', { confirmAuthorization: input.confirmAuthorization === true, timeoutMs: input.timeoutMs }, input.controllerHome);
1038
+ }
1039
+ if (input.actionId === COMPUTER_CONSOLE_UNLOCK_REVOKE_ACTION) {
1040
+ return executeProtectedConsoleUnlockLifecycle('console_unlock_revoke', { confirmAuthorization: input.confirmAuthorization === true, timeoutMs: input.timeoutMs }, input.controllerHome);
1041
+ }
831
1042
  if (input.actionId === DESKTOP_TARGET_CLOSE_ACTION) return closeDesktopTarget(input, optionalDesktopProvider(input));
832
1043
  const provider = desktopProvider(input);
833
1044
  if (input.actionId === DESKTOP_TARGET_OPEN_ACTION) return openDesktopTarget(input, provider);
@@ -178,14 +178,46 @@ async function observeDesktopPointerTarget(
178
178
  return { frame, point, ...(reboundSelector ? { reboundSelector } : {}) };
179
179
  }
180
180
 
181
+ function focusedAxNodes(root: Record<string, unknown> | undefined): Record<string, unknown>[] {
182
+ if (!root) return [];
183
+ const focused: Record<string, unknown>[] = [];
184
+ const visit = (node: Record<string, unknown>): void => {
185
+ if (node.focused === true) focused.push(node);
186
+ for (const child of recordArray(node.children)) visit(child);
187
+ };
188
+ visit(root);
189
+ return focused;
190
+ }
191
+
181
192
  function exactFocusedDesktopWindowId(observation: Record<string, unknown>): number | undefined {
182
193
  const snapshot = recordValue(observation.snapshot);
183
194
  const root = recordValue(snapshot?.root);
184
- const focusedAxWindows = recordArray(root?.children).filter((window) =>
185
- firstString(window, 'role') === 'AXWindow' && window.focused === true);
186
- if (focusedAxWindows.length !== 1) return undefined;
195
+ const axWindows = recordArray(root?.children).filter((window) => firstString(window, 'role') === 'AXWindow');
196
+ const explicitFocused = axWindows.filter((window) => window.focused === true);
197
+ let focusedAxWindow: Record<string, unknown> | undefined;
198
+ if (explicitFocused.length === 1) {
199
+ focusedAxWindow = explicitFocused[0];
200
+ } else if (explicitFocused.length > 1) {
201
+ return undefined;
202
+ } else {
203
+ // Chromium-family apps can expose the system-frontmost window with
204
+ // AXWindow.focused=false while a descendant/control in that window is the
205
+ // unique focused AX node. Recover the same window only from unique bounded
206
+ // geometry; any ambiguity still fails closed.
207
+ const focusedNodes = focusedAxNodes(root).filter((node) => firstString(node, 'role') !== 'AXApplication');
208
+ if (focusedNodes.length !== 1) return undefined;
209
+ const focusedFrame = desktopFrame(focusedNodes[0]?.frame);
210
+ if (!focusedFrame) return undefined;
211
+ const point = desktopFrameCenter(focusedFrame);
212
+ const containingWindows = axWindows.filter((window) => {
213
+ const frame = desktopFrame(window.frame);
214
+ return Boolean(frame && frameContainsPoint(frame, point.x, point.y));
215
+ });
216
+ if (containingWindows.length !== 1) return undefined;
217
+ focusedAxWindow = containingWindows[0];
218
+ }
187
219
 
188
- const focusedTitle = firstString(focusedAxWindows[0]!, 'title');
220
+ const focusedTitle = firstString(focusedAxWindow, 'title');
189
221
  if (!focusedTitle) return undefined;
190
222
  const matches = recordArray(observation.windows).filter((window) => {
191
223
  const windowId = firstNumber(window, 'windowId', 'window_id');
@@ -9,7 +9,7 @@ import {
9
9
  import type { ExternalPluginRegistrationInput } from './external-registration';
10
10
  import type { AssistantPluginActionDescriptor } from './types';
11
11
 
12
- const CONTROLLER_WRITE = [{ resource: 'repo-state' as const, mode: 'write' as const }];
12
+ const CONTROLLER_WRITE = [{ resource: 'provider-state' as const, mode: 'write' as const }];
13
13
  const SELECTOR_SCHEMA = {
14
14
  type: 'object',
15
15
  properties: {
@@ -436,10 +436,10 @@ export function desktopOperatorActions(): AssistantPluginActionDescriptor[] {
436
436
  {
437
437
  actionId: 'desktop_session_close',
438
438
  title: 'Close desktop session',
439
- description: 'Close one Desktop Operator interaction session without terminating the target application.',
439
+ description: 'Close one Desktop Operator interaction session. Application termination is disabled by default and requires an exact Controller-owned process id.',
440
440
  readOnly: false,
441
441
  risk: 'workspace_write',
442
- confirmation: 'none',
442
+ confirmation: 'authorization',
443
443
  defaultTimeoutMs: 5_000,
444
444
  cancellable: true,
445
445
  idempotent: true,
@@ -447,7 +447,15 @@ export function desktopOperatorActions(): AssistantPluginActionDescriptor[] {
447
447
  resourceClaims: CONTROLLER_WRITE,
448
448
  argumentsSchema: {
449
449
  type: 'object',
450
- properties: { interaction_id: { type: 'string' } },
450
+ properties: {
451
+ interaction_id: { type: 'string' },
452
+ terminate_owned_pid: {
453
+ type: 'integer',
454
+ minimum: 1,
455
+ maximum: 2_147_483_647,
456
+ description: 'Exact provider-launched process id that the durable Computer target authority has decided is no longer used by another active target.',
457
+ },
458
+ },
451
459
  required: ['interaction_id'],
452
460
  additionalProperties: false,
453
461
  },
@@ -1,5 +1,5 @@
1
1
  import { AssistantPluginError } from './errors';
2
- import { getExternalPluginRegistration, listExternalPluginRegistrations, type ExternalPluginRegistration } from './external-registration';
2
+ import { externalPluginRegistrationSetIdentity, listExternalPluginRegistrations, type ExternalPluginRegistration } from './external-registration';
3
3
  import { callExternalUnixSocket, probeExternalUnixSocketSync, type ExternalUnixSocketCallOptions } from './external-unix-socket';
4
4
  import { executeManagedPluginProcess, executeManagedPluginProcessSync, type ManagedPluginProcessSpec } from './managed-process-adapter';
5
5
  import { activateAndVerifyFrontmostApplication, restartVerifiedUserLaunchAgent, startVerifiedUserLaunchAgent, stopVerifiedUserLaunchAgent } from './local-system-adapter';
@@ -149,6 +149,17 @@ function managedSpec(registration: ExternalPluginRegistration): ManagedPluginPro
149
149
  };
150
150
  }
151
151
 
152
+ function providerActionTimeoutMs(
153
+ registration: ExternalPluginRegistration,
154
+ actionId: string,
155
+ explicitTimeoutMs: number | undefined,
156
+ ): number | undefined {
157
+ if (explicitTimeoutMs !== undefined) return explicitTimeoutMs;
158
+ if (actionId === 'manifest' || actionId === 'health') return registration.transport.healthTimeoutMs;
159
+ return registration.actions.find((action) => action.actionId === actionId)?.defaultTimeoutMs
160
+ ?? registration.transport.actionTimeoutMs;
161
+ }
162
+
152
163
  function probeProvider(
153
164
  registration: ExternalPluginRegistration,
154
165
  requestId: string,
@@ -185,15 +196,17 @@ async function callProvider(
185
196
  requestId,
186
197
  method: isProviderMethod ? actionId : 'execute',
187
198
  params: isProviderMethod ? undefined : { action: actionId, arguments: args },
188
- timeoutMs: timeoutMs ?? (isProviderMethod ? registration.transport.healthTimeoutMs : registration.transport.actionTimeoutMs),
199
+ timeoutMs: providerActionTimeoutMs(registration, actionId, timeoutMs),
189
200
  signal,
190
201
  }));
191
202
  }
203
+ const descriptor = registration.actions.find((action) => action.actionId === actionId);
192
204
  return await (dependencies.managedCall ?? executeManagedPluginProcess)(managedSpec(registration), {
193
205
  requestId,
194
206
  actionId,
195
207
  input: args,
196
- timeoutMs: timeoutMs ?? (actionId === 'manifest' || actionId === 'health' ? registration.transport.healthTimeoutMs : registration.transport.actionTimeoutMs),
208
+ timeoutMs: providerActionTimeoutMs(registration, actionId, timeoutMs),
209
+ effectOutcomeOnTimeout: descriptor && !descriptor.readOnly ? 'outcome_unknown' : 'failed',
197
210
  signal,
198
211
  });
199
212
  }
@@ -256,13 +269,36 @@ function externalProviderPolicyContext(
256
269
  };
257
270
  }
258
271
 
272
+ interface ExternalPluginAdapterSnapshot {
273
+ registrationSetIdentity: string;
274
+ adapters: readonly AssistantPluginAdapter[];
275
+ byPluginId: ReadonlyMap<string, AssistantPluginAdapter>;
276
+ }
277
+
278
+ const externalPluginAdapterSnapshots = new Map<string, ExternalPluginAdapterSnapshot>();
279
+
280
+ function externalPluginAdapterSnapshot(controllerHome: string): ExternalPluginAdapterSnapshot {
281
+ const registrationSetIdentity = externalPluginRegistrationSetIdentity(controllerHome);
282
+ const cached = externalPluginAdapterSnapshots.get(controllerHome);
283
+ if (cached?.registrationSetIdentity === registrationSetIdentity) return cached;
284
+
285
+ const adapters = listExternalPluginRegistrations(controllerHome)
286
+ .map((registration) => createExternalPluginAdapter(registration));
287
+ const snapshot: ExternalPluginAdapterSnapshot = {
288
+ registrationSetIdentity,
289
+ adapters,
290
+ byPluginId: new Map(adapters.map((adapter) => [adapter.pluginId, adapter])),
291
+ };
292
+ externalPluginAdapterSnapshots.set(controllerHome, snapshot);
293
+ return snapshot;
294
+ }
295
+
259
296
  export function getExternalPluginAdapter(controllerHome: string, pluginId: string): AssistantPluginAdapter | undefined {
260
- const registration = getExternalPluginRegistration(controllerHome, pluginId);
261
- return registration ? createExternalPluginAdapter(registration) : undefined;
297
+ return externalPluginAdapterSnapshot(controllerHome).byPluginId.get(pluginId);
262
298
  }
263
299
 
264
300
  export function listExternalPluginAdapters(controllerHome: string): AssistantPluginAdapter[] {
265
- return listExternalPluginRegistrations(controllerHome).map((registration) => createExternalPluginAdapter(registration));
301
+ return [...externalPluginAdapterSnapshot(controllerHome).adapters];
266
302
  }
267
303
 
268
304
  export function createExternalPluginAdapter(
@@ -1,5 +1,5 @@
1
1
  import { createHash } from 'crypto';
2
- import { existsSync, mkdirSync, readdirSync, rmSync } from 'fs';
2
+ import { existsSync, mkdirSync, readdirSync, rmSync, statSync } from 'fs';
3
3
  import { isAbsolute, join } from 'path';
4
4
  import { controllerSystemRoot, ensureControllerHome } from '../../cli/repositories/controller-home';
5
5
  import { readJsonFile, sanitizeFileComponent, writeJsonAtomic } from '../shared/json-files';
@@ -98,6 +98,26 @@ export function externalPluginRegistrationPath(controllerHome: string, pluginId:
98
98
  return join(registrationRoot(controllerHome), `${sanitizeFileComponent(pluginId)}.json`);
99
99
  }
100
100
 
101
+ export function externalPluginRegistrationSetIdentity(controllerHome: string): string {
102
+ const root = registrationRoot(controllerHome);
103
+ if (!existsSync(root)) return 'absent';
104
+ const names = readdirSync(root, { withFileTypes: true })
105
+ .filter((entry) => entry.isFile() && entry.name.endsWith('.json'))
106
+ .map((entry) => entry.name)
107
+ .sort((left, right) => left.localeCompare(right));
108
+ return names.map((name) => {
109
+ const path = join(root, name);
110
+ try {
111
+ const stat = statSync(path, { bigint: true });
112
+ return `${name}:${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
113
+ } catch {
114
+ // A concurrent registration replacement/removal is itself an identity
115
+ // change. Do not reuse the prior adapter snapshot across that race.
116
+ return `${name}:changed`;
117
+ }
118
+ }).join('|');
119
+ }
120
+
101
121
  function boundedInteger(value: number | undefined, fallback: number, min: number, max: number): number {
102
122
  if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;
103
123
  return Math.min(Math.max(Math.trunc(value), min), max);
@@ -7,6 +7,7 @@ import type {
7
7
  AssistantPluginPermissionScope,
8
8
  } from './types';
9
9
  import { AssistantPluginError } from './errors';
10
+ import { importStoredGoogleClientSecretFromClipboard } from '../safe-tooling/google-credential-store';
10
11
  import {
11
12
  type GmailPluginConfig,
12
13
  encodeBase64Url,
@@ -127,6 +128,24 @@ function gmailActions(): AssistantPluginActionDescriptor[] {
127
128
  additionalProperties: false,
128
129
  },
129
130
  },
131
+ {
132
+ actionId: 'import_oauth_client_secret_from_clipboard',
133
+ title: 'Import Gmail OAuth client secret',
134
+ description: 'Consume the current macOS clipboard once, store the OAuth client secret in Keychain, clear the clipboard, and never return credential material.',
135
+ readOnly: false,
136
+ risk: 'workspace_write',
137
+ confirmation: 'authorization',
138
+ defaultTimeoutMs: 10_000,
139
+ cancellable: false,
140
+ idempotent: false,
141
+ scopes: ['gmail.readonly'],
142
+ resourceClaims: [{ resource: 'provider-state', mode: 'write' }],
143
+ argumentsSchema: {
144
+ type: 'object',
145
+ properties: {},
146
+ additionalProperties: false,
147
+ },
148
+ },
130
149
  {
131
150
  actionId: 'list_messages',
132
151
  title: 'List Gmail messages',
@@ -668,7 +687,7 @@ function gmailProvider(config: GmailPluginConfig, repoRoot?: string): GmailProvi
668
687
  export function buildGmailPluginManifest(previousRevision = 0, previousUpdatedAt?: string, repoRoot?: string, context?: AssistantPluginBuildContext): AssistantPluginManifest {
669
688
  const root = repoRoot ?? process.cwd();
670
689
  const config = loadGmailPluginConfig(root, context);
671
- const auth = resolveGoogleAuth('gmail', config, { repoRoot: root });
690
+ const auth = resolveGoogleAuth('gmail', config, { repoRoot: root, controllerHome: context?.controllerHome });
672
691
  const state = pluginStateFromGoogleAuth(config, auth);
673
692
  return {
674
693
  schemaVersion: 1,
@@ -714,9 +733,11 @@ export async function executeGmailPluginAction(input: AssistantPluginActionExecu
714
733
  });
715
734
  return {
716
735
  config,
717
- auth: resolveGoogleAuth('gmail', config, { repoRoot: input.repoRoot }),
736
+ auth: resolveGoogleAuth('gmail', config, { repoRoot: input.repoRoot, controllerHome: input.controllerHome }),
718
737
  };
719
738
  }
739
+ case 'import_oauth_client_secret_from_clipboard':
740
+ return importStoredGoogleClientSecretFromClipboard('gmail');
720
741
  case 'list_messages':
721
742
  return gmailProvider(current, input.repoRoot).listMessages(input.args, current);
722
743
  case 'get_message':
@@ -394,7 +394,7 @@ function calendarProvider(config: GoogleCalendarPluginConfig, repoRoot?: string)
394
394
  export function buildGoogleCalendarPluginManifest(previousRevision = 0, previousUpdatedAt?: string, repoRoot?: string, context?: AssistantPluginBuildContext): AssistantPluginManifest {
395
395
  const root = repoRoot ?? process.cwd();
396
396
  const config = loadGoogleCalendarPluginConfig(root, context);
397
- const auth = resolveGoogleAuth('calendar', config, { repoRoot: root });
397
+ const auth = resolveGoogleAuth('calendar', config, { repoRoot: root, controllerHome: context?.controllerHome });
398
398
  const state = pluginStateFromGoogleAuth(config, auth);
399
399
  return {
400
400
  schemaVersion: 1,
@@ -441,7 +441,7 @@ export async function executeGoogleCalendarPluginAction(input: AssistantPluginAc
441
441
  });
442
442
  return {
443
443
  config,
444
- auth: resolveGoogleAuth('calendar', config, { repoRoot: input.repoRoot }),
444
+ auth: resolveGoogleAuth('calendar', config, { repoRoot: input.repoRoot, controllerHome: input.controllerHome }),
445
445
  };
446
446
  }
447
447
  case 'list_events':