@moretea-labs/forge 1.5.0-rc.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 (903) hide show
  1. package/AGENTS.md +120 -0
  2. package/CHANGELOG.md +36 -0
  3. package/CLAUDE.md +120 -0
  4. package/CODE_OF_CONDUCT.md +23 -0
  5. package/CONTRIBUTING.md +77 -0
  6. package/LICENSE +22 -0
  7. package/NOTICE +9 -0
  8. package/README.en.md +5 -0
  9. package/README.es.md +12 -0
  10. package/README.fr.md +12 -0
  11. package/README.ja.md +12 -0
  12. package/README.md +132 -0
  13. package/README.zh-CN.md +84 -0
  14. package/SECURITY.md +50 -0
  15. package/SKILL.md +431 -0
  16. package/SUPPORT.md +31 -0
  17. package/THIRD_PARTY_NOTICES.md +18 -0
  18. package/agents/openai.yaml +4 -0
  19. package/assets/AGENTS.md +68 -0
  20. package/assets/CLAUDE.md +68 -0
  21. package/assets/branding/README.md +10 -0
  22. package/assets/branding/forge-controller-flow.mmd +8 -0
  23. package/assets/hooks/AGENTS.md +75 -0
  24. package/assets/hooks/CLAUDE.md +75 -0
  25. package/assets/hooks/anti-simplification.sh +12 -0
  26. package/assets/hooks/changelog-guard.sh +80 -0
  27. package/assets/hooks/codex.hooks.template.json +60 -0
  28. package/assets/hooks/first-principles-guard.sh +72 -0
  29. package/assets/hooks/hook-input.sh +618 -0
  30. package/assets/hooks/lib/session-state.sh +106 -0
  31. package/assets/hooks/lib/workflow-state.sh +1730 -0
  32. package/assets/hooks/post-bash.sh +215 -0
  33. package/assets/hooks/post-edit-guard.sh +256 -0
  34. package/assets/hooks/post-tool-observer.sh +99 -0
  35. package/assets/hooks/pre-edit-guard.sh +240 -0
  36. package/assets/hooks/prompt-guard.sh +1077 -0
  37. package/assets/hooks/run-hook.sh +67 -0
  38. package/assets/hooks/security-sentinel.sh +115 -0
  39. package/assets/hooks/session-start-context.sh +593 -0
  40. package/assets/hooks/settings.template.json +60 -0
  41. package/assets/hooks/stop-orchestrator.sh +171 -0
  42. package/assets/hooks/subagent-return-channel-guard.sh +107 -0
  43. package/assets/hooks/worktree-guard.sh +39 -0
  44. package/assets/initializer-question-pack.v1.json +132 -0
  45. package/assets/initializer-question-pack.v1.schema.json +46 -0
  46. package/assets/initializer-question-pack.v2.json +174 -0
  47. package/assets/initializer-question-pack.v3.json +206 -0
  48. package/assets/initializer-question-pack.v3.schema.json +92 -0
  49. package/assets/initializer-question-pack.v4.json +557 -0
  50. package/assets/initializer-question-pack.v4.schema.json +169 -0
  51. package/assets/partials/01-header.partial.md +10 -0
  52. package/assets/partials/02-iron-rules.partial.md +30 -0
  53. package/assets/partials/03-philosophy.partial.md +32 -0
  54. package/assets/partials/04-project-structure.partial.md +56 -0
  55. package/assets/partials/05-workflow.partial.md +79 -0
  56. package/assets/partials/06-cloudflare.partial.md +20 -0
  57. package/assets/partials/07-footer.partial.md +38 -0
  58. package/assets/partials/08-orchestration.partial.md +49 -0
  59. package/assets/partials/09-compact-instructions.partial.md +11 -0
  60. package/assets/partials/_assembly-order.md +40 -0
  61. package/assets/partials-agents/01-header.partial.md +8 -0
  62. package/assets/partials-agents/02-operating-mode.partial.md +44 -0
  63. package/assets/partials-agents/03-orchestration.partial.md +45 -0
  64. package/assets/partials-agents/04-task-protocol.partial.md +69 -0
  65. package/assets/partials-agents/05-coding-constraints.partial.md +20 -0
  66. package/assets/partials-agents/06-quality-safety.partial.md +23 -0
  67. package/assets/partials-agents/07-cloudflare.partial.md +9 -0
  68. package/assets/partials-agents/08-deep-docs.partial.md +32 -0
  69. package/assets/plan-map.json +301 -0
  70. package/assets/plugin-registry.v1.json +8 -0
  71. package/assets/project-structures/ai-native-collaborative-editor.txt +25 -0
  72. package/assets/project-structures/ai-native-product-copilot.txt +21 -0
  73. package/assets/project-structures/ai-native-runtime-console.txt +25 -0
  74. package/assets/project-structures/ai-native-sidecar-kernel.txt +19 -0
  75. package/assets/project-structures/astro-ssr.txt +25 -0
  76. package/assets/project-structures/expo-nativewind.txt +52 -0
  77. package/assets/project-structures/monorepo.txt +63 -0
  78. package/assets/project-structures/remix.txt +50 -0
  79. package/assets/project-structures/tanstack-start-workers.txt +51 -0
  80. package/assets/project-structures/vite-tanstack.txt +58 -0
  81. package/assets/reference-configs/AGENTS.md +13 -0
  82. package/assets/reference-configs/CLAUDE.md +13 -0
  83. package/assets/reference-configs/agentic-development-flow.md +94 -0
  84. package/assets/reference-configs/ai-workflows.md +14 -0
  85. package/assets/reference-configs/changelog-versioning.md +13 -0
  86. package/assets/reference-configs/coding-standards.md +14 -0
  87. package/assets/reference-configs/development-protocol.md +21 -0
  88. package/assets/reference-configs/document-generation.md +38 -0
  89. package/assets/reference-configs/evaluator-rubric.md +19 -0
  90. package/assets/reference-configs/external-tooling.md +374 -0
  91. package/assets/reference-configs/git-strategy.md +14 -0
  92. package/assets/reference-configs/global-working-rules.md +64 -0
  93. package/assets/reference-configs/handoff-protocol.md +38 -0
  94. package/assets/reference-configs/harness-overview.md +124 -0
  95. package/assets/reference-configs/heartbeat-triage.md +57 -0
  96. package/assets/reference-configs/hook-operations.md +96 -0
  97. package/assets/reference-configs/release-deploy.md +40 -0
  98. package/assets/reference-configs/spa-day-protocol.md +14 -0
  99. package/assets/reference-configs/sprint-contracts.md +89 -0
  100. package/assets/reference-configs/workflow-orchestration.md +14 -0
  101. package/assets/skill-hooks.json +41 -0
  102. package/assets/skill-version.json +189 -0
  103. package/assets/skills/claude-review/SKILL.md +231 -0
  104. package/assets/skills/codex-review/SKILL.md +103 -0
  105. package/assets/templates/AGENTS.md +13 -0
  106. package/assets/templates/CLAUDE.md +13 -0
  107. package/assets/templates/architecture.template.md +80 -0
  108. package/assets/templates/brief.template.md +38 -0
  109. package/assets/templates/contract.template.md +104 -0
  110. package/assets/templates/decisions.template.md +85 -0
  111. package/assets/templates/factor-factory/factor-backtest-report.template.md +36 -0
  112. package/assets/templates/factor-factory/factor-hypothesis.template.md +30 -0
  113. package/assets/templates/factor-factory/factor-registry.template.json +5 -0
  114. package/assets/templates/gitignore.template +53 -0
  115. package/assets/templates/guides/metro-esm-gotchas.template.md +46 -0
  116. package/assets/templates/helpers/architecture-event.ts +822 -0
  117. package/assets/templates/helpers/architecture-queue.sh +647 -0
  118. package/assets/templates/helpers/archive-architecture-request.sh +244 -0
  119. package/assets/templates/helpers/archive-workflow.sh +295 -0
  120. package/assets/templates/helpers/capability-config.ts +394 -0
  121. package/assets/templates/helpers/capability-resolver.ts +505 -0
  122. package/assets/templates/helpers/capture-plan.sh +335 -0
  123. package/assets/templates/helpers/check-agent-tooling.sh +1533 -0
  124. package/assets/templates/helpers/check-architecture-sync.sh +287 -0
  125. package/assets/templates/helpers/check-brain-manifest.sh +255 -0
  126. package/assets/templates/helpers/check-context-files.sh +49 -0
  127. package/assets/templates/helpers/check-deploy-sql-order.sh +117 -0
  128. package/assets/templates/helpers/check-skill-version.ts +193 -0
  129. package/assets/templates/helpers/check-task-sync.sh +65 -0
  130. package/assets/templates/helpers/check-task-workflow.sh +1002 -0
  131. package/assets/templates/helpers/codex-handoff-resume.sh +269 -0
  132. package/assets/templates/helpers/context-contract-sync.sh +516 -0
  133. package/assets/templates/helpers/contract-run.ts +465 -0
  134. package/assets/templates/helpers/contract-worktree.sh +725 -0
  135. package/assets/templates/helpers/ensure-task-workflow.sh +1218 -0
  136. package/assets/templates/helpers/harness-trace-grade.sh +150 -0
  137. package/assets/templates/helpers/heartbeat-triage.sh +361 -0
  138. package/assets/templates/helpers/inspect-project-state.ts +280 -0
  139. package/assets/templates/helpers/maintenance-triage.sh +167 -0
  140. package/assets/templates/helpers/migrate-project-template.sh +54 -0
  141. package/assets/templates/helpers/migrate-workflow-docs.ts +413 -0
  142. package/assets/templates/helpers/new-plan.sh +183 -0
  143. package/assets/templates/helpers/new-spec.sh +50 -0
  144. package/assets/templates/helpers/new-sprint.sh +49 -0
  145. package/assets/templates/helpers/plan-to-todo.sh +799 -0
  146. package/assets/templates/helpers/prepare-codex-handoff.sh +203 -0
  147. package/assets/templates/helpers/prepare-handoff.sh +81 -0
  148. package/assets/templates/helpers/refresh-current-status.sh +469 -0
  149. package/assets/templates/helpers/select-agent-context-blocks.sh +66 -0
  150. package/assets/templates/helpers/ship-worktrees.sh +561 -0
  151. package/assets/templates/helpers/sprint-backlog.sh +837 -0
  152. package/assets/templates/helpers/summarize-failures.sh +125 -0
  153. package/assets/templates/helpers/switch-plan.sh +153 -0
  154. package/assets/templates/helpers/sync-brain-docs.sh +381 -0
  155. package/assets/templates/helpers/verify-contract.sh +705 -0
  156. package/assets/templates/helpers/verify-sprint.sh +680 -0
  157. package/assets/templates/helpers/workflow-contract.ts +202 -0
  158. package/assets/templates/helpers/workstream-sync.sh +263 -0
  159. package/assets/templates/implementation-notes.template.md +37 -0
  160. package/assets/templates/packages.template.md +45 -0
  161. package/assets/templates/plan.template.md +77 -0
  162. package/assets/templates/prd.template.md +165 -0
  163. package/assets/templates/research.template.md +25 -0
  164. package/assets/templates/review.template.md +78 -0
  165. package/assets/templates/spec.template.md +31 -0
  166. package/assets/templates/sprint.template.md +69 -0
  167. package/assets/templates/tech-stack.template.md +57 -0
  168. package/assets/versions.json +77 -0
  169. package/assets/workflow-contract.v1.json +671 -0
  170. package/bin/forge-desktop-helper.mjs +204 -0
  171. package/bin/forge-hook.mjs +32 -0
  172. package/bin/forge-runtime-service.mjs +34 -0
  173. package/bin/forge-runtime.mjs +30 -0
  174. package/bin/forge.mjs +32 -0
  175. package/docs/CHANGELOG.md +978 -0
  176. package/docs/README.md +72 -0
  177. package/docs/README.zh-CN.md +58 -0
  178. package/docs/architecture/chatgpt-handoff-facade.md +393 -0
  179. package/docs/architecture/current/README.md +158 -0
  180. package/docs/architecture/current/approved-target-architecture.zh-CN.md +1501 -0
  181. package/docs/architecture/current/architecture-invariants.md +331 -0
  182. package/docs/architecture/current/automation-and-schedule-engine.md +453 -0
  183. package/docs/architecture/current/codegraph-context-provider.md +226 -0
  184. package/docs/architecture/current/control-plane-authority-inventory.md +82 -0
  185. package/docs/architecture/current/controller-repository-decoupling.md +148 -0
  186. package/docs/architecture/current/dispatch-and-agent-strategy.md +354 -0
  187. package/docs/architecture/current/entity-model.md +619 -0
  188. package/docs/architecture/current/external-plugin-governance.md +396 -0
  189. package/docs/architecture/current/failure-recovery.md +471 -0
  190. package/docs/architecture/current/governance.md +213 -0
  191. package/docs/architecture/current/human-interaction-plane.md +87 -0
  192. package/docs/architecture/current/implementation-status.md +128 -0
  193. package/docs/architecture/current/job-and-run-lifecycle.md +413 -0
  194. package/docs/architecture/current/local-workspace-target-grants.md +70 -0
  195. package/docs/architecture/current/migration-roadmap.md +105 -0
  196. package/docs/architecture/current/multi-repository-execution.md +371 -0
  197. package/docs/architecture/current/operations-runbook.md +45 -0
  198. package/docs/architecture/current/peer-supercontroller-runtime.md +32 -0
  199. package/docs/architecture/current/personal-assistant-plugin-baseline.md +207 -0
  200. package/docs/architecture/current/repository-access-modes.md +102 -0
  201. package/docs/architecture/current/route-policy.md +15 -0
  202. package/docs/architecture/current/route-session-concurrency.md +85 -0
  203. package/docs/architecture/current/runtime-architecture-simplification.md +214 -0
  204. package/docs/architecture/current/runtime-directory-map.md +49 -0
  205. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +85 -0
  206. package/docs/architecture/current/scheduler-and-resource-claims.md +432 -0
  207. package/docs/architecture/current/session-aware-execution-and-authorization.md +77 -0
  208. package/docs/architecture/current/system-overview.md +144 -0
  209. package/docs/architecture/current/target-requirements-traceability.md +202 -0
  210. package/docs/architecture/current/thin-harness-governance-policy.md +32 -0
  211. package/docs/architecture/current/thin-harness-v1.md +313 -0
  212. package/docs/architecture/current/verification-and-release-gates.md +391 -0
  213. package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +100 -0
  214. package/docs/architecture/decisions/20260803-canonical-skill-surface.md +40 -0
  215. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +53 -0
  216. package/docs/architecture/diagrams/.gitkeep +1 -0
  217. package/docs/architecture/diagrams/agentic-dev-plugin-architecture.html +186 -0
  218. package/docs/architecture/domains/.gitkeep +0 -0
  219. package/docs/architecture/domains/public-surface.md +30 -0
  220. package/docs/architecture/domains/runtime-harness.md +33 -0
  221. package/docs/architecture/domains/verification.md +33 -0
  222. package/docs/architecture/domains/workflow-engine.md +30 -0
  223. package/docs/architecture/global-hook-runtime.md +162 -0
  224. package/docs/architecture/history.md +38 -0
  225. package/docs/architecture/index.md +114 -0
  226. package/docs/architecture/ios-semantic-automation-provider-v2.md +166 -0
  227. package/docs/architecture/modules/.gitkeep +0 -0
  228. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +24 -0
  229. package/docs/architecture/requests/.gitkeep +1 -0
  230. package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +59 -0
  231. package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +59 -0
  232. package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +59 -0
  233. package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +59 -0
  234. package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +59 -0
  235. package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +59 -0
  236. package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +59 -0
  237. package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +59 -0
  238. package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +59 -0
  239. package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +59 -0
  240. package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +59 -0
  241. package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +59 -0
  242. package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +59 -0
  243. package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +59 -0
  244. package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +59 -0
  245. package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +59 -0
  246. package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +59 -0
  247. package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +59 -0
  248. package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +59 -0
  249. package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +59 -0
  250. package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +59 -0
  251. package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +63 -0
  252. package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +60 -0
  253. package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +60 -0
  254. package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +60 -0
  255. package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +60 -0
  256. package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +60 -0
  257. package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +60 -0
  258. package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +68 -0
  259. package/docs/architecture/requests/archive/2026/root.md +68 -0
  260. package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +76 -0
  261. package/docs/architecture/requests/archive/2026/verification-evals-checks.md +68 -0
  262. package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +69 -0
  263. package/docs/architecture/reviews/2026-07-11-access-surface-review.md +99 -0
  264. package/docs/architecture/snapshots/.gitkeep +1 -0
  265. package/docs/forge-autonomous-goal-loop.md +7 -0
  266. package/docs/forge-chatgpt-browser-engine.md +11 -0
  267. package/docs/forge-chatgpt-mcp-setup.md +239 -0
  268. package/docs/forge-chatgpt-supervised-automation.md +11 -0
  269. package/docs/forge-github-issue-launcher.md +7 -0
  270. package/docs/forge-plugin-management.md +95 -0
  271. package/docs/forge-provider-configuration.md +7 -0
  272. package/docs/forge-runtime-self-healing-loop.md +7 -0
  273. package/docs/images/forge-banner-cn.svg +1 -0
  274. package/docs/images/forge-banner.svg +1 -0
  275. package/docs/images/forge-controller-flow.svg +1 -0
  276. package/docs/images/image.png +0 -0
  277. package/docs/images/repo-harness-gptpro-cn.png +0 -0
  278. package/docs/images/repo-harness-gptpro.png +0 -0
  279. package/docs/images/repo-harness-hook-carrot.png +0 -0
  280. package/docs/operations/chatgpt-personal-assistant-runtime.md +83 -0
  281. package/docs/operations/checkout-route-integrity.md +22 -0
  282. package/docs/operations/controller-browser-plugin.md +299 -0
  283. package/docs/operations/controller-desktop-plugin.md +112 -0
  284. package/docs/operations/controller-performance-and-502.md +126 -0
  285. package/docs/operations/controller-reliability-runbook.md +134 -0
  286. package/docs/operations/environment-hardening.md +50 -0
  287. package/docs/operations/features.md +45 -0
  288. package/docs/operations/features.zh-CN.md +45 -0
  289. package/docs/operations/github-repository.md +60 -0
  290. package/docs/operations/gmail-assistant-routines.md +186 -0
  291. package/docs/operations/homebrew.md +26 -0
  292. package/docs/operations/local-system-assistant.md +46 -0
  293. package/docs/operations/local-system-assistant.zh-CN.md +46 -0
  294. package/docs/operations/mcp-tool-exposure.md +58 -0
  295. package/docs/operations/mobile-intents-shortcuts.md +117 -0
  296. package/docs/operations/open-source-release-hygiene.md +31 -0
  297. package/docs/operations/personal-assistant-operator-guide.md +61 -0
  298. package/docs/operations/platform-support.md +62 -0
  299. package/docs/operations/platform-support.zh-CN.md +61 -0
  300. package/docs/operations/provider-configuration.md +31 -0
  301. package/docs/operations/releasing.md +86 -0
  302. package/docs/operations/releasing.zh-CN.md +86 -0
  303. package/docs/operations/route-session-concurrency-baseline.json +893 -0
  304. package/docs/operations/route-session-concurrency-baseline.md +94 -0
  305. package/docs/operations/runtime-performance-diagnostics.md +14 -0
  306. package/docs/operations/sqlite-control-plane-recovery.md +65 -0
  307. package/docs/operations/standalone-disaster-recovery.md +136 -0
  308. package/docs/operations/troubleshooting.md +72 -0
  309. package/docs/operations/troubleshooting.zh-CN.md +70 -0
  310. package/docs/public-usage-guide.md +33 -0
  311. package/docs/public-usage-guide.zh-CN.md +33 -0
  312. package/docs/tutorials/01-install-and-start.md +93 -0
  313. package/docs/tutorials/01-install-and-start.zh-CN.md +93 -0
  314. package/docs/tutorials/02-connect-chatgpt.md +82 -0
  315. package/docs/tutorials/02-connect-chatgpt.zh-CN.md +80 -0
  316. package/docs/tutorials/03-first-repository-task.md +57 -0
  317. package/docs/tutorials/03-first-repository-task.zh-CN.md +57 -0
  318. package/docs/tutorials/README.md +13 -0
  319. package/docs/tutorials/README.zh-CN.md +13 -0
  320. package/docs/wiki/Architecture.md +85 -0
  321. package/docs/wiki/Core-Concepts.md +27 -0
  322. package/docs/wiki/Home.md +36 -0
  323. package/docs/wiki/Implementation.md +172 -0
  324. package/docs/wiki/Installation.md +50 -0
  325. package/docs/wiki/Integrations.md +29 -0
  326. package/docs/wiki/Operations.md +26 -0
  327. package/docs/wiki/Quick-Start.md +46 -0
  328. package/docs/wiki/Releases-and-Upgrades.md +34 -0
  329. package/docs/wiki/Runtime-Architecture.md +50 -0
  330. package/docs/wiki/Security-Model.md +31 -0
  331. package/docs/wiki/Troubleshooting.md +38 -0
  332. package/docs/wiki/Work-Lifecycle.md +31 -0
  333. package/docs/wiki/_Sidebar.md +21 -0
  334. package/install.ps1 +48 -0
  335. package/install.sh +66 -0
  336. package/package.json +156 -0
  337. package/scripts/activate-source-baseline.ts +335 -0
  338. package/scripts/architecture-event.ts +822 -0
  339. package/scripts/architecture-queue.sh +647 -0
  340. package/scripts/archive-architecture-request.sh +244 -0
  341. package/scripts/archive-workflow.sh +295 -0
  342. package/scripts/assemble-template.ts +1172 -0
  343. package/scripts/benchmark-controller-hotpath.ts +212 -0
  344. package/scripts/benchmark-controller-round2.ts +139 -0
  345. package/scripts/benchmark-ios-agent-device.ts +514 -0
  346. package/scripts/benchmark-route-session-concurrency.ts +714 -0
  347. package/scripts/benchmark-thin-harness-gateway-ab.ts +632 -0
  348. package/scripts/benchmark-thin-harness-mcp-e2e.ts +479 -0
  349. package/scripts/benchmark-thin-harness.ts +251 -0
  350. package/scripts/bootstrap-runtime-maintenance-recovery.sh +183 -0
  351. package/scripts/canary-global-hook.sh +263 -0
  352. package/scripts/capability-config.ts +394 -0
  353. package/scripts/capability-resolver.ts +505 -0
  354. package/scripts/capture-plan.sh +335 -0
  355. package/scripts/check-agent-tooling.sh +1549 -0
  356. package/scripts/check-architecture-sync.sh +373 -0
  357. package/scripts/check-brain-manifest.sh +255 -0
  358. package/scripts/check-ci.sh +16 -0
  359. package/scripts/check-context-files.sh +49 -0
  360. package/scripts/check-deploy-sql-order.sh +117 -0
  361. package/scripts/check-mcp-compatibility.ts +93 -0
  362. package/scripts/check-npm-release.sh +32 -0
  363. package/scripts/check-open-source-tracked-surface.sh +146 -0
  364. package/scripts/check-package-identity.mjs +117 -0
  365. package/scripts/check-platform-support.mjs +79 -0
  366. package/scripts/check-public-docs.sh +105 -0
  367. package/scripts/check-public-release-surface.sh +19 -0
  368. package/scripts/check-release-published.sh +57 -0
  369. package/scripts/check-release-readiness.sh +43 -0
  370. package/scripts/check-release-version.mjs +74 -0
  371. package/scripts/check-runtime-architecture.mjs +593 -0
  372. package/scripts/check-runtime-env.mjs +89 -0
  373. package/scripts/check-skill-version.ts +193 -0
  374. package/scripts/check-tarball-install-smoke.sh +66 -0
  375. package/scripts/check-task-sync.sh +65 -0
  376. package/scripts/check-task-workflow.sh +1002 -0
  377. package/scripts/check-third-party-notices.mjs +36 -0
  378. package/scripts/codex-handoff-resume.sh +269 -0
  379. package/scripts/complete-control-plane-cutover.ts +126 -0
  380. package/scripts/context-contract-sync.sh +516 -0
  381. package/scripts/contract-run.ts +465 -0
  382. package/scripts/contract-worktree.sh +725 -0
  383. package/scripts/controller-ngrok-rotation.sh +678 -0
  384. package/scripts/create-project-dirs.sh +282 -0
  385. package/scripts/ensure-codegraph.sh +16 -0
  386. package/scripts/ensure-task-workflow.sh +1218 -0
  387. package/scripts/export-requirement-portfolio.ts +28 -0
  388. package/scripts/factor-lab-check.sh +73 -0
  389. package/scripts/factor-lab-new.sh +96 -0
  390. package/scripts/factor-lab-promote.sh +86 -0
  391. package/scripts/factor-lab-reject.sh +68 -0
  392. package/scripts/harness-trace-grade.sh +150 -0
  393. package/scripts/heartbeat-triage.sh +361 -0
  394. package/scripts/hook-dispatch-diet-report.ts +234 -0
  395. package/scripts/hook-shim.sh +93 -0
  396. package/scripts/init-project.sh +505 -0
  397. package/scripts/initializer-question-pack.ts +200 -0
  398. package/scripts/inspect-project-state.ts +280 -0
  399. package/scripts/install-desktop-operator-registration.ts +45 -0
  400. package/scripts/install-standalone-recovery.ts +74 -0
  401. package/scripts/lib/AGENTS.md +13 -0
  402. package/scripts/lib/CLAUDE.md +13 -0
  403. package/scripts/lib/controller-home-env.sh +69 -0
  404. package/scripts/lib/project-init-lib.sh +2759 -0
  405. package/scripts/load-standalone-recovery.sh +17 -0
  406. package/scripts/loop-engine-cutover-gate.ts +324 -0
  407. package/scripts/maintenance-triage.sh +167 -0
  408. package/scripts/migrate-project-template.sh +1189 -0
  409. package/scripts/migrate-requirement-portfolio.ts +86 -0
  410. package/scripts/migrate-workflow-docs.ts +413 -0
  411. package/scripts/new-plan.sh +183 -0
  412. package/scripts/new-spec.sh +50 -0
  413. package/scripts/new-sprint.sh +49 -0
  414. package/scripts/open-source-audit-allowlist.txt +46 -0
  415. package/scripts/package-source-archive.sh +147 -0
  416. package/scripts/plan-to-todo.sh +799 -0
  417. package/scripts/prepare-codex-handoff.sh +203 -0
  418. package/scripts/prepare-handoff.sh +81 -0
  419. package/scripts/public-release-files.txt +39 -0
  420. package/scripts/public-release.ts +174 -0
  421. package/scripts/publish-release-tarball.sh +27 -0
  422. package/scripts/refresh-current-status.sh +469 -0
  423. package/scripts/refresh-ios-physical-runtime.ts +196 -0
  424. package/scripts/repair-executable-modes.ts +8 -0
  425. package/scripts/rollout-all-registered-repos.sh +7 -0
  426. package/scripts/route-nl-vs-ts-eval.ts +679 -0
  427. package/scripts/run-bun-test-file.ts +182 -0
  428. package/scripts/run-governed-gate.ts +140 -0
  429. package/scripts/run-mobile-monitor-bridge.ts +71 -0
  430. package/scripts/run-skill-evals.ts +1022 -0
  431. package/scripts/run-skill-hook.ts +244 -0
  432. package/scripts/run-supervised-command.ts +24 -0
  433. package/scripts/run-tests-portable.sh +20 -0
  434. package/scripts/select-agent-context-blocks.sh +66 -0
  435. package/scripts/setup-plugins.sh +43 -0
  436. package/scripts/ship-worktrees.sh +561 -0
  437. package/scripts/smoke-browser-cdp-bridge.ts +93 -0
  438. package/scripts/smoke-chatgpt-supervised-automation.ts +208 -0
  439. package/scripts/smoke-ios-physical-device.ts +114 -0
  440. package/scripts/smoke-mcp-http-runtime.ts +216 -0
  441. package/scripts/smoke-mcp-tool-surface.ts +117 -0
  442. package/scripts/smoke-runtime-recovery.ts +220 -0
  443. package/scripts/smoke-schedule-engine.ts +283 -0
  444. package/scripts/sprint-backlog.sh +837 -0
  445. package/scripts/stage-runtime-release.ts +38 -0
  446. package/scripts/summarize-failures.sh +125 -0
  447. package/scripts/switch-plan.sh +153 -0
  448. package/scripts/sync-brain-docs.sh +381 -0
  449. package/scripts/sync-codex-installed-copies.sh +183 -0
  450. package/scripts/test-governance.ts +75 -0
  451. package/scripts/verify-contract.sh +705 -0
  452. package/scripts/verify-forge-runtime.sh +31 -0
  453. package/scripts/verify-sprint.sh +680 -0
  454. package/scripts/windows-paths.d.mts +7 -0
  455. package/scripts/windows-paths.mjs +28 -0
  456. package/scripts/workflow-contract.ts +206 -0
  457. package/scripts/workstream-sync.sh +263 -0
  458. package/src/cli/agent-jobs/executable-resolver.ts +289 -0
  459. package/src/cli/agent-jobs/executor-health.ts +252 -0
  460. package/src/cli/agent-jobs/integration.ts +963 -0
  461. package/src/cli/agent-jobs/job-manager.ts +2030 -0
  462. package/src/cli/agent-jobs/types.ts +219 -0
  463. package/src/cli/agent-jobs/worker-lifecycle.ts +288 -0
  464. package/src/cli/chatgpt-browser/bind-server.ts +504 -0
  465. package/src/cli/chatgpt-browser/binding.ts +140 -0
  466. package/src/cli/chatgpt-browser/bridge-extension.ts +221 -0
  467. package/src/cli/chatgpt-browser/bridge-provider.ts +268 -0
  468. package/src/cli/chatgpt-browser/engine.ts +569 -0
  469. package/src/cli/chatgpt-browser/file-policy.ts +158 -0
  470. package/src/cli/chatgpt-browser/native-provider.ts +553 -0
  471. package/src/cli/chatgpt-browser/oracle-provider.ts +437 -0
  472. package/src/cli/chatgpt-browser/prompt-assembler.ts +29 -0
  473. package/src/cli/chatgpt-browser/session-store.ts +301 -0
  474. package/src/cli/chatgpt-browser/types.ts +172 -0
  475. package/src/cli/commands/adopt-plan.ts +186 -0
  476. package/src/cli/commands/brain-root.ts +132 -0
  477. package/src/cli/commands/brain.ts +609 -0
  478. package/src/cli/commands/capability-context.ts +613 -0
  479. package/src/cli/commands/chatgpt.ts +424 -0
  480. package/src/cli/commands/controller.ts +680 -0
  481. package/src/cli/commands/docs.ts +103 -0
  482. package/src/cli/commands/doctor.ts +476 -0
  483. package/src/cli/commands/global-runtime.ts +323 -0
  484. package/src/cli/commands/hook.ts +34 -0
  485. package/src/cli/commands/init-hook.ts +870 -0
  486. package/src/cli/commands/init.ts +829 -0
  487. package/src/cli/commands/install.ts +86 -0
  488. package/src/cli/commands/mcp.ts +315 -0
  489. package/src/cli/commands/migrate.ts +154 -0
  490. package/src/cli/commands/plugin.ts +74 -0
  491. package/src/cli/commands/prompt-guard-decision.ts +238 -0
  492. package/src/cli/commands/recovery.ts +667 -0
  493. package/src/cli/commands/repository.ts +224 -0
  494. package/src/cli/commands/run.ts +23 -0
  495. package/src/cli/commands/runtime.ts +191 -0
  496. package/src/cli/commands/security.ts +440 -0
  497. package/src/cli/commands/status.ts +137 -0
  498. package/src/cli/commands/tools.ts +167 -0
  499. package/src/cli/controller/check-runner.ts +1022 -0
  500. package/src/cli/controller/codex-continuation.ts +153 -0
  501. package/src/cli/controller/completion-backlog.ts +380 -0
  502. package/src/cli/controller/completion-orchestrator.ts +1807 -0
  503. package/src/cli/controller/completion-target.ts +96 -0
  504. package/src/cli/controller/composite-operations.ts +196 -0
  505. package/src/cli/controller/composite-result.ts +130 -0
  506. package/src/cli/controller/context-pack.ts +652 -0
  507. package/src/cli/controller/execution-completion.ts +175 -0
  508. package/src/cli/controller/execution-policy.ts +392 -0
  509. package/src/cli/controller/governance.ts +594 -0
  510. package/src/cli/controller/issue-store.ts +1421 -0
  511. package/src/cli/controller/launch-agents.ts +410 -0
  512. package/src/cli/controller/legacy-issue-cutover.ts +415 -0
  513. package/src/cli/controller/lifecycle-authority.ts +16 -0
  514. package/src/cli/controller/migrated-issue-decision.ts +237 -0
  515. package/src/cli/controller/operational-plan.ts +226 -0
  516. package/src/cli/controller/postcondition.ts +134 -0
  517. package/src/cli/controller/progress.ts +656 -0
  518. package/src/cli/controller/project-state.ts +147 -0
  519. package/src/cli/controller/requirement-portfolio-export.ts +146 -0
  520. package/src/cli/controller/requirement-portfolio-migration.ts +613 -0
  521. package/src/cli/controller/run-evidence.ts +43 -0
  522. package/src/cli/controller/runtime-config.ts +92 -0
  523. package/src/cli/controller/stuck-state-migration.ts +396 -0
  524. package/src/cli/controller/task-ledger.ts +632 -0
  525. package/src/cli/controller/task-status-resolver.ts +403 -0
  526. package/src/cli/controller/types.ts +273 -0
  527. package/src/cli/controller/work-mode.ts +186 -0
  528. package/src/cli/controller/worklog.ts +201 -0
  529. package/src/cli/diagnostic-entry.ts +39 -0
  530. package/src/cli/editing/edit-session.ts +1606 -0
  531. package/src/cli/editing/executable-modes.ts +70 -0
  532. package/src/cli/github/github.ts +274 -0
  533. package/src/cli/github/plugin.ts +345 -0
  534. package/src/cli/github/session.ts +104 -0
  535. package/src/cli/hook/prompt-guard-decision.ts +238 -0
  536. package/src/cli/hook/prompt-intents.ts +534 -0
  537. package/src/cli/hook/route-registry.ts +107 -0
  538. package/src/cli/hook/runtime.ts +303 -0
  539. package/src/cli/hook/state-snapshot.ts +388 -0
  540. package/src/cli/hook-entry.ts +51 -0
  541. package/src/cli/index.ts +574 -0
  542. package/src/cli/installer/managed-entries.ts +78 -0
  543. package/src/cli/installer/shared.ts +65 -0
  544. package/src/cli/installer/targets/claude.ts +136 -0
  545. package/src/cli/installer/targets/codex.ts +174 -0
  546. package/src/cli/installer/targets/registry.ts +28 -0
  547. package/src/cli/installer/types.ts +72 -0
  548. package/src/cli/local-bridge/connector-freshness.ts +529 -0
  549. package/src/cli/local-bridge/console-view-models.ts +324 -0
  550. package/src/cli/local-bridge/dashboard.ts +1312 -0
  551. package/src/cli/local-bridge/facade-api.ts +1877 -0
  552. package/src/cli/local-bridge/job-store.ts +1451 -0
  553. package/src/cli/local-bridge/mobile-intents.ts +344 -0
  554. package/src/cli/local-bridge/mobile-monitor.ts +209 -0
  555. package/src/cli/local-bridge/server.ts +3183 -0
  556. package/src/cli/local-bridge/types.ts +176 -0
  557. package/src/cli/mcp/access-mode.ts +132 -0
  558. package/src/cli/mcp/access-tools.ts +387 -0
  559. package/src/cli/mcp/audit.ts +32 -0
  560. package/src/cli/mcp/auth.ts +402 -0
  561. package/src/cli/mcp/instructions.ts +33 -0
  562. package/src/cli/mcp/legacy-context.ts +16 -0
  563. package/src/cli/mcp/legacy-tool-service.ts +5516 -0
  564. package/src/cli/mcp/multi-repository.ts +423 -0
  565. package/src/cli/mcp/oauth.ts +226 -0
  566. package/src/cli/mcp/paths.ts +134 -0
  567. package/src/cli/mcp/policy.ts +230 -0
  568. package/src/cli/mcp/proxy-env.ts +62 -0
  569. package/src/cli/mcp/readiness-projection.ts +24 -0
  570. package/src/cli/mcp/redaction.ts +21 -0
  571. package/src/cli/mcp/repo.ts +24 -0
  572. package/src/cli/mcp/repository-tools.ts +1295 -0
  573. package/src/cli/mcp/server.ts +341 -0
  574. package/src/cli/mcp/setup.ts +793 -0
  575. package/src/cli/mcp/tool-capability-cache.ts +87 -0
  576. package/src/cli/mcp/tools.ts +9 -0
  577. package/src/cli/mcp/toolset-names.ts +70 -0
  578. package/src/cli/mcp/toolset-selection.ts +41 -0
  579. package/src/cli/mcp/toolset.ts +300 -0
  580. package/src/cli/mcp/transports/AGENTS.md +39 -0
  581. package/src/cli/mcp/transports/CLAUDE.md +39 -0
  582. package/src/cli/mcp/transports/http.ts +1234 -0
  583. package/src/cli/mcp/transports/session-registry.ts +428 -0
  584. package/src/cli/mcp/transports/stdio.ts +8 -0
  585. package/src/cli/mcp/types.ts +41 -0
  586. package/src/cli/mcp/umbrella-tools.ts +117 -0
  587. package/src/cli/repo-adoption/reclaim-runtime.ts +681 -0
  588. package/src/cli/repositories/branch-name-policy.ts +57 -0
  589. package/src/cli/repositories/command-classifier.ts +600 -0
  590. package/src/cli/repositories/command-executor.ts +1066 -0
  591. package/src/cli/repositories/command-normalization.ts +53 -0
  592. package/src/cli/repositories/command-scope.ts +264 -0
  593. package/src/cli/repositories/controller-home.ts +88 -0
  594. package/src/cli/repositories/entity-migration.ts +199 -0
  595. package/src/cli/repositories/ephemeral-workspace.ts +62 -0
  596. package/src/cli/repositories/git-command-executor.ts +301 -0
  597. package/src/cli/repositories/goal-registry.ts +239 -0
  598. package/src/cli/repositories/identity.ts +64 -0
  599. package/src/cli/repositories/local-project-onboarding.ts +539 -0
  600. package/src/cli/repositories/locks.ts +262 -0
  601. package/src/cli/repositories/registry.ts +1057 -0
  602. package/src/cli/repositories/runtime-storage.ts +411 -0
  603. package/src/cli/repositories/safe-patch.ts +421 -0
  604. package/src/cli/repositories/selected-path-actions.ts +341 -0
  605. package/src/cli/repositories/structured-git.ts +257 -0
  606. package/src/cli/repositories/types.ts +155 -0
  607. package/src/cli/repositories/umbrella.ts +134 -0
  608. package/src/cli/repositories/workbench.ts +140 -0
  609. package/src/cli/repositories/worktree-storage.ts +137 -0
  610. package/src/cli/repository/inspector.ts +637 -0
  611. package/src/cli/repository/session-cache.ts +453 -0
  612. package/src/cli/runtime/helper-runner.ts +172 -0
  613. package/src/cli/runtime-invocation.ts +318 -0
  614. package/src/cli/tools/codegraph.ts +676 -0
  615. package/src/cli/v81-entry.ts +29 -0
  616. package/src/core/adoption/gitignore-plan.ts +127 -0
  617. package/src/core/adoption/helper-wrapper-plan.ts +159 -0
  618. package/src/core/adoption/manifest-templates.ts +60 -0
  619. package/src/core/adoption/modes.ts +7 -0
  620. package/src/core/adoption/operations.ts +126 -0
  621. package/src/core/adoption/plan.ts +149 -0
  622. package/src/core/adoption/render.ts +70 -0
  623. package/src/core/adoption/rollback.ts +62 -0
  624. package/src/core/adoption/summary.ts +43 -0
  625. package/src/core/adoption/workflow-contract-asset.ts +14 -0
  626. package/src/core/adoption/workflow-contract-plan.ts +31 -0
  627. package/src/effects/fs-transaction.ts +540 -0
  628. package/src/effects/git-executable.ts +59 -0
  629. package/src/effects/managed-block.ts +86 -0
  630. package/src/effects/path-safety.ts +47 -0
  631. package/src/effects/process-runner.ts +192 -0
  632. package/src/runtime/assistant/action-proposals.ts +279 -0
  633. package/src/runtime/assistant/intent.ts +395 -0
  634. package/src/runtime/assistant/model-provider.ts +460 -0
  635. package/src/runtime/assistant/openapi.ts +223 -0
  636. package/src/runtime/assistant/policy.ts +89 -0
  637. package/src/runtime/assistant/readiness.ts +258 -0
  638. package/src/runtime/assistant/routine-runtime.ts +477 -0
  639. package/src/runtime/assistant/schedule-binding.ts +171 -0
  640. package/src/runtime/assistant/standing-grants.ts +375 -0
  641. package/src/runtime/assistant/store.ts +243 -0
  642. package/src/runtime/assistant/types.ts +135 -0
  643. package/src/runtime/context/codegraph-read-provider.ts +347 -0
  644. package/src/runtime/context/codegraph-sidecar.cjs +207 -0
  645. package/src/runtime/control-plane/dispatch-priority.ts +67 -0
  646. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +151 -0
  647. package/src/runtime/control-plane/execution/execution-identity.ts +456 -0
  648. package/src/runtime/control-plane/execution/session-store.ts +175 -0
  649. package/src/runtime/control-plane/execution/validation.ts +117 -0
  650. package/src/runtime/control-plane/execution/verification-evidence.ts +191 -0
  651. package/src/runtime/control-plane/execution/work-handle-store.ts +225 -0
  652. package/src/runtime/control-plane/execution/work-prepare-request-store.ts +159 -0
  653. package/src/runtime/control-plane/execution/work-task-receipt.ts +445 -0
  654. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +821 -0
  655. package/src/runtime/control-plane/facade/capability-registry.ts +279 -0
  656. package/src/runtime/control-plane/facade/check-normalization.ts +233 -0
  657. package/src/runtime/control-plane/facade/codex-delegation.ts +196 -0
  658. package/src/runtime/control-plane/facade/controller-session-store.ts +199 -0
  659. package/src/runtime/control-plane/facade/facade-result.ts +41 -0
  660. package/src/runtime/control-plane/facade/goal-workloop-access.ts +177 -0
  661. package/src/runtime/control-plane/facade/goal-workloop.ts +1216 -0
  662. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +221 -0
  663. package/src/runtime/control-plane/facade/index.ts +16 -0
  664. package/src/runtime/control-plane/facade/operation-digest.ts +528 -0
  665. package/src/runtime/control-plane/facade/plan-contract-store.ts +403 -0
  666. package/src/runtime/control-plane/facade/policy-gate.ts +149 -0
  667. package/src/runtime/control-plane/facade/requirement-board.ts +280 -0
  668. package/src/runtime/control-plane/facade/self-healing-loop.ts +555 -0
  669. package/src/runtime/control-plane/facade/suggested-actions.ts +108 -0
  670. package/src/runtime/control-plane/facade/types.ts +729 -0
  671. package/src/runtime/control-plane/facade/work-admission-policy.ts +93 -0
  672. package/src/runtime/control-plane/facade/work-continuation.ts +104 -0
  673. package/src/runtime/control-plane/facade/work-contract-store.ts +1118 -0
  674. package/src/runtime/control-plane/facade/work-task-projection.ts +66 -0
  675. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +365 -0
  676. package/src/runtime/control-plane/global-scheduler/scheduler.ts +920 -0
  677. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +89 -0
  678. package/src/runtime/control-plane/goal-loop/config-facade.ts +700 -0
  679. package/src/runtime/control-plane/goal-loop/config-store.ts +570 -0
  680. package/src/runtime/control-plane/goal-loop/config-types.ts +213 -0
  681. package/src/runtime/control-plane/goal-loop/executor-router.ts +109 -0
  682. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +149 -0
  683. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +304 -0
  684. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +1001 -0
  685. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +160 -0
  686. package/src/runtime/control-plane/goal-loop/index.ts +13 -0
  687. package/src/runtime/control-plane/goal-loop/local-tools.ts +290 -0
  688. package/src/runtime/control-plane/goal-loop/policy-gates.ts +203 -0
  689. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +93 -0
  690. package/src/runtime/control-plane/goal-loop/provider-registry.ts +545 -0
  691. package/src/runtime/control-plane/goal-loop/types.ts +378 -0
  692. package/src/runtime/control-plane/governance/access-policy.ts +147 -0
  693. package/src/runtime/control-plane/governance/authorization.ts +195 -0
  694. package/src/runtime/control-plane/governance/external-effects.ts +43 -0
  695. package/src/runtime/control-plane/launcher/thin-launcher.ts +97 -0
  696. package/src/runtime/control-plane/persistence/metadata-payload-policy.ts +53 -0
  697. package/src/runtime/control-plane/persistence/requirement-store.ts +241 -0
  698. package/src/runtime/control-plane/persistence/sqlite-store.ts +539 -0
  699. package/src/runtime/control-plane/release-retention.ts +447 -0
  700. package/src/runtime/control-plane/repo-actor/actor.ts +181 -0
  701. package/src/runtime/control-plane/repo-actor/registry.ts +20 -0
  702. package/src/runtime/control-plane/routing/index.ts +1 -0
  703. package/src/runtime/control-plane/routing/route-policy.ts +379 -0
  704. package/src/runtime/control-plane/runtime-cleanup.ts +727 -0
  705. package/src/runtime/control-plane/runtime-generation.ts +509 -0
  706. package/src/runtime/control-plane/runtime-pid-ownership.ts +11 -0
  707. package/src/runtime/control-plane/runtime-status-client.ts +90 -0
  708. package/src/runtime/control-plane/startup-recovery.ts +198 -0
  709. package/src/runtime/diagnostics/connectivity-observability.ts +475 -0
  710. package/src/runtime/diagnostics/mcp-timing.ts +64 -0
  711. package/src/runtime/diagnostics/performance.ts +379 -0
  712. package/src/runtime/diagnostics/process-facade.ts +350 -0
  713. package/src/runtime/diagnostics/read-only-tool.ts +226 -0
  714. package/src/runtime/evidence/artifact-store.ts +154 -0
  715. package/src/runtime/evidence/event-ledger.ts +80 -0
  716. package/src/runtime/evidence/evidence-store.ts +68 -0
  717. package/src/runtime/evidence/process-check-receipt.ts +43 -0
  718. package/src/runtime/evidence/result-store.ts +209 -0
  719. package/src/runtime/evidence/sensitive-output.ts +353 -0
  720. package/src/runtime/execution/jobs/child-reference.ts +124 -0
  721. package/src/runtime/execution/jobs/legacy-adapter.ts +22 -0
  722. package/src/runtime/execution/jobs/receipt-recovery.ts +119 -0
  723. package/src/runtime/execution/jobs/receipt-store.ts +243 -0
  724. package/src/runtime/execution/jobs/store.ts +737 -0
  725. package/src/runtime/execution/jobs/timeouts.ts +109 -0
  726. package/src/runtime/execution/jobs/types.ts +230 -0
  727. package/src/runtime/execution/jobs/wait.ts +45 -0
  728. package/src/runtime/execution/process-runtime/canary.ts +26 -0
  729. package/src/runtime/execution/process-runtime/check-facade.ts +272 -0
  730. package/src/runtime/execution/process-runtime/check-receipt.ts +185 -0
  731. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +60 -0
  732. package/src/runtime/execution/process-runtime/command-facade.ts +321 -0
  733. package/src/runtime/execution/process-runtime/gc.ts +171 -0
  734. package/src/runtime/execution/process-runtime/index.ts +9 -0
  735. package/src/runtime/execution/process-runtime/interactive-admission.ts +23 -0
  736. package/src/runtime/execution/process-runtime/process-runner-entry.ts +466 -0
  737. package/src/runtime/execution/process-runtime/resource-claims.ts +440 -0
  738. package/src/runtime/execution/process-runtime/runtime.ts +1816 -0
  739. package/src/runtime/execution/process-runtime/store.ts +687 -0
  740. package/src/runtime/execution/process-runtime/types.ts +352 -0
  741. package/src/runtime/execution/thin-harness/async-process.ts +181 -0
  742. package/src/runtime/execution/thin-harness/batch-executor.ts +671 -0
  743. package/src/runtime/execution/thin-harness/execution-router.ts +700 -0
  744. package/src/runtime/execution/thin-harness/fast-executor.ts +1263 -0
  745. package/src/runtime/execution/thin-harness/fast-receipt.ts +235 -0
  746. package/src/runtime/execution/thin-harness/fingerprint-worker.ts +191 -0
  747. package/src/runtime/execution/thin-harness/index.ts +13 -0
  748. package/src/runtime/execution/thin-harness/latency-trace.ts +107 -0
  749. package/src/runtime/execution/thin-harness/lightweight-lanes.ts +745 -0
  750. package/src/runtime/execution/thin-harness/mutation-gate.ts +578 -0
  751. package/src/runtime/execution/thin-harness/proposal-store.ts +409 -0
  752. package/src/runtime/execution/thin-harness/request-ledger.ts +595 -0
  753. package/src/runtime/execution/thin-harness/search-worker.ts +114 -0
  754. package/src/runtime/execution/thin-harness/types.ts +313 -0
  755. package/src/runtime/execution/thin-harness/workspace-savepoint.ts +333 -0
  756. package/src/runtime/execution/workers/executor.ts +687 -0
  757. package/src/runtime/execution/workers/ownership.ts +94 -0
  758. package/src/runtime/execution/workers/worker-entry.ts +277 -0
  759. package/src/runtime/gateway/mcp/execution-tools.ts +2009 -0
  760. package/src/runtime/gateway/mcp/persisted-check-process.ts +255 -0
  761. package/src/runtime/gateway/mcp/process-tools.ts +230 -0
  762. package/src/runtime/gateway/mcp/resource-policy.ts +195 -0
  763. package/src/runtime/gateway/mcp/router.ts +1088 -0
  764. package/src/runtime/gateway/mcp/runtime-tools.ts +5994 -0
  765. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +219 -0
  766. package/src/runtime/health/evaluator.ts +474 -0
  767. package/src/runtime/health/index.ts +2 -0
  768. package/src/runtime/health/operational-view.ts +198 -0
  769. package/src/runtime/maintenance/cleanup.ts +419 -0
  770. package/src/runtime/model-clients/deepseek-adapter.ts +312 -0
  771. package/src/runtime/model-clients/index.ts +2 -0
  772. package/src/runtime/model-clients/types.ts +101 -0
  773. package/src/runtime/observability/gateway-contention-metrics.ts +129 -0
  774. package/src/runtime/observability/route-session-benchmark.ts +110 -0
  775. package/src/runtime/personal-assistant/gmail-triage-manager.ts +231 -0
  776. package/src/runtime/personal-assistant/reporting-runtime.ts +344 -0
  777. package/src/runtime/personal-assistant/triage-runtime.ts +748 -0
  778. package/src/runtime/plugins/app-store-connect-adapter.ts +868 -0
  779. package/src/runtime/plugins/browser-adapter.ts +2812 -0
  780. package/src/runtime/plugins/browser-automation-service.ts +46 -0
  781. package/src/runtime/plugins/browser-handoff-host.ts +304 -0
  782. package/src/runtime/plugins/browser-handoff.ts +371 -0
  783. package/src/runtime/plugins/browser-macos-bridge.ts +865 -0
  784. package/src/runtime/plugins/browser-node-bridge-host.ts +64 -0
  785. package/src/runtime/plugins/browser-node-bridge.ts +249 -0
  786. package/src/runtime/plugins/desktop-adapter.ts +374 -0
  787. package/src/runtime/plugins/desktop-operator-registration.ts +418 -0
  788. package/src/runtime/plugins/errors.ts +39 -0
  789. package/src/runtime/plugins/execution-origin.ts +26 -0
  790. package/src/runtime/plugins/external-adapter.ts +322 -0
  791. package/src/runtime/plugins/external-registration.ts +308 -0
  792. package/src/runtime/plugins/external-unix-socket-probe.cjs +79 -0
  793. package/src/runtime/plugins/external-unix-socket.ts +238 -0
  794. package/src/runtime/plugins/first-party-registry.ts +37 -0
  795. package/src/runtime/plugins/github-adapter.ts +266 -0
  796. package/src/runtime/plugins/gmail-adapter.ts +729 -0
  797. package/src/runtime/plugins/google-calendar-adapter.ts +468 -0
  798. package/src/runtime/plugins/google-shared.ts +578 -0
  799. package/src/runtime/plugins/google-tasks-adapter.ts +535 -0
  800. package/src/runtime/plugins/interaction-session.ts +252 -0
  801. package/src/runtime/plugins/ios/agent-device-capabilities.ts +258 -0
  802. package/src/runtime/plugins/ios/agent-device-failures.ts +95 -0
  803. package/src/runtime/plugins/ios/agent-device-provider.ts +63 -0
  804. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +268 -0
  805. package/src/runtime/plugins/ios/app-adapters.ts +122 -0
  806. package/src/runtime/plugins/ios-adapter.ts +509 -0
  807. package/src/runtime/plugins/ios-agent-device.ts +2311 -0
  808. package/src/runtime/plugins/ios-physical-device.ts +955 -0
  809. package/src/runtime/plugins/local-system-adapter.ts +1016 -0
  810. package/src/runtime/plugins/macos-capability-broker.ts +73 -0
  811. package/src/runtime/plugins/managed-process-adapter.ts +366 -0
  812. package/src/runtime/plugins/resend-adapter.ts +506 -0
  813. package/src/runtime/plugins/store.ts +1025 -0
  814. package/src/runtime/plugins/types.ts +138 -0
  815. package/src/runtime/projections/controller-context.ts +596 -0
  816. package/src/runtime/projections/git-status-sampler.ts +84 -0
  817. package/src/runtime/projections/invalidation.ts +250 -0
  818. package/src/runtime/projections/materialized-view.ts +694 -0
  819. package/src/runtime/recovery/actions.ts +158 -0
  820. package/src/runtime/recovery/audit.ts +38 -0
  821. package/src/runtime/recovery/classifier.ts +163 -0
  822. package/src/runtime/recovery/index.ts +9 -0
  823. package/src/runtime/recovery/local-jobs-repair.ts +393 -0
  824. package/src/runtime/recovery/maintenance-executor.ts +822 -0
  825. package/src/runtime/recovery/patch-handoff.ts +50 -0
  826. package/src/runtime/recovery/probe.ts +308 -0
  827. package/src/runtime/recovery/store.ts +35 -0
  828. package/src/runtime/recovery/types.ts +175 -0
  829. package/src/runtime/release/identity.ts +101 -0
  830. package/src/runtime/release/release-gate.ts +137 -0
  831. package/src/runtime/resources/claims/conflicts.ts +205 -0
  832. package/src/runtime/resources/index.ts +1 -0
  833. package/src/runtime/resources/leases/store.ts +539 -0
  834. package/src/runtime/resources/leases/types.ts +50 -0
  835. package/src/runtime/resources/ownership.ts +72 -0
  836. package/src/runtime/root/controller-services.ts +42 -0
  837. package/src/runtime/root/entry.ts +70 -0
  838. package/src/runtime/root/gateway-adapter.ts +46 -0
  839. package/src/runtime/root/local-bridge.ts +72 -0
  840. package/src/runtime/root/mcp-transport.ts +198 -0
  841. package/src/runtime/root/ownership.ts +94 -0
  842. package/src/runtime/root/readiness.ts +69 -0
  843. package/src/runtime/root/release-manifest.ts +147 -0
  844. package/src/runtime/root/release-materialize.ts +509 -0
  845. package/src/runtime/root/release-store.ts +236 -0
  846. package/src/runtime/root/runtime.ts +318 -0
  847. package/src/runtime/root/scheduler.ts +58 -0
  848. package/src/runtime/root/service-runner-entry.ts +20 -0
  849. package/src/runtime/root/service-runner.ts +69 -0
  850. package/src/runtime/root/service.ts +291 -0
  851. package/src/runtime/root/status.ts +127 -0
  852. package/src/runtime/root/types.ts +112 -0
  853. package/src/runtime/root/write-fence.ts +309 -0
  854. package/src/runtime/safe-tooling/browser-safe.ts +133 -0
  855. package/src/runtime/safe-tooling/external-filesystem.ts +304 -0
  856. package/src/runtime/safe-tooling/google-credential-store.ts +95 -0
  857. package/src/runtime/safe-tooling/google-oauth-broker.ts +286 -0
  858. package/src/runtime/safe-tooling/index.ts +11 -0
  859. package/src/runtime/safe-tooling/ios-development.ts +1039 -0
  860. package/src/runtime/safe-tooling/job-summary.ts +361 -0
  861. package/src/runtime/safe-tooling/plugin-summary.ts +53 -0
  862. package/src/runtime/safe-tooling/resend-oauth.ts +387 -0
  863. package/src/runtime/safe-tooling/review-artifacts.ts +133 -0
  864. package/src/runtime/safe-tooling/types.ts +103 -0
  865. package/src/runtime/safe-tooling/workspace-auth.ts +116 -0
  866. package/src/runtime/shared/bounded-child-supervisor.ts +235 -0
  867. package/src/runtime/shared/idempotent-retry.ts +128 -0
  868. package/src/runtime/shared/json-files.ts +43 -0
  869. package/src/runtime/shared/local-bridge-surface.ts +231 -0
  870. package/src/runtime/shared/managed-env.ts +154 -0
  871. package/src/runtime/shared/node-ts-loader.mjs +50 -0
  872. package/src/runtime/shared/process-environment.ts +97 -0
  873. package/src/runtime/shared/process-identity.ts +72 -0
  874. package/src/runtime/shared/process-tree.ts +227 -0
  875. package/src/runtime/shared/response-budget.ts +246 -0
  876. package/src/runtime/standalone-recovery/core.ts +2275 -0
  877. package/src/runtime/standalone-recovery/entry.ts +686 -0
  878. package/src/runtime/standalone-recovery/http-transport.ts +317 -0
  879. package/src/runtime/standalone-recovery/installer.ts +747 -0
  880. package/src/runtime/standalone-recovery/release.ts +241 -0
  881. package/src/runtime/watchdog/workflow-watchdog.ts +118 -0
  882. package/src/runtime/workflow/campaigns/cleanup.ts +263 -0
  883. package/src/runtime/workflow/campaigns/engine.ts +112 -0
  884. package/src/runtime/workflow/campaigns/normalize.ts +100 -0
  885. package/src/runtime/workflow/campaigns/review.ts +315 -0
  886. package/src/runtime/workflow/campaigns/store.ts +526 -0
  887. package/src/runtime/workflow/campaigns/supervisor.ts +112 -0
  888. package/src/runtime/workflow/campaigns/types.ts +290 -0
  889. package/src/runtime/workflow/campaigns/workspace-agent.ts +155 -0
  890. package/src/runtime/workflow/campaigns/workspace.ts +200 -0
  891. package/src/runtime/workflow/findings/store.ts +165 -0
  892. package/src/runtime/workflow/findings/types.ts +36 -0
  893. package/src/runtime/workflow/portfolio/engine.ts +20 -0
  894. package/src/runtime/workflow/portfolio/store.ts +185 -0
  895. package/src/runtime/workflow/portfolio/types.ts +29 -0
  896. package/src/runtime/workflow/schedules/engine.ts +620 -0
  897. package/src/runtime/workflow/schedules/settlement.ts +144 -0
  898. package/src/runtime/workflow/schedules/store.ts +417 -0
  899. package/src/runtime/workflow/schedules/types.ts +124 -0
  900. package/src/runtime/workspace-targets/index.ts +24 -0
  901. package/src/runtime/workspace-targets/target-grant.ts +721 -0
  902. package/src/testing/test-governance.ts +626 -0
  903. package/src/version.ts +21 -0
@@ -0,0 +1,865 @@
1
+ import { execFile } from 'child_process';
2
+ import { existsSync, writeFileSync } from 'fs';
3
+ import { homedir } from 'os';
4
+ import {
5
+ callBrowserAutomationBroker,
6
+ captureBrowserAutomationRegion,
7
+ type BrowserAutomationBrokerAction,
8
+ } from './browser-automation-service';
9
+ import { AssistantPluginError } from './errors';
10
+
11
+ const RECORD_SEPARATOR = String.fromCharCode(30);
12
+ const DEFAULT_NATIVE_TIMEOUT_MS = 5_000;
13
+ const MAX_NATIVE_OUTPUT_BYTES = 1_048_576;
14
+
15
+ export type MacOsBrowserProduct = 'chrome' | 'vivaldi';
16
+
17
+ interface MacOsBrowserDefinition {
18
+ product: MacOsBrowserProduct;
19
+ appName: string;
20
+ bundleId: string;
21
+ processName: string;
22
+ appPaths: string[];
23
+ }
24
+
25
+ export interface MacOsBrowserTabRef {
26
+ windowId: string;
27
+ tabId: string;
28
+ }
29
+
30
+ export interface MacOsBrowserMetadata {
31
+ product: MacOsBrowserProduct;
32
+ appName: string;
33
+ bundleId: string;
34
+ frontmost: boolean;
35
+ url: string;
36
+ title: string;
37
+ bounds: { x: number; y: number; width: number; height: number };
38
+ windowId?: string;
39
+ tabId?: string;
40
+ active?: boolean;
41
+ loading?: boolean;
42
+ }
43
+
44
+ export interface MacOsBrowserAttachAttempt {
45
+ product: MacOsBrowserProduct;
46
+ appName: string;
47
+ bundleId: string;
48
+ status: 'selected' | 'available' | 'not_installed' | 'not_running' | 'unavailable';
49
+ frontmost?: boolean;
50
+ error?: string;
51
+ }
52
+
53
+ export interface MacOsBrowserAttachment {
54
+ metadata: MacOsBrowserMetadata;
55
+ attempts: MacOsBrowserAttachAttempt[];
56
+ }
57
+
58
+ export interface MacOsBrowserAttachObservation {
59
+ checkedAt: string;
60
+ ready: boolean;
61
+ selectedProduct?: MacOsBrowserProduct;
62
+ attempts: MacOsBrowserAttachAttempt[];
63
+ }
64
+
65
+ export function macOsBrowserJavaScriptAutomationDisabled(error: unknown): boolean {
66
+ const message = error instanceof Error ? error.message : String(error ?? '');
67
+ return /Executing JavaScript through AppleScript is turned off|allow JavaScript from Apple Events/i.test(message);
68
+ }
69
+
70
+ interface MacOsBrowserRuntimeHooks {
71
+ platform: NodeJS.Platform;
72
+ appExists(path: string): boolean;
73
+ processRunning(processName: string, timeoutMs: number): Promise<boolean>;
74
+ // Test-only escape hatches. Production intentionally leaves these undefined so
75
+ // Apple Events and screen capture are attributed to the stable helper process.
76
+ runAppleScript?: (script: string, args: string[], timeoutMs: number) => Promise<string>;
77
+ captureRegion?: (region: { x: number; y: number; width: number; height: number }, path: string, timeoutMs: number) => Promise<Buffer>;
78
+ }
79
+
80
+ function execFileText(file: string, args: string[], timeoutMs: number): Promise<string> {
81
+ return new Promise((resolve, reject) => {
82
+ execFile(file, args, {
83
+ encoding: 'utf8',
84
+ timeout: timeoutMs,
85
+ maxBuffer: MAX_NATIVE_OUTPUT_BYTES,
86
+ env: {
87
+ PATH: '/usr/bin:/bin:/usr/sbin:/sbin',
88
+ HOME: process.env.HOME,
89
+ TMPDIR: process.env.TMPDIR,
90
+ LANG: process.env.LANG,
91
+ LC_ALL: process.env.LC_ALL,
92
+ },
93
+ }, (error, stdout, stderr) => {
94
+ if (error) {
95
+ const diagnostic = String(stderr || error.message).trim().slice(-2_000);
96
+ reject(new Error(diagnostic || error.message));
97
+ return;
98
+ }
99
+ resolve(String(stdout).trim());
100
+ });
101
+ });
102
+ }
103
+
104
+ const defaultRuntimeHooks: MacOsBrowserRuntimeHooks = {
105
+ platform: process.platform,
106
+ appExists: (path) => existsSync(path),
107
+ processRunning: async (processName, timeoutMs) => {
108
+ try {
109
+ await execFileText('/usr/bin/pgrep', ['-x', processName], timeoutMs);
110
+ return true;
111
+ } catch {
112
+ return false;
113
+ }
114
+ },
115
+ };
116
+
117
+ async function runBrowserAutomationText(
118
+ request: BrowserAutomationBrokerAction,
119
+ testScript: string,
120
+ testArgs: string[],
121
+ timeoutMs: number,
122
+ ): Promise<string> {
123
+ if (runtimeHooks.runAppleScript) return await runtimeHooks.runAppleScript(testScript, testArgs, timeoutMs);
124
+ const result = await callBrowserAutomationBroker(request, timeoutMs);
125
+ if (typeof result.value !== 'string') {
126
+ throw new AssistantPluginError(
127
+ 'PLUGIN_MACOS_CAPABILITY_BROKER_PROTOCOL_ERROR',
128
+ 'Stable Forge macOS capability broker returned an invalid text result.',
129
+ { retryable: true },
130
+ );
131
+ }
132
+ return result.value;
133
+ }
134
+
135
+ async function captureBrowserAutomation(
136
+ region: { x: number; y: number; width: number; height: number },
137
+ path: string,
138
+ timeoutMs: number,
139
+ ): Promise<Buffer> {
140
+ if (runtimeHooks.captureRegion) return await runtimeHooks.captureRegion(region, path, timeoutMs);
141
+ const bytes = await captureBrowserAutomationRegion(region, timeoutMs);
142
+ writeFileSync(path, bytes);
143
+ return bytes;
144
+ }
145
+
146
+ let runtimeHooks: MacOsBrowserRuntimeHooks = { ...defaultRuntimeHooks };
147
+ let lastAttachObservation: MacOsBrowserAttachObservation | undefined;
148
+
149
+ export function setMacOsBrowserRuntimeHooksForTest(hooks: Partial<MacOsBrowserRuntimeHooks>): void {
150
+ runtimeHooks = { ...defaultRuntimeHooks, ...hooks };
151
+ }
152
+
153
+ export function resetMacOsBrowserRuntimeHooksForTest(): void {
154
+ runtimeHooks = { ...defaultRuntimeHooks };
155
+ lastAttachObservation = undefined;
156
+ }
157
+
158
+ export function getMacOsBrowserAttachObservation(): MacOsBrowserAttachObservation | undefined {
159
+ return lastAttachObservation
160
+ ? { ...lastAttachObservation, attempts: lastAttachObservation.attempts.map((attempt) => ({ ...attempt })) }
161
+ : undefined;
162
+ }
163
+
164
+ const BROWSERS: Record<MacOsBrowserProduct, MacOsBrowserDefinition> = {
165
+ chrome: {
166
+ product: 'chrome',
167
+ appName: 'Google Chrome',
168
+ bundleId: 'com.google.Chrome',
169
+ processName: 'Google Chrome',
170
+ appPaths: ['/Applications/Google Chrome.app', `${homedir()}/Applications/Google Chrome.app`],
171
+ },
172
+ vivaldi: {
173
+ product: 'vivaldi',
174
+ appName: 'Vivaldi',
175
+ bundleId: 'com.vivaldi.Vivaldi',
176
+ processName: 'Vivaldi',
177
+ appPaths: ['/Applications/Vivaldi.app', `${homedir()}/Applications/Vivaldi.app`],
178
+ },
179
+ };
180
+
181
+ function browserDefinition(product: MacOsBrowserProduct): MacOsBrowserDefinition {
182
+ return BROWSERS[product];
183
+ }
184
+
185
+ function quotedAppleScript(value: string): string {
186
+ return JSON.stringify(value);
187
+ }
188
+
189
+ function browserTellScript(browser: MacOsBrowserDefinition, body: string): string {
190
+ return `tell application ${quotedAppleScript(browser.appName)}\n${body}\nend tell`;
191
+ }
192
+
193
+ function metadataScript(browser: MacOsBrowserDefinition): string {
194
+ return browserTellScript(browser, `
195
+ if (count of windows) is 0 then error "FORGE_NO_BROWSER_WINDOW"
196
+ set targetWindow to front window
197
+ set targetTab to active tab of targetWindow
198
+ set windowBounds to bounds of targetWindow
199
+ set separator to ASCII character 30
200
+ return (frontmost as text) & separator & (URL of targetTab as text) & separator & (title of targetTab as text) & separator & ((item 1 of windowBounds) as text) & separator & ((item 2 of windowBounds) as text) & separator & ((item 3 of windowBounds) as text) & separator & ((item 4 of windowBounds) as text)
201
+ `);
202
+ }
203
+
204
+ function targetTabPreamble(ref: MacOsBrowserTabRef): string {
205
+ return `set targetWindow to first window whose id is ${quotedAppleScript(ref.windowId)}\nset targetTab to first tab of targetWindow whose id is ${quotedAppleScript(ref.tabId)}`;
206
+ }
207
+
208
+ function targetMetadataScript(browser: MacOsBrowserDefinition, ref: MacOsBrowserTabRef): string {
209
+ return browserTellScript(browser, `
210
+ ${targetTabPreamble(ref)}
211
+ set windowBounds to bounds of targetWindow
212
+ set separator to ASCII character 30
213
+ set targetIsActive to ((id of active tab of targetWindow) is (id of targetTab))
214
+ return (frontmost as text) & separator & (URL of targetTab as text) & separator & "" & separator & ((item 1 of windowBounds) as text) & separator & ((item 2 of windowBounds) as text) & separator & ((item 3 of windowBounds) as text) & separator & ((item 4 of windowBounds) as text) & separator & "" & separator & "" & separator & (targetIsActive as text) & separator & (loading of targetTab as text)
215
+ `);
216
+ }
217
+
218
+ function activateTargetTabScript(browser: MacOsBrowserDefinition, ref: MacOsBrowserTabRef): string {
219
+ return browserTellScript(browser, `
220
+ ${targetTabPreamble(ref)}
221
+ set targetTabIndex to 1
222
+ repeat with candidateTab in tabs of targetWindow
223
+ if ((id of candidateTab) as text) is ((id of targetTab) as text) then exit repeat
224
+ set targetTabIndex to targetTabIndex + 1
225
+ end repeat
226
+ set active tab index of targetWindow to targetTabIndex
227
+ set index of targetWindow to 1
228
+ activate
229
+ `);
230
+ }
231
+
232
+ function createOwnedTabScript(browser: MacOsBrowserDefinition): string {
233
+ return `on run argv
234
+ set targetUrl to item 1 of argv
235
+ ${browserTellScript(browser, `
236
+ if (count of windows) is 0 then error "FORGE_NO_BROWSER_WINDOW"
237
+ set targetWindow to front window
238
+ set originalActiveIndex to active tab index of targetWindow
239
+ set targetTab to make new tab at end of tabs of targetWindow with properties {URL:targetUrl}
240
+ set targetTabId to id of targetTab
241
+ set active tab index of targetWindow to originalActiveIndex
242
+ set separator to ASCII character 30
243
+ return ((id of targetWindow) as text) & separator & (targetTabId as text)
244
+ `)}
245
+ end run`;
246
+ }
247
+
248
+ function closeOwnedTabScript(browser: MacOsBrowserDefinition, ref: MacOsBrowserTabRef): string {
249
+ return browserTellScript(browser, `
250
+ try
251
+ ${targetTabPreamble(ref)}
252
+ close targetTab
253
+ end try
254
+ `);
255
+ }
256
+
257
+ function executeJavaScriptScript(browser: MacOsBrowserDefinition, ref?: MacOsBrowserTabRef): string {
258
+ return `on run argv
259
+ set javascriptSource to item 1 of argv
260
+ ${browserTellScript(browser, ref ? `
261
+ ${targetTabPreamble(ref)}
262
+ return execute targetTab javascript javascriptSource
263
+ ` : `
264
+ if (count of windows) is 0 then error "FORGE_NO_BROWSER_WINDOW"
265
+ return execute active tab of front window javascript javascriptSource
266
+ `)}
267
+ end run`;
268
+ }
269
+
270
+ function navigateScript(browser: MacOsBrowserDefinition, ref?: MacOsBrowserTabRef): string {
271
+ return `on run argv
272
+ set targetUrl to item 1 of argv
273
+ ${browserTellScript(browser, ref ? `
274
+ ${targetTabPreamble(ref)}
275
+ set URL of targetTab to targetUrl
276
+ return targetUrl
277
+ ` : `
278
+ if (count of windows) is 0 then error "FORGE_NO_BROWSER_WINDOW"
279
+ set URL of active tab of front window to targetUrl
280
+ return targetUrl
281
+ `)}
282
+ end run`;
283
+ }
284
+
285
+ function reloadScript(browser: MacOsBrowserDefinition, ref?: MacOsBrowserTabRef): string {
286
+ return browserTellScript(browser, ref ? `
287
+ ${targetTabPreamble(ref)}
288
+ reload targetTab
289
+ ` : `
290
+ if (count of windows) is 0 then error "FORGE_NO_BROWSER_WINDOW"
291
+ reload active tab of front window
292
+ `);
293
+ }
294
+
295
+ function activateScript(browser: MacOsBrowserDefinition): string {
296
+ return browserTellScript(browser, 'activate');
297
+ }
298
+
299
+ function parseInteger(value: string, field: string): number {
300
+ const parsed = Number.parseInt(value, 10);
301
+ if (!Number.isFinite(parsed)) throw new Error(`Invalid ${field} returned by browser scripting.`);
302
+ return parsed;
303
+ }
304
+
305
+ function parseBrowserId(value: string, field: string): string {
306
+ const parsed = value.trim();
307
+ if (!parsed) throw new Error(`Invalid ${field} returned by browser scripting.`);
308
+ return parsed;
309
+ }
310
+
311
+ function parseMetadata(product: MacOsBrowserProduct, raw: string): MacOsBrowserMetadata {
312
+ const browser = browserDefinition(product);
313
+ const parts = raw.split(RECORD_SEPARATOR);
314
+ if (parts.length < 7) throw new Error(`Browser scripting returned incomplete metadata for ${browser.appName}.`);
315
+ const left = parseInteger(parts[3] ?? '', 'window left');
316
+ const top = parseInteger(parts[4] ?? '', 'window top');
317
+ const right = parseInteger(parts[5] ?? '', 'window right');
318
+ const bottom = parseInteger(parts[6] ?? '', 'window bottom');
319
+ return {
320
+ product,
321
+ appName: browser.appName,
322
+ bundleId: browser.bundleId,
323
+ frontmost: (parts[0] ?? '').toLowerCase() === 'true',
324
+ url: parts[1] ?? '',
325
+ title: parts[2] ?? '',
326
+ bounds: {
327
+ x: left,
328
+ y: top,
329
+ width: Math.max(1, right - left),
330
+ height: Math.max(1, bottom - top),
331
+ },
332
+ windowId: parts[7] ? parseBrowserId(parts[7], 'window id') : undefined,
333
+ tabId: parts[8] ? parseBrowserId(parts[8], 'tab id') : undefined,
334
+ active: parts[9] ? (parts[9] ?? '').toLowerCase() === 'true' : undefined,
335
+ loading: parts[10] ? (parts[10] ?? '').toLowerCase() === 'true' : undefined,
336
+ };
337
+ }
338
+
339
+ async function inspectBrowser(product: MacOsBrowserProduct, timeoutMs: number): Promise<{ metadata?: MacOsBrowserMetadata; attempt: MacOsBrowserAttachAttempt }> {
340
+ const browser = browserDefinition(product);
341
+ const base = { product, appName: browser.appName, bundleId: browser.bundleId };
342
+ if (runtimeHooks.platform !== 'darwin') {
343
+ return { attempt: { ...base, status: 'unavailable', error: 'Apple Events browser attach is available only on macOS.' } };
344
+ }
345
+ if (!browser.appPaths.some((path) => runtimeHooks.appExists(path))) {
346
+ return { attempt: { ...base, status: 'not_installed', error: `${browser.appName} is not installed.` } };
347
+ }
348
+ if (!(await runtimeHooks.processRunning(browser.processName, timeoutMs))) {
349
+ return { attempt: { ...base, status: 'not_running', error: `${browser.appName} is not running.` } };
350
+ }
351
+ try {
352
+ const metadata = parseMetadata(product, await runBrowserAutomationText(
353
+ { action: 'metadata', product },
354
+ metadataScript(browser),
355
+ [],
356
+ timeoutMs,
357
+ ));
358
+ return {
359
+ metadata,
360
+ attempt: {
361
+ ...base,
362
+ status: 'available',
363
+ frontmost: metadata.frontmost,
364
+ },
365
+ };
366
+ } catch (error) {
367
+ return {
368
+ attempt: {
369
+ ...base,
370
+ status: 'unavailable',
371
+ error: error instanceof Error ? error.message : String(error),
372
+ },
373
+ };
374
+ }
375
+ }
376
+
377
+ export function macOsActiveBrowserAttachSupported(): boolean {
378
+ return runtimeHooks.platform === 'darwin';
379
+ }
380
+
381
+ export async function discoverMacOsBrowserAttachment(
382
+ candidates: MacOsBrowserProduct[],
383
+ timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
384
+ ): Promise<{ attachment?: MacOsBrowserAttachment; attempts: MacOsBrowserAttachAttempt[] }> {
385
+ const normalized = Array.from(new Set(candidates)).filter((entry): entry is MacOsBrowserProduct => entry === 'chrome' || entry === 'vivaldi');
386
+ const inspected = [] as Array<{ metadata?: MacOsBrowserMetadata; attempt: MacOsBrowserAttachAttempt }>;
387
+ for (const product of normalized) inspected.push(await inspectBrowser(product, timeoutMs));
388
+ const available = inspected.filter((entry): entry is { metadata: MacOsBrowserMetadata; attempt: MacOsBrowserAttachAttempt } => Boolean(entry.metadata));
389
+ const selected = available.find((entry) => entry.metadata.frontmost) ?? available[0];
390
+ const attempts = inspected.map((entry) => ({ ...entry.attempt }));
391
+ if (!selected) {
392
+ lastAttachObservation = { checkedAt: new Date().toISOString(), ready: false, attempts: attempts.map((attempt) => ({ ...attempt })) };
393
+ return { attempts };
394
+ }
395
+ const selectedAttempt = attempts.find((entry) => entry.product === selected.metadata.product);
396
+ if (selectedAttempt) selectedAttempt.status = 'selected';
397
+ lastAttachObservation = {
398
+ checkedAt: new Date().toISOString(),
399
+ ready: true,
400
+ selectedProduct: selected.metadata.product,
401
+ attempts: attempts.map((attempt) => ({ ...attempt })),
402
+ };
403
+ return {
404
+ attempts,
405
+ attachment: {
406
+ metadata: selected.metadata,
407
+ attempts,
408
+ },
409
+ };
410
+ }
411
+
412
+ function serializeEvaluation(expression: string | ((...args: unknown[]) => unknown), arg?: unknown): string {
413
+ const source = typeof expression === 'string'
414
+ ? expression
415
+ : `(${expression.toString()})(${arg === undefined ? 'undefined' : JSON.stringify(arg)})`;
416
+ return `(() => {
417
+ try {
418
+ const value = (${source});
419
+ return JSON.stringify({ ok: true, value: value === undefined ? { __forgeUndefined: true } : value });
420
+ } catch (error) {
421
+ return JSON.stringify({ ok: false, error: String(error && (error.stack || error.message) || error) });
422
+ }
423
+ })()`;
424
+ }
425
+
426
+ function selectorSource(selector: string, body: string): string {
427
+ return `(() => {
428
+ const element = document.querySelector(${JSON.stringify(selector)});
429
+ if (!element) throw new Error(${JSON.stringify(`Selector not found: ${selector}`)});
430
+ ${body}
431
+ })()`;
432
+ }
433
+
434
+ function keyEventSource(selector: string | undefined, keySpec: string): string {
435
+ const parts = keySpec.split('+').filter(Boolean);
436
+ const key = parts.at(-1) ?? keySpec;
437
+ const modifiers = new Set(parts.slice(0, -1).map((entry) => entry.toLowerCase()));
438
+ const target = selector
439
+ ? `document.querySelector(${JSON.stringify(selector)})`
440
+ : 'document.activeElement || document.body';
441
+ return `(() => {
442
+ const element = ${target};
443
+ if (!element) throw new Error(${JSON.stringify(selector ? `Selector not found: ${selector}` : 'No active element.')});
444
+ if (typeof element.focus === 'function') element.focus();
445
+ const init = {
446
+ key: ${JSON.stringify(key)},
447
+ code: ${JSON.stringify(key.length === 1 ? `Key${key.toUpperCase()}` : key)},
448
+ bubbles: true,
449
+ cancelable: true,
450
+ metaKey: ${modifiers.has('meta') || modifiers.has('cmd') || modifiers.has('command')},
451
+ ctrlKey: ${modifiers.has('control') || modifiers.has('ctrl')},
452
+ altKey: ${modifiers.has('alt') || modifiers.has('option')},
453
+ shiftKey: ${modifiers.has('shift')}
454
+ };
455
+ element.dispatchEvent(new KeyboardEvent('keydown', init));
456
+ element.dispatchEvent(new KeyboardEvent('keypress', init));
457
+ if (${JSON.stringify(key)} === 'Enter') {
458
+ const form = element.form || (typeof element.closest === 'function' ? element.closest('form') : null);
459
+ if (form && typeof form.requestSubmit === 'function') form.requestSubmit();
460
+ else if (typeof element.click === 'function' && /^(BUTTON|A)$/.test(element.tagName || '')) element.click();
461
+ }
462
+ element.dispatchEvent(new KeyboardEvent('keyup', init));
463
+ return true;
464
+ })()`;
465
+ }
466
+
467
+ export class MacOsAppleEventsPage {
468
+ private metadata: MacOsBrowserMetadata;
469
+ private readonly browser: MacOsBrowserDefinition;
470
+ private readonly timeoutMs: number;
471
+ private readonly targetRef?: MacOsBrowserTabRef;
472
+
473
+ constructor(attachment: MacOsBrowserAttachment, timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS, targetRef?: MacOsBrowserTabRef) {
474
+ this.metadata = { ...attachment.metadata, ...(targetRef ? { windowId: targetRef.windowId, tabId: targetRef.tabId } : {}) };
475
+ this.browser = browserDefinition(attachment.metadata.product);
476
+ this.timeoutMs = timeoutMs;
477
+ this.targetRef = targetRef;
478
+ }
479
+
480
+ private async runAutomation(
481
+ request: BrowserAutomationBrokerAction,
482
+ script: string,
483
+ args: string[] = [],
484
+ timeoutMs = this.timeoutMs,
485
+ ): Promise<string> {
486
+ try {
487
+ return await runBrowserAutomationText(request, script, args, timeoutMs);
488
+ } catch (error) {
489
+ const message = error instanceof Error ? error.message : String(error);
490
+ throw new AssistantPluginError('PLUGIN_BROWSER_NATIVE_OPERATION_FAILED', `${this.browser.appName} Apple Events operation failed: ${message}`, {
491
+ retryable: true,
492
+ details: { browserProduct: this.browser.product, bundleId: this.browser.bundleId },
493
+ });
494
+ }
495
+ }
496
+
497
+ private async refreshMetadata(): Promise<MacOsBrowserMetadata> {
498
+ const script = this.targetRef ? targetMetadataScript(this.browser, this.targetRef) : metadataScript(this.browser);
499
+ this.metadata = parseMetadata(this.browser.product, await this.runAutomation(
500
+ { action: 'metadata', product: this.browser.product, ...(this.targetRef ? { ref: this.targetRef } : {}) },
501
+ script,
502
+ ));
503
+ return this.metadata;
504
+ }
505
+
506
+ private async executeJavaScriptRaw(source: string, timeoutMs = this.timeoutMs): Promise<string> {
507
+ try {
508
+ return await this.runAutomation(
509
+ { action: 'execute_javascript', product: this.browser.product, ...(this.targetRef ? { ref: this.targetRef } : {}), source },
510
+ executeJavaScriptScript(this.browser, this.targetRef),
511
+ [source],
512
+ timeoutMs,
513
+ );
514
+ } catch (error) {
515
+ if (macOsBrowserJavaScriptAutomationDisabled(error)) {
516
+ throw new AssistantPluginError(
517
+ 'PLUGIN_BROWSER_JAVASCRIPT_PERMISSION_REQUIRED',
518
+ `${this.browser.appName} allows tab/window automation, but DOM actions require Settings > Privacy > Apple Events > Allow JavaScript from Apple Events.`,
519
+ { retryable: false, details: { browserProduct: this.browser.product, bundleId: this.browser.bundleId } },
520
+ );
521
+ }
522
+ throw error;
523
+ }
524
+ }
525
+
526
+ tabRef(): MacOsBrowserTabRef | undefined {
527
+ return this.targetRef ? { ...this.targetRef } : undefined;
528
+ }
529
+
530
+ async goto(url: string, options: Record<string, unknown> = {}): Promise<unknown> {
531
+ const timeout = typeof options.timeout === 'number' ? Math.trunc(options.timeout) : this.timeoutMs;
532
+ if (this.targetRef) {
533
+ throw new AssistantPluginError(
534
+ 'PLUGIN_BROWSER_BACKGROUND_NAVIGATION_REQUIRES_REPLACEMENT',
535
+ 'Chrome/Vivaldi background tabs cannot be navigated reliably in place through Apple Events; create a replacement plugin-owned tab instead.',
536
+ { retryable: true, details: { browserProduct: this.browser.product, windowId: this.targetRef.windowId, tabId: this.targetRef.tabId } },
537
+ );
538
+ }
539
+ await this.runAutomation(
540
+ { action: 'navigate', product: this.browser.product, url },
541
+ navigateScript(this.browser),
542
+ [url],
543
+ timeout,
544
+ );
545
+ await this.waitForLoadState(String(options.waitUntil ?? 'domcontentloaded'), { timeout });
546
+ await this.refreshMetadata();
547
+ return undefined;
548
+ }
549
+
550
+ async reload(options: Record<string, unknown> = {}): Promise<unknown> {
551
+ const timeout = typeof options.timeout === 'number' ? Math.trunc(options.timeout) : this.timeoutMs;
552
+ await this.runAutomation(
553
+ { action: 'reload', product: this.browser.product, ...(this.targetRef ? { ref: this.targetRef } : {}) },
554
+ reloadScript(this.browser, this.targetRef),
555
+ [],
556
+ timeout,
557
+ );
558
+ await this.waitForLoadState(String(options.waitUntil ?? 'domcontentloaded'), { timeout });
559
+ await this.refreshMetadata();
560
+ return undefined;
561
+ }
562
+
563
+ async goBack(options: Record<string, unknown> = {}): Promise<unknown> {
564
+ await this.evaluate('history.back()');
565
+ await this.waitForLoadState(String(options.waitUntil ?? 'domcontentloaded'), options);
566
+ await this.refreshMetadata();
567
+ return undefined;
568
+ }
569
+
570
+ async title(): Promise<string> {
571
+ if (this.targetRef) {
572
+ try {
573
+ const title = await this.evaluate<string>('document.title || ""');
574
+ this.metadata = { ...this.metadata, title };
575
+ return title;
576
+ } catch {
577
+ // Chrome can expose a valid background tab while refusing AppleScript title/name coercion.
578
+ // A missing tab still fails through the metadata fallback below.
579
+ }
580
+ }
581
+ return (await this.refreshMetadata()).title;
582
+ }
583
+
584
+ url(): string {
585
+ return this.metadata.url;
586
+ }
587
+
588
+ async identity(): Promise<{ url: string; title: string }> {
589
+ try {
590
+ const identity = await this.evaluate<{ url: string; title: string }>(
591
+ '({ url: String(document.location.href || ""), title: String(document.title || "") })',
592
+ );
593
+ if (identity && typeof identity.url === 'string' && identity.url) {
594
+ const normalized = { url: identity.url, title: typeof identity.title === 'string' ? identity.title : '' };
595
+ this.metadata = { ...this.metadata, ...normalized };
596
+ return normalized;
597
+ }
598
+ } catch (error) {
599
+ if (!macOsBrowserJavaScriptAutomationDisabled(error)
600
+ && !(error instanceof AssistantPluginError && error.code === 'PLUGIN_BROWSER_JAVASCRIPT_PERMISSION_REQUIRED')) throw error;
601
+ }
602
+ const metadata = await this.refreshMetadata();
603
+ return { url: metadata.url, title: metadata.title };
604
+ }
605
+
606
+ async content(): Promise<string> {
607
+ return await this.evaluate<string>('document.documentElement ? document.documentElement.outerHTML : ""');
608
+ }
609
+
610
+ async evaluate<T>(expression: string | ((...args: unknown[]) => unknown), arg?: unknown): Promise<T> {
611
+ const raw = await this.executeJavaScriptRaw(serializeEvaluation(expression, arg));
612
+ let parsed: { ok?: boolean; value?: unknown; error?: string };
613
+ try {
614
+ parsed = JSON.parse(raw) as { ok?: boolean; value?: unknown; error?: string };
615
+ } catch {
616
+ throw new AssistantPluginError('PLUGIN_BROWSER_NATIVE_PROTOCOL_ERROR', `${this.browser.appName} returned an invalid JavaScript result.`, {
617
+ retryable: true,
618
+ });
619
+ }
620
+ if (!parsed.ok) throw new Error(parsed.error || 'Browser JavaScript evaluation failed.');
621
+ if (parsed.value && typeof parsed.value === 'object' && (parsed.value as { __forgeUndefined?: unknown }).__forgeUndefined === true) {
622
+ return undefined as T;
623
+ }
624
+ return parsed.value as T;
625
+ }
626
+
627
+ async screenshot(options: Record<string, unknown>): Promise<Buffer> {
628
+ const path = typeof options.path === 'string' ? options.path : undefined;
629
+ if (!path) throw new Error('Native browser screenshot requires an output path.');
630
+ const metadata = await this.refreshMetadata();
631
+ if (this.targetRef && (!metadata.frontmost || metadata.active !== true)) {
632
+ throw new AssistantPluginError('PLUGIN_BROWSER_FOREGROUND_REQUIRED', 'Native screenshot refused to activate a background plugin-owned tab. Bring the tab to the foreground explicitly before capturing it.', {
633
+ retryable: true,
634
+ details: { browserProduct: this.browser.product, windowId: this.targetRef.windowId, tabId: this.targetRef.tabId },
635
+ });
636
+ }
637
+ return await captureBrowserAutomation(metadata.bounds, path, this.timeoutMs);
638
+ }
639
+
640
+ async click(selector: string): Promise<void> {
641
+ await this.evaluate(selectorSource(selector, 'if (typeof element.click !== "function") throw new Error("Element is not clickable."); element.click(); return true;'));
642
+ }
643
+
644
+ async dblclick(selector: string): Promise<void> {
645
+ await this.evaluate(selectorSource(selector, `element.dispatchEvent(new MouseEvent('dblclick', { bubbles: true, cancelable: true, view: window })); return true;`));
646
+ }
647
+
648
+ async hover(selector: string): Promise<void> {
649
+ await this.evaluate(selectorSource(selector, `for (const type of ['mouseover', 'mouseenter', 'mousemove']) element.dispatchEvent(new MouseEvent(type, { bubbles: true, cancelable: true, view: window })); return true;`));
650
+ }
651
+
652
+ async focus(selector: string): Promise<void> {
653
+ await this.evaluate(selectorSource(selector, 'if (typeof element.focus !== "function") throw new Error("Element is not focusable."); element.focus(); return true;'));
654
+ }
655
+
656
+ async fill(selector: string, value: string): Promise<void> {
657
+ await this.evaluate(selectorSource(selector, `
658
+ if ('value' in element) {
659
+ const prototype = element instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype;
660
+ const setter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set;
661
+ if (setter) setter.call(element, ${JSON.stringify(value)}); else element.value = ${JSON.stringify(value)};
662
+ } else if (element.isContentEditable) element.textContent = ${JSON.stringify(value)};
663
+ else throw new Error('Element does not accept text input.');
664
+ element.dispatchEvent(new Event('input', { bubbles: true }));
665
+ element.dispatchEvent(new Event('change', { bubbles: true }));
666
+ return true;
667
+ `));
668
+ }
669
+
670
+ async type(selector: string, text: string): Promise<void> {
671
+ const current = await this.evaluate<string>(selectorSource(selector, `return 'value' in element ? String(element.value || '') : String(element.textContent || '');`));
672
+ await this.fill(selector, `${current}${text}`);
673
+ }
674
+
675
+ async press(selector: string, key: string): Promise<void> {
676
+ await this.evaluate(keyEventSource(selector, key));
677
+ }
678
+
679
+ async selectOption(selector: string, values: string | string[]): Promise<unknown> {
680
+ const normalized = Array.isArray(values) ? values : [values];
681
+ return await this.evaluate(selectorSource(selector, `
682
+ if (!(element instanceof HTMLSelectElement)) throw new Error('Element is not a select.');
683
+ const selected = new Set(${JSON.stringify(normalized)});
684
+ for (const option of element.options) option.selected = selected.has(option.value) || selected.has(option.label);
685
+ element.dispatchEvent(new Event('input', { bubbles: true }));
686
+ element.dispatchEvent(new Event('change', { bubbles: true }));
687
+ return Array.from(element.selectedOptions).map((option) => option.value);
688
+ `));
689
+ }
690
+
691
+ async check(selector: string): Promise<void> {
692
+ await this.setChecked(selector, true);
693
+ }
694
+
695
+ async uncheck(selector: string): Promise<void> {
696
+ await this.setChecked(selector, false);
697
+ }
698
+
699
+ private async setChecked(selector: string, checked: boolean): Promise<void> {
700
+ await this.evaluate(selectorSource(selector, `
701
+ if (!('checked' in element)) throw new Error('Element is not checkable.');
702
+ element.checked = ${checked};
703
+ element.dispatchEvent(new Event('input', { bubbles: true }));
704
+ element.dispatchEvent(new Event('change', { bubbles: true }));
705
+ return true;
706
+ `));
707
+ }
708
+
709
+ async waitForSelector(selector: string, options: Record<string, unknown> = {}): Promise<unknown> {
710
+ const timeout = typeof options.timeout === 'number' ? Math.trunc(options.timeout) : this.timeoutMs;
711
+ const state = String(options.state ?? 'visible');
712
+ const deadline = Date.now() + timeout;
713
+ while (Date.now() <= deadline) {
714
+ const observed = await this.evaluate<{ attached: boolean; visible: boolean }>(`(() => {
715
+ const element = document.querySelector(${JSON.stringify(selector)});
716
+ if (!element) return { attached: false, visible: false };
717
+ const style = getComputedStyle(element);
718
+ const rect = element.getBoundingClientRect();
719
+ return { attached: true, visible: style.visibility !== 'hidden' && style.display !== 'none' && rect.width > 0 && rect.height > 0 };
720
+ })()`);
721
+ const matched = state === 'attached' ? observed.attached
722
+ : state === 'detached' ? !observed.attached
723
+ : state === 'hidden' ? !observed.attached || !observed.visible
724
+ : observed.visible;
725
+ if (matched) return observed;
726
+ await new Promise((resolve) => setTimeout(resolve, 100));
727
+ }
728
+ throw new Error(`Timeout waiting for selector ${selector} in state ${state}.`);
729
+ }
730
+
731
+ async waitForLoadState(state = 'domcontentloaded', options: Record<string, unknown> = {}): Promise<void> {
732
+ const timeout = typeof options.timeout === 'number' ? Math.trunc(options.timeout) : this.timeoutMs;
733
+ const deadline = Date.now() + timeout;
734
+ while (Date.now() <= deadline) {
735
+ if (this.targetRef) {
736
+ try {
737
+ const metadata = await this.refreshMetadata();
738
+ if (metadata.loading === false) return;
739
+ } catch {
740
+ // Fall through to DOM readiness when native loading metadata is unavailable.
741
+ }
742
+ }
743
+ try {
744
+ const readyState = await this.evaluate<string>('document.readyState');
745
+ if (state === 'load' || state === 'networkidle') {
746
+ if (readyState === 'complete') return;
747
+ } else if (readyState === 'interactive' || readyState === 'complete') return;
748
+ } catch (error) {
749
+ if (error instanceof AssistantPluginError && error.code === 'PLUGIN_BROWSER_JAVASCRIPT_PERMISSION_REQUIRED') {
750
+ const metadata = await this.refreshMetadata();
751
+ if (metadata.url && metadata.url !== 'about:blank' && metadata.url !== 'chrome://newtab/' && metadata.url !== 'vivaldi://newtab/') return;
752
+ }
753
+ // Navigation can transiently invalidate the current JavaScript execution context.
754
+ }
755
+ await new Promise((resolve) => setTimeout(resolve, 100));
756
+ }
757
+ throw new Error(`Timeout waiting for browser load state ${state}.`);
758
+ }
759
+
760
+ locator(_selector: string): { screenshot: (options?: Record<string, unknown>) => Promise<Buffer> } {
761
+ return { screenshot: async (options = {}) => this.screenshot(options) };
762
+ }
763
+
764
+ on(_event: string, _handler: (...args: unknown[]) => void): void {
765
+ // Apple Events does not expose Playwright console/network event streams.
766
+ }
767
+
768
+ async bringToFront(): Promise<void> {
769
+ if (this.targetRef) {
770
+ this.metadata = await activateMacOsBrowserOwnedTab(this.browser.product, this.targetRef, this.timeoutMs);
771
+ return;
772
+ }
773
+ await this.runAutomation(
774
+ { action: 'activate', product: this.browser.product },
775
+ activateScript(this.browser),
776
+ );
777
+ }
778
+
779
+ keyboard = {
780
+ press: async (key: string): Promise<void> => {
781
+ await this.evaluate(keyEventSource(undefined, key));
782
+ },
783
+ };
784
+ }
785
+
786
+ export async function readMacOsBrowserOwnedTabMetadata(
787
+ product: MacOsBrowserProduct,
788
+ ref: MacOsBrowserTabRef,
789
+ timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
790
+ ): Promise<MacOsBrowserMetadata> {
791
+ const browser = browserDefinition(product);
792
+ return parseMetadata(product, await runBrowserAutomationText(
793
+ { action: 'metadata', product, ref },
794
+ targetMetadataScript(browser, ref),
795
+ [],
796
+ timeoutMs,
797
+ ));
798
+ }
799
+
800
+ export async function activateMacOsBrowserOwnedTab(
801
+ product: MacOsBrowserProduct,
802
+ ref: MacOsBrowserTabRef,
803
+ timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
804
+ ): Promise<MacOsBrowserMetadata> {
805
+ const browser = browserDefinition(product);
806
+ await runBrowserAutomationText(
807
+ { action: 'activate', product, ref },
808
+ activateTargetTabScript(browser, ref),
809
+ [],
810
+ timeoutMs,
811
+ );
812
+ return readMacOsBrowserOwnedTabMetadata(product, ref, timeoutMs);
813
+ }
814
+
815
+ export function createMacOsBrowserPage(attachment: MacOsBrowserAttachment, timeoutMs?: number): MacOsAppleEventsPage {
816
+ return new MacOsAppleEventsPage(attachment, timeoutMs);
817
+ }
818
+
819
+ export async function createMacOsBrowserOwnedPage(
820
+ attachment: MacOsBrowserAttachment,
821
+ url: string,
822
+ timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
823
+ ): Promise<MacOsAppleEventsPage> {
824
+ const browser = browserDefinition(attachment.metadata.product);
825
+ const raw = await runBrowserAutomationText(
826
+ { action: 'create_tab', product: attachment.metadata.product, url },
827
+ createOwnedTabScript(browser),
828
+ [url],
829
+ timeoutMs,
830
+ );
831
+ const parts = raw.split(RECORD_SEPARATOR);
832
+ if (parts.length < 2) throw new Error(`Browser scripting returned incomplete owned-tab metadata for ${browser.appName}.`);
833
+ const ref = { windowId: parseBrowserId(parts[0] ?? '', 'window id'), tabId: parseBrowserId(parts[1] ?? '', 'tab id') };
834
+ return new MacOsAppleEventsPage({
835
+ ...attachment,
836
+ metadata: { ...attachment.metadata, url, title: '', windowId: ref.windowId, tabId: ref.tabId, active: false },
837
+ }, timeoutMs, ref);
838
+ }
839
+
840
+ export async function reattachMacOsBrowserOwnedPage(
841
+ product: MacOsBrowserProduct,
842
+ ref: MacOsBrowserTabRef,
843
+ timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
844
+ ): Promise<{ page: MacOsAppleEventsPage; attachment: MacOsBrowserAttachment }> {
845
+ const metadata = await readMacOsBrowserOwnedTabMetadata(product, ref, timeoutMs);
846
+ const attachment: MacOsBrowserAttachment = {
847
+ metadata,
848
+ attempts: [{ product, appName: metadata.appName, bundleId: metadata.bundleId, status: 'selected', frontmost: metadata.frontmost }],
849
+ };
850
+ return { page: new MacOsAppleEventsPage(attachment, timeoutMs, ref), attachment };
851
+ }
852
+
853
+ export async function closeMacOsBrowserOwnedTab(
854
+ product: MacOsBrowserProduct,
855
+ ref: MacOsBrowserTabRef,
856
+ timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
857
+ ): Promise<void> {
858
+ const browser = browserDefinition(product);
859
+ await runBrowserAutomationText(
860
+ { action: 'close_tab', product, ref },
861
+ closeOwnedTabScript(browser, ref),
862
+ [],
863
+ timeoutMs,
864
+ );
865
+ }