farming-code 2.2.6

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 (453) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +287 -0
  3. package/README.zh_cn.md +329 -0
  4. package/SECURITY.md +29 -0
  5. package/THIRD_PARTY_NOTICES.md +106 -0
  6. package/backend/acp/client-services.js +312 -0
  7. package/backend/acp/patch-decisions.js +137 -0
  8. package/backend/acp/permission-security.js +108 -0
  9. package/backend/acp-runtime.js +1144 -0
  10. package/backend/acp-session-state.js +448 -0
  11. package/backend/acp-transcript.js +169 -0
  12. package/backend/agent-activity.js +186 -0
  13. package/backend/agent-env.js +250 -0
  14. package/backend/agent-json-stream.js +268 -0
  15. package/backend/agent-manager.js +4259 -0
  16. package/backend/agent-memory-report.js +583 -0
  17. package/backend/agent-order.js +162 -0
  18. package/backend/agent-provider-session.js +287 -0
  19. package/backend/agent-session-history.js +888 -0
  20. package/backend/app-server-api.js +917 -0
  21. package/backend/async-cache.js +94 -0
  22. package/backend/auth.js +178 -0
  23. package/backend/claude-settings.js +121 -0
  24. package/backend/cli-agents.js +484 -0
  25. package/backend/codex-app-server-home.js +39 -0
  26. package/backend/codex-app-server-runtime.js +901 -0
  27. package/backend/codex-context-window.js +189 -0
  28. package/backend/codex-models.js +229 -0
  29. package/backend/codex-rollout-follower.js +243 -0
  30. package/backend/codex-session-history.js +553 -0
  31. package/backend/codex-transcript-sanitizer.js +103 -0
  32. package/backend/codex-transcript.js +2341 -0
  33. package/backend/command-runner-child.js +67 -0
  34. package/backend/config-manager.js +815 -0
  35. package/backend/control-api.js +151 -0
  36. package/backend/data/chinese-poetic-words.json +8223 -0
  37. package/backend/data/poetic-word-sources/china.json +49209 -0
  38. package/backend/data/poetic-word-sources/india.json +9763 -0
  39. package/backend/data/poetic-word-sources/japan.json +8455 -0
  40. package/backend/executable-discovery.js +207 -0
  41. package/backend/farming-app-cli.js +790 -0
  42. package/backend/farming-cli.js +400 -0
  43. package/backend/farming-session-store.js +373 -0
  44. package/backend/haiku-token.js +772 -0
  45. package/backend/index-html.js +49 -0
  46. package/backend/input-parts.js +54 -0
  47. package/backend/input-routing.js +24 -0
  48. package/backend/json-cli-runtime.js +161 -0
  49. package/backend/local-session-engine.js +620 -0
  50. package/backend/main-agent-skills.js +292 -0
  51. package/backend/main-page-session.js +119 -0
  52. package/backend/native-pty-host-client.js +516 -0
  53. package/backend/native-pty-host-path.js +22 -0
  54. package/backend/native-pty-host.js +816 -0
  55. package/backend/native-session-engine.js +196 -0
  56. package/backend/network.js +23 -0
  57. package/backend/npm-update-helper.js +196 -0
  58. package/backend/packaged-node-pty.js +79 -0
  59. package/backend/provider-session-id.js +47 -0
  60. package/backend/qr-share-tickets.js +100 -0
  61. package/backend/review-diff-router.js +180 -0
  62. package/backend/review-diff-service.js +1270 -0
  63. package/backend/review-session-router.js +74 -0
  64. package/backend/review-session-service.js +432 -0
  65. package/backend/review-session-store.js +144 -0
  66. package/backend/review-state-router.js +116 -0
  67. package/backend/review-state-store.js +287 -0
  68. package/backend/run-history-store.js +70 -0
  69. package/backend/server.js +2446 -0
  70. package/backend/session-engine-bridge.js +110 -0
  71. package/backend/session-engine-router.js +66 -0
  72. package/backend/session-engine.js +39 -0
  73. package/backend/shell-busy-integration.js +472 -0
  74. package/backend/slash-command-discovery.js +296 -0
  75. package/backend/storage-layout.js +101 -0
  76. package/backend/system-monitor.js +77 -0
  77. package/backend/terminal-runtime-cleanup.js +80 -0
  78. package/backend/terminal-screen-state.js +240 -0
  79. package/backend/terminal-screen-worker-pool.js +165 -0
  80. package/backend/terminal-screen-worker-thread.js +161 -0
  81. package/backend/terminal-screen-worker.js +255 -0
  82. package/backend/terminal-status.js +356 -0
  83. package/backend/theme-manager.js +145 -0
  84. package/backend/update-service.js +1183 -0
  85. package/backend/usage-forecast.js +86 -0
  86. package/backend/usage-monitor.js +1357 -0
  87. package/backend/workspace-discovery.js +311 -0
  88. package/backend/workspace-file-router.js +431 -0
  89. package/backend/workspace-file-service.js +2765 -0
  90. package/bin/farming +5 -0
  91. package/config/farming.deploy.env.example +13 -0
  92. package/config/farming.install.env.example +17 -0
  93. package/dist/assets/App-BrP-ENHg.css +1 -0
  94. package/dist/assets/App-Dza5yEDe.js +124 -0
  95. package/dist/assets/FileEditorMarkdownPreview-DRDNQ8mX.css +1 -0
  96. package/dist/assets/FileEditorMarkdownPreview-elKWc8Im.js +404 -0
  97. package/dist/assets/FileEditorPane-BQLocXOp.js +5 -0
  98. package/dist/assets/IconGlyphs-RkMAdBXF.js +1 -0
  99. package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  100. package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  101. package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  102. package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  103. package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  104. package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  105. package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  106. package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  107. package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  108. package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  109. package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  110. package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  111. package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  112. package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  113. package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  114. package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  115. package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  116. package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  117. package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  118. package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  119. package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  120. package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  121. package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  122. package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  123. package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  124. package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  125. package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  126. package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  127. package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  128. package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  129. package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  130. package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  131. package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  132. package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  133. package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  134. package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  135. package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  136. package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  137. package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  138. package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  139. package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  140. package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  141. package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  142. package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  143. package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  144. package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  145. package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  146. package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  147. package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  148. package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  149. package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  150. package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  151. package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  152. package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  153. package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  154. package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  155. package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  156. package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  157. package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  158. package/dist/assets/ProjectFilesSection-lS1azbgj.js +12 -0
  159. package/dist/assets/ReviewPage-DgnmgU2T.js +3 -0
  160. package/dist/assets/abap-Cc5D5h5i.js +1 -0
  161. package/dist/assets/abnfDiagram-VRR7QNED-BgawzDQT.js +1 -0
  162. package/dist/assets/apex-BKopwLmx.js +1 -0
  163. package/dist/assets/api-D1lyBYIQ.js +1 -0
  164. package/dist/assets/arc-CWoVlxJw.js +1 -0
  165. package/dist/assets/architecture-TIHT7OUA-CbJBFh3w.js +1 -0
  166. package/dist/assets/architectureDiagram-ZJ3FMSHR-DUShwPg0.js +36 -0
  167. package/dist/assets/array-HeX70jSN.js +1 -0
  168. package/dist/assets/azcli-DI-C34WA.js +1 -0
  169. package/dist/assets/bat-Cbp6u42z.js +1 -0
  170. package/dist/assets/bicep-4QA1jTCM.js +2 -0
  171. package/dist/assets/blockDiagram-677ZJIJ3-CeGZviXR.js +132 -0
  172. package/dist/assets/c4Diagram-LMCZKHZV-CLhYht6S.js +10 -0
  173. package/dist/assets/cameligo-Dda_adPs.js +1 -0
  174. package/dist/assets/channel-Uw90AO0b.js +1 -0
  175. package/dist/assets/chunk-2Q5K7J3B-d5WWh8jo.js +1 -0
  176. package/dist/assets/chunk-32BRIVSS-LFYpT-Cu.js +1 -0
  177. package/dist/assets/chunk-52WLFC77-BH6jDw9J.js +10 -0
  178. package/dist/assets/chunk-5FCAYU7R-C7AmIhYv.js +1 -0
  179. package/dist/assets/chunk-5HE753X5-C8cXaouP.js +1 -0
  180. package/dist/assets/chunk-5JV3BV7I-C1PtimcA.js +1 -0
  181. package/dist/assets/chunk-5TONJI2A-_81zUME8.js +2 -0
  182. package/dist/assets/chunk-5VM5RSS4-Dlw7AXWp.js +15 -0
  183. package/dist/assets/chunk-7BUUIJ7U-ZBRhjLOh.js +1 -0
  184. package/dist/assets/chunk-BIQX33UG-CWmzxeAw.js +1 -0
  185. package/dist/assets/chunk-C7G6YPKG-B_mIUlb7.js +1 -0
  186. package/dist/assets/chunk-CQNSW5MT-CMayolwI.js +1 -0
  187. package/dist/assets/chunk-CYSBUYHQ-lSPbrL3Z.js +1 -0
  188. package/dist/assets/chunk-DECur_0Z.js +1 -0
  189. package/dist/assets/chunk-EMLP6XTP-D9-jtCnM.js +1 -0
  190. package/dist/assets/chunk-EX3LRPZG-C63hVuAJ.js +231 -0
  191. package/dist/assets/chunk-FWX5IMBZ-CboX-WF_.js +2 -0
  192. package/dist/assets/chunk-HOUHSVGY-BOgSd6Un.js +1 -0
  193. package/dist/assets/chunk-ICXQ74PX-C0K-pgZt.js +2 -0
  194. package/dist/assets/chunk-JG7HCLWE-Cib606u_.js +2 -0
  195. package/dist/assets/chunk-JWPE2WC7-DSyBRaRG.js +1 -0
  196. package/dist/assets/chunk-KEIR6QF5-CNOHik0T.js +161 -0
  197. package/dist/assets/chunk-MOJQB5TN-CVMfwN_7.js +88 -0
  198. package/dist/assets/chunk-MOZMSUNE-D6JeZqmE.js +1 -0
  199. package/dist/assets/chunk-OGEWGWER-DLT3pxyw.js +1 -0
  200. package/dist/assets/chunk-OSBZ3O6U-C0W8KSeg.js +1 -0
  201. package/dist/assets/chunk-PUDLZKDR-Cd079yIQ.js +156 -0
  202. package/dist/assets/chunk-Q4XR5HBZ-D0jHa6SO.js +70 -0
  203. package/dist/assets/chunk-QBLGF6JB-p4omp7uO.js +1 -0
  204. package/dist/assets/chunk-R7FJI6CG-CZ_p9hSr.js +1 -0
  205. package/dist/assets/chunk-RYQCIY6F-CZA9pvFX.js +1 -0
  206. package/dist/assets/chunk-U6XO7XAA-CcXKsWxp.js +2 -0
  207. package/dist/assets/chunk-V7JOEXUC-CVDtR75H.js +206 -0
  208. package/dist/assets/chunk-VAUOI2AC-B-W2_9Ot.js +1 -0
  209. package/dist/assets/chunk-VR4S4FIN-FD3kWh32.js +1 -0
  210. package/dist/assets/chunk-WYO6CB5R-C2bGaS5r.js +127 -0
  211. package/dist/assets/chunk-XXDRQBXY-BBXwjhUx.js +1 -0
  212. package/dist/assets/chunk-Y2CYZVJY-Di0sYzi1.js +1 -0
  213. package/dist/assets/chunk-YOTPTUD7-BXHmEk89.js +1 -0
  214. package/dist/assets/chunk-ZGVPDNZ5-ymgts0zo.js +62 -0
  215. package/dist/assets/chunk-ZIRB5QZD-DncwlQQc.js +32 -0
  216. package/dist/assets/classDiagram-OUVF2IWQ-DKW_dtku.js +1 -0
  217. package/dist/assets/classDiagram-v2-EOCWNBFH-C8Fi7-yv.js +1 -0
  218. package/dist/assets/clojure-CvY8A83L.js +1 -0
  219. package/dist/assets/code-dark-Cjb1QGhu.css +1 -0
  220. package/dist/assets/code-mobile-3C2Rr-CN.css +1 -0
  221. package/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  222. package/dist/assets/coffee-4LX2Sv8A.js +1 -0
  223. package/dist/assets/core-ZlAPicox.js +3 -0
  224. package/dist/assets/cose-bilkent-JH36ORCC-BNIAz0nN.js +1 -0
  225. package/dist/assets/cpp-D4AzSV28.js +1 -0
  226. package/dist/assets/csharp-C4nWN4Yd.js +1 -0
  227. package/dist/assets/csp-CiEaaS5Z.js +1 -0
  228. package/dist/assets/css-DXxBRsbk.js +3 -0
  229. package/dist/assets/css.worker-DyDu5ynT.js +89 -0
  230. package/dist/assets/cssMode-DDWxTPm_.js +1 -0
  231. package/dist/assets/cynefin-VYW2F7L2-DgXGHlRt.js +1 -0
  232. package/dist/assets/cynefinDiagram-TSTJHNR4-CwpobXIl.js +62 -0
  233. package/dist/assets/cypher-DOMzqyFA.js +1 -0
  234. package/dist/assets/cytoscape.esm-Cl8iC3D7.js +321 -0
  235. package/dist/assets/dagre-DXlcHgr3.js +1 -0
  236. package/dist/assets/dagre-VKFMJZFB-Dkhlfjna.js +4 -0
  237. package/dist/assets/dart-BWS7MXt_.js +1 -0
  238. package/dist/assets/defaultLocale-GJwWH1Jr.js +1 -0
  239. package/dist/assets/diagram-FQU43EPY-hA8dicp6.js +3 -0
  240. package/dist/assets/diagram-G47NLZAW-BTY6JTzO.js +24 -0
  241. package/dist/assets/diagram-NH7WQ7WH-xkaHHX9M.js +24 -0
  242. package/dist/assets/diagram-OA4YK3LP-gk_fg9UU.js +30 -0
  243. package/dist/assets/diagram-WEI45ONY-BvC8xd6T.js +41 -0
  244. package/dist/assets/dist-ClAL-Tv5.js +1 -0
  245. package/dist/assets/dockerfile-Baf4U3xT.js +1 -0
  246. package/dist/assets/ebnfDiagram-CCIWWBDH-CR7RaNat.js +1 -0
  247. package/dist/assets/ecl-CT7udlkQ.js +1 -0
  248. package/dist/assets/editor-CtbFZlk0.css +1 -0
  249. package/dist/assets/editor.api2-B9h6iFPK.js +872 -0
  250. package/dist/assets/editor.worker-Dpt_xPrs.js +26 -0
  251. package/dist/assets/elixir-CIbAZw5l.js +1 -0
  252. package/dist/assets/erDiagram-Q63AITRT-_M-JFPbj.js +85 -0
  253. package/dist/assets/eventmodeling-45OFAUF4-DXYTQ2nt.js +1 -0
  254. package/dist/assets/file-icons-EFUGSSwf.js +1 -0
  255. package/dist/assets/flow9-Dqiw45WV.js +1 -0
  256. package/dist/assets/flowDiagram-23GEKE2U-DAiS5Y7G.js +1 -0
  257. package/dist/assets/freemarker2-QBsTERH-.js +3 -0
  258. package/dist/assets/fsharp-E8E2L9jU.js +1 -0
  259. package/dist/assets/ganttDiagram-NO4QXBWP-Bl8P1yf_.js +292 -0
  260. package/dist/assets/gitGraph-TEB2WS4Q-CzTBjEvV.js +1 -0
  261. package/dist/assets/gitGraphDiagram-IHSO6WYX-DoHa5ysz.js +106 -0
  262. package/dist/assets/go-CouVSN4D.js +1 -0
  263. package/dist/assets/graphlib-CbSvZcZU.js +1 -0
  264. package/dist/assets/graphql-a6h6h5-t.js +1 -0
  265. package/dist/assets/handlebars-CuoxPo5A.js +1 -0
  266. package/dist/assets/hcl-vso3e6N-.js +1 -0
  267. package/dist/assets/html-gX5PEu0Q.js +1 -0
  268. package/dist/assets/html.worker-IWNXhnIC.js +502 -0
  269. package/dist/assets/htmlMode-DIWUbUxd.js +1 -0
  270. package/dist/assets/index-BpHPeJf0.js +10 -0
  271. package/dist/assets/info-DKCQHKI2-DznP7j3s.js +1 -0
  272. package/dist/assets/infoDiagram-FWYZ7A6U-DSFcSuUs.js +2 -0
  273. package/dist/assets/ini-SwZZkotR.js +1 -0
  274. package/dist/assets/init-BPLPMQ3Y.js +1 -0
  275. package/dist/assets/ishikawaDiagram-FXEZZL3T-DdkqullI.js +70 -0
  276. package/dist/assets/java-CtRLC4_3.js +1 -0
  277. package/dist/assets/javascript-BYKGIUGs.js +1 -0
  278. package/dist/assets/journeyDiagram-5HDEW3XC-B4hRnQJr.js +139 -0
  279. package/dist/assets/json.worker-c4h5s80L.js +58 -0
  280. package/dist/assets/jsonMode-AFmQQP6u.js +7 -0
  281. package/dist/assets/jsx-runtime-BthL93pI.js +1 -0
  282. package/dist/assets/julia-CuJWFKQH.js +1 -0
  283. package/dist/assets/kanban-definition-HUTT4EX6-tm2FZB2E.js +89 -0
  284. package/dist/assets/katex-C8DPyI6s.js +257 -0
  285. package/dist/assets/kotlin-B_kBhsre.js +1 -0
  286. package/dist/assets/less-CtrHIfz3.js +2 -0
  287. package/dist/assets/lexon-yVt1pJLu.js +1 -0
  288. package/dist/assets/line-CmsjK4kn.js +1 -0
  289. package/dist/assets/linear-Dld3_ERu.js +1 -0
  290. package/dist/assets/liquid-DBIl-f0z.js +1 -0
  291. package/dist/assets/lspLanguageFeatures-DK6tqicV.js +4 -0
  292. package/dist/assets/lua-prOwgJ4U.js +1 -0
  293. package/dist/assets/m3-DhrdTQ84.js +1 -0
  294. package/dist/assets/main-DTJwH51M.css +1 -0
  295. package/dist/assets/map-LZWWoeWa.js +1 -0
  296. package/dist/assets/markdown-DoI5HwSM.js +1 -0
  297. package/dist/assets/mdx-DS-bVtZN.js +1 -0
  298. package/dist/assets/mermaid-parser.core-BQtepoLd.js +4 -0
  299. package/dist/assets/mermaid.core-C7UT_EEL.js +11 -0
  300. package/dist/assets/mindmap-definition-LN4V7U3C-DplfjGms.js +96 -0
  301. package/dist/assets/mips-Dye5jsBU.js +1 -0
  302. package/dist/assets/monaco.contribution-CyLosfZI.js +2 -0
  303. package/dist/assets/msdax-TkNOyIL8.js +1 -0
  304. package/dist/assets/mysql-CEc-RKZF.js +1 -0
  305. package/dist/assets/objective-c-CqqCsQz0.js +1 -0
  306. package/dist/assets/ordinal-BLrOss5K.js +1 -0
  307. package/dist/assets/packet-7NZHBO7P-BDEPOPha.js +1 -0
  308. package/dist/assets/pascal-DO_pj8yg.js +1 -0
  309. package/dist/assets/pascaligo-1cbdZdF3.js +1 -0
  310. package/dist/assets/path-YdFzr2W6.js +1 -0
  311. package/dist/assets/pegDiagram-2B236MQR-lu3SdkQs.js +1 -0
  312. package/dist/assets/perl-B_N3PYfC.js +1 -0
  313. package/dist/assets/pgsql-9iYk1FQ7.js +1 -0
  314. package/dist/assets/php-rO2sgoUM.js +1 -0
  315. package/dist/assets/pie-RZYD4A2V-DWIrwPJQ.js +1 -0
  316. package/dist/assets/pieDiagram-ENE6RG2P-3fHbmDf9.js +39 -0
  317. package/dist/assets/pla-Cbgv60kq.js +1 -0
  318. package/dist/assets/postiats-y6xrhy_M.js +1 -0
  319. package/dist/assets/powerquery-BaD8gWNE.js +1 -0
  320. package/dist/assets/powershell-BMhG4JVe.js +1 -0
  321. package/dist/assets/preload-helper-mJowh_hw.js +1 -0
  322. package/dist/assets/protobuf-CdOP5kN3.js +2 -0
  323. package/dist/assets/pug-Ck60hNF9.js +1 -0
  324. package/dist/assets/python-C93q3xXz.js +1 -0
  325. package/dist/assets/qoder-C9LmmOSf.svg +1 -0
  326. package/dist/assets/qoder-Cf9gl0Y5.svg +1 -0
  327. package/dist/assets/qoder-gHCinseV.svg +1 -0
  328. package/dist/assets/qrcode-DV-_rjU8.js +3 -0
  329. package/dist/assets/qsharp-BcaKFfP-.js +1 -0
  330. package/dist/assets/quadrantDiagram-ABIIQ3AL-a5qoWz-X.js +7 -0
  331. package/dist/assets/r-rFNes0iK.js +1 -0
  332. package/dist/assets/radar-I7S5WNFK-B7OaD8vp.js +1 -0
  333. package/dist/assets/railroad-3IZDKUUU-BXW2nuCA.js +1 -0
  334. package/dist/assets/railroad-abnf-AHOZXSZD-Buw9QG2r.js +1 -0
  335. package/dist/assets/railroad-ebnf-EBAXGLYW-BjSi4sWJ.js +1 -0
  336. package/dist/assets/railroad-peg-LSFZ7HO6-DN1wIVhS.js +1 -0
  337. package/dist/assets/railroadDiagram-RFXS5EU6-D2TOuXW9.js +1 -0
  338. package/dist/assets/razor-CBifNGXO.js +1 -0
  339. package/dist/assets/react-dom-gtU6X-Hj.js +1 -0
  340. package/dist/assets/redis-DkpQ3K6G.js +1 -0
  341. package/dist/assets/redshift-Di9N5TI3.js +1 -0
  342. package/dist/assets/requirementDiagram-TGXJPOKE-LQBWpUvd.js +84 -0
  343. package/dist/assets/restructuredtext-By5ZzLt6.js +1 -0
  344. package/dist/assets/review-BcnwQtJv.css +1 -0
  345. package/dist/assets/rough.esm-c4PR5shF.js +1 -0
  346. package/dist/assets/ruby-fF5zGiLp.js +1 -0
  347. package/dist/assets/rust-C5b3AYY6.js +1 -0
  348. package/dist/assets/sankeyDiagram-HTMAVEWB-B1ohYoyK.js +40 -0
  349. package/dist/assets/sb-CD07UNRs.js +1 -0
  350. package/dist/assets/scala-jtn1ip9G.js +1 -0
  351. package/dist/assets/scheme-C4vqMkn_.js +1 -0
  352. package/dist/assets/scss-I4Glxjbz.js +3 -0
  353. package/dist/assets/sequenceDiagram-DBY2YBRQ-C3vM-hMq.js +162 -0
  354. package/dist/assets/shell-DubUcuns.js +1 -0
  355. package/dist/assets/sizeCapture-X5ZJPWSS-daTB6OcF.js +1 -0
  356. package/dist/assets/solidity-CNy2KSl2.js +1 -0
  357. package/dist/assets/sophia-D9_URt84.js +1 -0
  358. package/dist/assets/sparql-DviXpm4C.js +1 -0
  359. package/dist/assets/sql-vDRbAZgK.js +1 -0
  360. package/dist/assets/src-WBW1QxJt.js +1 -0
  361. package/dist/assets/st-CnpnRqA7.js +1 -0
  362. package/dist/assets/stateDiagram-2N3HPSRC-BvFhOryI.js +1 -0
  363. package/dist/assets/stateDiagram-v2-6OUMAXLB-WMrz4PNo.js +1 -0
  364. package/dist/assets/swift-D_g8Ganz.js +1 -0
  365. package/dist/assets/swimlanes-5IMT3BWC-DKF_b-2s.js +2 -0
  366. package/dist/assets/swimlanesDiagram-G3AALYLV-BGswC9oC.js +8 -0
  367. package/dist/assets/systemverilog-OuZa5h1M.js +1 -0
  368. package/dist/assets/tcl-DBm9ucsV.js +1 -0
  369. package/dist/assets/timeline-definition-FHXFAJF6-vAs11ux_.js +120 -0
  370. package/dist/assets/tokens-BwenNn5Q.css +1 -0
  371. package/dist/assets/treeView-QDETBFTQ-BVfICaZQ.js +1 -0
  372. package/dist/assets/treemap-6X3UGDF4-oWHPqo17.js +1 -0
  373. package/dist/assets/ts.worker-BwM5Ha3L.js +67719 -0
  374. package/dist/assets/tsMode-DGZTlTj8.js +11 -0
  375. package/dist/assets/twig-BRzEqX5Y.js +1 -0
  376. package/dist/assets/typescript-KJKfYO7K.js +1 -0
  377. package/dist/assets/typespec-D4ZgGeX8.js +1 -0
  378. package/dist/assets/useWorkspaceMenuKeyboard-CneKAZUJ.js +1 -0
  379. package/dist/assets/vb-DcP4s6WS.js +1 -0
  380. package/dist/assets/vennDiagram-L72KCM5P-BybTX_9B.js +34 -0
  381. package/dist/assets/wardley-OPB4EBWU-Dg8t5y3s.js +1 -0
  382. package/dist/assets/wardleyDiagram-EHGQE667-CicUmMBR.js +78 -0
  383. package/dist/assets/wgsl-CnRJ_QUf.js +298 -0
  384. package/dist/assets/workers-BSQRIkqa.js +1 -0
  385. package/dist/assets/workspace-view-state-CTyDzk2D.js +1 -0
  386. package/dist/assets/xml-C8FAcN6j.js +1 -0
  387. package/dist/assets/xychartDiagram-FW5EYKEG-BhWDyCX-.js +7 -0
  388. package/dist/assets/yaml-BQ4NrRhG.js +1 -0
  389. package/dist/assets/zsh-CLpveKlF.svg +1 -0
  390. package/dist/assets/zsh-FxSpMPbz.svg +1 -0
  391. package/dist/farming-2/app-icon-v2-180.png +0 -0
  392. package/dist/farming-2/app-icon-v2-192.png +0 -0
  393. package/dist/farming-2/app-icon-v2-512.png +0 -0
  394. package/dist/farming-2/app-icon-v2-maskable-512.png +0 -0
  395. package/dist/farming-2/app-icon-v2-master.png +0 -0
  396. package/dist/farming-2/favicon-v2-16.png +0 -0
  397. package/dist/farming-2/favicon-v2-32.png +0 -0
  398. package/dist/farming-2/favicon-v2-48.png +0 -0
  399. package/dist/farming-2/favicon-v2-64.png +0 -0
  400. package/dist/farming-2/favicon-v2.ico +0 -0
  401. package/dist/farming-2/favicon.ico +0 -0
  402. package/dist/farming-2/github-social-preview.png +0 -0
  403. package/dist/farming-2/images/avatar-watercolor-v1-bee-garden.png +0 -0
  404. package/dist/farming-2/images/avatar-watercolor-v2.png +0 -0
  405. package/dist/farming-2/images/avatar-watercolor-v3.png +0 -0
  406. package/dist/farming-2/legacy-icons-v1/favicon.ico +1 -0
  407. package/dist/farming-2/legacy-icons-v1/logo-16.png +0 -0
  408. package/dist/farming-2/legacy-icons-v1/logo-180.png +0 -0
  409. package/dist/farming-2/legacy-icons-v1/logo-192.png +0 -0
  410. package/dist/farming-2/legacy-icons-v1/logo-32.png +0 -0
  411. package/dist/farming-2/legacy-icons-v1/logo-48.png +0 -0
  412. package/dist/farming-2/legacy-icons-v1/logo-512.png +0 -0
  413. package/dist/farming-2/legacy-icons-v1/logo-64.png +0 -0
  414. package/dist/farming-2/logo-16.png +0 -0
  415. package/dist/farming-2/logo-180.png +0 -0
  416. package/dist/farming-2/logo-192.png +0 -0
  417. package/dist/farming-2/logo-32.png +0 -0
  418. package/dist/farming-2/logo-48.png +0 -0
  419. package/dist/farming-2/logo-512.png +0 -0
  420. package/dist/farming-2/logo-64.png +0 -0
  421. package/dist/farming-2/site.webmanifest +27 -0
  422. package/dist/farming-2/style_capsules/watercolor-pastoral.json +94 -0
  423. package/dist/index.html +27 -0
  424. package/frontend/ghostty-loader.js +24 -0
  425. package/frontend/runtime-paths.js +28 -0
  426. package/frontend/session-bridge.js +82 -0
  427. package/frontend/session-modal-bridge.js +331 -0
  428. package/frontend/skin-bridge.js +25 -0
  429. package/frontend/skins/crt/app.js +6940 -0
  430. package/frontend/skins/crt/assets/branding/farming-crt-icon.svg +11 -0
  431. package/frontend/skins/crt/assets/branding/farming-crt-logo-v1.png +0 -0
  432. package/frontend/skins/crt/assets/effects/phosphor-noise.svg +11 -0
  433. package/frontend/skins/crt/assets/fonts/departure-mono/DepartureMonoNerdFontMono-Regular.otf +0 -0
  434. package/frontend/skins/crt/assets/fonts/departure-mono/LICENSE +93 -0
  435. package/frontend/skins/crt/effects.js +8 -0
  436. package/frontend/skins/crt/index.html +1712 -0
  437. package/frontend/skins/crt/styles/billing.css +1003 -0
  438. package/frontend/skins/crt/styles/effects.css +171 -0
  439. package/frontend/skins/crt/styles/history.css +215 -0
  440. package/frontend/skins/crt/styles/monochrome-green.css +509 -0
  441. package/frontend/skins/crt/styles/search.css +271 -0
  442. package/frontend/terminal-bridge.js +192 -0
  443. package/frontend/theme-loader.js +84 -0
  444. package/frontend/themes/terminal/theme.json +24 -0
  445. package/frontend/vendor/ghostty-web/LICENSE +21 -0
  446. package/frontend/vendor/ghostty-web/__vite-browser-external-2447137e.js +4 -0
  447. package/frontend/vendor/ghostty-web/ghostty-vt.wasm +0 -0
  448. package/frontend/vendor/ghostty-web/ghostty-web.js +2963 -0
  449. package/frontend/vendor/ghostty-web/ghostty-web.umd.cjs +13 -0
  450. package/frontend/vendor/ghostty-web/index.d.ts +1842 -0
  451. package/index.html +23 -0
  452. package/package.json +144 -0
  453. package/scripts/sync-ghostty-vendor.js +66 -0
package/SECURITY.md ADDED
@@ -0,0 +1,29 @@
1
+ # Security Policy
2
+
3
+ > Chinese version: [SECURITY.zh_cn.md](./SECURITY.zh_cn.md)
4
+
5
+ Farming controls real terminals and AI coding-agent processes on the target machine. Treat every deployment as access to that machine.
6
+
7
+ ## Supported Versions
8
+
9
+ The active development branch and the latest published release receive security fixes.
10
+
11
+ ## Deployment Guidance
12
+
13
+ - Run Farming on trusted development machines and trusted networks.
14
+ - Do not expose Farming directly to the public internet without an additional security layer such as VPN, SSH tunnel, HTTPS reverse proxy, or network ACLs.
15
+ - Keep token authentication enabled outside trusted local development.
16
+ - Use `FARMING_DISABLE_AUTH=1` only for local development on a trusted machine.
17
+ - Install and configure Codex / Claude Code permissions according to their own security model; Farming hosts their CLI sessions but does not replace their permission system.
18
+ - Do not commit real tokens, private `.env` files, internal hosts, personal machine paths, or private screenshots.
19
+
20
+ ## Reporting A Vulnerability
21
+
22
+ Please report security issues privately to the maintainers instead of opening a public issue with exploit details.
23
+
24
+ Maintainers:
25
+
26
+ - [zhuwenzhuang](https://github.com/zhuwenzhuang)
27
+ - [l4wei](https://github.com/l4wei)
28
+
29
+ When reporting, include the affected version or commit, deployment mode, reproduction steps, and the expected impact.
@@ -0,0 +1,106 @@
1
+ # Third Party Notices
2
+
3
+ Farming is licensed under the MIT License. This file summarizes third-party
4
+ software and external tools that Farming bundles, depends on, or interoperates
5
+ with.
6
+
7
+ ## Bundled Production Dependencies
8
+
9
+ Farming's app bundle installs the production dependency tree pinned by
10
+ `package.json` and `package-lock.json`. Package-level license files are
11
+ preserved in bundled `node_modules` when bundled dependencies are enabled.
12
+
13
+ ## Direct Runtime Dependencies
14
+
15
+ | Package | Version | License | Purpose |
16
+ | --- | --- | --- | --- |
17
+ | `@agentclientprotocol/sdk` | 1.2.1 | Apache-2.0 | ACP JSON-RPC client and protocol types |
18
+ | `@agentclientprotocol/codex-acp` | 1.1.2 | Apache-2.0 | Codex ACP adapter |
19
+ | `@agentclientprotocol/claude-agent-acp` | 0.58.1 | Apache-2.0 | Claude Code ACP adapter |
20
+ | `@xterm/addon-clipboard` | 0.2.0 | MIT | Browser terminal clipboard integration |
21
+ | `@xterm/addon-fit` | 0.11.0 | MIT | Browser terminal sizing |
22
+ | `@xterm/addon-search` | 0.16.0 | MIT | Browser terminal search |
23
+ | `@xterm/addon-serialize` | 0.14.0 | MIT | Terminal screen serialization |
24
+ | `@xterm/addon-webgl` | 0.19.0 | MIT | CRT terminal GPU renderer |
25
+ | `@xterm/headless` | 6.0.0 | MIT | Backend terminal screen state |
26
+ | `@xterm/xterm` | 6.0.0 | MIT | Browser terminal renderer |
27
+ | `ansi-to-html` | 0.7.2 | MIT | ANSI text rendering support |
28
+ | `chokidar` | 5.0.0 | MIT | Filesystem watching |
29
+ | `diff` | 9.0.0 | BSD-3-Clause | Character-level diff ranges for code review |
30
+ | `express` | 4.22.1 | MIT | HTTP API server |
31
+ | `ghostty-web` | 0.4.0 | MIT | Optional/debug terminal renderer assets |
32
+ | `highlight.js` | 11.11.1 | BSD-3-Clause | Syntax highlighting |
33
+ | `katex` | 0.17.0 | MIT | Mathematical notation rendering |
34
+ | `material-icon-theme` | 5.36.1 | MIT | File and folder icons |
35
+ | `mermaid` | 11.16.0 | MIT | Diagram rendering |
36
+ | `monaco-editor` | 0.55.1 | MIT | Lightweight code editor |
37
+ | `node-pty` | 1.2.0-beta.12 | MIT | Native pseudo-terminal integration |
38
+ | `qrcode-generator` | 2.0.4 | MIT | Browser share QR generation |
39
+ | `react` | 19.2.4 | MIT | Frontend UI framework |
40
+ | `react-arborist` | 3.10.5 | MIT | Tree view UI |
41
+ | `react-dom` | 19.2.4 | MIT | React DOM renderer |
42
+ | `react-markdown` | 10.1.0 | MIT | Markdown rendering |
43
+ | `rehype-highlight` | 7.0.2 | MIT | Markdown syntax-highlighting integration |
44
+ | `rehype-katex` | 7.0.1 | MIT | Markdown math rendering integration |
45
+ | `remark-gfm` | 4.0.1 | MIT | GitHub Flavored Markdown support |
46
+ | `remark-math` | 6.0.0 | MIT | Markdown math syntax support |
47
+ | `ripgrep` | 0.3.1 | MIT | Node wrapper for file search support |
48
+ | `ws` | 8.21.0 | MIT | WebSocket server/client support |
49
+ | `yaml` | 2.9.0 | ISC | YAML parsing |
50
+
51
+ ## Vendored Assets
52
+
53
+ Farming vendors `ghostty-web` distribution files under
54
+ `frontend/vendor/ghostty-web` for the optional Ghostty debug renderer. The
55
+ source package is `ghostty-web` 0.4.0, licensed under MIT. Its license is kept
56
+ beside the vendored files at `frontend/vendor/ghostty-web/LICENSE`.
57
+
58
+ If vendored assets are updated, keep this notice in sync with the package name,
59
+ version, and license.
60
+
61
+ The CRT skin bundles one font file under `frontend/skins/crt/fonts/`:
62
+
63
+ | Font | License | Purpose |
64
+ | --- | --- | --- |
65
+
66
+ The corresponding license texts are stored beside the font files.
67
+
68
+ ## Bundled Data
69
+
70
+ Farming includes a generated Chinese poetic token word list at
71
+ `backend/data/chinese-poetic-words.json`. It is derived from the
72
+ `chinese-poetry/chinese-poetry` dataset, licensed under MIT:
73
+ https://github.com/chinese-poetry/chinese-poetry.
74
+
75
+ The generated file stores the source commit and selected corpus directories.
76
+ The original corpus is not bundled in the runtime package.
77
+
78
+ ## Development And Build Dependencies
79
+
80
+ Farming also uses development-time tools such as TypeScript, Vite, ESLint,
81
+ Playwright, Puppeteer, esbuild, and package builders. These tools are not part
82
+ of the app runtime dependency set unless a release artifact explicitly embeds
83
+ their code.
84
+
85
+ ## External Interoperability
86
+
87
+ Farming can launch or observe coding-agent CLIs installed by the user, including
88
+ OpenCode and the terminal forms of OpenAI Codex CLI and Anthropic Claude Code.
89
+ The optional structured ACP runtime includes the pinned Codex and Claude ACP
90
+ adapter dependency trees, including the provider SDK/runtime packages required
91
+ by those adapters. Those packages remain separate projects governed by their
92
+ own terms and licenses; package-level license files remain in `node_modules`.
93
+
94
+ Farming is not affiliated with, sponsored by, or endorsed by OpenAI, Anthropic,
95
+ Microsoft, or the maintainers of the third-party projects listed above.
96
+
97
+ ## Design References
98
+
99
+ Farming's interface is influenced by modern coding workbenches and agent tools,
100
+ including Codex, Visual Studio Code, and browser IDEs. This notice covers
101
+ software and assets used by Farming; design inspiration alone does not imply
102
+ that those projects are bundled with Farming.
103
+
104
+ The CRT skin also studies the visual behavior of cool-retro-term. Farming's
105
+ browser shaders are an independent implementation and do not copy or bundle
106
+ cool-retro-term source code.
@@ -0,0 +1,312 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { spawn } = require('child_process');
4
+ const nodePty = require('../packaged-node-pty');
5
+
6
+ const fsp = fs.promises;
7
+ const DEFAULT_MAX_FILE_BYTES = 8 * 1024 * 1024;
8
+ const DEFAULT_TERMINAL_OUTPUT_BYTES = 1024 * 1024;
9
+ const MAX_TERMINAL_OUTPUT_BYTES = 16 * 1024 * 1024;
10
+ const MAX_ACTIVE_TERMINALS_PER_AGENT = 32;
11
+
12
+ function isInside(root, target) {
13
+ const relative = path.relative(root, target);
14
+ return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative));
15
+ }
16
+
17
+ function requireMatchingSession(binding, params) {
18
+ if (!binding?.sessionId || String(params?.sessionId || '') !== binding.sessionId) {
19
+ throw new Error('ACP client request does not match the active session');
20
+ }
21
+ }
22
+
23
+ async function resolveWorkspacePath(binding, requestedPath, options = {}) {
24
+ const value = String(requestedPath || '');
25
+ if (!path.isAbsolute(value)) throw new Error('ACP file and terminal paths must be absolute');
26
+ const logicalRoot = path.resolve(binding.cwd);
27
+ const root = await fsp.realpath(binding.cwd);
28
+ const logicalTarget = path.resolve(value);
29
+ const target = isInside(logicalRoot, logicalTarget)
30
+ ? path.resolve(root, path.relative(logicalRoot, logicalTarget))
31
+ : isInside(root, logicalTarget)
32
+ ? logicalTarget
33
+ : null;
34
+ if (!target) throw new Error('ACP path is outside the Agent workspace');
35
+
36
+ if (options.allowMissing === true) {
37
+ const parent = await fsp.realpath(path.dirname(target));
38
+ if (!isInside(root, parent)) throw new Error('ACP path resolves outside the Agent workspace');
39
+ return target;
40
+ }
41
+
42
+ const realTarget = await fsp.realpath(target);
43
+ if (!isInside(root, realTarget)) throw new Error('ACP path resolves outside the Agent workspace');
44
+ return realTarget;
45
+ }
46
+
47
+ class AcpClientFileSystem {
48
+ constructor(options = {}) {
49
+ this.maxFileBytes = options.maxFileBytes || DEFAULT_MAX_FILE_BYTES;
50
+ }
51
+
52
+ async readTextFile(binding, params) {
53
+ requireMatchingSession(binding, params);
54
+ const target = await resolveWorkspacePath(binding, params.path);
55
+ const stat = await fsp.stat(target);
56
+ if (!stat.isFile()) throw new Error('ACP read path must be a file');
57
+ if (stat.size > this.maxFileBytes) throw new Error('ACP text file is too large to read');
58
+ const content = await fsp.readFile(target, 'utf8');
59
+ const requestedLine = params.line == null ? 1 : Number(params.line);
60
+ const requestedLimit = params.limit == null ? null : Number(params.limit);
61
+ if (!Number.isInteger(requestedLine) || requestedLine < 1) throw new Error('ACP read line must be a positive integer');
62
+ if (requestedLimit !== null && (!Number.isInteger(requestedLimit) || requestedLimit < 0)) {
63
+ throw new Error('ACP read limit must be a non-negative integer');
64
+ }
65
+ if (requestedLine === 1 && requestedLimit === null) return { content };
66
+ const lines = content.split('\n');
67
+ const start = requestedLine - 1;
68
+ const end = requestedLimit === null ? lines.length : start + requestedLimit;
69
+ return { content: lines.slice(start, end).join('\n') };
70
+ }
71
+
72
+ async writeTextFile(binding, params) {
73
+ requireMatchingSession(binding, params);
74
+ const content = String(params.content ?? '');
75
+ if (Buffer.byteLength(content, 'utf8') > this.maxFileBytes) {
76
+ throw new Error('ACP text file is too large to write');
77
+ }
78
+ const target = await resolveWorkspacePath(binding, params.path, { allowMissing: true });
79
+ let mode = 0o666;
80
+ try {
81
+ const existing = await fsp.realpath(target);
82
+ const root = await fsp.realpath(binding.cwd);
83
+ if (!isInside(root, existing)) throw new Error('ACP path resolves outside the Agent workspace');
84
+ const stat = await fsp.stat(existing);
85
+ if (!stat.isFile()) throw new Error('ACP write path must be a file');
86
+ mode = stat.mode;
87
+ } catch (error) {
88
+ if (error?.code !== 'ENOENT') throw error;
89
+ }
90
+ const temporary = path.join(path.dirname(target), `.${path.basename(target)}.farming-acp-${process.pid}-${Date.now()}.tmp`);
91
+ try {
92
+ await fsp.writeFile(temporary, content, { mode });
93
+ await fsp.rename(temporary, target);
94
+ } catch (error) {
95
+ await fsp.rm(temporary, { force: true }).catch(() => {});
96
+ throw error;
97
+ }
98
+ return {};
99
+ }
100
+ }
101
+
102
+ function boundedOutputLimit(value) {
103
+ const parsed = Number(value);
104
+ if (!Number.isFinite(parsed) || parsed <= 0) return DEFAULT_TERMINAL_OUTPUT_BYTES;
105
+ return Math.min(MAX_TERMINAL_OUTPUT_BYTES, Math.max(1, Math.floor(parsed)));
106
+ }
107
+
108
+ function trimUtf8Start(buffer, limit) {
109
+ if (buffer.length <= limit) return { buffer, truncated: false };
110
+ let start = buffer.length - limit;
111
+ while (start < buffer.length && (buffer[start] & 0xc0) === 0x80) start += 1;
112
+ return { buffer: buffer.subarray(start), truncated: true };
113
+ }
114
+
115
+ class AcpClientTerminalManager {
116
+ constructor(options = {}) {
117
+ this.spawn = options.spawn || spawn;
118
+ this.ptySpawn = typeof options.ptySpawn === 'function'
119
+ ? options.ptySpawn
120
+ : typeof options.spawn === 'function'
121
+ ? null
122
+ : nodePty.spawn;
123
+ this.sequence = 0;
124
+ this.terminals = new Map();
125
+ }
126
+
127
+ activeCount(agentId) {
128
+ let count = 0;
129
+ for (const record of this.terminals.values()) {
130
+ if (record.agentId === agentId && !record.released && !record.exitStatus) count += 1;
131
+ }
132
+ return count;
133
+ }
134
+
135
+ async create(binding, params) {
136
+ requireMatchingSession(binding, params);
137
+ if (this.activeCount(binding.agentId) >= MAX_ACTIVE_TERMINALS_PER_AGENT) {
138
+ throw new Error('ACP terminal limit reached for this Agent');
139
+ }
140
+ const command = String(params.command || '').trim();
141
+ if (!command) throw new Error('ACP terminal command is required');
142
+ const cwd = params.cwd
143
+ ? await resolveWorkspacePath(binding, params.cwd)
144
+ : await fsp.realpath(binding.cwd);
145
+ const env = { ...binding.env };
146
+ for (const item of Array.isArray(params.env) ? params.env : []) {
147
+ const name = String(item?.name || '');
148
+ if (!name || name.includes('=') || name.includes('\0')) throw new Error('Invalid ACP terminal environment variable');
149
+ env[name] = String(item?.value ?? '');
150
+ }
151
+ const terminalId = `acp-terminal-${++this.sequence}`;
152
+ const args = Array.isArray(params.args) ? params.args.map(String) : [];
153
+ const child = this.ptySpawn
154
+ ? this.ptySpawn(command, args, {
155
+ cwd,
156
+ env,
157
+ name: 'xterm-256color',
158
+ cols: 80,
159
+ rows: 24,
160
+ })
161
+ : this.spawn(command, args, {
162
+ cwd,
163
+ env,
164
+ stdio: ['ignore', 'pipe', 'pipe'],
165
+ });
166
+ const record = {
167
+ terminalId,
168
+ agentId: binding.agentId,
169
+ sessionId: binding.sessionId,
170
+ command,
171
+ args,
172
+ cwd,
173
+ startedAt: Date.now(),
174
+ endedAt: null,
175
+ child,
176
+ output: Buffer.alloc(0),
177
+ outputLimit: boundedOutputLimit(params.outputByteLimit),
178
+ truncated: false,
179
+ exitStatus: null,
180
+ released: false,
181
+ waiters: [],
182
+ interactive: Boolean(this.ptySpawn),
183
+ };
184
+ this.terminals.set(terminalId, record);
185
+ const append = chunk => {
186
+ const next = Buffer.concat([record.output, Buffer.from(chunk)]);
187
+ const bounded = trimUtf8Start(next, record.outputLimit);
188
+ record.output = bounded.buffer;
189
+ record.truncated = record.truncated || bounded.truncated;
190
+ };
191
+ if (record.interactive) {
192
+ child.onData(append);
193
+ child.onExit(event => this.finish(record, {
194
+ exitCode: Number.isInteger(event?.exitCode) ? event.exitCode : null,
195
+ signal: Number.isInteger(event?.signal) && event.signal > 0 ? String(event.signal) : null,
196
+ }));
197
+ } else {
198
+ child.stdout?.on('data', append);
199
+ child.stderr?.on('data', append);
200
+ child.on('error', error => {
201
+ append(`${error.message || error}\n`);
202
+ this.finish(record, { exitCode: null, signal: 'spawn-error' });
203
+ });
204
+ child.on('close', (code, signal) => this.finish(record, {
205
+ exitCode: Number.isInteger(code) ? code : null,
206
+ signal: signal ? String(signal) : null,
207
+ }));
208
+ }
209
+ return { terminalId };
210
+ }
211
+
212
+ require(binding, params, options = {}) {
213
+ requireMatchingSession(binding, params);
214
+ const record = this.terminals.get(String(params.terminalId || ''));
215
+ if (!record || record.agentId !== binding.agentId || record.sessionId !== binding.sessionId) {
216
+ throw new Error('Unknown ACP terminal');
217
+ }
218
+ if (record.released && options.allowReleased !== true) throw new Error('ACP terminal has been released');
219
+ return record;
220
+ }
221
+
222
+ finish(record, exitStatus) {
223
+ if (record.exitStatus) return;
224
+ record.exitStatus = exitStatus;
225
+ record.endedAt = Date.now();
226
+ const waiters = record.waiters.splice(0);
227
+ waiters.forEach(resolve => resolve({ ...exitStatus }));
228
+ }
229
+
230
+ output(binding, params) {
231
+ const record = this.require(binding, params);
232
+ return {
233
+ output: record.output.toString('utf8'),
234
+ truncated: record.truncated,
235
+ ...(record.exitStatus ? { exitStatus: { ...record.exitStatus } } : {}),
236
+ };
237
+ }
238
+
239
+ waitForExit(binding, params) {
240
+ const record = this.require(binding, params);
241
+ if (record.exitStatus) return { ...record.exitStatus };
242
+ return new Promise(resolve => record.waiters.push(resolve));
243
+ }
244
+
245
+ input(binding, params) {
246
+ const record = this.require(binding, params);
247
+ if (!record.interactive) throw new Error('ACP terminal does not accept interactive input');
248
+ if (record.exitStatus) throw new Error('ACP terminal has already exited');
249
+ const input = String(params.input ?? '');
250
+ if (Buffer.byteLength(input, 'utf8') > 64 * 1024) throw new Error('ACP terminal input is too large');
251
+ record.child.write(input);
252
+ return {};
253
+ }
254
+
255
+ resize(binding, params) {
256
+ const record = this.require(binding, params);
257
+ if (!record.interactive) return {};
258
+ const cols = Number(params.cols);
259
+ const rows = Number(params.rows);
260
+ if (!Number.isInteger(cols) || cols < 2 || cols > 1000 || !Number.isInteger(rows) || rows < 1 || rows > 1000) {
261
+ throw new Error('ACP terminal size is invalid');
262
+ }
263
+ if (!record.exitStatus) record.child.resize(cols, rows);
264
+ return {};
265
+ }
266
+
267
+ kill(binding, params) {
268
+ const record = this.require(binding, params);
269
+ if (!record.exitStatus && !record.child.killed) record.child.kill('SIGTERM');
270
+ return {};
271
+ }
272
+
273
+ release(binding, params) {
274
+ const record = this.require(binding, params);
275
+ if (!record.exitStatus && !record.child.killed) record.child.kill('SIGTERM');
276
+ record.released = true;
277
+ return {};
278
+ }
279
+
280
+ display(terminalId) {
281
+ const record = this.terminals.get(String(terminalId || ''));
282
+ if (!record) return null;
283
+ return {
284
+ command: record.command,
285
+ args: [...record.args],
286
+ cwd: record.cwd,
287
+ output: record.output.toString('utf8'),
288
+ truncated: record.truncated,
289
+ exitStatus: record.exitStatus ? { ...record.exitStatus } : null,
290
+ released: record.released,
291
+ startedAt: record.startedAt,
292
+ endedAt: record.endedAt,
293
+ durationMs: Math.max(0, (record.endedAt || Date.now()) - record.startedAt),
294
+ interactive: record.interactive,
295
+ };
296
+ }
297
+
298
+ cleanupAgent(agentId) {
299
+ for (const [terminalId, record] of this.terminals) {
300
+ if (record.agentId !== agentId) continue;
301
+ if (!record.exitStatus && !record.child.killed) record.child.kill('SIGTERM');
302
+ this.terminals.delete(terminalId);
303
+ this.finish(record, { exitCode: null, signal: 'SIGTERM' });
304
+ }
305
+ }
306
+ }
307
+
308
+ module.exports = {
309
+ AcpClientFileSystem,
310
+ AcpClientTerminalManager,
311
+ resolveWorkspacePath,
312
+ };
@@ -0,0 +1,137 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { resolveWorkspacePath } = require('./client-services');
4
+
5
+ const fsp = fs.promises;
6
+
7
+ class AcpPatchDecisionError extends Error {
8
+ constructor(message, statusCode = 409) {
9
+ super(message);
10
+ this.name = 'AcpPatchDecisionError';
11
+ this.statusCode = statusCode;
12
+ }
13
+ }
14
+
15
+ function inside(root, target) {
16
+ const relative = path.relative(root, target);
17
+ return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative));
18
+ }
19
+
20
+ function logicalPatchPath(root, requestedPath) {
21
+ const workspace = path.resolve(root);
22
+ let realWorkspace = workspace;
23
+ try {
24
+ realWorkspace = fs.realpathSync.native(workspace);
25
+ } catch {
26
+ // The caller will report the missing workspace through the normal file operation.
27
+ }
28
+ const value = String(requestedPath || '').trim();
29
+ if (!value || value.includes('\0')) throw new AcpPatchDecisionError('ACP patch path is invalid', 400);
30
+ const target = path.resolve(path.isAbsolute(value) ? value : path.join(workspace, value));
31
+ if (!inside(workspace, target) && !inside(realWorkspace, target)) {
32
+ throw new AcpPatchDecisionError('ACP patch is outside the Agent workspace', 403);
33
+ }
34
+ return target;
35
+ }
36
+
37
+ function relativeWorkspacePath(root, target) {
38
+ const workspace = path.resolve(root);
39
+ let realWorkspace = workspace;
40
+ try {
41
+ realWorkspace = fs.realpathSync.native(workspace);
42
+ } catch {
43
+ // Fall through to the logical root.
44
+ }
45
+ const base = inside(workspace, target) ? workspace : realWorkspace;
46
+ return path.relative(base, target);
47
+ }
48
+
49
+ function matchingDiffBlocks(entry, root, requestedPath) {
50
+ const requested = logicalPatchPath(root, requestedPath);
51
+ return (Array.isArray(entry?.content) ? entry.content : []).filter(block => {
52
+ if (block?.type !== 'diff' || typeof block.path !== 'string') return false;
53
+ try {
54
+ return logicalPatchPath(root, block.path) === requested;
55
+ } catch {
56
+ return false;
57
+ }
58
+ });
59
+ }
60
+
61
+ function patchBlock(entry, root, requestedPath) {
62
+ const matches = matchingDiffBlocks(entry, root, requestedPath);
63
+ if (matches.length === 0) throw new AcpPatchDecisionError('ACP patch file was not found', 404);
64
+ if (matches.length > 1) throw new AcpPatchDecisionError('ACP patch file has multiple changes; open Review to resolve them', 409);
65
+ return matches[0];
66
+ }
67
+
68
+ function patchKind(block) {
69
+ return String(block?._meta?.kind || '').trim().toLowerCase();
70
+ }
71
+
72
+ async function existingTarget(root, requestedPath) {
73
+ const logical = logicalPatchPath(root, requestedPath);
74
+ let stat;
75
+ try {
76
+ stat = await fsp.lstat(logical);
77
+ } catch (error) {
78
+ if (error?.code === 'ENOENT') return { exists: false, logical, target: null, stat: null };
79
+ throw error;
80
+ }
81
+ if (stat.isSymbolicLink()) throw new AcpPatchDecisionError('ACP patch decision will not modify a symbolic link', 409);
82
+ if (!stat.isFile()) throw new AcpPatchDecisionError('ACP patch target is not a regular file', 409);
83
+ const target = await resolveWorkspacePath({ cwd: root }, logical);
84
+ return { exists: true, logical, target, stat };
85
+ }
86
+
87
+ async function missingTarget(root, requestedPath) {
88
+ const logical = logicalPatchPath(root, requestedPath);
89
+ const target = await resolveWorkspacePath({ cwd: root }, logical, { allowMissing: true });
90
+ return { logical, target };
91
+ }
92
+
93
+ async function atomicWrite(target, content, mode = 0o666) {
94
+ const temporary = path.join(path.dirname(target), `.${path.basename(target)}.farming-acp-revert-${process.pid}-${Date.now()}.tmp`);
95
+ try {
96
+ await fsp.writeFile(temporary, content, { mode });
97
+ await fsp.rename(temporary, target);
98
+ } catch (error) {
99
+ await fsp.rm(temporary, { force: true }).catch(() => {});
100
+ throw error;
101
+ }
102
+ }
103
+
104
+ async function rejectPatch({ entry, root, requestedPath }) {
105
+ const block = patchBlock(entry, root, requestedPath);
106
+ const oldText = block.oldText == null ? '' : String(block.oldText);
107
+ const newText = block.newText == null ? '' : String(block.newText);
108
+ const kind = patchKind(block);
109
+ const added = block.oldText == null || ['add', 'added', 'create', 'created'].includes(kind);
110
+ const deleted = ['delete', 'deleted', 'remove', 'removed'].includes(kind);
111
+ const current = await existingTarget(root, requestedPath);
112
+
113
+ if (deleted) {
114
+ if (current.exists) throw new AcpPatchDecisionError('File changed after this ACP patch; it was not reverted', 409);
115
+ const target = await missingTarget(root, requestedPath);
116
+ await atomicWrite(target.target, oldText);
117
+ return { action: 'reverted', path: relativeWorkspacePath(root, target.logical) };
118
+ }
119
+
120
+ if (!current.exists) throw new AcpPatchDecisionError('File changed after this ACP patch; it was not reverted', 409);
121
+ const currentText = await fsp.readFile(current.target, 'utf8');
122
+ if (currentText !== newText) throw new AcpPatchDecisionError('File changed after this ACP patch; it was not reverted', 409);
123
+
124
+ if (added) {
125
+ await fsp.rm(current.target);
126
+ } else {
127
+ await atomicWrite(current.target, oldText, current.stat.mode);
128
+ }
129
+ return { action: 'reverted', path: relativeWorkspacePath(root, current.logical) };
130
+ }
131
+
132
+ module.exports = {
133
+ AcpPatchDecisionError,
134
+ logicalPatchPath,
135
+ patchBlock,
136
+ rejectPatch,
137
+ };
@@ -0,0 +1,108 @@
1
+ const { domainToUnicode } = require('url');
2
+
3
+ const BIDI_NAMES = new Map([
4
+ [0x061c, 'arabic letter mark'],
5
+ [0x200e, 'left-to-right mark'],
6
+ [0x200f, 'right-to-left mark'],
7
+ [0x202a, 'left-to-right embedding'],
8
+ [0x202b, 'right-to-left embedding'],
9
+ [0x202c, 'pop directional formatting'],
10
+ [0x202d, 'left-to-right override'],
11
+ [0x202e, 'right-to-left override'],
12
+ [0x2066, 'left-to-right isolate'],
13
+ [0x2067, 'right-to-left isolate'],
14
+ [0x2068, 'first strong isolate'],
15
+ [0x2069, 'pop directional isolate'],
16
+ ]);
17
+
18
+ const INVISIBLE_NAMES = new Map([
19
+ [0x00a0, 'no-break space'],
20
+ [0x00ad, 'soft hyphen'],
21
+ [0x180e, 'mongolian vowel separator'],
22
+ [0x200b, 'zero-width space'],
23
+ [0x200c, 'zero-width non-joiner'],
24
+ [0x200d, 'zero-width joiner'],
25
+ [0x2060, 'word joiner'],
26
+ [0x3000, 'ideographic space'],
27
+ [0xfeff, 'zero-width no-break space'],
28
+ ]);
29
+
30
+ function codePointLabel(character) {
31
+ return `U+${character.codePointAt(0).toString(16).toUpperCase().padStart(4, '0')}`;
32
+ }
33
+
34
+ function scriptName(character) {
35
+ const scripts = [
36
+ ['Cyrillic', /\p{Script=Cyrillic}/u],
37
+ ['Greek', /\p{Script=Greek}/u],
38
+ ['Arabic', /\p{Script=Arabic}/u],
39
+ ['Hebrew', /\p{Script=Hebrew}/u],
40
+ ['Han', /\p{Script=Han}/u],
41
+ ['Hiragana', /\p{Script=Hiragana}/u],
42
+ ['Katakana', /\p{Script=Katakana}/u],
43
+ ['Latin', /\p{Script=Latin}/u],
44
+ ];
45
+ return scripts.find(([, matcher]) => matcher.test(character))?.[0] || 'Unicode';
46
+ }
47
+
48
+ function classifyCharacter(character) {
49
+ const point = character.codePointAt(0);
50
+ if (BIDI_NAMES.has(point)) {
51
+ return { character: '', codePoint: codePointLabel(character), kind: 'bidi-control', description: BIDI_NAMES.get(point) };
52
+ }
53
+ if (
54
+ INVISIBLE_NAMES.has(point)
55
+ || (point >= 0x2061 && point <= 0x2064)
56
+ || (point >= 0x2000 && point <= 0x200a)
57
+ || [0x1680, 0x202f, 0x205f].includes(point)
58
+ || /\p{Control}|\p{Format}/u.test(character)
59
+ ) {
60
+ return {
61
+ character: '',
62
+ codePoint: codePointLabel(character),
63
+ kind: 'invisible',
64
+ description: INVISIBLE_NAMES.get(point) || 'invisible or formatting character',
65
+ };
66
+ }
67
+ return {
68
+ character,
69
+ codePoint: codePointLabel(character),
70
+ kind: 'confusable',
71
+ description: `${scriptName(character)} character`,
72
+ };
73
+ }
74
+
75
+ function scanUnicode(value) {
76
+ const seen = new Set();
77
+ const findings = [];
78
+ for (const character of String(value || '')) {
79
+ if (character.codePointAt(0) <= 0x7f || seen.has(character)) continue;
80
+ seen.add(character);
81
+ findings.push(classifyCharacter(character));
82
+ }
83
+ return findings;
84
+ }
85
+
86
+ function permissionSecurityWarnings(request) {
87
+ const meta = { ...(request?._meta || {}), ...(request?.toolCall?._meta || {}) };
88
+ const sandbox = meta.sandbox_authorization;
89
+ if (!sandbox || typeof sandbox !== 'object' || Array.isArray(sandbox)) return [];
90
+ const warnings = [];
91
+ const add = (targetType, value, displayValue = value) => {
92
+ const characters = scanUnicode(displayValue);
93
+ if (characters.length > 0) warnings.push({ targetType, value, displayValue, characters });
94
+ };
95
+ for (const host of Array.isArray(sandbox.network_hosts) ? sandbox.network_hosts : []) {
96
+ const value = String(host || '');
97
+ add('host', value, domainToUnicode(value) || value);
98
+ }
99
+ for (const targetPath of Array.isArray(sandbox.write_paths) ? sandbox.write_paths : []) {
100
+ add('path', String(targetPath || ''));
101
+ }
102
+ return warnings;
103
+ }
104
+
105
+ module.exports = {
106
+ permissionSecurityWarnings,
107
+ scanUnicode,
108
+ };