farming-code 2.2.27 → 2.2.29

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 (284) hide show
  1. package/README.md +15 -30
  2. package/README.zh_cn.md +15 -30
  3. package/THIRD_PARTY_NOTICES.md +28 -6
  4. package/backend/acp/packaged-claude-acp.js +13 -0
  5. package/backend/acp/packaged-codex-acp.js +2 -2
  6. package/backend/acp-runtime.js +52 -3
  7. package/backend/acp-transcript.js +174 -9
  8. package/backend/agent-manager.js +1081 -96
  9. package/backend/atomic-json-store.js +37 -0
  10. package/backend/cli-agents.js +9 -7
  11. package/backend/config-manager.js +211 -58
  12. package/backend/control-api.js +2 -1
  13. package/backend/data/LICENSE.agent-browser +201 -0
  14. package/backend/data/runtime-dependency-manifest.json +199 -0
  15. package/backend/data/runtime-dependency-sources.json +5 -0
  16. package/backend/executable-discovery.js +7 -0
  17. package/backend/farming-agent-bootstrap.js +49 -0
  18. package/backend/farming-agent-bootstrap.zh_cn.md +7 -0
  19. package/backend/farming-app-cli.js +168 -65
  20. package/backend/farming-cli.js +57 -0
  21. package/backend/farming-session-store.js +92 -89
  22. package/backend/index-html.js +13 -0
  23. package/backend/main-agent-skills.js +13 -0
  24. package/backend/npm-update-helper.js +43 -6
  25. package/backend/preview-session-manager.js +68 -0
  26. package/backend/provider-adapters.js +54 -5
  27. package/backend/review-session-store.js +32 -25
  28. package/backend/review-state-store.js +13 -14
  29. package/backend/run-history-store.js +13 -16
  30. package/backend/runtime-dependency-manager.js +759 -0
  31. package/backend/runtime-executable-invocation.js +20 -0
  32. package/backend/server-process-identity.js +47 -0
  33. package/backend/server.js +231 -223
  34. package/backend/slash-command-discovery.js +138 -1
  35. package/backend/storage-layout.js +35 -0
  36. package/backend/update-service.js +27 -1
  37. package/backend/workspace-file-router.js +141 -0
  38. package/backend/workspace-file-service.js +19 -0
  39. package/backend/workspace-root-registry.js +6 -4
  40. package/config/farming.install.env.example +4 -0
  41. package/dist/acp/LICENSE.claude-agent-acp +191 -0
  42. package/dist/acp/LICENSE.claude-agent-sdk +1 -0
  43. package/dist/acp/claude-agent-acp-0.59.0.mjs +41606 -0
  44. package/dist/assets/App-BKNUILuL.css +1 -0
  45. package/dist/assets/App-Ex2oVVXO.js +693 -0
  46. package/dist/assets/{FileEditorMarkdownPreview-Da5jguUs.js → FileEditorMarkdownPreview-Cs9cLv8a.js} +5 -5
  47. package/dist/assets/FileEditorPane-CNtuGjQ3.js +2 -0
  48. package/dist/assets/IconGlyphs-BClgag6E.js +1 -0
  49. package/dist/assets/ProjectFilesSection-Cf2BEcAN.js +12 -0
  50. package/dist/assets/ReviewPage-BRuxFaH5.js +3 -0
  51. package/dist/assets/{abnfDiagram-VRR7QNED-nnglrXFi.js → abnfDiagram-VRR7QNED-BY1qwq8A.js} +1 -1
  52. package/dist/assets/api-w2x5QfxB.js +1 -0
  53. package/dist/assets/{arc-CWoVlxJw.js → arc-DgZRAlwj.js} +1 -1
  54. package/dist/assets/{architectureDiagram-ZJ3FMSHR-BEXMaFfY.js → architectureDiagram-ZJ3FMSHR-jFn144od.js} +1 -1
  55. package/dist/assets/{blockDiagram-677ZJIJ3-1mCezSBk.js → blockDiagram-677ZJIJ3-BmRjlV0H.js} +1 -1
  56. package/dist/assets/{c4Diagram-LMCZKHZV-DhTiI6Uv.js → c4Diagram-LMCZKHZV-DUKul6tT.js} +1 -1
  57. package/dist/assets/{workspace-editor-monaco-DLlws5Ig.js → channel-CI9j3QFD.js} +1 -1
  58. package/dist/assets/chunk-2Q5K7J3B-87UnWaoh.js +1 -0
  59. package/dist/assets/{chunk-32BRIVSS-CCdsKd73.js → chunk-32BRIVSS-rGVu23o5.js} +1 -1
  60. package/dist/assets/{chunk-52WLFC77-Gncjk4LF.js → chunk-52WLFC77-CvFDKgbB.js} +1 -1
  61. package/dist/assets/{chunk-5VM5RSS4-Dlw7AXWp.js → chunk-5VM5RSS4-CFgnRW1C.js} +1 -1
  62. package/dist/assets/{chunk-7BUUIJ7U-ZBRhjLOh.js → chunk-7BUUIJ7U-Cp7bqW6s.js} +1 -1
  63. package/dist/assets/{chunk-C7G6YPKG-CiDVUP82.js → chunk-C7G6YPKG-BIS1gjZO.js} +1 -1
  64. package/dist/assets/{chunk-EX3LRPZG-z6gXP2_N.js → chunk-EX3LRPZG-BKG-cR9j.js} +1 -1
  65. package/dist/assets/{chunk-FWX5IMBZ-DMZBccQa.js → chunk-FWX5IMBZ-B8PsTr8a.js} +2 -2
  66. package/dist/assets/{chunk-HOUHSVGY-D8tIeoPk.js → chunk-HOUHSVGY-BHFOAiXT.js} +1 -1
  67. package/dist/assets/{chunk-ICXQ74PX-b6oQ2Q17.js → chunk-ICXQ74PX-CvLE1J9X.js} +1 -1
  68. package/dist/assets/{chunk-JWPE2WC7-DSyBRaRG.js → chunk-JWPE2WC7-D8misks7.js} +1 -1
  69. package/dist/assets/{chunk-MOJQB5TN-DAVH_p2a.js → chunk-MOJQB5TN-D-oNgSNH.js} +1 -1
  70. package/dist/assets/{chunk-OGEWGWER-DxoiMCI-.js → chunk-OGEWGWER-C2N-la9e.js} +1 -1
  71. package/dist/assets/{chunk-PUDLZKDR-NsOWh7HM.js → chunk-PUDLZKDR-BwI3Jz8q.js} +1 -1
  72. package/dist/assets/{chunk-Q4XR5HBZ-Di4H7L21.js → chunk-Q4XR5HBZ-BuqGfsXA.js} +1 -1
  73. package/dist/assets/{chunk-RYQCIY6F-CZA9pvFX.js → chunk-RYQCIY6F-Bq4XZcGt.js} +1 -1
  74. package/dist/assets/{chunk-V7JOEXUC-DttpZg9Y.js → chunk-V7JOEXUC-QZLzdTTJ.js} +1 -1
  75. package/dist/assets/chunk-VAUOI2AC-Cb0-kQ9g.js +1 -0
  76. package/dist/assets/{chunk-VR4S4FIN-D-Fmtd4Z.js → chunk-VR4S4FIN-DcZTpML_.js} +1 -1
  77. package/dist/assets/{chunk-WYO6CB5R-CUxMtfK2.js → chunk-WYO6CB5R-DCU8wuny.js} +2 -2
  78. package/dist/assets/chunk-XXDRQBXY-BZAC1Krv.js +1 -0
  79. package/dist/assets/{chunk-ZGVPDNZ5-CoV2QEl0.js → chunk-ZGVPDNZ5-B7r85QbY.js} +1 -1
  80. package/dist/assets/{chunk-ZIRB5QZD-DncwlQQc.js → chunk-ZIRB5QZD-BgEnDWhQ.js} +1 -1
  81. package/dist/assets/classDiagram-OUVF2IWQ-DcvGOuvi.js +1 -0
  82. package/dist/assets/classDiagram-v2-EOCWNBFH-DDYUSofQ.js +1 -0
  83. package/dist/assets/code-dark-BEZTQwYZ.css +1 -0
  84. package/dist/assets/{cose-bilkent-JH36ORCC-BNIAz0nN.js → cose-bilkent-JH36ORCC-CThXS2qG.js} +1 -1
  85. package/dist/assets/{cssMode-DDWxTPm_.js → cssMode-Bdg5RpcJ.js} +1 -1
  86. package/dist/assets/{cynefinDiagram-TSTJHNR4-0xPI92Lg.js → cynefinDiagram-TSTJHNR4-DxBgzw25.js} +1 -1
  87. package/dist/assets/{dagre-DXlcHgr3.js → dagre-BM-GvGUZ.js} +1 -1
  88. package/dist/assets/{dagre-VKFMJZFB-DfuMG4gU.js → dagre-VKFMJZFB-B7UCRmxR.js} +1 -1
  89. package/dist/assets/{diagram-FQU43EPY-CT00bLZ6.js → diagram-FQU43EPY-CeL2DwKx.js} +1 -1
  90. package/dist/assets/{diagram-G47NLZAW-Xbh7zXUx.js → diagram-G47NLZAW-BEirglCC.js} +1 -1
  91. package/dist/assets/{diagram-NH7WQ7WH-SRDVPfn7.js → diagram-NH7WQ7WH-C6wcI-Rl.js} +1 -1
  92. package/dist/assets/{diagram-OA4YK3LP-CQRli4Np.js → diagram-OA4YK3LP-DpM-XXtJ.js} +1 -1
  93. package/dist/assets/{diagram-WEI45ONY-DMf17WQi.js → diagram-WEI45ONY-BQyaut9k.js} +1 -1
  94. package/dist/assets/{ebnfDiagram-CCIWWBDH-DhpFkgJ5.js → ebnfDiagram-CCIWWBDH-UmAXsUhr.js} +1 -1
  95. package/dist/assets/{erDiagram-Q63AITRT-1IwxWmJo.js → erDiagram-Q63AITRT-CdYLEOch.js} +1 -1
  96. package/dist/assets/file-icons-BOlcJ0ZF.js +1 -0
  97. package/dist/assets/flowDiagram-23GEKE2U-CO-z9-tq.js +1 -0
  98. package/dist/assets/{freemarker2-QBsTERH-.js → freemarker2-DfMDJfnE.js} +1 -1
  99. package/dist/assets/{ganttDiagram-NO4QXBWP-BNCdfyr1.js → ganttDiagram-NO4QXBWP-DgSUNdUB.js} +1 -1
  100. package/dist/assets/{gitGraphDiagram-IHSO6WYX-pbyWZuiX.js → gitGraphDiagram-IHSO6WYX-DjwjtRtF.js} +1 -1
  101. package/dist/assets/{handlebars-CuoxPo5A.js → handlebars-BEdPtzMT.js} +1 -1
  102. package/dist/assets/{html-gX5PEu0Q.js → html-B1fPb1QD.js} +1 -1
  103. package/dist/assets/html2canvas-DsczWxBa.js +5 -0
  104. package/dist/assets/{htmlMode-DIWUbUxd.js → htmlMode-CY2ZjHxH.js} +1 -1
  105. package/dist/assets/{index-CtwKYTiC.js → index-CQNaZc3l.js} +2 -2
  106. package/dist/assets/{infoDiagram-FWYZ7A6U-BcTOgDbe.js → infoDiagram-FWYZ7A6U-Bi9076l2.js} +1 -1
  107. package/dist/assets/{ishikawaDiagram-FXEZZL3T-DCdvGKrn.js → ishikawaDiagram-FXEZZL3T-DaMaNZN7.js} +1 -1
  108. package/dist/assets/{javascript-BYKGIUGs.js → javascript-BV2OsWA0.js} +1 -1
  109. package/dist/assets/{journeyDiagram-5HDEW3XC-BZ-1q_IT.js → journeyDiagram-5HDEW3XC-CfDy69EZ.js} +1 -1
  110. package/dist/assets/{jsonMode-AFmQQP6u.js → jsonMode-zd07aeuX.js} +1 -1
  111. package/dist/assets/{kanban-definition-HUTT4EX6-BIgejCjj.js → kanban-definition-HUTT4EX6-XFvZ722B.js} +1 -1
  112. package/dist/assets/{line-CfptFMmX.js → line-BXK9PKLn.js} +1 -1
  113. package/dist/assets/{linear-Dld3_ERu.js → linear-CULvmq2Z.js} +1 -1
  114. package/dist/assets/{liquid-DBIl-f0z.js → liquid-BParI24X.js} +1 -1
  115. package/dist/assets/{lspLanguageFeatures-DK6tqicV.js → lspLanguageFeatures-BzredkoV.js} +1 -1
  116. package/dist/assets/main-DK9Sy7-c.css +1 -0
  117. package/dist/assets/{map-LZWWoeWa.js → map-C9Qw9eWh.js} +1 -1
  118. package/dist/assets/{mdx-DS-bVtZN.js → mdx-vGzUJN98.js} +1 -1
  119. package/dist/assets/{mermaid.core-gSpX30pV.js → mermaid.core-CzazaIKr.js} +3 -3
  120. package/dist/assets/{mindmap-definition-LN4V7U3C-BKBaI4LW.js → mindmap-definition-LN4V7U3C-Uoff7hZ3.js} +1 -1
  121. package/dist/assets/{monaco.contribution-BXz-lfFB.js → monaco.contribution-BmaeBQEc.js} +2 -2
  122. package/dist/assets/{ordinal-BLrOss5K.js → ordinal-r6pIwRdZ.js} +1 -1
  123. package/dist/assets/{pegDiagram-2B236MQR-sBvDY3VX.js → pegDiagram-2B236MQR-CCBiHQjk.js} +1 -1
  124. package/dist/assets/{pieDiagram-ENE6RG2P-DWlWcu08.js → pieDiagram-ENE6RG2P-D61s7l75.js} +1 -1
  125. package/dist/assets/{python-C93q3xXz.js → python-CUwdLgsI.js} +1 -1
  126. package/dist/assets/{quadrantDiagram-ABIIQ3AL-DZutUd3J.js → quadrantDiagram-ABIIQ3AL-D_CWk2DQ.js} +1 -1
  127. package/dist/assets/{railroadDiagram-RFXS5EU6-DQb3lXGM.js → railroadDiagram-RFXS5EU6-CdlCHtxN.js} +1 -1
  128. package/dist/assets/{razor-CBifNGXO.js → razor-BScebUxU.js} +1 -1
  129. package/dist/assets/{requirementDiagram-TGXJPOKE-DqFGXu2e.js → requirementDiagram-TGXJPOKE-BLpHtkoC.js} +1 -1
  130. package/dist/assets/{sankeyDiagram-HTMAVEWB-d7ECahnO.js → sankeyDiagram-HTMAVEWB-CkhYZN2j.js} +1 -1
  131. package/dist/assets/{sequenceDiagram-DBY2YBRQ-DdsbKqct.js → sequenceDiagram-DBY2YBRQ-8bploKJl.js} +1 -1
  132. package/dist/assets/{sizeCapture-X5ZJPWSS-daTB6OcF.js → sizeCapture-X5ZJPWSS-DtSdkS0d.js} +1 -1
  133. package/dist/assets/{src-WBW1QxJt.js → src-6yeq6WBA.js} +1 -1
  134. package/dist/assets/{stateDiagram-2N3HPSRC-P6iSrgwR.js → stateDiagram-2N3HPSRC-DfmVGpfA.js} +1 -1
  135. package/dist/assets/stateDiagram-v2-6OUMAXLB-B2c9CQ-J.js +1 -0
  136. package/dist/assets/{swimlanes-5IMT3BWC-BGnZJx1M.js → swimlanes-5IMT3BWC-DRLk2zRF.js} +2 -2
  137. package/dist/assets/swimlanesDiagram-G3AALYLV-B7_APh_h.js +8 -0
  138. package/dist/assets/{timeline-definition-FHXFAJF6-rA-r3aUR.js → timeline-definition-FHXFAJF6-Cngfy588.js} +1 -1
  139. package/dist/assets/{tsMode-B0oUTcXQ.js → tsMode-DzUAibXK.js} +1 -1
  140. package/dist/assets/{typescript-KJKfYO7K.js → typescript-D9EOeM7N.js} +1 -1
  141. package/dist/assets/{vennDiagram-L72KCM5P-DiVKUjA9.js → vennDiagram-L72KCM5P-DeJn63Lq.js} +1 -1
  142. package/dist/assets/{wardleyDiagram-EHGQE667-Cfxh7UOn.js → wardleyDiagram-EHGQE667-BH1nzy77.js} +1 -1
  143. package/dist/assets/{workers-BSQRIkqa.js → workers-DAiomYZM.js} +1 -1
  144. package/dist/assets/workspace-editor-model-CSGCl21x.js +1 -0
  145. package/dist/assets/{workspace-editor-monaco-BIpqcWf1.js → workspace-editor-monaco-CJNwbpCy.js} +3 -3
  146. package/dist/assets/workspace-editor-monaco-CO9w8YV0.js +1 -0
  147. package/dist/assets/workspace-view-state-BjKPYp0E.js +7 -0
  148. package/dist/assets/{xml-C8FAcN6j.js → xml-wWl1dhkQ.js} +1 -1
  149. package/dist/assets/{xychartDiagram-FW5EYKEG--hmryQeL.js → xychartDiagram-FW5EYKEG-SkO2prCU.js} +1 -1
  150. package/dist/assets/{yaml-BQ4NrRhG.js → yaml-Dc2WDaOZ.js} +1 -1
  151. package/dist/crt-markdown-renderer.js +46 -46
  152. package/dist/index.html +32 -3
  153. package/extensions/browser/backend/agent-browser-runtime.js +1041 -0
  154. package/extensions/browser/backend/agent-capability.js +55 -0
  155. package/extensions/browser/backend/browser-mcp-server.js +621 -0
  156. package/extensions/browser/backend/browser-resource-manager.js +1309 -0
  157. package/extensions/browser/backend/browser-resource-store.js +190 -0
  158. package/extensions/browser/backend/browser-router.js +133 -0
  159. package/extensions/browser/backend/executable-discovery.js +224 -0
  160. package/extensions/browser/backend/farming-browser-client.js +83 -0
  161. package/extensions/browser/backend/index.js +7 -0
  162. package/extensions/browser/bin/farming-browser +471 -0
  163. package/extensions/browser/frontend/BrowserSidebarPortals.tsx +360 -0
  164. package/extensions/browser/frontend/BrowserViewer.tsx +500 -0
  165. package/extensions/browser/frontend/browser-resource-state.ts +60 -0
  166. package/extensions/browser/frontend/browser.css +567 -0
  167. package/extensions/browser/frontend/types.ts +31 -0
  168. package/extensions/browser/frontend/useBrowserResources.ts +158 -0
  169. package/frontend/session-bridge.js +7 -6
  170. package/frontend/skins/crt/app.js +64 -4
  171. package/index.html +31 -2
  172. package/package.json +27 -18
  173. package/shared/backend-connection-status.d.ts +12 -0
  174. package/shared/backend-connection-status.js +35 -4
  175. package/shared/browser-protocol.js +1 -1
  176. package/backend/agent-activity.js +0 -35
  177. package/dist/assets/App-BrP-ENHg.css +0 -1
  178. package/dist/assets/App-Cm8qTjsc.js +0 -210
  179. package/dist/assets/FileEditorPane-fFqHA4wW.js +0 -2
  180. package/dist/assets/IconGlyphs-C2WFcoJS.js +0 -1
  181. package/dist/assets/ProjectFilesSection-Cyy3Vcn8.js +0 -12
  182. package/dist/assets/ReviewPage-L1vh1Ggs.js +0 -3
  183. package/dist/assets/api-D8nyOEbz.js +0 -1
  184. package/dist/assets/channel-BVWNatUB.js +0 -1
  185. package/dist/assets/chunk-2Q5K7J3B-d5WWh8jo.js +0 -1
  186. package/dist/assets/chunk-VAUOI2AC-UHNr_yhX.js +0 -1
  187. package/dist/assets/chunk-XXDRQBXY-BBXwjhUx.js +0 -1
  188. package/dist/assets/classDiagram-OUVF2IWQ-Db0ib5iE.js +0 -1
  189. package/dist/assets/classDiagram-v2-EOCWNBFH-Bkf69XF9.js +0 -1
  190. package/dist/assets/code-dark-BKtvf0Xc.css +0 -1
  191. package/dist/assets/file-icons-BqiH0rDI.js +0 -1
  192. package/dist/assets/flowDiagram-23GEKE2U-DYFo2xmB.js +0 -1
  193. package/dist/assets/main-XMXgyJJt.css +0 -1
  194. package/dist/assets/stateDiagram-v2-6OUMAXLB-DIYSf_qh.js +0 -1
  195. package/dist/assets/swimlanesDiagram-G3AALYLV-BIkrlKrZ.js +0 -8
  196. package/dist/assets/workspace-editor-model-D0Im34S5.js +0 -1
  197. package/dist/assets/workspace-view-state-BiuEbmRr.js +0 -7
  198. /package/dist/acp/{codex-acp-1.1.4.js → codex-acp-1.1.4.mjs} +0 -0
  199. /package/dist/assets/{abap-Cc5D5h5i.js → abap-CtX5nWyX.js} +0 -0
  200. /package/dist/assets/{apex-BKopwLmx.js → apex-DQJRAHwc.js} +0 -0
  201. /package/dist/assets/{array-HeX70jSN.js → array-BTwzYU0x.js} +0 -0
  202. /package/dist/assets/{azcli-DI-C34WA.js → azcli-9SMrOQ4q.js} +0 -0
  203. /package/dist/assets/{bat-Cbp6u42z.js → bat-CBGLUsw1.js} +0 -0
  204. /package/dist/assets/{bicep-4QA1jTCM.js → bicep-pDx8da1v.js} +0 -0
  205. /package/dist/assets/{cameligo-Dda_adPs.js → cameligo-hZV3vQ6_.js} +0 -0
  206. /package/dist/assets/{chunk-Y2CYZVJY-Di0sYzi1.js → chunk-Y2CYZVJY-BYi0W5ea.js} +0 -0
  207. /package/dist/assets/{clojure-CvY8A83L.js → clojure-BhCwU3gq.js} +0 -0
  208. /package/dist/assets/{coffee-4LX2Sv8A.js → coffee-BVB1PsgH.js} +0 -0
  209. /package/dist/assets/{core-B9MwRjDE.js → core-vPkV8P_m.js} +0 -0
  210. /package/dist/assets/{cpp-D4AzSV28.js → cpp-eTjuiNPq.js} +0 -0
  211. /package/dist/assets/{csharp-C4nWN4Yd.js → csharp-1kP-kKZT.js} +0 -0
  212. /package/dist/assets/{csp-CiEaaS5Z.js → csp-C_iQqIes.js} +0 -0
  213. /package/dist/assets/{css-DXxBRsbk.js → css-CxOs7IfP.js} +0 -0
  214. /package/dist/assets/{cypher-DOMzqyFA.js → cypher-Cd-a9Y82.js} +0 -0
  215. /package/dist/assets/{cytoscape.esm-Cl8iC3D7.js → cytoscape.esm-OLojuicg.js} +0 -0
  216. /package/dist/assets/{dart-BWS7MXt_.js → dart-whhXpexn.js} +0 -0
  217. /package/dist/assets/{defaultLocale-GJwWH1Jr.js → defaultLocale-CPimVhfE.js} +0 -0
  218. /package/dist/assets/{dist-ClAL-Tv5.js → dist-CLPYXg1u.js} +0 -0
  219. /package/dist/assets/{dockerfile-Baf4U3xT.js → dockerfile-DibBi8b6.js} +0 -0
  220. /package/dist/assets/{ecl-CT7udlkQ.js → ecl-DlF1KdoW.js} +0 -0
  221. /package/dist/assets/{editor.api2-B9h6iFPK.js → editor.api2-D74ufkbr.js} +0 -0
  222. /package/dist/assets/{elixir-CIbAZw5l.js → elixir-CHQ8uFT3.js} +0 -0
  223. /package/dist/assets/{flow9-Dqiw45WV.js → flow9-8nUnVKk1.js} +0 -0
  224. /package/dist/assets/{fsharp-E8E2L9jU.js → fsharp-DNZNZyEE.js} +0 -0
  225. /package/dist/assets/{go-CouVSN4D.js → go-_kPJjNc_.js} +0 -0
  226. /package/dist/assets/{graphlib-CbSvZcZU.js → graphlib-CBGF9gA9.js} +0 -0
  227. /package/dist/assets/{graphql-a6h6h5-t.js → graphql-4HCNVt5g.js} +0 -0
  228. /package/dist/assets/{hcl-vso3e6N-.js → hcl-C87ymY0o.js} +0 -0
  229. /package/dist/assets/{ini-SwZZkotR.js → ini-BYrrGNTc.js} +0 -0
  230. /package/dist/assets/{init-BPLPMQ3Y.js → init-8_PCa3LO.js} +0 -0
  231. /package/dist/assets/{java-CtRLC4_3.js → java-B211rJbk.js} +0 -0
  232. /package/dist/assets/{julia-CuJWFKQH.js → julia-DVPsRtBm.js} +0 -0
  233. /package/dist/assets/{katex-C8DPyI6s.js → katex-C2iYad0m.js} +0 -0
  234. /package/dist/assets/{kotlin-B_kBhsre.js → kotlin-BYyNerjp.js} +0 -0
  235. /package/dist/assets/{less-CtrHIfz3.js → less-EC9UblGE.js} +0 -0
  236. /package/dist/assets/{lexon-yVt1pJLu.js → lexon-B1yuUdqW.js} +0 -0
  237. /package/dist/assets/{lua-prOwgJ4U.js → lua-Bo6GFzxT.js} +0 -0
  238. /package/dist/assets/{m3-DhrdTQ84.js → m3-C-Y9cBVI.js} +0 -0
  239. /package/dist/assets/{markdown-DoI5HwSM.js → markdown-BHu-wLbe.js} +0 -0
  240. /package/dist/assets/{mermaid-parser.core-BQtepoLd.js → mermaid-parser.core-IxcGtNYG.js} +0 -0
  241. /package/dist/assets/{mips-Dye5jsBU.js → mips-Dkds26rX.js} +0 -0
  242. /package/dist/assets/{msdax-TkNOyIL8.js → msdax-PU4g-8_g.js} +0 -0
  243. /package/dist/assets/{mysql-CEc-RKZF.js → mysql-fPpuGpS7.js} +0 -0
  244. /package/dist/assets/{objective-c-CqqCsQz0.js → objective-c-Wy1e5JUf.js} +0 -0
  245. /package/dist/assets/{pascal-DO_pj8yg.js → pascal-BIXwvrqU.js} +0 -0
  246. /package/dist/assets/{pascaligo-1cbdZdF3.js → pascaligo-DwR0AtL_.js} +0 -0
  247. /package/dist/assets/{path-YdFzr2W6.js → path-BxQuywGl.js} +0 -0
  248. /package/dist/assets/{perl-B_N3PYfC.js → perl-CGHAl8my.js} +0 -0
  249. /package/dist/assets/{pgsql-9iYk1FQ7.js → pgsql-B91M73E2.js} +0 -0
  250. /package/dist/assets/{php-rO2sgoUM.js → php-C70ttrCx.js} +0 -0
  251. /package/dist/assets/{pla-Cbgv60kq.js → pla-BNrXaRh0.js} +0 -0
  252. /package/dist/assets/{postiats-y6xrhy_M.js → postiats-Dv2IAZR9.js} +0 -0
  253. /package/dist/assets/{powerquery-BaD8gWNE.js → powerquery-CkY5Wq7J.js} +0 -0
  254. /package/dist/assets/{powershell-BMhG4JVe.js → powershell-uGIYLU3C.js} +0 -0
  255. /package/dist/assets/{protobuf-CdOP5kN3.js → protobuf-CavfmJu-.js} +0 -0
  256. /package/dist/assets/{pug-Ck60hNF9.js → pug-Drqnyitx.js} +0 -0
  257. /package/dist/assets/{qrcode-DV-_rjU8.js → qrcode-7uGsTEmi.js} +0 -0
  258. /package/dist/assets/{qsharp-BcaKFfP-.js → qsharp-C7yF-Dti.js} +0 -0
  259. /package/dist/assets/{r-rFNes0iK.js → r-HXLGP0_-.js} +0 -0
  260. /package/dist/assets/{redis-DkpQ3K6G.js → redis-C4y6mf2p.js} +0 -0
  261. /package/dist/assets/{redshift-Di9N5TI3.js → redshift-DdQrFPrv.js} +0 -0
  262. /package/dist/assets/{restructuredtext-By5ZzLt6.js → restructuredtext-CBrf2PNj.js} +0 -0
  263. /package/dist/assets/{rough.esm-c4PR5shF.js → rough.esm-6CnTHTkH.js} +0 -0
  264. /package/dist/assets/{ruby-fF5zGiLp.js → ruby-CVtMoX2B.js} +0 -0
  265. /package/dist/assets/{rust-C5b3AYY6.js → rust-Ckq4sbMP.js} +0 -0
  266. /package/dist/assets/{sb-CD07UNRs.js → sb-er66OpE3.js} +0 -0
  267. /package/dist/assets/{scala-jtn1ip9G.js → scala-BdWZz-hH.js} +0 -0
  268. /package/dist/assets/{scheme-C4vqMkn_.js → scheme-kTV_s2kP.js} +0 -0
  269. /package/dist/assets/{scss-I4Glxjbz.js → scss-Bymy2VJQ.js} +0 -0
  270. /package/dist/assets/{shell-DubUcuns.js → shell-bwEP1LQ1.js} +0 -0
  271. /package/dist/assets/{solidity-CNy2KSl2.js → solidity-DCddeBgL.js} +0 -0
  272. /package/dist/assets/{sophia-D9_URt84.js → sophia-BMN3AQig.js} +0 -0
  273. /package/dist/assets/{sparql-DviXpm4C.js → sparql-CSXOLjzi.js} +0 -0
  274. /package/dist/assets/{sql-vDRbAZgK.js → sql-COg8ewmK.js} +0 -0
  275. /package/dist/assets/{st-CnpnRqA7.js → st-CIaZtBS_.js} +0 -0
  276. /package/dist/assets/{swift-D_g8Ganz.js → swift-DXiOhUHu.js} +0 -0
  277. /package/dist/assets/{systemverilog-OuZa5h1M.js → systemverilog-BTDE6Dr2.js} +0 -0
  278. /package/dist/assets/{tcl-DBm9ucsV.js → tcl-B0zy9NvV.js} +0 -0
  279. /package/dist/assets/{twig-BRzEqX5Y.js → twig-D594l4Z1.js} +0 -0
  280. /package/dist/assets/{typespec-D4ZgGeX8.js → typespec-XKVjaPqo.js} +0 -0
  281. /package/dist/assets/{useWorkspaceMenuKeyboard-Brws6Ar9.js → useWorkspaceMenuKeyboard-Bpy_s69Z.js} +0 -0
  282. /package/dist/assets/{vb-DcP4s6WS.js → vb-B2wYoKRV.js} +0 -0
  283. /package/dist/assets/{wgsl-CnRJ_QUf.js → wgsl-D0Yf2LbK.js} +0 -0
  284. /package/dist/assets/{workspace-working-copy-D8-s_Sgh.js → workspace-working-copy-C3FSR3N6.js} +0 -0
@@ -0,0 +1,158 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react'
2
+ import { appPath } from '@/lib/base-path'
3
+ import { projectFilesWorkspaceId } from '@/lib/project-workspaces'
4
+ import {
5
+ applyBrowserResource,
6
+ applyBrowserResourceDeletion,
7
+ applyBrowserResourceSnapshot,
8
+ type BrowserResourceCollection,
9
+ type BrowserResourceDeletion,
10
+ } from './browser-resource-state'
11
+ import type { BrowserCapability, BrowserResource } from './types'
12
+
13
+ async function browserRequest<T>(pathname: string, init?: RequestInit): Promise<T> {
14
+ const response = await fetch(appPath(pathname), {
15
+ ...init,
16
+ headers: {
17
+ Accept: 'application/json',
18
+ ...(init?.body ? { 'Content-Type': 'application/json' } : {}),
19
+ ...init?.headers,
20
+ },
21
+ })
22
+ const data = await response.json().catch(() => ({})) as { error?: string }
23
+ if (!response.ok) throw new Error(data.error || `Browser request failed (${response.status})`)
24
+ return data as T
25
+ }
26
+
27
+ export function useBrowserResources() {
28
+ const [collection, setCollection] = useState<BrowserResourceCollection>({
29
+ collectionRevision: 0,
30
+ resources: [],
31
+ })
32
+ const [capability, setCapability] = useState<BrowserCapability | null>(null)
33
+ const [loading, setLoading] = useState(true)
34
+ const [refreshVersion, setRefreshVersion] = useState(0)
35
+
36
+ const mergeResource = useCallback((resource: BrowserResource) => {
37
+ setCollection(current => applyBrowserResource(current, resource))
38
+ }, [])
39
+
40
+ useEffect(() => {
41
+ let active = true
42
+ setLoading(true)
43
+ void browserRequest<BrowserCapability>('/api/browsers/capability').then(async nextCapability => {
44
+ if (!active) return
45
+ setCapability(nextCapability)
46
+ if (!nextCapability.available) {
47
+ setCollection({ collectionRevision: 0, resources: [] })
48
+ setLoading(false)
49
+ return
50
+ }
51
+ const list = await browserRequest<BrowserResourceCollection>('/api/browsers')
52
+ if (!active) return
53
+ setCollection(current => applyBrowserResourceSnapshot(current, list))
54
+ setLoading(false)
55
+ }).catch(() => {
56
+ if (active) setLoading(false)
57
+ })
58
+ return () => {
59
+ active = false
60
+ }
61
+ }, [refreshVersion])
62
+
63
+ useEffect(() => {
64
+ if (capability?.available !== true) return undefined
65
+ let active = true
66
+ const events = new EventSource(appPath('/api/browsers/events'))
67
+ events.addEventListener('resources', event => {
68
+ if (!active) return
69
+ const payload = JSON.parse((event as MessageEvent<string>).data) as BrowserResourceCollection
70
+ setCollection(current => applyBrowserResourceSnapshot(current, payload))
71
+ })
72
+ events.addEventListener('resource', event => {
73
+ if (!active) return
74
+ mergeResource(JSON.parse((event as MessageEvent<string>).data) as BrowserResource)
75
+ })
76
+ events.addEventListener('deleted', event => {
77
+ if (!active) return
78
+ const payload = JSON.parse((event as MessageEvent<string>).data) as BrowserResourceDeletion
79
+ setCollection(current => applyBrowserResourceDeletion(current, payload))
80
+ })
81
+ return () => {
82
+ active = false
83
+ events.close()
84
+ }
85
+ }, [capability?.available, mergeResource])
86
+
87
+ const create = useCallback(async (workspace: string, options: { name?: string; url?: string } = {}) => {
88
+ const resource = await browserRequest<BrowserResource>('/api/browsers', {
89
+ method: 'POST',
90
+ body: JSON.stringify({
91
+ rootId: projectFilesWorkspaceId(workspace),
92
+ name: options.name,
93
+ url: options.url,
94
+ }),
95
+ })
96
+ mergeResource(resource)
97
+ return resource
98
+ }, [mergeResource])
99
+
100
+ const rename = useCallback(async (id: string, name: string) => {
101
+ const resource = await browserRequest<BrowserResource>(`/api/browsers/${encodeURIComponent(id)}`, {
102
+ method: 'PATCH',
103
+ body: JSON.stringify({ name }),
104
+ })
105
+ mergeResource(resource)
106
+ return resource
107
+ }, [mergeResource])
108
+
109
+ const transition = useCallback(async (id: string, operation: 'start' | 'stop') => {
110
+ const resource = await browserRequest<BrowserResource>(
111
+ `/api/browsers/${encodeURIComponent(id)}/${operation}`,
112
+ { method: 'POST' },
113
+ )
114
+ mergeResource(resource)
115
+ return resource
116
+ }, [mergeResource])
117
+
118
+ const start = useCallback((id: string) => transition(id, 'start'), [transition])
119
+ const stop = useCallback((id: string) => transition(id, 'stop'), [transition])
120
+
121
+ const remove = useCallback(async (id: string) => {
122
+ const deletion = await browserRequest<BrowserResourceDeletion>(
123
+ `/api/browsers/${encodeURIComponent(id)}`,
124
+ { method: 'DELETE' },
125
+ )
126
+ setCollection(current => applyBrowserResourceDeletion(current, deletion))
127
+ }, [])
128
+
129
+ const refreshCapability = useCallback(() => {
130
+ setRefreshVersion(version => version + 1)
131
+ }, [])
132
+
133
+ const byWorkspace = useMemo(() => {
134
+ const result = new Map<string, BrowserResource[]>()
135
+ for (const resource of collection.resources) {
136
+ const current = result.get(resource.workspace) ?? []
137
+ current.push(resource)
138
+ result.set(resource.workspace, current)
139
+ }
140
+ return result
141
+ }, [collection.resources])
142
+
143
+ return {
144
+ resources: collection.resources,
145
+ byWorkspace,
146
+ capability,
147
+ loading,
148
+ create,
149
+ rename,
150
+ start,
151
+ stop,
152
+ remove,
153
+ mergeResource,
154
+ refreshCapability,
155
+ }
156
+ }
157
+
158
+ export type BrowserResourcesController = ReturnType<typeof useBrowserResources>
@@ -34,17 +34,18 @@
34
34
  },
35
35
 
36
36
  sendComposerMessage(agentId, message, attachments = [], options = {}) {
37
- const requestId = options.onResult
38
- ? `composer-${Date.now().toString(36)}-${++composerRequestSequence}`
39
- : '';
37
+ const requestedId = typeof options.requestId === 'string' ? options.requestId.trim() : '';
38
+ const requestId = requestedId
39
+ || globalThis.crypto?.randomUUID?.()
40
+ || `composer-${Date.now().toString(36)}-${++composerRequestSequence}`;
40
41
  const sent = send({
41
42
  type: 'composer-input',
42
43
  agentId,
43
44
  message,
44
- ...(requestId ? { requestId } : {}),
45
+ requestId,
45
46
  ...(attachments.length > 0 ? { attachments } : {}),
46
47
  });
47
- if (sent && requestId) composerResults.set(requestId, options.onResult);
48
+ if (sent && options.onResult) composerResults.set(requestId, options.onResult);
48
49
  return sent;
49
50
  },
50
51
 
@@ -58,7 +59,7 @@
58
59
  },
59
60
 
60
61
  rejectPendingComposerMessages(message = 'Connection unavailable') {
61
- composerResults.forEach(callback => callback({ accepted: false, message }));
62
+ composerResults.forEach(callback => callback({ accepted: false, message, uncertain: true }));
62
63
  composerResults.clear();
63
64
  },
64
65
 
@@ -101,6 +101,7 @@ let structuredComposerConfigId = '';
101
101
  let structuredComposerAttachments = [];
102
102
  const structuredComposerHistory = new Map();
103
103
  const structuredComposerPendingFollowUps = new Map();
104
+ const structuredComposerRequestIds = new Map();
104
105
  let structuredComposerHistoryIndex = -1;
105
106
  let structuredComposerCompositionEndAt = 0;
106
107
  let structuredComposerRestoreFocusAfterInterrupt = false;
@@ -6962,6 +6963,27 @@ function structuredComposerPromptAttachments() {
6962
6963
  ));
6963
6964
  }
6964
6965
 
6966
+ function structuredComposerRequestKey(agentId, message, attachments = []) {
6967
+ return JSON.stringify({
6968
+ agentId,
6969
+ message,
6970
+ attachments: attachments.map((attachment) => ({
6971
+ kind: attachment.kind,
6972
+ path: attachment.path,
6973
+ type: attachment.type,
6974
+ })),
6975
+ });
6976
+ }
6977
+
6978
+ function structuredComposerRequestId(requestKey) {
6979
+ const existing = structuredComposerRequestIds.get(requestKey);
6980
+ if (existing) return existing;
6981
+ const requestId = globalThis.crypto?.randomUUID?.()
6982
+ || `composer-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
6983
+ structuredComposerRequestIds.set(requestKey, requestId);
6984
+ return requestId;
6985
+ }
6986
+
6965
6987
  function structuredComposerHistoryFor(agentId) {
6966
6988
  if (!agentId) return [];
6967
6989
  return structuredComposerHistory.get(agentId) || [];
@@ -7580,10 +7602,17 @@ function setupStructuredSessionComposer() {
7580
7602
  const draft = input.value;
7581
7603
  const message = structuredComposerMessage(draft);
7582
7604
  const promptAttachments = structuredComposerPromptAttachments();
7605
+ const submittedAttachmentIds = structuredComposerAttachments.map((attachment) => attachment.id);
7583
7606
  if (!message && promptAttachments.length === 0) return;
7584
7607
  const statusNode = document.getElementById('crt-structured-composer-status');
7585
7608
  const completeSubmission = () => {
7586
7609
  addStructuredComposerHistory(agentId, draft);
7610
+ const ownsComposer = focusedAgentId === agentId
7611
+ && structuredSessionGeneration === generation
7612
+ && input.value === draft
7613
+ && structuredComposerAttachments.length === submittedAttachmentIds.length
7614
+ && structuredComposerAttachments.every((attachment, index) => attachment.id === submittedAttachmentIds[index]);
7615
+ if (!ownsComposer) return;
7587
7616
  input.value = '';
7588
7617
  structuredComposerAttachments = [];
7589
7618
  renderStructuredComposerAttachments();
@@ -7595,17 +7624,48 @@ function setupStructuredSessionComposer() {
7595
7624
  updateStructuredComposerState(agent);
7596
7625
  setTimeout(() => void refreshStructuredSession(agentId, true, generation), 160);
7597
7626
  };
7598
- const sent = action === 'send' && structuredRuntimeStatus(agent) !== 'idle'
7599
- ? (queueStructuredComposerFollowUp(agentId, message, promptAttachments), true)
7600
- : getSessionClient()?.sendComposerMessage(agentId, message, promptAttachments);
7627
+ if (action === 'send' && structuredRuntimeStatus(agent) !== 'idle') {
7628
+ queueStructuredComposerFollowUp(agentId, message, promptAttachments);
7629
+ completeSubmission();
7630
+ return;
7631
+ }
7632
+ const requestKey = structuredComposerRequestKey(agentId, message, promptAttachments);
7633
+ const requestId = structuredComposerRequestId(requestKey);
7634
+ const sent = getSessionClient()?.sendComposerMessage(agentId, message, promptAttachments, {
7635
+ requestId,
7636
+ onResult(result) {
7637
+ if (result?.accepted === true) {
7638
+ if (structuredComposerRequestIds.get(requestKey) === requestId) {
7639
+ structuredComposerRequestIds.delete(requestKey);
7640
+ }
7641
+ completeSubmission();
7642
+ return;
7643
+ }
7644
+ if (result?.uncertain !== true && structuredComposerRequestIds.get(requestKey) === requestId) {
7645
+ structuredComposerRequestIds.delete(requestKey);
7646
+ }
7647
+ if (focusedAgentId !== agentId || structuredSessionGeneration !== generation) return;
7648
+ if (statusNode) {
7649
+ statusNode.textContent = result?.message || 'Submission was not accepted';
7650
+ statusNode.classList.add('error');
7651
+ }
7652
+ input.focus();
7653
+ },
7654
+ });
7601
7655
  if (!sent) {
7656
+ if (structuredComposerRequestIds.get(requestKey) === requestId) {
7657
+ structuredComposerRequestIds.delete(requestKey);
7658
+ }
7602
7659
  if (statusNode) {
7603
7660
  statusNode.textContent = 'Connection unavailable';
7604
7661
  statusNode.classList.add('error');
7605
7662
  }
7606
7663
  return;
7607
7664
  }
7608
- completeSubmission();
7665
+ if (statusNode) {
7666
+ statusNode.textContent = 'SENDING...';
7667
+ statusNode.classList.remove('error');
7668
+ }
7609
7669
  });
7610
7670
  }
7611
7671
 
package/index.html CHANGED
@@ -1,9 +1,38 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
2
+ <html lang="en" data-appearance-preference="system">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
- <meta name="theme-color" content="#f8f4e8" />
6
+ <meta name="color-scheme" content="light dark" />
7
+ <meta name="theme-color" content="#ffffff" />
8
+ <style>
9
+ html,
10
+ body {
11
+ background: #ffffff;
12
+ }
13
+
14
+ html[data-appearance='dark'],
15
+ html[data-appearance='dark'] body {
16
+ background: #181818;
17
+ color-scheme: dark;
18
+ }
19
+ </style>
20
+ <script>
21
+ (() => {
22
+ const root = document.documentElement
23
+ const preference = ['light', 'dark'].includes(root.dataset.appearancePreference)
24
+ ? root.dataset.appearancePreference
25
+ : 'system'
26
+ const appearance = preference === 'system'
27
+ ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
28
+ : preference
29
+ root.dataset.appearance = appearance
30
+ document.querySelector('meta[name="theme-color"]')?.setAttribute(
31
+ 'content',
32
+ appearance === 'dark' ? '#181818' : '#ffffff',
33
+ )
34
+ })()
35
+ </script>
7
36
  <meta name="apple-mobile-web-app-capable" content="yes" />
8
37
  <meta name="mobile-web-app-capable" content="yes" />
9
38
  <meta name="apple-mobile-web-app-title" content="Farming 2" />
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "farming-code",
3
- "version": "2.2.27",
3
+ "version": "2.2.29",
4
4
  "description": "Farming Code is a self-hosted browser workspace for running and supervising AI coding agents",
5
5
  "main": "backend/server.js",
6
6
  "bin": {
7
- "farming": "bin/farming"
7
+ "farming": "bin/farming",
8
+ "farming-browser": "extensions/browser/bin/farming-browser"
8
9
  },
9
10
  "files": [
10
11
  "backend/*.js",
12
+ "backend/farming-agent-bootstrap.zh_cn.md",
11
13
  "backend/usage-history-scanner.ts",
12
14
  "backend/acp/",
13
15
  "backend/data/",
@@ -20,6 +22,7 @@
20
22
  "frontend/skins/",
21
23
  "frontend/themes/",
22
24
  "frontend/vendor/ghostty-web/",
25
+ "extensions/browser/",
23
26
  "shared/",
24
27
  "LICENSE",
25
28
  "README.md",
@@ -30,11 +33,12 @@
30
33
  ],
31
34
  "scripts": {
32
35
  "sync:ghostty-vendor": "node scripts/sync-ghostty-vendor.js",
33
- "prepare:acp-vendor": "node scripts/prepare-codex-acp-vendor.js --copy",
36
+ "prepare:acp-vendor": "node scripts/prepare-codex-acp-vendor.js --copy && node scripts/prepare-claude-acp-vendor.js --copy",
37
+ "prepare:runtime-manifest": "node scripts/build-runtime-dependency-manifest.js",
34
38
  "build:usage-history": "node scripts/build-usage-history-scanner.js",
35
- "prebuild": "node scripts/build-usage-history-scanner.js && node scripts/sync-ghostty-vendor.js && node scripts/prepare-codex-acp-vendor.js",
39
+ "prebuild": "node scripts/build-usage-history-scanner.js && node scripts/sync-ghostty-vendor.js && npm run prepare:acp-vendor && npm run prepare:runtime-manifest",
36
40
  "prepack": "FARMING_BASE_PATH=/farming npm run build",
37
- "pretest": "npm run prepare:acp-vendor && npm run build:usage-history",
41
+ "pretest": "npm run prepare:acp-vendor && npm run prepare:runtime-manifest && npm run build:usage-history",
38
42
  "start": "npm run build && node backend/server.js",
39
43
  "start:net": "node backend/farming-net-server.js",
40
44
  "start:no-auth": "FARMING_DISABLE_AUTH=1 npm start",
@@ -61,6 +65,7 @@
61
65
  "test": "node scripts/run-tests.js",
62
66
  "test:pre-release:codex-ui": "FARMING_REAL_CODEX_BIN=\"$(command -v codex)\" FARMING_CODEX_BIN=\"$PWD/tests/e2e/fixtures/real-codex-no-update\" FARMING_REAL_CODEX_RELEASE_CASE=1 FARMING_E2E_REAL_CODEX=1 FARMING_PLAYWRIGHT_INTERNAL=1 playwright test tests/e2e/internal/real-codex-release-case.spec.ts --project=chromium --workers=1 --retries=0 --trace=retain-on-failure",
63
67
  "test:pre-release:terminal-input": "playwright test tests/e2e/terminal-input-performance.spec.ts --project=chromium --workers=1 --retries=0 --trace=retain-on-failure",
68
+ "test:performance:transcript": "node backend/tests/test-acp-transcript-performance.js",
64
69
  "test:performance:audit": "node tests/performance/agent-usage-hotpath.js && FARMING_PLAYWRIGHT_INTERNAL=1 playwright test tests/e2e/internal/performance-bottlenecks.spec.ts --project=chromium --workers=1 --retries=0 --trace=retain-on-failure",
65
70
  "test:performance:scale": "FARMING_PLAYWRIGHT_INTERNAL=1 playwright test tests/e2e/internal/performance-scaling.spec.ts --project=chromium --workers=1 --retries=0 --trace=retain-on-failure",
66
71
  "test:update:platforms": "node scripts/test-update-platforms.js",
@@ -79,18 +84,17 @@
79
84
  "check": "npm run typecheck && npm run lint && npm test"
80
85
  },
81
86
  "keywords": [
82
- "ai-agent",
83
- "ai-agent-workspace",
87
+ "coding-agent-workspace",
88
+ "agent-supervision",
89
+ "agent-orchestration",
90
+ "multi-agent",
84
91
  "browser-terminal",
85
- "claude-code",
86
- "coding-agent",
87
- "codex",
88
- "codex-cli",
89
- "developer-tools",
90
- "farming-code",
91
- "remote-workspace",
92
+ "browser-workspace",
93
+ "remote-development",
92
94
  "self-hosted",
93
- "terminal"
95
+ "codex",
96
+ "claude-code",
97
+ "opencode"
94
98
  ],
95
99
  "author": "",
96
100
  "license": "MIT",
@@ -109,9 +113,8 @@
109
113
  "node": "^22.13.0 || >=24.0.0"
110
114
  },
111
115
  "dependencies": {
112
- "@agentclientprotocol/claude-agent-acp": "0.59.0",
113
- "@agentclientprotocol/codex-acp": "1.1.4",
114
116
  "@agentclientprotocol/sdk": "1.2.1",
117
+ "@modelcontextprotocol/sdk": "^1.29.0",
115
118
  "@xterm/addon-clipboard": "^0.2.0",
116
119
  "@xterm/addon-fit": "^0.11.0",
117
120
  "@xterm/addon-search": "^0.16.0",
@@ -125,6 +128,7 @@
125
128
  "express": "^4.22.2",
126
129
  "ghostty-web": "^0.4.0",
127
130
  "highlight.js": "^11.11.1",
131
+ "html2canvas": "^1.4.1",
128
132
  "katex": "^0.17.0",
129
133
  "material-icon-theme": "^5.36.1",
130
134
  "mermaid": "^11.16.0",
@@ -140,10 +144,14 @@
140
144
  "remark-gfm": "^4.0.1",
141
145
  "remark-math": "^6.0.0",
142
146
  "ripgrep": "^0.3.1",
147
+ "tar": "7.5.19",
143
148
  "ws": "^8.21.0",
144
- "yaml": "^2.9.0"
149
+ "yaml": "^2.9.0",
150
+ "zod": "^3.25.76"
145
151
  },
146
152
  "devDependencies": {
153
+ "@agentclientprotocol/claude-agent-acp": "0.59.0",
154
+ "@agentclientprotocol/codex-acp": "1.1.4",
147
155
  "@eslint/js": "^10.0.1",
148
156
  "@playwright/test": "^1.59.1",
149
157
  "@types/node": "^26.1.1",
@@ -151,6 +159,7 @@
151
159
  "@types/react-dom": "^19.2.3",
152
160
  "@vitejs/plugin-react": "^6.0.1",
153
161
  "@yao-pkg/pkg": "6.20.0",
162
+ "agent-browser": "0.32.3",
154
163
  "esbuild": "^0.27.7",
155
164
  "eslint": "^10.2.0",
156
165
  "patch-package": "8.0.1",
@@ -1,16 +1,28 @@
1
1
  export const BACKEND_INITIAL_CONNECT_GRACE_MS: number
2
+ export const BACKEND_HEARTBEAT_FAILURE_MS: number
2
3
  export const BACKEND_HEARTBEAT_STALE_MS: number
4
+ export const BACKEND_OBSERVER_LAG_RESET_MS: number
3
5
 
4
6
  export type BackendConnectionState = 'connecting' | 'lost' | 'stale' | null
5
7
  export interface PageVisibilitySnapshot {
6
8
  visible: boolean
7
9
  visibleSince: number
8
10
  }
11
+ export interface BackendObservation {
12
+ now: number
13
+ continuousSince: number
14
+ }
15
+
16
+ export function advanceBackendObservation(
17
+ current: BackendObservation,
18
+ observedAt: number,
19
+ ): BackendObservation
9
20
 
10
21
  export function classifyBackendConnection(input: {
11
22
  connected: boolean
12
23
  everConnected: boolean
13
24
  lastMessageAt: number
25
+ disconnectedAt: number | null
14
26
  visibleSince: number
15
27
  now: number
16
28
  }): BackendConnectionState
@@ -1,18 +1,46 @@
1
- const BACKEND_INITIAL_CONNECT_GRACE_MS = 3000;
1
+ const BACKEND_INITIAL_CONNECT_GRACE_MS = 8000;
2
2
  const BACKEND_HEARTBEAT_STALE_MS = 6000;
3
+ const BACKEND_HEARTBEAT_FAILURE_MS = 14000;
4
+ const BACKEND_OBSERVER_LAG_RESET_MS = 2500;
5
+
6
+ function advanceBackendObservation(current, observedAt) {
7
+ const now = Number.isFinite(observedAt) ? observedAt : Date.now();
8
+ const previousNow = Number.isFinite(current?.now) ? current.now : now;
9
+ const continuousSince = Number.isFinite(current?.continuousSince)
10
+ ? current.continuousSince
11
+ : previousNow;
12
+ return {
13
+ now,
14
+ continuousSince: now - previousNow > BACKEND_OBSERVER_LAG_RESET_MS
15
+ ? now
16
+ : continuousSince,
17
+ };
18
+ }
3
19
 
4
20
  function classifyBackendConnection({
5
21
  connected,
6
22
  everConnected,
7
23
  lastMessageAt,
24
+ disconnectedAt,
8
25
  visibleSince,
9
26
  now,
10
27
  }) {
28
+ if (!connected) {
29
+ const disconnectObservedAt = Number.isFinite(disconnectedAt)
30
+ ? disconnectedAt
31
+ : lastMessageAt;
32
+ const disconnectedElapsed = Math.max(
33
+ 0,
34
+ now - Math.max(disconnectObservedAt, visibleSince),
35
+ );
36
+ return disconnectedElapsed >= BACKEND_INITIAL_CONNECT_GRACE_MS
37
+ ? 'lost'
38
+ : 'connecting';
39
+ }
11
40
  const observationStartedAt = Math.max(lastMessageAt, visibleSince);
12
41
  const elapsed = Math.max(0, now - observationStartedAt);
13
- if (!connected && everConnected) return 'lost';
14
- if (!connected && elapsed >= BACKEND_INITIAL_CONNECT_GRACE_MS) return 'connecting';
15
- if (connected && elapsed >= BACKEND_HEARTBEAT_STALE_MS) return 'stale';
42
+ if (elapsed >= BACKEND_HEARTBEAT_FAILURE_MS) return 'stale';
43
+ if (elapsed >= BACKEND_HEARTBEAT_STALE_MS) return 'connecting';
16
44
  return null;
17
45
  }
18
46
 
@@ -34,7 +62,10 @@ function reducePageVisibilitySnapshot(current, {
34
62
 
35
63
  module.exports = {
36
64
  BACKEND_INITIAL_CONNECT_GRACE_MS,
65
+ BACKEND_HEARTBEAT_FAILURE_MS,
37
66
  BACKEND_HEARTBEAT_STALE_MS,
67
+ BACKEND_OBSERVER_LAG_RESET_MS,
68
+ advanceBackendObservation,
38
69
  classifyBackendConnection,
39
70
  reducePageVisibilitySnapshot,
40
71
  };
@@ -101,7 +101,7 @@ function validateServerMessage(value) {
101
101
  case 'error': valid = stringField(value, 'message'); break;
102
102
  case 'command-ack': valid = stringField(value, 'requestId') && stringField(value, 'command'); break;
103
103
  case 'state': valid = objectMessage(value.state) && Array.isArray(value.state.agents); break;
104
- case 'composer-input-result': valid = stringField(value, 'requestId') && stringField(value, 'agentId') && typeof value.accepted === 'boolean' && stringField(value, 'message', true); break;
104
+ case 'composer-input-result': valid = stringField(value, 'requestId') && stringField(value, 'agentId') && typeof value.accepted === 'boolean' && stringField(value, 'message', true) && (!Object.prototype.hasOwnProperty.call(value, 'uncertain') || typeof value.uncertain === 'boolean'); break;
105
105
  case 'agent-started': valid = stringField(value, 'agentId'); break;
106
106
  case 'session-output': valid = objectMessage(value.stream) && stringField(value.stream, 'agentId'); break;
107
107
  case 'session-preview': valid = objectMessage(value.preview) && stringField(value.preview, 'agentId'); break;
@@ -1,35 +0,0 @@
1
- const { deriveRuntimeObservation } = require('./runtime-observation');
2
-
3
- function agentKindForCommand(command) {
4
- const executable = String(command || '')
5
- .trim()
6
- .split(/\s+/)
7
- .find(token => token !== 'env' && !/^[A-Za-z_][A-Za-z0-9_]*=/.test(token));
8
- const basename = (executable || '').split('/').pop() || '';
9
- if (basename === 'codex') return 'codex';
10
- if (basename === 'claude') return 'claude';
11
- if (['bash', 'zsh', 'sh', 'fish'].includes(basename)) return 'shell';
12
- return executable ? 'agent' : null;
13
- }
14
-
15
- function isRecoverableEngineAgent(agent) {
16
- return agent && agent.engineName === 'native';
17
- }
18
-
19
- function isRestartBlockingAgent(agent) {
20
- if (!agent || agent.isMain === true || agent.archived === true) return false;
21
- if (agent.status === 'pending') return true;
22
- if (agent.status !== 'running') return false;
23
- if (isRecoverableEngineAgent(agent)) return false;
24
-
25
- const observation = deriveRuntimeObservation(agent);
26
- if (observation.phase === 'starting' || observation.phase === 'working' || observation.phase === 'waiting') return true;
27
- if (observation.phase === 'idle' || observation.phase === 'exited') return false;
28
- return observation.kind !== 'shell';
29
- }
30
-
31
- module.exports = {
32
- agentKindForCommand,
33
- isRecoverableEngineAgent,
34
- isRestartBlockingAgent,
35
- };
@@ -1 +0,0 @@
1
- .xterm{cursor:text;-webkit-user-select:none;user-select:none;position:relative}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{z-index:5;position:absolute;top:0}.xterm .xterm-helper-textarea{opacity:0;z-index:-5;white-space:nowrap;resize:none;border:0;width:0;height:0;margin:0;padding:0;position:absolute;top:0;left:-9999em;overflow:hidden}.xterm .composition-view{color:#fff;white-space:nowrap;z-index:1;background:#000;display:none;position:absolute}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{cursor:default;background-color:#000;position:absolute;inset:0;overflow-y:scroll}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;top:0;left:0}.xterm-char-measure-element{visibility:hidden;line-height:normal;display:inline-block;position:absolute;top:0;left:-9999em}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{z-index:10;color:#0000;pointer-events:none;position:absolute;inset:0}.xterm .xterm-accessibility-tree:not(.debug) ::selection{color:#0000}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre;font-family:monospace}.xterm .xterm-accessibility-tree>div{transform-origin:0;width:fit-content}.xterm .live-region{width:1px;height:1px;position:absolute;left:-9999px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{-webkit-text-decoration:underline double;text-decoration:underline double}.xterm-underline-3{-webkit-text-decoration:underline wavy;text-decoration:underline wavy}.xterm-underline-4{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.xterm-underline-5{-webkit-text-decoration:underline dashed;text-decoration:underline dashed}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:underline overline}.xterm-overline.xterm-underline-2{-webkit-text-decoration:overline double underline;text-decoration:overline double underline}.xterm-overline.xterm-underline-3{-webkit-text-decoration:overline wavy underline;text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{-webkit-text-decoration:overline dotted underline;text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{-webkit-text-decoration:overline dashed underline;text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;pointer-events:none;position:absolute;top:0;right:0}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;z-index:11;background:0 0;transition:opacity .1s linear}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{display:none;position:absolute}.xterm .xterm-scrollable-element>.shadow.top{width:100%;height:3px;box-shadow:var(--vscode-scrollbar-shadow,#000) 0 6px 6px -6px inset;display:block;top:0;left:3px}.xterm .xterm-scrollable-element>.shadow.left{width:3px;height:100%;box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset;display:block;top:3px;left:0}.xterm .xterm-scrollable-element>.shadow.top-left-corner{width:3px;height:3px;display:block;top:0;left:0}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset}