farming-code 2.2.23 → 2.2.28

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 (264) hide show
  1. package/README.md +9 -2
  2. package/README.zh_cn.md +9 -2
  3. package/THIRD_PARTY_NOTICES.md +3 -0
  4. package/backend/acp-runtime.js +15 -1
  5. package/backend/agent-manager.js +1054 -94
  6. package/backend/atomic-json-store.js +37 -0
  7. package/backend/cli-agents.js +9 -7
  8. package/backend/config-manager.js +167 -58
  9. package/backend/control-api.js +2 -1
  10. package/backend/farming-agent-bootstrap.js +49 -0
  11. package/backend/farming-agent-bootstrap.zh_cn.md +5 -0
  12. package/backend/farming-app-cli.js +9 -2
  13. package/backend/farming-cli.js +55 -0
  14. package/backend/farming-session-store.js +92 -89
  15. package/backend/main-agent-skills.js +17 -0
  16. package/backend/native-pty-host-client.js +99 -7
  17. package/backend/native-pty-host-path.js +20 -0
  18. package/backend/native-pty-host.js +6 -5
  19. package/backend/preview-session-manager.js +68 -0
  20. package/backend/provider-adapters.js +44 -5
  21. package/backend/review-session-store.js +32 -25
  22. package/backend/review-state-store.js +13 -14
  23. package/backend/run-history-store.js +13 -16
  24. package/backend/server.js +103 -78
  25. package/backend/storage-layout.js +20 -0
  26. package/backend/workspace-file-router.js +171 -6
  27. package/backend/workspace-file-service.js +19 -0
  28. package/backend/workspace-root-registry.js +6 -4
  29. package/dist/assets/App-CM7Cy-l4.css +1 -0
  30. package/dist/assets/App-CPG4WcjO.js +658 -0
  31. package/dist/assets/{FileEditorMarkdownPreview-KbnE8VC8.js → FileEditorMarkdownPreview-DYOMm-b1.js} +5 -5
  32. package/dist/assets/FileEditorPane-DXXq82aM.js +2 -0
  33. package/dist/assets/IconGlyphs-DrdPjYXr.js +1 -0
  34. package/dist/assets/ProjectFilesSection-CP66XVPl.js +12 -0
  35. package/dist/assets/{ReviewPage-L1vh1Ggs.js → ReviewPage-w21MEPD6.js} +1 -1
  36. package/dist/assets/{abnfDiagram-VRR7QNED-nnglrXFi.js → abnfDiagram-VRR7QNED-BY1qwq8A.js} +1 -1
  37. package/dist/assets/api-w2x5QfxB.js +1 -0
  38. package/dist/assets/{arc-CWoVlxJw.js → arc-DgZRAlwj.js} +1 -1
  39. package/dist/assets/{architectureDiagram-ZJ3FMSHR-BEXMaFfY.js → architectureDiagram-ZJ3FMSHR-jFn144od.js} +1 -1
  40. package/dist/assets/{blockDiagram-677ZJIJ3-1mCezSBk.js → blockDiagram-677ZJIJ3-BmRjlV0H.js} +1 -1
  41. package/dist/assets/{c4Diagram-LMCZKHZV-DhTiI6Uv.js → c4Diagram-LMCZKHZV-DUKul6tT.js} +1 -1
  42. package/dist/assets/{workspace-editor-monaco-DLlws5Ig.js → channel-CI9j3QFD.js} +1 -1
  43. package/dist/assets/chunk-2Q5K7J3B-87UnWaoh.js +1 -0
  44. package/dist/assets/{chunk-32BRIVSS-CCdsKd73.js → chunk-32BRIVSS-rGVu23o5.js} +1 -1
  45. package/dist/assets/{chunk-52WLFC77-Gncjk4LF.js → chunk-52WLFC77-CvFDKgbB.js} +1 -1
  46. package/dist/assets/{chunk-5VM5RSS4-Dlw7AXWp.js → chunk-5VM5RSS4-CFgnRW1C.js} +1 -1
  47. package/dist/assets/{chunk-7BUUIJ7U-ZBRhjLOh.js → chunk-7BUUIJ7U-Cp7bqW6s.js} +1 -1
  48. package/dist/assets/{chunk-C7G6YPKG-CiDVUP82.js → chunk-C7G6YPKG-BIS1gjZO.js} +1 -1
  49. package/dist/assets/{chunk-EX3LRPZG-z6gXP2_N.js → chunk-EX3LRPZG-BKG-cR9j.js} +1 -1
  50. package/dist/assets/{chunk-FWX5IMBZ-DMZBccQa.js → chunk-FWX5IMBZ-B8PsTr8a.js} +2 -2
  51. package/dist/assets/{chunk-HOUHSVGY-D8tIeoPk.js → chunk-HOUHSVGY-BHFOAiXT.js} +1 -1
  52. package/dist/assets/{chunk-ICXQ74PX-b6oQ2Q17.js → chunk-ICXQ74PX-CvLE1J9X.js} +1 -1
  53. package/dist/assets/{chunk-JWPE2WC7-DSyBRaRG.js → chunk-JWPE2WC7-D8misks7.js} +1 -1
  54. package/dist/assets/{chunk-MOJQB5TN-DAVH_p2a.js → chunk-MOJQB5TN-D-oNgSNH.js} +1 -1
  55. package/dist/assets/{chunk-OGEWGWER-DxoiMCI-.js → chunk-OGEWGWER-C2N-la9e.js} +1 -1
  56. package/dist/assets/{chunk-PUDLZKDR-NsOWh7HM.js → chunk-PUDLZKDR-BwI3Jz8q.js} +1 -1
  57. package/dist/assets/{chunk-Q4XR5HBZ-Di4H7L21.js → chunk-Q4XR5HBZ-BuqGfsXA.js} +1 -1
  58. package/dist/assets/{chunk-RYQCIY6F-CZA9pvFX.js → chunk-RYQCIY6F-Bq4XZcGt.js} +1 -1
  59. package/dist/assets/{chunk-V7JOEXUC-DttpZg9Y.js → chunk-V7JOEXUC-QZLzdTTJ.js} +1 -1
  60. package/dist/assets/chunk-VAUOI2AC-Cb0-kQ9g.js +1 -0
  61. package/dist/assets/{chunk-VR4S4FIN-D-Fmtd4Z.js → chunk-VR4S4FIN-DcZTpML_.js} +1 -1
  62. package/dist/assets/{chunk-WYO6CB5R-CUxMtfK2.js → chunk-WYO6CB5R-DCU8wuny.js} +2 -2
  63. package/dist/assets/chunk-XXDRQBXY-BZAC1Krv.js +1 -0
  64. package/dist/assets/{chunk-ZGVPDNZ5-CoV2QEl0.js → chunk-ZGVPDNZ5-B7r85QbY.js} +1 -1
  65. package/dist/assets/{chunk-ZIRB5QZD-DncwlQQc.js → chunk-ZIRB5QZD-BgEnDWhQ.js} +1 -1
  66. package/dist/assets/classDiagram-OUVF2IWQ-DcvGOuvi.js +1 -0
  67. package/dist/assets/classDiagram-v2-EOCWNBFH-DDYUSofQ.js +1 -0
  68. package/dist/assets/code-dark-BDjwj7Um.css +1 -0
  69. package/dist/assets/{cose-bilkent-JH36ORCC-BNIAz0nN.js → cose-bilkent-JH36ORCC-CThXS2qG.js} +1 -1
  70. package/dist/assets/{cssMode-DDWxTPm_.js → cssMode-Bdg5RpcJ.js} +1 -1
  71. package/dist/assets/{cynefinDiagram-TSTJHNR4-0xPI92Lg.js → cynefinDiagram-TSTJHNR4-DxBgzw25.js} +1 -1
  72. package/dist/assets/{dagre-DXlcHgr3.js → dagre-BM-GvGUZ.js} +1 -1
  73. package/dist/assets/{dagre-VKFMJZFB-DfuMG4gU.js → dagre-VKFMJZFB-B7UCRmxR.js} +1 -1
  74. package/dist/assets/{diagram-FQU43EPY-CT00bLZ6.js → diagram-FQU43EPY-CeL2DwKx.js} +1 -1
  75. package/dist/assets/{diagram-G47NLZAW-Xbh7zXUx.js → diagram-G47NLZAW-BEirglCC.js} +1 -1
  76. package/dist/assets/{diagram-NH7WQ7WH-SRDVPfn7.js → diagram-NH7WQ7WH-C6wcI-Rl.js} +1 -1
  77. package/dist/assets/{diagram-OA4YK3LP-CQRli4Np.js → diagram-OA4YK3LP-DpM-XXtJ.js} +1 -1
  78. package/dist/assets/{diagram-WEI45ONY-DMf17WQi.js → diagram-WEI45ONY-BQyaut9k.js} +1 -1
  79. package/dist/assets/{ebnfDiagram-CCIWWBDH-DhpFkgJ5.js → ebnfDiagram-CCIWWBDH-UmAXsUhr.js} +1 -1
  80. package/dist/assets/{erDiagram-Q63AITRT-1IwxWmJo.js → erDiagram-Q63AITRT-CdYLEOch.js} +1 -1
  81. package/dist/assets/file-icons-BOlcJ0ZF.js +1 -0
  82. package/dist/assets/flowDiagram-23GEKE2U-CO-z9-tq.js +1 -0
  83. package/dist/assets/{freemarker2-QBsTERH-.js → freemarker2-DfMDJfnE.js} +1 -1
  84. package/dist/assets/{ganttDiagram-NO4QXBWP-BNCdfyr1.js → ganttDiagram-NO4QXBWP-DgSUNdUB.js} +1 -1
  85. package/dist/assets/{gitGraphDiagram-IHSO6WYX-pbyWZuiX.js → gitGraphDiagram-IHSO6WYX-DjwjtRtF.js} +1 -1
  86. package/dist/assets/{handlebars-CuoxPo5A.js → handlebars-BEdPtzMT.js} +1 -1
  87. package/dist/assets/{html-gX5PEu0Q.js → html-B1fPb1QD.js} +1 -1
  88. package/dist/assets/html2canvas-DsczWxBa.js +5 -0
  89. package/dist/assets/{htmlMode-DIWUbUxd.js → htmlMode-CY2ZjHxH.js} +1 -1
  90. package/dist/assets/{index-DhTUO8DA.js → index-BzQO3pUr.js} +2 -2
  91. package/dist/assets/{infoDiagram-FWYZ7A6U-BcTOgDbe.js → infoDiagram-FWYZ7A6U-Bi9076l2.js} +1 -1
  92. package/dist/assets/{ishikawaDiagram-FXEZZL3T-DCdvGKrn.js → ishikawaDiagram-FXEZZL3T-DaMaNZN7.js} +1 -1
  93. package/dist/assets/{javascript-BYKGIUGs.js → javascript-BV2OsWA0.js} +1 -1
  94. package/dist/assets/{journeyDiagram-5HDEW3XC-BZ-1q_IT.js → journeyDiagram-5HDEW3XC-CfDy69EZ.js} +1 -1
  95. package/dist/assets/{jsonMode-AFmQQP6u.js → jsonMode-zd07aeuX.js} +1 -1
  96. package/dist/assets/{kanban-definition-HUTT4EX6-BIgejCjj.js → kanban-definition-HUTT4EX6-XFvZ722B.js} +1 -1
  97. package/dist/assets/{line-CfptFMmX.js → line-BXK9PKLn.js} +1 -1
  98. package/dist/assets/{linear-Dld3_ERu.js → linear-CULvmq2Z.js} +1 -1
  99. package/dist/assets/{liquid-DBIl-f0z.js → liquid-BParI24X.js} +1 -1
  100. package/dist/assets/{lspLanguageFeatures-DK6tqicV.js → lspLanguageFeatures-BzredkoV.js} +1 -1
  101. package/dist/assets/main-BlVUXfxa.css +1 -0
  102. package/dist/assets/{map-LZWWoeWa.js → map-C9Qw9eWh.js} +1 -1
  103. package/dist/assets/{mdx-DS-bVtZN.js → mdx-vGzUJN98.js} +1 -1
  104. package/dist/assets/{mermaid.core-gSpX30pV.js → mermaid.core-CzazaIKr.js} +3 -3
  105. package/dist/assets/{mindmap-definition-LN4V7U3C-BKBaI4LW.js → mindmap-definition-LN4V7U3C-Uoff7hZ3.js} +1 -1
  106. package/dist/assets/{monaco.contribution-BXz-lfFB.js → monaco.contribution-BmaeBQEc.js} +2 -2
  107. package/dist/assets/{ordinal-BLrOss5K.js → ordinal-r6pIwRdZ.js} +1 -1
  108. package/dist/assets/{pegDiagram-2B236MQR-sBvDY3VX.js → pegDiagram-2B236MQR-CCBiHQjk.js} +1 -1
  109. package/dist/assets/{pieDiagram-ENE6RG2P-DWlWcu08.js → pieDiagram-ENE6RG2P-D61s7l75.js} +1 -1
  110. package/dist/assets/{python-C93q3xXz.js → python-CUwdLgsI.js} +1 -1
  111. package/dist/assets/{quadrantDiagram-ABIIQ3AL-DZutUd3J.js → quadrantDiagram-ABIIQ3AL-D_CWk2DQ.js} +1 -1
  112. package/dist/assets/{railroadDiagram-RFXS5EU6-DQb3lXGM.js → railroadDiagram-RFXS5EU6-CdlCHtxN.js} +1 -1
  113. package/dist/assets/{razor-CBifNGXO.js → razor-BScebUxU.js} +1 -1
  114. package/dist/assets/{requirementDiagram-TGXJPOKE-DqFGXu2e.js → requirementDiagram-TGXJPOKE-BLpHtkoC.js} +1 -1
  115. package/dist/assets/{sankeyDiagram-HTMAVEWB-d7ECahnO.js → sankeyDiagram-HTMAVEWB-CkhYZN2j.js} +1 -1
  116. package/dist/assets/{sequenceDiagram-DBY2YBRQ-DdsbKqct.js → sequenceDiagram-DBY2YBRQ-8bploKJl.js} +1 -1
  117. package/dist/assets/{sizeCapture-X5ZJPWSS-daTB6OcF.js → sizeCapture-X5ZJPWSS-DtSdkS0d.js} +1 -1
  118. package/dist/assets/{src-WBW1QxJt.js → src-6yeq6WBA.js} +1 -1
  119. package/dist/assets/{stateDiagram-2N3HPSRC-P6iSrgwR.js → stateDiagram-2N3HPSRC-DfmVGpfA.js} +1 -1
  120. package/dist/assets/stateDiagram-v2-6OUMAXLB-B2c9CQ-J.js +1 -0
  121. package/dist/assets/{swimlanes-5IMT3BWC-BGnZJx1M.js → swimlanes-5IMT3BWC-DRLk2zRF.js} +2 -2
  122. package/dist/assets/swimlanesDiagram-G3AALYLV-B7_APh_h.js +8 -0
  123. package/dist/assets/{timeline-definition-FHXFAJF6-rA-r3aUR.js → timeline-definition-FHXFAJF6-Cngfy588.js} +1 -1
  124. package/dist/assets/{tsMode-B0oUTcXQ.js → tsMode-DzUAibXK.js} +1 -1
  125. package/dist/assets/{typescript-KJKfYO7K.js → typescript-D9EOeM7N.js} +1 -1
  126. package/dist/assets/{vennDiagram-L72KCM5P-DiVKUjA9.js → vennDiagram-L72KCM5P-DeJn63Lq.js} +1 -1
  127. package/dist/assets/{wardleyDiagram-EHGQE667-Cfxh7UOn.js → wardleyDiagram-EHGQE667-BH1nzy77.js} +1 -1
  128. package/dist/assets/{workers-BSQRIkqa.js → workers-DAiomYZM.js} +1 -1
  129. package/dist/assets/workspace-editor-model-CSGCl21x.js +1 -0
  130. package/dist/assets/workspace-editor-monaco-CFEfFNcA.js +1 -0
  131. package/dist/assets/{workspace-editor-monaco-BIpqcWf1.js → workspace-editor-monaco-tXA-udGx.js} +3 -3
  132. package/dist/assets/workspace-view-state-BS_V8JVs.js +7 -0
  133. package/dist/assets/{xml-C8FAcN6j.js → xml-wWl1dhkQ.js} +1 -1
  134. package/dist/assets/{xychartDiagram-FW5EYKEG--hmryQeL.js → xychartDiagram-FW5EYKEG-SkO2prCU.js} +1 -1
  135. package/dist/assets/{yaml-BQ4NrRhG.js → yaml-Dc2WDaOZ.js} +1 -1
  136. package/dist/crt-markdown-renderer.js +46 -46
  137. package/dist/index.html +1 -1
  138. package/extensions/browser/backend/agent-capability.js +55 -0
  139. package/extensions/browser/backend/browser-mcp-server.js +269 -0
  140. package/extensions/browser/backend/browser-resource-manager.js +524 -0
  141. package/extensions/browser/backend/browser-resource-store.js +149 -0
  142. package/extensions/browser/backend/browser-router.js +128 -0
  143. package/extensions/browser/backend/cdp-browser-runtime.js +648 -0
  144. package/extensions/browser/backend/cdp-client.js +167 -0
  145. package/extensions/browser/backend/executable-discovery.js +91 -0
  146. package/extensions/browser/backend/farming-browser-client.js +83 -0
  147. package/extensions/browser/backend/index.js +7 -0
  148. package/extensions/browser/bin/farming-browser +117 -0
  149. package/extensions/browser/frontend/BrowserSidebarPortals.tsx +362 -0
  150. package/extensions/browser/frontend/BrowserViewer.tsx +329 -0
  151. package/extensions/browser/frontend/browser-resource-state.ts +60 -0
  152. package/extensions/browser/frontend/browser.css +516 -0
  153. package/extensions/browser/frontend/types.ts +25 -0
  154. package/extensions/browser/frontend/useBrowserResources.ts +151 -0
  155. package/frontend/session-bridge.js +7 -6
  156. package/frontend/skins/crt/app.js +64 -4
  157. package/package.json +18 -13
  158. package/shared/browser-protocol.js +1 -1
  159. package/dist/assets/App-BbNBDA__.js +0 -210
  160. package/dist/assets/App-BrP-ENHg.css +0 -1
  161. package/dist/assets/FileEditorPane-5_HUejjd.js +0 -2
  162. package/dist/assets/IconGlyphs-C2WFcoJS.js +0 -1
  163. package/dist/assets/ProjectFilesSection-C1RAJWOE.js +0 -12
  164. package/dist/assets/api-D8nyOEbz.js +0 -1
  165. package/dist/assets/channel-BVWNatUB.js +0 -1
  166. package/dist/assets/chunk-2Q5K7J3B-d5WWh8jo.js +0 -1
  167. package/dist/assets/chunk-VAUOI2AC-UHNr_yhX.js +0 -1
  168. package/dist/assets/chunk-XXDRQBXY-BBXwjhUx.js +0 -1
  169. package/dist/assets/classDiagram-OUVF2IWQ-Db0ib5iE.js +0 -1
  170. package/dist/assets/classDiagram-v2-EOCWNBFH-Bkf69XF9.js +0 -1
  171. package/dist/assets/code-dark-BKtvf0Xc.css +0 -1
  172. package/dist/assets/file-icons-CHWt5nSy.js +0 -1
  173. package/dist/assets/flowDiagram-23GEKE2U-DYFo2xmB.js +0 -1
  174. package/dist/assets/main-XMXgyJJt.css +0 -1
  175. package/dist/assets/stateDiagram-v2-6OUMAXLB-DIYSf_qh.js +0 -1
  176. package/dist/assets/swimlanesDiagram-G3AALYLV-BIkrlKrZ.js +0 -8
  177. package/dist/assets/workspace-editor-model-D0Im34S5.js +0 -1
  178. package/dist/assets/workspace-view-state-BqB4HM7r.js +0 -7
  179. /package/dist/assets/{abap-Cc5D5h5i.js → abap-CtX5nWyX.js} +0 -0
  180. /package/dist/assets/{apex-BKopwLmx.js → apex-DQJRAHwc.js} +0 -0
  181. /package/dist/assets/{array-HeX70jSN.js → array-BTwzYU0x.js} +0 -0
  182. /package/dist/assets/{azcli-DI-C34WA.js → azcli-9SMrOQ4q.js} +0 -0
  183. /package/dist/assets/{bat-Cbp6u42z.js → bat-CBGLUsw1.js} +0 -0
  184. /package/dist/assets/{bicep-4QA1jTCM.js → bicep-pDx8da1v.js} +0 -0
  185. /package/dist/assets/{cameligo-Dda_adPs.js → cameligo-hZV3vQ6_.js} +0 -0
  186. /package/dist/assets/{chunk-Y2CYZVJY-Di0sYzi1.js → chunk-Y2CYZVJY-BYi0W5ea.js} +0 -0
  187. /package/dist/assets/{clojure-CvY8A83L.js → clojure-BhCwU3gq.js} +0 -0
  188. /package/dist/assets/{coffee-4LX2Sv8A.js → coffee-BVB1PsgH.js} +0 -0
  189. /package/dist/assets/{core-B9MwRjDE.js → core-vPkV8P_m.js} +0 -0
  190. /package/dist/assets/{cpp-D4AzSV28.js → cpp-eTjuiNPq.js} +0 -0
  191. /package/dist/assets/{csharp-C4nWN4Yd.js → csharp-1kP-kKZT.js} +0 -0
  192. /package/dist/assets/{csp-CiEaaS5Z.js → csp-C_iQqIes.js} +0 -0
  193. /package/dist/assets/{css-DXxBRsbk.js → css-CxOs7IfP.js} +0 -0
  194. /package/dist/assets/{cypher-DOMzqyFA.js → cypher-Cd-a9Y82.js} +0 -0
  195. /package/dist/assets/{cytoscape.esm-Cl8iC3D7.js → cytoscape.esm-OLojuicg.js} +0 -0
  196. /package/dist/assets/{dart-BWS7MXt_.js → dart-whhXpexn.js} +0 -0
  197. /package/dist/assets/{defaultLocale-GJwWH1Jr.js → defaultLocale-CPimVhfE.js} +0 -0
  198. /package/dist/assets/{dist-ClAL-Tv5.js → dist-CLPYXg1u.js} +0 -0
  199. /package/dist/assets/{dockerfile-Baf4U3xT.js → dockerfile-DibBi8b6.js} +0 -0
  200. /package/dist/assets/{ecl-CT7udlkQ.js → ecl-DlF1KdoW.js} +0 -0
  201. /package/dist/assets/{editor.api2-B9h6iFPK.js → editor.api2-D74ufkbr.js} +0 -0
  202. /package/dist/assets/{elixir-CIbAZw5l.js → elixir-CHQ8uFT3.js} +0 -0
  203. /package/dist/assets/{flow9-Dqiw45WV.js → flow9-8nUnVKk1.js} +0 -0
  204. /package/dist/assets/{fsharp-E8E2L9jU.js → fsharp-DNZNZyEE.js} +0 -0
  205. /package/dist/assets/{go-CouVSN4D.js → go-_kPJjNc_.js} +0 -0
  206. /package/dist/assets/{graphlib-CbSvZcZU.js → graphlib-CBGF9gA9.js} +0 -0
  207. /package/dist/assets/{graphql-a6h6h5-t.js → graphql-4HCNVt5g.js} +0 -0
  208. /package/dist/assets/{hcl-vso3e6N-.js → hcl-C87ymY0o.js} +0 -0
  209. /package/dist/assets/{ini-SwZZkotR.js → ini-BYrrGNTc.js} +0 -0
  210. /package/dist/assets/{init-BPLPMQ3Y.js → init-8_PCa3LO.js} +0 -0
  211. /package/dist/assets/{java-CtRLC4_3.js → java-B211rJbk.js} +0 -0
  212. /package/dist/assets/{julia-CuJWFKQH.js → julia-DVPsRtBm.js} +0 -0
  213. /package/dist/assets/{katex-C8DPyI6s.js → katex-C2iYad0m.js} +0 -0
  214. /package/dist/assets/{kotlin-B_kBhsre.js → kotlin-BYyNerjp.js} +0 -0
  215. /package/dist/assets/{less-CtrHIfz3.js → less-EC9UblGE.js} +0 -0
  216. /package/dist/assets/{lexon-yVt1pJLu.js → lexon-B1yuUdqW.js} +0 -0
  217. /package/dist/assets/{lua-prOwgJ4U.js → lua-Bo6GFzxT.js} +0 -0
  218. /package/dist/assets/{m3-DhrdTQ84.js → m3-C-Y9cBVI.js} +0 -0
  219. /package/dist/assets/{markdown-DoI5HwSM.js → markdown-BHu-wLbe.js} +0 -0
  220. /package/dist/assets/{mermaid-parser.core-BQtepoLd.js → mermaid-parser.core-IxcGtNYG.js} +0 -0
  221. /package/dist/assets/{mips-Dye5jsBU.js → mips-Dkds26rX.js} +0 -0
  222. /package/dist/assets/{msdax-TkNOyIL8.js → msdax-PU4g-8_g.js} +0 -0
  223. /package/dist/assets/{mysql-CEc-RKZF.js → mysql-fPpuGpS7.js} +0 -0
  224. /package/dist/assets/{objective-c-CqqCsQz0.js → objective-c-Wy1e5JUf.js} +0 -0
  225. /package/dist/assets/{pascal-DO_pj8yg.js → pascal-BIXwvrqU.js} +0 -0
  226. /package/dist/assets/{pascaligo-1cbdZdF3.js → pascaligo-DwR0AtL_.js} +0 -0
  227. /package/dist/assets/{path-YdFzr2W6.js → path-BxQuywGl.js} +0 -0
  228. /package/dist/assets/{perl-B_N3PYfC.js → perl-CGHAl8my.js} +0 -0
  229. /package/dist/assets/{pgsql-9iYk1FQ7.js → pgsql-B91M73E2.js} +0 -0
  230. /package/dist/assets/{php-rO2sgoUM.js → php-C70ttrCx.js} +0 -0
  231. /package/dist/assets/{pla-Cbgv60kq.js → pla-BNrXaRh0.js} +0 -0
  232. /package/dist/assets/{postiats-y6xrhy_M.js → postiats-Dv2IAZR9.js} +0 -0
  233. /package/dist/assets/{powerquery-BaD8gWNE.js → powerquery-CkY5Wq7J.js} +0 -0
  234. /package/dist/assets/{powershell-BMhG4JVe.js → powershell-uGIYLU3C.js} +0 -0
  235. /package/dist/assets/{protobuf-CdOP5kN3.js → protobuf-CavfmJu-.js} +0 -0
  236. /package/dist/assets/{pug-Ck60hNF9.js → pug-Drqnyitx.js} +0 -0
  237. /package/dist/assets/{qrcode-DV-_rjU8.js → qrcode-7uGsTEmi.js} +0 -0
  238. /package/dist/assets/{qsharp-BcaKFfP-.js → qsharp-C7yF-Dti.js} +0 -0
  239. /package/dist/assets/{r-rFNes0iK.js → r-HXLGP0_-.js} +0 -0
  240. /package/dist/assets/{redis-DkpQ3K6G.js → redis-C4y6mf2p.js} +0 -0
  241. /package/dist/assets/{redshift-Di9N5TI3.js → redshift-DdQrFPrv.js} +0 -0
  242. /package/dist/assets/{restructuredtext-By5ZzLt6.js → restructuredtext-CBrf2PNj.js} +0 -0
  243. /package/dist/assets/{rough.esm-c4PR5shF.js → rough.esm-6CnTHTkH.js} +0 -0
  244. /package/dist/assets/{ruby-fF5zGiLp.js → ruby-CVtMoX2B.js} +0 -0
  245. /package/dist/assets/{rust-C5b3AYY6.js → rust-Ckq4sbMP.js} +0 -0
  246. /package/dist/assets/{sb-CD07UNRs.js → sb-er66OpE3.js} +0 -0
  247. /package/dist/assets/{scala-jtn1ip9G.js → scala-BdWZz-hH.js} +0 -0
  248. /package/dist/assets/{scheme-C4vqMkn_.js → scheme-kTV_s2kP.js} +0 -0
  249. /package/dist/assets/{scss-I4Glxjbz.js → scss-Bymy2VJQ.js} +0 -0
  250. /package/dist/assets/{shell-DubUcuns.js → shell-bwEP1LQ1.js} +0 -0
  251. /package/dist/assets/{solidity-CNy2KSl2.js → solidity-DCddeBgL.js} +0 -0
  252. /package/dist/assets/{sophia-D9_URt84.js → sophia-BMN3AQig.js} +0 -0
  253. /package/dist/assets/{sparql-DviXpm4C.js → sparql-CSXOLjzi.js} +0 -0
  254. /package/dist/assets/{sql-vDRbAZgK.js → sql-COg8ewmK.js} +0 -0
  255. /package/dist/assets/{st-CnpnRqA7.js → st-CIaZtBS_.js} +0 -0
  256. /package/dist/assets/{swift-D_g8Ganz.js → swift-DXiOhUHu.js} +0 -0
  257. /package/dist/assets/{systemverilog-OuZa5h1M.js → systemverilog-BTDE6Dr2.js} +0 -0
  258. /package/dist/assets/{tcl-DBm9ucsV.js → tcl-B0zy9NvV.js} +0 -0
  259. /package/dist/assets/{twig-BRzEqX5Y.js → twig-D594l4Z1.js} +0 -0
  260. /package/dist/assets/{typespec-D4ZgGeX8.js → typespec-XKVjaPqo.js} +0 -0
  261. /package/dist/assets/{useWorkspaceMenuKeyboard-Brws6Ar9.js → useWorkspaceMenuKeyboard-Bpy_s69Z.js} +0 -0
  262. /package/dist/assets/{vb-DcP4s6WS.js → vb-B2wYoKRV.js} +0 -0
  263. /package/dist/assets/{wgsl-CnRJ_QUf.js → wgsl-D0Yf2LbK.js} +0 -0
  264. /package/dist/assets/{workspace-working-copy-D8-s_Sgh.js → workspace-working-copy-C3FSR3N6.js} +0 -0
@@ -0,0 +1,37 @@
1
+ const crypto = require('crypto');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ function atomicWriteJson(file, value, options = {}) {
6
+ const fileSystem = options.fileSystem || fs;
7
+ const temporaryFile = `${file}.${process.pid}.${crypto.randomUUID()}.tmp`;
8
+ const suffix = options.trailingNewline ? '\n' : '';
9
+ let descriptor = null;
10
+
11
+ fileSystem.mkdirSync(path.dirname(file), { recursive: true });
12
+ try {
13
+ descriptor = fileSystem.openSync(temporaryFile, 'wx', options.mode);
14
+ fileSystem.writeFileSync(descriptor, `${JSON.stringify(value, null, 2)}${suffix}`, 'utf8');
15
+ fileSystem.fdatasyncSync(descriptor);
16
+ fileSystem.closeSync(descriptor);
17
+ descriptor = null;
18
+ fileSystem.renameSync(temporaryFile, file);
19
+ } finally {
20
+ if (descriptor !== null) {
21
+ try {
22
+ fileSystem.closeSync(descriptor);
23
+ } catch {
24
+ // Preserve the original write failure.
25
+ }
26
+ }
27
+ try {
28
+ fileSystem.unlinkSync(temporaryFile);
29
+ } catch {
30
+ // A successful rename already removed the temporary path.
31
+ }
32
+ }
33
+ }
34
+
35
+ module.exports = {
36
+ atomicWriteJson,
37
+ };
@@ -49,7 +49,8 @@ const CLI_AGENTS = [
49
49
  permissions: {
50
50
  supportsDangerousSkip: true,
51
51
  dangerousSkipArgs: ['--dangerously-skip-permissions']
52
- }
52
+ },
53
+ systemPromptArg: '--append-system-prompt'
53
54
  },
54
55
  {
55
56
  name: 'bash',
@@ -459,12 +460,13 @@ function resolveLaunchCommand(command, options = {}) {
459
460
  launchArgs.unshift('--permission-mode', claudePermissionMode);
460
461
  }
461
462
 
462
- if (
463
- options.mainAgentSystemPrompt &&
464
- spec &&
465
- typeof spec.systemPromptArg === 'string'
466
- ) {
467
- launchArgs.push(spec.systemPromptArg, options.mainAgentSystemPrompt);
463
+ const systemPrompt = [options.farmingSystemPrompt, options.mainAgentSystemPrompt]
464
+ .filter(value => typeof value === 'string' && value.trim())
465
+ .join('\n\n');
466
+ if (systemPrompt && spec && typeof spec.systemPromptArg === 'string') {
467
+ launchArgs.push(spec.systemPromptArg, systemPrompt);
468
+ } else if (systemPrompt && spec?.name === 'codex') {
469
+ launchArgs.unshift('-c', `developer_instructions=${JSON.stringify(systemPrompt)}`);
468
470
  }
469
471
 
470
472
  return {
@@ -1,7 +1,9 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const os = require('os');
4
+ const { atomicWriteJson } = require('./atomic-json-store');
4
5
  const { ensureMainAgentSkillFiles } = require('./main-agent-skills');
6
+ const { ensureFarmingAgentBootstrapFile } = require('./farming-agent-bootstrap');
5
7
  const { normalizeClaudeModelValue } = require('./claude-settings');
6
8
  const { isTemporaryProviderSessionId } = require('./provider-session-id');
7
9
  const { FarmingSessionStore, MAX_MAIN_PAGE_SESSION_KEYS } = require('./farming-session-store');
@@ -68,6 +70,8 @@ const DEFAULT_CRT_TERMINAL_FONT_SIZE = 15;
68
70
  const MIN_CRT_TERMINAL_FONT_SIZE = 10;
69
71
  const MAX_CRT_TERMINAL_FONT_SIZE = 20;
70
72
  const MAX_INSTANCE_NAME_LENGTH = 80;
73
+ const MAX_PROJECT_OPERATIONS = 32;
74
+ const PROJECT_OPERATION_ID_PATTERN = /^[A-Za-z0-9._:-]{1,160}$/;
71
75
 
72
76
  const PERSISTED_SETTING_KEYS = new Set([
73
77
  'workspace',
@@ -76,12 +80,14 @@ const PERSISTED_SETTING_KEYS = new Set([
76
80
  'projectWorkspaces',
77
81
  'pinnedProjectWorkspaces',
78
82
  'projectNames',
83
+ 'projectOperations',
79
84
  'instanceName',
80
85
  'theme',
81
86
  'appearance',
82
87
  'language',
83
88
  'heartbeatInterval',
84
89
  'dangerouslySkipAgentPermissionsByDefault',
90
+ 'browserExtensionEnabled',
85
91
  'crtSkinEffectsEnabled',
86
92
  'crtDynamicHeatEnabled',
87
93
  'crtTerminalFontSize',
@@ -113,8 +119,8 @@ function cloneAgentHomes(agentHomes) {
113
119
  }
114
120
 
115
121
  class ConfigManager {
116
- constructor() {
117
- this.farmingDir = storageLayout.farmingConfigDir();
122
+ constructor(options = {}) {
123
+ this.farmingDir = options.configDir || storageLayout.farmingConfigDir();
118
124
  this.settingsFile = storageLayout.settingsFile(this.farmingDir);
119
125
  this.sessionStore = new FarmingSessionStore(this.farmingDir, {
120
126
  normalizeMainPageSessionKeys: keys => this.normalizeMainPageSessionKeys(keys),
@@ -122,6 +128,7 @@ class ConfigManager {
122
128
  this.runHistoryStore = new RunHistoryStore(this.farmingDir, {
123
129
  normalizeTaskHistory: entries => this.normalizeTaskHistory(entries),
124
130
  });
131
+ this.writeJson = typeof options.writeJson === 'function' ? options.writeJson : atomicWriteJson;
125
132
  this.settings = null;
126
133
  }
127
134
 
@@ -221,7 +228,7 @@ class ConfigManager {
221
228
  const expanded = this.expandWorkspacePath(entry);
222
229
  if (!expanded) continue;
223
230
  const resolved = path.resolve(expanded);
224
- if (resolved === path.parse(resolved).root || this.isInternalWorkspace(resolved)) continue;
231
+ if (this.isInternalWorkspace(resolved)) continue;
225
232
  let canonical = resolved;
226
233
  try {
227
234
  canonical = fs.realpathSync(resolved);
@@ -305,12 +312,14 @@ class ConfigManager {
305
312
  projectWorkspaces: [],
306
313
  pinnedProjectWorkspaces: [],
307
314
  projectNames: {},
315
+ projectOperations: {},
308
316
  instanceName: '',
309
317
  theme: 'terminal',
310
318
  appearance: 'system',
311
319
  language: 'en',
312
320
  heartbeatInterval: 1000,
313
321
  dangerouslySkipAgentPermissionsByDefault: false,
322
+ browserExtensionEnabled: false,
314
323
  crtSkinEffectsEnabled: true,
315
324
  crtDynamicHeatEnabled: false,
316
325
  crtTerminalFontSize: DEFAULT_CRT_TERMINAL_FONT_SIZE,
@@ -329,7 +338,7 @@ class ConfigManager {
329
338
  codexModelPreset: 'gpt-5.5:xhigh',
330
339
  version: '2'
331
340
  };
332
- fs.writeFileSync(this.settingsFile, JSON.stringify(defaultSettings, null, 2));
341
+ this.writeSettingsFile(defaultSettings);
333
342
  console.log('Created default settings:', this.settingsFile);
334
343
  }
335
344
 
@@ -341,12 +350,14 @@ class ConfigManager {
341
350
  projectWorkspaces: [],
342
351
  pinnedProjectWorkspaces: [],
343
352
  projectNames: {},
353
+ projectOperations: {},
344
354
  instanceName: '',
345
355
  theme: 'terminal',
346
356
  appearance: 'system',
347
357
  language: 'en',
348
358
  heartbeatInterval: 1000,
349
359
  dangerouslySkipAgentPermissionsByDefault: false,
360
+ browserExtensionEnabled: false,
350
361
  crtSkinEffectsEnabled: true,
351
362
  crtDynamicHeatEnabled: false,
352
363
  crtTerminalFontSize: DEFAULT_CRT_TERMINAL_FONT_SIZE,
@@ -391,6 +402,7 @@ class ConfigManager {
391
402
  this.settings.projectWorkspaces = this.normalizeProjectWorkspaces(this.settings.projectWorkspaces);
392
403
  this.settings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(this.settings.pinnedProjectWorkspaces);
393
404
  this.settings.projectNames = this.normalizeProjectNames(this.settings.projectNames);
405
+ this.settings.projectOperations = this.normalizeProjectOperations(this.settings.projectOperations);
394
406
  this.settings.instanceName = this.normalizeInstanceName(this.settings.instanceName);
395
407
  this.settings.agentHomes = this.normalizeAgentHomes(this.settings.agentHomes);
396
408
  if (this.settings.updateUrl === LEGACY_DEFAULT_UPDATE_URL || this.settings.updateUrl === API_DEFAULT_UPDATE_URL) {
@@ -407,20 +419,22 @@ class ConfigManager {
407
419
  this.runHistoryStore.init({ legacyTaskHistory });
408
420
  this.settings.appearance = this.normalizeAppearance(this.settings.appearance);
409
421
  this.settings.language = this.normalizeLanguage(this.settings.language);
422
+ this.settings.browserExtensionEnabled = this.settings.browserExtensionEnabled === true;
410
423
  this.settings.crtSkinEffectsEnabled = this.settings.crtSkinEffectsEnabled !== false;
411
424
  this.settings.crtDynamicHeatEnabled = this.settings.crtDynamicHeatEnabled === true;
412
425
  this.settings.crtTerminalFontSize = this.normalizeCrtTerminalFontSize(this.settings.crtTerminalFontSize);
413
426
  this.normalizeAgentLaunchSettings(launchRawSettings);
414
427
  this.pruneUnknownSettings();
415
428
  ensureMainAgentSkillFiles(this.farmingDir);
429
+ ensureFarmingAgentBootstrapFile(this.farmingDir);
416
430
  this.writeSettingsFile();
417
431
  console.log('Loaded settings:', this.settings);
418
432
  }
419
433
 
420
- pruneUnknownSettings() {
421
- for (const key of Object.keys(this.settings || {})) {
434
+ pruneUnknownSettings(settings = this.settings) {
435
+ for (const key of Object.keys(settings || {})) {
422
436
  if (!PERSISTED_SETTING_KEYS.has(key)) {
423
- delete this.settings[key];
437
+ delete settings[key];
424
438
  }
425
439
  }
426
440
  }
@@ -498,16 +512,59 @@ class ConfigManager {
498
512
  return normalized;
499
513
  }
500
514
 
515
+ normalizeProjectOperations(projectOperations) {
516
+ if (!projectOperations || typeof projectOperations !== 'object' || Array.isArray(projectOperations)) return {};
517
+ const entries = Object.entries(projectOperations)
518
+ .filter(([id, operation]) => (
519
+ PROJECT_OPERATION_ID_PATTERN.test(id)
520
+ && operation
521
+ && typeof operation === 'object'
522
+ && ['create-worktree', 'delete-worktree'].includes(operation.type)
523
+ && ['pending', 'unknown', 'succeeded', 'failed', 'blocked'].includes(operation.state)
524
+ ))
525
+ .sort((left, right) => (Number(right[1].updatedAt) || 0) - (Number(left[1].updatedAt) || 0))
526
+ .map(([id, operation]) => [id, {
527
+ id,
528
+ type: operation.type,
529
+ state: operation.state,
530
+ signature: typeof operation.signature === 'string' ? operation.signature.slice(0, 128) : '',
531
+ request: operation.request && typeof operation.request === 'object'
532
+ ? JSON.parse(JSON.stringify(operation.request))
533
+ : {},
534
+ result: operation.result && typeof operation.result === 'object'
535
+ ? JSON.parse(JSON.stringify(operation.result))
536
+ : null,
537
+ error: typeof operation.error === 'string' ? operation.error.slice(0, 2000) : '',
538
+ startedAt: Number(operation.startedAt) || 0,
539
+ updatedAt: Number(operation.updatedAt) || 0,
540
+ finishedAt: Number(operation.finishedAt) || null,
541
+ }]);
542
+ const unresolved = entries.filter(([, operation]) => (
543
+ ['pending', 'unknown', 'blocked'].includes(operation.state)
544
+ ));
545
+ const terminal = entries.filter(([, operation]) => (
546
+ !['pending', 'unknown', 'blocked'].includes(operation.state)
547
+ ));
548
+ return Object.fromEntries([
549
+ ...unresolved,
550
+ ...terminal.slice(0, Math.max(0, MAX_PROJECT_OPERATIONS - unresolved.length)),
551
+ ]);
552
+ }
553
+
501
554
  setProjectName(workspace, name) {
502
555
  const normalized = this.normalizeProjectNames({ [workspace]: name });
503
556
  const entry = Object.entries(normalized)[0];
504
557
  if (!entry) throw new Error('Project workspace and name are required');
505
558
  const [normalizedWorkspace, normalizedName] = entry;
506
- this.settings.projectNames = {
507
- ...this.settings.projectNames,
508
- [normalizedWorkspace]: normalizedName,
559
+ const nextSettings = {
560
+ ...this.settings,
561
+ projectNames: {
562
+ ...this.settings.projectNames,
563
+ [normalizedWorkspace]: normalizedName,
564
+ },
509
565
  };
510
- this.writeSettingsFile();
566
+ this.writeSettingsFile(nextSettings);
567
+ this.settings = nextSettings;
511
568
  return {
512
569
  workspace: normalizedWorkspace,
513
570
  name: normalizedName,
@@ -668,23 +725,23 @@ class ConfigManager {
668
725
  return merged;
669
726
  }
670
727
 
671
- applyCodexProfileToLegacySettings(codexProfile) {
672
- this.settings.codexApprovalMode = codexProfile.approvalMode;
673
- this.settings.codexModel = codexProfile.model;
674
- this.settings.codexReasoningEffort = codexProfile.reasoningEffort;
675
- this.settings.codexServiceTier = codexProfile.serviceTier;
676
- this.settings.codexModelPreset = codexProfile.modelPreset;
728
+ applyCodexProfileToLegacySettings(codexProfile, settings = this.settings) {
729
+ settings.codexApprovalMode = codexProfile.approvalMode;
730
+ settings.codexModel = codexProfile.model;
731
+ settings.codexReasoningEffort = codexProfile.reasoningEffort;
732
+ settings.codexServiceTier = codexProfile.serviceTier;
733
+ settings.codexModelPreset = codexProfile.modelPreset;
677
734
  }
678
735
 
679
- normalizeAgentLaunchSettings(rawSettings = {}) {
736
+ normalizeAgentLaunchSettings(rawSettings = {}, settings = this.settings) {
680
737
  const changedProfiles = this.getChangedAgentLaunchProfiles(rawSettings);
681
- const mergedProfiles = this.mergeAgentLaunchProfiles(this.settings.agentLaunchProfiles, changedProfiles);
682
- this.settings.agentLaunchProfiles = {
738
+ const mergedProfiles = this.mergeAgentLaunchProfiles(settings.agentLaunchProfiles, changedProfiles);
739
+ settings.agentLaunchProfiles = {
683
740
  codex: this.normalizeCodexLaunchProfile(mergedProfiles.codex, changedProfiles.codex || {}),
684
741
  claude: this.normalizeClaudeLaunchProfile(mergedProfiles.claude),
685
742
  };
686
- this.settings.defaultLaunchAgent = this.normalizeDefaultLaunchAgent(this.settings.defaultLaunchAgent);
687
- this.applyCodexProfileToLegacySettings(this.settings.agentLaunchProfiles.codex);
743
+ settings.defaultLaunchAgent = this.normalizeDefaultLaunchAgent(settings.defaultLaunchAgent);
744
+ this.applyCodexProfileToLegacySettings(settings.agentLaunchProfiles.codex, settings);
688
745
  }
689
746
 
690
747
  getWorkspace() {
@@ -760,8 +817,10 @@ class ConfigManager {
760
817
  }
761
818
 
762
819
  getSettings() {
820
+ const publicSettings = { ...this.settings };
821
+ delete publicSettings.projectOperations;
763
822
  return {
764
- ...this.settings,
823
+ ...publicSettings,
765
824
  instanceName: this.getInstanceName(),
766
825
  workspace: this.farmingDir,
767
826
  mainPageSessionKeys: this.getMainPageSessionKeys(),
@@ -783,7 +842,6 @@ class ConfigManager {
783
842
  }
784
843
  if (
785
844
  !canonicalWorkspace
786
- || canonicalWorkspace === path.parse(canonicalWorkspace).root
787
845
  || this.isInternalWorkspace(canonicalWorkspace)
788
846
  ) {
789
847
  throw new Error('Project workspace is invalid or unavailable');
@@ -860,6 +918,64 @@ class ConfigManager {
860
918
  }
861
919
  }
862
920
 
921
+ getProjectOperation(requestId) {
922
+ const id = String(requestId || '').trim();
923
+ if (!PROJECT_OPERATION_ID_PATTERN.test(id)) return null;
924
+ const operation = this.settings.projectOperations?.[id];
925
+ return operation ? JSON.parse(JSON.stringify(operation)) : null;
926
+ }
927
+
928
+ commitProjectOperation(operation, membership = {}) {
929
+ const normalized = this.normalizeProjectOperations({ [operation?.id]: operation });
930
+ const nextOperation = normalized[operation?.id];
931
+ if (!nextOperation) throw new Error('Project operation is invalid');
932
+ const existingOperation = this.settings.projectOperations?.[nextOperation.id];
933
+ const unresolvedCount = Object.values(this.settings.projectOperations || {})
934
+ .filter(candidate => ['pending', 'unknown', 'blocked'].includes(candidate.state)).length;
935
+ if (!existingOperation && nextOperation.state === 'pending' && unresolvedCount >= MAX_PROJECT_OPERATIONS) {
936
+ throw new Error('Too many unresolved Project operations require reconciliation');
937
+ }
938
+ const nextOperations = this.normalizeProjectOperations({
939
+ ...this.settings.projectOperations,
940
+ [nextOperation.id]: nextOperation,
941
+ });
942
+ const nextSettings = {
943
+ ...this.settings,
944
+ projectOperations: nextOperations,
945
+ };
946
+ if (membership.mountWorkspace) {
947
+ const mounted = this.normalizeProjectWorkspaces([
948
+ membership.mountWorkspace,
949
+ ...(this.settings.projectWorkspaces || []),
950
+ ]);
951
+ nextSettings.projectWorkspaces = mounted;
952
+ nextSettings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(
953
+ this.settings.pinnedProjectWorkspaces,
954
+ );
955
+ }
956
+ if (membership.removeWorkspace) {
957
+ const expanded = this.expandWorkspacePath(membership.removeWorkspace);
958
+ const resolved = expanded ? path.resolve(expanded) : '';
959
+ const candidates = new Set([expanded, resolved].filter(Boolean));
960
+ try {
961
+ candidates.add(fs.realpathSync(resolved));
962
+ } catch {
963
+ // A deleted worktree is removed by its last canonical path.
964
+ }
965
+ nextSettings.projectWorkspaces = (this.settings.projectWorkspaces || [])
966
+ .filter(workspace => !candidates.has(workspace));
967
+ nextSettings.pinnedProjectWorkspaces = (this.settings.pinnedProjectWorkspaces || [])
968
+ .filter(workspace => !candidates.has(workspace));
969
+ }
970
+ this.writeSettingsFile(nextSettings);
971
+ this.settings = nextSettings;
972
+ return {
973
+ operation: JSON.parse(JSON.stringify(nextOperation)),
974
+ projectWorkspaces: [...(nextSettings.projectWorkspaces || [])],
975
+ pinnedProjectWorkspaces: [...(nextSettings.pinnedProjectWorkspaces || [])],
976
+ };
977
+ }
978
+
863
979
  getMainPageSessionKeys() {
864
980
  return this.sessionStore ? this.sessionStore.getMainPageSessionKeys() : [];
865
981
  }
@@ -904,19 +1020,8 @@ class ConfigManager {
904
1020
  return this.runHistoryStore ? this.runHistoryStore.getEntries() : [];
905
1021
  }
906
1022
 
907
- writeSettingsFile() {
908
- fs.mkdirSync(this.farmingDir, { recursive: true });
909
- const tempFile = `${this.settingsFile}.${process.pid}.${Date.now()}.tmp`;
910
- try {
911
- fs.writeFileSync(tempFile, JSON.stringify(this.settings, null, 2));
912
- fs.renameSync(tempFile, this.settingsFile);
913
- } finally {
914
- try {
915
- fs.unlinkSync(tempFile);
916
- } catch {
917
- // A successful rename already removed the temporary path.
918
- }
919
- }
1023
+ writeSettingsFile(settings = this.settings) {
1024
+ this.writeJson(this.settingsFile, settings);
920
1025
  }
921
1026
 
922
1027
  appendTaskHistory(entry) {
@@ -930,6 +1035,7 @@ class ConfigManager {
930
1035
  : undefined;
931
1036
  const settingsPatch = { ...(newSettings || {}) };
932
1037
  delete settingsPatch.mainPageSessionKeys;
1038
+ delete settingsPatch.projectOperations;
933
1039
  const incomingTaskHistory = Object.prototype.hasOwnProperty.call(settingsPatch, 'taskHistory')
934
1040
  ? settingsPatch.taskHistory
935
1041
  : undefined;
@@ -937,38 +1043,41 @@ class ConfigManager {
937
1043
  const previousMainWorkspace = this.settings.lastMainWorkspace || this.farmingDir;
938
1044
  const previousProfiles = this.settings.agentLaunchProfiles || {};
939
1045
  const incomingProfiles = settingsPatch.agentLaunchProfiles || {};
940
- this.settings = {
1046
+ const nextSettings = {
941
1047
  ...this.settings,
942
1048
  ...settingsPatch,
943
1049
  agentLaunchProfiles: this.mergeAgentLaunchProfiles(previousProfiles, incomingProfiles),
944
1050
  workspace: this.farmingDir
945
1051
  };
946
- this.settings.lastMainWorkspace = this.normalizeMainWorkspace(this.settings.lastMainWorkspace, previousMainWorkspace);
947
- this.settings.workspaceHistory = this.normalizeWorkspaceHistory(this.settings.workspaceHistory);
948
- this.settings.projectWorkspaces = this.normalizeProjectWorkspaces(this.settings.projectWorkspaces);
949
- this.settings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(this.settings.pinnedProjectWorkspaces);
950
- this.settings.projectNames = this.normalizeProjectNames(this.settings.projectNames);
951
- this.settings.instanceName = this.normalizeInstanceName(this.settings.instanceName);
952
- this.settings.agentHomes = this.normalizeAgentHomes(this.settings.agentHomes);
953
- this.settings.updateUrl = this.normalizeUpdateUrl(this.settings.updateUrl);
954
- this.settings.searchTimeoutMs = this.normalizeSearchTimeoutMs(this.settings.searchTimeoutMs);
955
- delete this.settings.codexRuntimeMode;
956
- delete this.settings.mainPageSessionKeys;
957
- delete this.settings.taskHistory;
1052
+ nextSettings.lastMainWorkspace = this.normalizeMainWorkspace(nextSettings.lastMainWorkspace, previousMainWorkspace);
1053
+ nextSettings.workspaceHistory = this.normalizeWorkspaceHistory(nextSettings.workspaceHistory);
1054
+ nextSettings.projectWorkspaces = this.normalizeProjectWorkspaces(nextSettings.projectWorkspaces);
1055
+ nextSettings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(nextSettings.pinnedProjectWorkspaces);
1056
+ nextSettings.projectNames = this.normalizeProjectNames(nextSettings.projectNames);
1057
+ nextSettings.projectOperations = this.normalizeProjectOperations(nextSettings.projectOperations);
1058
+ nextSettings.instanceName = this.normalizeInstanceName(nextSettings.instanceName);
1059
+ nextSettings.agentHomes = this.normalizeAgentHomes(nextSettings.agentHomes);
1060
+ nextSettings.updateUrl = this.normalizeUpdateUrl(nextSettings.updateUrl);
1061
+ nextSettings.searchTimeoutMs = this.normalizeSearchTimeoutMs(nextSettings.searchTimeoutMs);
1062
+ delete nextSettings.codexRuntimeMode;
1063
+ delete nextSettings.mainPageSessionKeys;
1064
+ delete nextSettings.taskHistory;
958
1065
  if (incomingMainPageSessionKeys !== undefined) {
959
1066
  this.setMainPageSessionKeys(incomingMainPageSessionKeys);
960
1067
  }
961
1068
  if (incomingTaskHistory !== undefined && this.runHistoryStore) {
962
1069
  this.runHistoryStore.setEntries(incomingTaskHistory);
963
1070
  }
964
- this.settings.appearance = this.normalizeAppearance(this.settings.appearance);
965
- this.settings.language = this.normalizeLanguage(this.settings.language);
966
- this.settings.crtSkinEffectsEnabled = this.settings.crtSkinEffectsEnabled !== false;
967
- this.settings.crtDynamicHeatEnabled = this.settings.crtDynamicHeatEnabled === true;
968
- this.settings.crtTerminalFontSize = this.normalizeCrtTerminalFontSize(this.settings.crtTerminalFontSize);
969
- this.normalizeAgentLaunchSettings(settingsPatch);
970
- this.pruneUnknownSettings();
971
- this.writeSettingsFile();
1071
+ nextSettings.appearance = this.normalizeAppearance(nextSettings.appearance);
1072
+ nextSettings.language = this.normalizeLanguage(nextSettings.language);
1073
+ nextSettings.browserExtensionEnabled = nextSettings.browserExtensionEnabled === true;
1074
+ nextSettings.crtSkinEffectsEnabled = nextSettings.crtSkinEffectsEnabled !== false;
1075
+ nextSettings.crtDynamicHeatEnabled = nextSettings.crtDynamicHeatEnabled === true;
1076
+ nextSettings.crtTerminalFontSize = this.normalizeCrtTerminalFontSize(nextSettings.crtTerminalFontSize);
1077
+ this.normalizeAgentLaunchSettings(settingsPatch, nextSettings);
1078
+ this.pruneUnknownSettings(nextSettings);
1079
+ this.writeSettingsFile(nextSettings);
1080
+ this.settings = nextSettings;
972
1081
  }
973
1082
  }
974
1083
 
@@ -419,9 +419,10 @@ function createControlRouter(agentManager, options = {}) {
419
419
 
420
420
  router.delete('/agents/:agentId', async (req, res) => {
421
421
  const agentId = req.params.agentId;
422
+ const recordHistory = req.query?.recordHistory !== '0';
422
423
  let requested;
423
424
  try {
424
- requested = await agentManager.requestKillAgent(agentId);
425
+ requested = await agentManager.requestKillAgent(agentId, { recordHistory });
425
426
  } catch (error) {
426
427
  res.status(503).json({
427
428
  error: error?.message || 'Agent lifecycle recovery is unavailable',
@@ -0,0 +1,49 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const storageLayout = require('./storage-layout');
4
+
5
+ const sourceFile = path.join(__dirname, 'farming-agent-bootstrap.zh_cn.md');
6
+
7
+ function renderFarmingAgentBootstrap() {
8
+ return fs.readFileSync(sourceFile, 'utf8').trim();
9
+ }
10
+
11
+ function ensureFarmingAgentBootstrapFile(configDir) {
12
+ const target = storageLayout.farmingAgentBootstrapFile(configDir);
13
+ const content = `${renderFarmingAgentBootstrap()}\n`;
14
+ try {
15
+ if (fs.readFileSync(target, 'utf8') === content) return target;
16
+ } catch {
17
+ // Install the current Farming-owned prompt below.
18
+ }
19
+ fs.mkdirSync(path.dirname(target), { recursive: true });
20
+ const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
21
+ fs.writeFileSync(temporary, content, { encoding: 'utf8', mode: 0o600 });
22
+ fs.renameSync(temporary, target);
23
+ return target;
24
+ }
25
+
26
+ function appendOpenCodeBootstrap(env, bootstrapFile) {
27
+ const next = { ...env };
28
+ let config = {};
29
+ if (next.OPENCODE_CONFIG_CONTENT) {
30
+ try {
31
+ const parsed = JSON.parse(next.OPENCODE_CONFIG_CONTENT);
32
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) config = parsed;
33
+ } catch {
34
+ return next;
35
+ }
36
+ }
37
+ const instructions = Array.isArray(config.instructions)
38
+ ? config.instructions.filter(value => typeof value === 'string')
39
+ : [];
40
+ config.instructions = [...new Set([...instructions, bootstrapFile])];
41
+ next.OPENCODE_CONFIG_CONTENT = JSON.stringify(config);
42
+ return next;
43
+ }
44
+
45
+ module.exports = {
46
+ appendOpenCodeBootstrap,
47
+ ensureFarmingAgentBootstrapFile,
48
+ renderFarmingAgentBootstrap,
49
+ };
@@ -0,0 +1,5 @@
1
+ 你由 Farming 启动并托管。Farming 是一个供用户同时运行、观察和管理多个 AI 编程 Agent 的工作区,统一承载 Agent 对话、终端、项目文件,以及可由用户和 Agent 共同使用的扩展资源。
2
+
3
+ Farming 可能为当前会话提供系统浏览器、Agent 协作等能力。能力是否可用以 `farming capabilities` 的实时结果为准,不要自行假设。
4
+
5
+ 当任务需要查看或操作网页时,你可以主动查询能力,并自行决定是否创建新的 Farming Browser 或连接已有 Browser。Farming Browser 会显示在用户界面中,用户和你操作的是同一个浏览器会话。只启用完成当前任务所需的能力。
@@ -22,8 +22,8 @@ const DEFAULT_SERVER_STOP_TIMEOUT_MS = 30_000;
22
22
  const SERVER_STOP_POLL_MS = 100;
23
23
  const SERVER_PROCESS_IDENTITY_FORMAT = 'ps-lstart-c-utc-v1';
24
24
  const SERVER_COMMANDS = new Set(['start', 'serve', 'daemon', 'stop', 'status', 'logs', 'url', 'help']);
25
- const CONTROL_COMMANDS = new Set(['skills', 'memory', 'report', 'list', 'spawn', 'output', 'send', 'kill']);
26
- const SERVER_BACKED_CONTROL_COMMANDS = new Set(['list', 'spawn', 'output', 'send', 'kill']);
25
+ const CONTROL_COMMANDS = new Set(['skills', 'capabilities', 'memory', 'report', 'list', 'spawn', 'output', 'send', 'kill']);
26
+ const SERVER_BACKED_CONTROL_COMMANDS = new Set(['capabilities', 'list', 'spawn', 'output', 'send', 'kill']);
27
27
 
28
28
  function defaultConfigDir(env = process.env) {
29
29
  return storageLayout.farmingConfigDir(env);
@@ -1086,6 +1086,8 @@ function usage() {
1086
1086
 
1087
1087
  Agent control commands are also available:
1088
1088
  farming skills
1089
+ farming capabilities [--json]
1090
+ farming browser <capability|create|list|start|stop|snapshot|navigate|click|fill|type|press|scroll|screenshot> ...
1089
1091
  farming list [--json] [--parent <agentId>]
1090
1092
  farming spawn --workspace <repo> -- <command...>
1091
1093
  farming output <agentId> [--tail <chars>]
@@ -1125,6 +1127,11 @@ async function run(argv = process.argv.slice(2)) {
1125
1127
  return 0;
1126
1128
  }
1127
1129
 
1130
+ if (argv[0] === 'browser') {
1131
+ const { run: runBrowserCli } = require('../extensions/browser/bin/farming-browser');
1132
+ return runBrowserCli(argv.slice(1));
1133
+ }
1134
+
1128
1135
  if (SERVER_BACKED_CONTROL_COMMANDS.has(argv[0])) {
1129
1136
  return runServerBackedControlCli(argv);
1130
1137
  }
@@ -8,6 +8,7 @@ const storageLayout = require('./storage-layout');
8
8
  function usage() {
9
9
  return `Usage:
10
10
  farming skills
11
+ farming capabilities [--json]
11
12
  farming memory report [--period today|yesterday|week] [--since <time>] [--until <time>] [--home <path>] [--json]
12
13
  farming list [--json] [--parent <agentId>]
13
14
  farming spawn [--workspace <path>] [--task <text>] [--parent <agentId>] [--json] -- <command...>
@@ -20,6 +21,7 @@ Examples:
20
21
  farming memory report --period today
21
22
  farming memory report --period week --json
22
23
  farming skills
24
+ farming capabilities
23
25
  farming list --parent "$FARMING_AGENT_ID"
24
26
  farming output agent-123 --tail 2000
25
27
  farming send agent-123 "Please run the focused tests"`;
@@ -76,6 +78,13 @@ function parseArgs(argv) {
76
78
  return { command };
77
79
  }
78
80
 
81
+ if (command === 'capabilities') {
82
+ if (rest.some(arg => arg !== '--json')) {
83
+ throw new Error('capabilities accepts only --json');
84
+ }
85
+ return { command, options: { json: rest.includes('--json') } };
86
+ }
87
+
79
88
  if (command === 'memory' || command === 'report') {
80
89
  const subcommand = command === 'memory' ? rest.shift() : 'report';
81
90
  if (subcommand !== 'report') {
@@ -293,6 +302,42 @@ function formatAgent(agent) {
293
302
  return `${marker} ${agent.id} | ${agent.command} | ${agent.status} | ${agent.cwd}${parent}${task}`;
294
303
  }
295
304
 
305
+ function farmingCapabilities(browser) {
306
+ const state = browser?.available === true
307
+ ? 'available'
308
+ : (browser?.enabled === true ? 'unavailable' : 'disabled');
309
+ return {
310
+ runtime: 'farming',
311
+ agentId: process.env.FARMING_AGENT_ID || '',
312
+ projectWorkspace: process.env.FARMING_PROJECT_WORKSPACE || '',
313
+ capabilities: [{
314
+ id: 'browser',
315
+ state,
316
+ summary: state === 'available'
317
+ ? 'An installed system Chromium Browser can be created or attached in Farming on demand.'
318
+ : (browser?.message || 'System Browser integration is unavailable in Farming.'),
319
+ commands: state === 'available'
320
+ ? {
321
+ list: 'farming browser list',
322
+ create: 'farming browser create',
323
+ help: 'farming browser --help',
324
+ }
325
+ : {},
326
+ }],
327
+ };
328
+ }
329
+
330
+ function formatCapabilities(report) {
331
+ const lines = ['Farming runtime capabilities:'];
332
+ for (const capability of report.capabilities) {
333
+ lines.push(`- ${capability.id}: ${capability.state} — ${capability.summary}`);
334
+ for (const [label, command] of Object.entries(capability.commands || {})) {
335
+ lines.push(` ${label}: ${command}`);
336
+ }
337
+ }
338
+ return lines.join('\n');
339
+ }
340
+
296
341
  async function run(argv = process.argv.slice(2), io = process) {
297
342
  const parsed = parseArgs(argv);
298
343
 
@@ -306,6 +351,14 @@ async function run(argv = process.argv.slice(2), io = process) {
306
351
  return 0;
307
352
  }
308
353
 
354
+ if (parsed.command === 'capabilities') {
355
+ const report = farmingCapabilities(await request('/api/browsers/capability'));
356
+ io.stdout.write(parsed.options.json
357
+ ? `${JSON.stringify(report, null, 2)}\n`
358
+ : `${formatCapabilities(report)}\n`);
359
+ return 0;
360
+ }
361
+
309
362
  if (parsed.command === 'memory-report') {
310
363
  const report = buildMemoryReport({
311
364
  period: parsed.options.period,
@@ -382,6 +435,8 @@ async function run(argv = process.argv.slice(2), io = process) {
382
435
 
383
436
  module.exports = {
384
437
  formatAgent,
438
+ farmingCapabilities,
439
+ formatCapabilities,
385
440
  getToken,
386
441
  httpRequest,
387
442
  isAuthDisabled,