farming-code 2.2.29 → 2.2.32

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 (385) hide show
  1. package/README.md +25 -66
  2. package/README.zh_cn.md +15 -66
  3. package/THIRD_PARTY_NOTICES.md +7 -0
  4. package/backend/acp/{client-services.js → client-services.cjs} +132 -134
  5. package/backend/acp/packaged-claude-acp.cjs +37 -0
  6. package/backend/acp/packaged-codex-acp.cjs +37 -0
  7. package/backend/acp/patch-decisions.cjs +182 -0
  8. package/backend/acp/permission-security.cjs +131 -0
  9. package/backend/{acp-checkpoint-store.js → acp-checkpoint-store.cjs} +90 -59
  10. package/backend/{acp-runtime.js → acp-runtime.cjs} +1219 -1125
  11. package/backend/acp-session-state.cjs +622 -0
  12. package/backend/acp-transcript.cjs +525 -0
  13. package/backend/agent-env.cjs +257 -0
  14. package/backend/agent-extension-discovery.cjs +452 -0
  15. package/backend/agent-extension-inventory.cjs +116 -0
  16. package/backend/agent-json-stream.cjs +283 -0
  17. package/backend/agent-lifecycle-journal.cjs +185 -0
  18. package/backend/{agent-manager.js → agent-manager.cjs} +3116 -4275
  19. package/backend/agent-order-transaction.cjs +85 -0
  20. package/backend/agent-order.cjs +159 -0
  21. package/backend/agent-provider-session.cjs +98 -0
  22. package/backend/agent-runtime-binding.cjs +179 -0
  23. package/backend/agent-session-history.cjs +1022 -0
  24. package/backend/agent-session-inventory.cjs +291 -0
  25. package/backend/async-cache.cjs +104 -0
  26. package/backend/atomic-json-store.cjs +67 -0
  27. package/backend/auth.cjs +261 -0
  28. package/backend/authoritative-inventory-cache.cjs +383 -0
  29. package/backend/business-health.cjs +68 -0
  30. package/backend/chat-runtime.cjs +50 -0
  31. package/backend/claude-settings.cjs +132 -0
  32. package/backend/cli-agents.cjs +435 -0
  33. package/backend/codex-context-window.cjs +196 -0
  34. package/backend/codex-models.cjs +228 -0
  35. package/backend/codex-session-archive.cjs +82 -0
  36. package/backend/codex-session-history.cjs +590 -0
  37. package/backend/{codex-terminal-profile.js → codex-terminal-profile.cjs} +149 -155
  38. package/backend/codex-transcript-sanitizer.cjs +130 -0
  39. package/backend/codex-transcript.cjs +2107 -0
  40. package/backend/command-runner-child.cjs +105 -0
  41. package/backend/config-manager.cjs +1263 -0
  42. package/backend/control-api.cjs +439 -0
  43. package/backend/data/LICENSE.cua +21 -0
  44. package/backend/executable-discovery.cjs +204 -0
  45. package/backend/farming-agent-bootstrap.cjs +81 -0
  46. package/backend/farming-agent-bootstrap.zh_cn.md +6 -2
  47. package/backend/{farming-app-cli.js → farming-app-cli.cjs} +441 -493
  48. package/backend/farming-cli.cjs +414 -0
  49. package/backend/farming-net-pass.cjs +319 -0
  50. package/backend/farming-net-registry.cjs +123 -0
  51. package/backend/farming-net-server.cjs +309 -0
  52. package/backend/farming-session-store.cjs +651 -0
  53. package/backend/git-worktree-info.cjs +181 -0
  54. package/backend/haiku-token.cjs +828 -0
  55. package/backend/index-html.cjs +96 -0
  56. package/backend/input-parts.cjs +68 -0
  57. package/backend/input-routing.cjs +40 -0
  58. package/backend/{local-session-engine.js → local-session-engine.cjs} +276 -282
  59. package/backend/main-agent-skills.cjs +309 -0
  60. package/backend/main-page-session.cjs +132 -0
  61. package/backend/native-pty-controller-generation.cjs +139 -0
  62. package/backend/{native-pty-host-client.js → native-pty-host-client.cjs} +338 -346
  63. package/backend/native-pty-host-identity.cjs +125 -0
  64. package/backend/native-pty-host-path.cjs +68 -0
  65. package/backend/{native-pty-host.js → native-pty-host.cjs} +480 -569
  66. package/backend/native-session-engine.cjs +296 -0
  67. package/backend/network.cjs +57 -0
  68. package/backend/npm-update-helper.cjs +399 -0
  69. package/backend/packaged-node-pty.cjs +120 -0
  70. package/backend/preview-session-manager.cjs +89 -0
  71. package/backend/provider-adapters.cjs +492 -0
  72. package/backend/provider-home-configuration.cjs +211 -0
  73. package/backend/provider-session-id.cjs +79 -0
  74. package/backend/provider-session-service.cjs +333 -0
  75. package/backend/qr-share-tickets.cjs +119 -0
  76. package/backend/resource-broadcast-protocol.cjs +50 -0
  77. package/backend/review-diff-router.cjs +202 -0
  78. package/backend/review-diff-service.cjs +1267 -0
  79. package/backend/review-session-router.cjs +93 -0
  80. package/backend/review-session-service.cjs +470 -0
  81. package/backend/review-session-store.cjs +161 -0
  82. package/backend/review-state-router.cjs +132 -0
  83. package/backend/review-state-store.cjs +299 -0
  84. package/backend/run-history-store.cjs +97 -0
  85. package/backend/runtime-dependency-manager.cjs +893 -0
  86. package/backend/runtime-executable-invocation.cjs +37 -0
  87. package/backend/runtime-observation.cjs +96 -0
  88. package/backend/server-process-identity.cjs +70 -0
  89. package/backend/server.cjs +3356 -0
  90. package/backend/session-engine-bridge.cjs +144 -0
  91. package/backend/session-engine-router.cjs +105 -0
  92. package/backend/session-engine.cjs +64 -0
  93. package/backend/session-stream-protocol.cjs +181 -0
  94. package/backend/shell-busy-integration.cjs +442 -0
  95. package/backend/slash-command-discovery.cjs +423 -0
  96. package/backend/storage-layout.cjs +263 -0
  97. package/backend/system-monitor.cjs +96 -0
  98. package/backend/terminal-attach-checkpoint.cjs +73 -0
  99. package/backend/terminal-exit-quiescence.cjs +57 -0
  100. package/backend/{terminal-reducer-flow-control.js → terminal-reducer-flow-control.cjs} +45 -22
  101. package/backend/terminal-runtime-cleanup.cjs +99 -0
  102. package/backend/{terminal-screen-state.js → terminal-screen-state.cjs} +100 -108
  103. package/backend/{terminal-screen-worker-pool.js → terminal-screen-worker-pool.cjs} +89 -79
  104. package/backend/{terminal-screen-worker-thread.js → terminal-screen-worker-thread.cjs} +64 -65
  105. package/backend/terminal-screen-worker.cjs +352 -0
  106. package/backend/terminal-state-serialization.cjs +147 -0
  107. package/backend/{terminal-status.js → terminal-status.cjs} +137 -187
  108. package/backend/theme-manager.cjs +185 -0
  109. package/backend/update-service.cjs +675 -0
  110. package/backend/usage-forecast.cjs +95 -0
  111. package/backend/{usage-history-client.js → usage-history-client.cjs} +144 -94
  112. package/backend/usage-history-smoke.cjs +85 -0
  113. package/backend/usage-history-worker.cjs +60 -0
  114. package/backend/{usage-monitor.js → usage-monitor.cjs} +363 -390
  115. package/backend/workspace-directory.cjs +239 -0
  116. package/backend/workspace-discovery.cjs +271 -0
  117. package/backend/{workspace-file-router.js → workspace-file-router.cjs} +213 -282
  118. package/backend/{workspace-file-service.js → workspace-file-service.cjs} +1139 -1318
  119. package/backend/workspace-root-registry.cjs +192 -0
  120. package/bin/farming +1 -1
  121. package/config/farming.deploy.env.example +1 -1
  122. package/config/farming.install.env.example +1 -1
  123. package/dist/acp/codex-acp-1.1.4.mjs +405 -8
  124. package/dist/assets/App-BCkdpWB6.css +1 -0
  125. package/dist/assets/App-CRjKpaGp.js +697 -0
  126. package/dist/assets/CodeSelect-Ci8sKZPU.js +1 -0
  127. package/dist/assets/CodeSelect-T2eNzrOc.css +1 -0
  128. package/dist/assets/{FileEditorMarkdownPreview-Cs9cLv8a.js → FileEditorMarkdownPreview-V06QHlAg.js} +55 -55
  129. package/dist/assets/FileEditorPane-BX-Wjg9U.js +2 -0
  130. package/dist/assets/IconGlyphs-YhV7tqd4.js +1 -0
  131. package/dist/assets/ProjectFilesSection-BDT2_r0o.js +12 -0
  132. package/dist/assets/ReviewPage-BqAs5sG1.js +3 -0
  133. package/dist/assets/code-dark-B7eM_9G9.css +1 -0
  134. package/dist/assets/{cssMode-Bdg5RpcJ.js → cssMode-ADdAlxTO.js} +1 -1
  135. package/dist/assets/{editor.api2-D74ufkbr.js → editor.api2-BFLAr0YF.js} +162 -162
  136. package/dist/assets/file-icons-BpeqWkIB.js +1 -0
  137. package/dist/assets/{freemarker2-DfMDJfnE.js → freemarker2-C90q5jrp.js} +1 -1
  138. package/dist/assets/{handlebars-BEdPtzMT.js → handlebars-BwUQcEDq.js} +1 -1
  139. package/dist/assets/{html-B1fPb1QD.js → html-1s3uPKfh.js} +1 -1
  140. package/dist/assets/{htmlMode-CY2ZjHxH.js → htmlMode-xtKD99de.js} +1 -1
  141. package/dist/assets/{index-CQNaZc3l.js → index-C8MchCem.js} +3 -3
  142. package/dist/assets/{javascript-BV2OsWA0.js → javascript-Ph7ijyny.js} +1 -1
  143. package/dist/assets/{jsonMode-zd07aeuX.js → jsonMode-D-jGAnFH.js} +1 -1
  144. package/dist/assets/linkComputer-CbGyI_qx.js +1 -0
  145. package/dist/assets/{liquid-BParI24X.js → liquid-0IamE_cI.js} +1 -1
  146. package/dist/assets/{lspLanguageFeatures-BzredkoV.js → lspLanguageFeatures-BxnQunWF.js} +1 -1
  147. package/dist/assets/main-CLKXa6hf.css +1 -0
  148. package/dist/assets/{mdx-vGzUJN98.js → mdx-DdNmfivn.js} +1 -1
  149. package/dist/assets/{monaco.contribution-BmaeBQEc.js → monaco.contribution-B43jsUs1.js} +2 -2
  150. package/dist/assets/{python-CUwdLgsI.js → python-IAt4X5TS.js} +1 -1
  151. package/dist/assets/{razor-BScebUxU.js → razor-DRkFYW0S.js} +1 -1
  152. package/dist/assets/review-C8-oPKXk.css +1 -0
  153. package/dist/assets/{tsMode-DzUAibXK.js → tsMode-_d_4U2gf.js} +1 -1
  154. package/dist/assets/{typescript-D9EOeM7N.js → typescript-C7zcMq9l.js} +1 -1
  155. package/dist/assets/{workers-DAiomYZM.js → workers-D0nOyJzf.js} +1 -1
  156. package/dist/assets/workspace-editor-model-DND_Y-Bj.js +1 -0
  157. package/dist/assets/workspace-editor-monaco-BPWhgcIB.js +4 -0
  158. package/dist/assets/workspace-editor-monaco-N641qPjX.js +1 -0
  159. package/dist/assets/workspace-view-state-k1bTlJ_Z.js +13 -0
  160. package/dist/assets/{xml-wWl1dhkQ.js → xml-BR-HvxT8.js} +1 -1
  161. package/dist/assets/{yaml-Dc2WDaOZ.js → yaml-YtFQwh4q.js} +1 -1
  162. package/dist/index.html +2 -1
  163. package/extensions/browser/backend/agent-browser-runtime.cjs +1040 -0
  164. package/extensions/browser/backend/agent-capability.cjs +85 -0
  165. package/extensions/browser/backend/browser-mcp-server.cjs +655 -0
  166. package/extensions/browser/backend/browser-resource-manager.cjs +1486 -0
  167. package/extensions/browser/backend/browser-resource-store.cjs +228 -0
  168. package/extensions/browser/backend/browser-router.cjs +203 -0
  169. package/extensions/browser/backend/executable-discovery.cjs +248 -0
  170. package/extensions/browser/backend/farming-browser-client.cjs +116 -0
  171. package/extensions/browser/backend/index.cjs +32 -0
  172. package/extensions/browser/backend/managed-chromium-installer.cjs +833 -0
  173. package/extensions/browser/bin/farming-browser +16 -7
  174. package/extensions/computer/backend/agent-capability.cjs +72 -0
  175. package/extensions/computer/backend/computer-constants.cjs +59 -0
  176. package/extensions/computer/backend/computer-mcp-server.cjs +182 -0
  177. package/extensions/computer/backend/computer-resource-manager.cjs +1219 -0
  178. package/extensions/computer/backend/computer-resource-store.cjs +190 -0
  179. package/extensions/computer/backend/computer-router.cjs +257 -0
  180. package/extensions/computer/backend/cua-tools.json +3067 -0
  181. package/extensions/computer/backend/farming-computer-client.cjs +84 -0
  182. package/extensions/computer/backend/index.cjs +35 -0
  183. package/extensions/computer/backend/isolated-browser-provider.cjs +157 -0
  184. package/extensions/computer/bin/farming-computer +131 -0
  185. package/frontend/farming-net/app.js +255 -262
  186. package/frontend/ghostty-loader.js +24 -20
  187. package/frontend/reading-anchor.js +210 -193
  188. package/frontend/runtime-paths.js +24 -26
  189. package/frontend/session-bridge.js +90 -111
  190. package/frontend/session-modal-bridge.js +184 -302
  191. package/frontend/skin-bridge.js +20 -23
  192. package/frontend/skins/crt/app.js +7686 -7901
  193. package/frontend/skins/crt/effects.js +7 -6
  194. package/frontend/skins/crt/index.html +6 -6
  195. package/frontend/skins/crt/styles/markdown.css +4 -4
  196. package/frontend/terminal-bridge.js +174 -181
  197. package/frontend/terminal-replay.js +320 -345
  198. package/frontend/theme-loader.js +55 -71
  199. package/index.html +1 -0
  200. package/package.json +64 -37
  201. package/shared/backend-connection-status.js +38 -69
  202. package/shared/browser-protocol.js +235 -110
  203. package/shared/websocket-liveness.js +40 -0
  204. package/backend/acp/packaged-claude-acp.js +0 -13
  205. package/backend/acp/packaged-codex-acp.js +0 -13
  206. package/backend/acp/patch-decisions.js +0 -153
  207. package/backend/acp/permission-security.js +0 -108
  208. package/backend/acp-session-state.js +0 -644
  209. package/backend/acp-transcript.js +0 -512
  210. package/backend/agent-env.js +0 -250
  211. package/backend/agent-json-stream.js +0 -268
  212. package/backend/agent-lifecycle-journal.js +0 -133
  213. package/backend/agent-memory-report.js +0 -583
  214. package/backend/agent-order.js +0 -166
  215. package/backend/agent-provider-session.js +0 -76
  216. package/backend/agent-runtime-binding.js +0 -174
  217. package/backend/agent-session-history.js +0 -953
  218. package/backend/async-cache.js +0 -94
  219. package/backend/atomic-json-store.js +0 -37
  220. package/backend/auth.js +0 -251
  221. package/backend/bundle-update-helper.js +0 -113
  222. package/backend/chat-runtime.js +0 -28
  223. package/backend/claude-settings.js +0 -121
  224. package/backend/cli-agents.js +0 -486
  225. package/backend/codex-context-window.js +0 -189
  226. package/backend/codex-models.js +0 -226
  227. package/backend/codex-rollout-follower.js +0 -326
  228. package/backend/codex-session-archive.js +0 -65
  229. package/backend/codex-session-history.js +0 -647
  230. package/backend/codex-transcript-sanitizer.js +0 -115
  231. package/backend/codex-transcript.js +0 -2564
  232. package/backend/command-runner-child.js +0 -67
  233. package/backend/config-manager.js +0 -1133
  234. package/backend/control-api.js +0 -455
  235. package/backend/executable-discovery.js +0 -216
  236. package/backend/farming-agent-bootstrap.js +0 -49
  237. package/backend/farming-cli.js +0 -457
  238. package/backend/farming-net-pass.js +0 -285
  239. package/backend/farming-net-registry.js +0 -112
  240. package/backend/farming-net-server.js +0 -298
  241. package/backend/farming-session-store.js +0 -677
  242. package/backend/git-worktree-info.js +0 -181
  243. package/backend/haiku-token.js +0 -772
  244. package/backend/index-html.js +0 -62
  245. package/backend/input-parts.js +0 -54
  246. package/backend/input-routing.js +0 -24
  247. package/backend/json-cli-runtime.js +0 -275
  248. package/backend/main-agent-skills.js +0 -305
  249. package/backend/main-page-session.js +0 -122
  250. package/backend/native-pty-controller-generation.js +0 -106
  251. package/backend/native-pty-host-identity.js +0 -86
  252. package/backend/native-pty-host-path.js +0 -42
  253. package/backend/native-session-engine.js +0 -268
  254. package/backend/network.js +0 -23
  255. package/backend/npm-update-helper.js +0 -374
  256. package/backend/packaged-node-pty.js +0 -99
  257. package/backend/preview-session-manager.js +0 -68
  258. package/backend/provider-adapters.js +0 -399
  259. package/backend/provider-session-id.js +0 -47
  260. package/backend/provider-session-service.js +0 -345
  261. package/backend/qr-share-tickets.js +0 -100
  262. package/backend/review-diff-router.js +0 -180
  263. package/backend/review-diff-service.js +0 -1270
  264. package/backend/review-session-router.js +0 -74
  265. package/backend/review-session-service.js +0 -446
  266. package/backend/review-session-store.js +0 -151
  267. package/backend/review-state-router.js +0 -116
  268. package/backend/review-state-store.js +0 -286
  269. package/backend/run-history-store.js +0 -67
  270. package/backend/runtime-dependency-manager.js +0 -759
  271. package/backend/runtime-executable-invocation.js +0 -20
  272. package/backend/runtime-observation.js +0 -81
  273. package/backend/server-process-identity.js +0 -47
  274. package/backend/server.js +0 -3267
  275. package/backend/session-engine-bridge.js +0 -129
  276. package/backend/session-engine-router.js +0 -66
  277. package/backend/session-engine.js +0 -39
  278. package/backend/session-stream-protocol.js +0 -185
  279. package/backend/shell-busy-integration.js +0 -472
  280. package/backend/slash-command-discovery.js +0 -433
  281. package/backend/storage-layout.js +0 -190
  282. package/backend/system-monitor.js +0 -77
  283. package/backend/terminal-attach-checkpoint.js +0 -74
  284. package/backend/terminal-exit-quiescence.js +0 -39
  285. package/backend/terminal-runtime-cleanup.js +0 -80
  286. package/backend/terminal-screen-worker.js +0 -337
  287. package/backend/terminal-state-serialization.js +0 -127
  288. package/backend/theme-manager.js +0 -163
  289. package/backend/update-service.js +0 -1545
  290. package/backend/usage-forecast.js +0 -86
  291. package/backend/usage-history-scanner.ts +0 -2718
  292. package/backend/usage-history-smoke.js +0 -64
  293. package/backend/usage-history-worker.js +0 -34
  294. package/backend/workspace-directory.js +0 -232
  295. package/backend/workspace-discovery.js +0 -311
  296. package/backend/workspace-root-registry.js +0 -166
  297. package/dist/assets/App-BKNUILuL.css +0 -1
  298. package/dist/assets/App-Ex2oVVXO.js +0 -693
  299. package/dist/assets/FileEditorPane-CNtuGjQ3.js +0 -2
  300. package/dist/assets/IconGlyphs-BClgag6E.js +0 -1
  301. package/dist/assets/ProjectFilesSection-Cf2BEcAN.js +0 -12
  302. package/dist/assets/ReviewPage-BRuxFaH5.js +0 -3
  303. package/dist/assets/code-dark-BEZTQwYZ.css +0 -1
  304. package/dist/assets/file-icons-BOlcJ0ZF.js +0 -1
  305. package/dist/assets/main-DK9Sy7-c.css +0 -1
  306. package/dist/assets/review-BcnwQtJv.css +0 -1
  307. package/dist/assets/workspace-editor-model-CSGCl21x.js +0 -1
  308. package/dist/assets/workspace-editor-monaco-CJNwbpCy.js +0 -4
  309. package/dist/assets/workspace-editor-monaco-CO9w8YV0.js +0 -1
  310. package/dist/assets/workspace-view-state-BjKPYp0E.js +0 -7
  311. package/extensions/browser/backend/agent-browser-runtime.js +0 -1041
  312. package/extensions/browser/backend/agent-capability.js +0 -55
  313. package/extensions/browser/backend/browser-mcp-server.js +0 -621
  314. package/extensions/browser/backend/browser-resource-manager.js +0 -1309
  315. package/extensions/browser/backend/browser-resource-store.js +0 -190
  316. package/extensions/browser/backend/browser-router.js +0 -133
  317. package/extensions/browser/backend/executable-discovery.js +0 -224
  318. package/extensions/browser/backend/farming-browser-client.js +0 -83
  319. package/extensions/browser/backend/index.js +0 -7
  320. package/extensions/browser/frontend/BrowserSidebarPortals.tsx +0 -360
  321. package/extensions/browser/frontend/BrowserViewer.tsx +0 -500
  322. package/extensions/browser/frontend/browser-resource-state.ts +0 -60
  323. package/extensions/browser/frontend/browser.css +0 -567
  324. package/extensions/browser/frontend/types.ts +0 -31
  325. package/extensions/browser/frontend/useBrowserResources.ts +0 -158
  326. package/frontend/vendor/ghostty-web/index.d.ts +0 -1842
  327. package/shared/backend-connection-status.d.ts +0 -37
  328. package/shared/browser-protocol.d.ts +0 -5
  329. /package/dist/assets/{api-w2x5QfxB.js → api-ByCV9MEr.js} +0 -0
  330. /package/dist/assets/{core-vPkV8P_m.js → core-Czwdx12k.js} +0 -0
  331. /package/dist/assets/{fsharp-DNZNZyEE.js → fsharp-BjPpkoJe.js} +0 -0
  332. /package/dist/assets/{go-_kPJjNc_.js → go-BkIDmSUP.js} +0 -0
  333. /package/dist/assets/{graphql-4HCNVt5g.js → graphql-CCJTpqi1.js} +0 -0
  334. /package/dist/assets/{hcl-C87ymY0o.js → hcl-s4z8lUFg.js} +0 -0
  335. /package/dist/assets/{ini-BYrrGNTc.js → ini-CyUW1I7Z.js} +0 -0
  336. /package/dist/assets/{java-B211rJbk.js → java-CFCcGRiM.js} +0 -0
  337. /package/dist/assets/{julia-DVPsRtBm.js → julia-DQyH_EYb.js} +0 -0
  338. /package/dist/assets/{kotlin-BYyNerjp.js → kotlin-B8hA5O51.js} +0 -0
  339. /package/dist/assets/{less-EC9UblGE.js → less-DaVdaas0.js} +0 -0
  340. /package/dist/assets/{lexon-B1yuUdqW.js → lexon-DLBhPd3y.js} +0 -0
  341. /package/dist/assets/{lua-Bo6GFzxT.js → lua-gB1c_cif.js} +0 -0
  342. /package/dist/assets/{m3-C-Y9cBVI.js → m3-C2T3z3gB.js} +0 -0
  343. /package/dist/assets/{markdown-BHu-wLbe.js → markdown-CKq-Euj1.js} +0 -0
  344. /package/dist/assets/{mips-Dkds26rX.js → mips-Bcs5qIDX.js} +0 -0
  345. /package/dist/assets/{msdax-PU4g-8_g.js → msdax-CBP48FHF.js} +0 -0
  346. /package/dist/assets/{mysql-fPpuGpS7.js → mysql-c7tiPcFj.js} +0 -0
  347. /package/dist/assets/{objective-c-Wy1e5JUf.js → objective-c-D4BZkeEV.js} +0 -0
  348. /package/dist/assets/{pascal-BIXwvrqU.js → pascal-CJDZg0MN.js} +0 -0
  349. /package/dist/assets/{pascaligo-DwR0AtL_.js → pascaligo-Bygi8Ynl.js} +0 -0
  350. /package/dist/assets/{perl-CGHAl8my.js → perl-aS8bkf7E.js} +0 -0
  351. /package/dist/assets/{pgsql-B91M73E2.js → pgsql-CzNAYFYl.js} +0 -0
  352. /package/dist/assets/{php-C70ttrCx.js → php-DOtoEFTT.js} +0 -0
  353. /package/dist/assets/{pla-BNrXaRh0.js → pla-DugRnao1.js} +0 -0
  354. /package/dist/assets/{postiats-Dv2IAZR9.js → postiats-DsXwusKh.js} +0 -0
  355. /package/dist/assets/{powerquery-CkY5Wq7J.js → powerquery-DL3o72oD.js} +0 -0
  356. /package/dist/assets/{powershell-uGIYLU3C.js → powershell-C1qHekys.js} +0 -0
  357. /package/dist/assets/{protobuf-CavfmJu-.js → protobuf-DHgsc-cH.js} +0 -0
  358. /package/dist/assets/{pug-Drqnyitx.js → pug-FZXlE_Iu.js} +0 -0
  359. /package/dist/assets/{qrcode-7uGsTEmi.js → qrcode-DJDTdjL7.js} +0 -0
  360. /package/dist/assets/{qsharp-C7yF-Dti.js → qsharp-bLyhI3DT.js} +0 -0
  361. /package/dist/assets/{r-HXLGP0_-.js → r-DjFGXbAa.js} +0 -0
  362. /package/dist/assets/{redis-C4y6mf2p.js → redis-DSoZ_V6u.js} +0 -0
  363. /package/dist/assets/{redshift-DdQrFPrv.js → redshift-CzkdCsrg.js} +0 -0
  364. /package/dist/assets/{restructuredtext-CBrf2PNj.js → restructuredtext-B_XPrGCQ.js} +0 -0
  365. /package/dist/assets/{ruby-CVtMoX2B.js → ruby-Cry2RneJ.js} +0 -0
  366. /package/dist/assets/{rust-Ckq4sbMP.js → rust-CWzdbFq1.js} +0 -0
  367. /package/dist/assets/{sb-er66OpE3.js → sb-DmofU59h.js} +0 -0
  368. /package/dist/assets/{scala-BdWZz-hH.js → scala-BUC2l-vN.js} +0 -0
  369. /package/dist/assets/{scheme-kTV_s2kP.js → scheme-CNIB_72f.js} +0 -0
  370. /package/dist/assets/{scss-Bymy2VJQ.js → scss-DcL4-NbX.js} +0 -0
  371. /package/dist/assets/{shell-bwEP1LQ1.js → shell-CgAGvSSA.js} +0 -0
  372. /package/dist/assets/{solidity-DCddeBgL.js → solidity-DSkt6O_P.js} +0 -0
  373. /package/dist/assets/{sophia-BMN3AQig.js → sophia--5ytcjDN.js} +0 -0
  374. /package/dist/assets/{sparql-CSXOLjzi.js → sparql-C1Srr7cD.js} +0 -0
  375. /package/dist/assets/{sql-COg8ewmK.js → sql-2k_O5fj7.js} +0 -0
  376. /package/dist/assets/{st-CIaZtBS_.js → st-DCCCPqfz.js} +0 -0
  377. /package/dist/assets/{swift-DXiOhUHu.js → swift-Dd8mAfOt.js} +0 -0
  378. /package/dist/assets/{systemverilog-BTDE6Dr2.js → systemverilog-B0-aZYXu.js} +0 -0
  379. /package/dist/assets/{tcl-B0zy9NvV.js → tcl-CZAZwPVX.js} +0 -0
  380. /package/dist/assets/{twig-D594l4Z1.js → twig-D-Ag0tdS.js} +0 -0
  381. /package/dist/assets/{typespec-XKVjaPqo.js → typespec-B7kTFp0Z.js} +0 -0
  382. /package/dist/assets/{useWorkspaceMenuKeyboard-Bpy_s69Z.js → useWorkspaceMenuKeyboard-uYZpDxhU.js} +0 -0
  383. /package/dist/assets/{vb-B2wYoKRV.js → vb-20w1JPum.js} +0 -0
  384. /package/dist/assets/{wgsl-D0Yf2LbK.js → wgsl-CLJfqFt0.js} +0 -0
  385. /package/dist/assets/{workspace-working-copy-C3FSR3N6.js → workspace-working-copy-Cfz07cOd.js} +0 -0
@@ -1,1133 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const os = require('os');
4
- const { atomicWriteJson } = require('./atomic-json-store');
5
- const { ensureMainAgentSkillFiles } = require('./main-agent-skills');
6
- const { ensureFarmingAgentBootstrapFile } = require('./farming-agent-bootstrap');
7
- const { normalizeClaudeModelValue } = require('./claude-settings');
8
- const { isTemporaryProviderSessionId } = require('./provider-session-id');
9
- const { FarmingSessionStore, MAX_MAIN_PAGE_SESSION_KEYS } = require('./farming-session-store');
10
- const { RunHistoryStore } = require('./run-history-store');
11
- const { isSupportedHistoryAgent } = require('./cli-agents');
12
- const storageLayout = require('./storage-layout');
13
-
14
- function splitCodexModelPreset(preset) {
15
- if (preset === 'config') {
16
- return { model: 'config', effort: 'config' };
17
- }
18
- if (typeof preset !== 'string') {
19
- return { model: 'gpt-5.5', effort: 'xhigh' };
20
- }
21
-
22
- const [model, effort] = preset.split(':');
23
- return {
24
- model: model || 'gpt-5.5',
25
- effort: effort || 'xhigh',
26
- };
27
- }
28
-
29
- function joinCodexModelPreset(model, effort) {
30
- if (model === 'config') return 'config';
31
- return effort ? `${model}:${effort}` : model;
32
- }
33
-
34
- const DEFAULT_CODEX_LAUNCH_PROFILE = {
35
- approvalMode: 'approve',
36
- model: 'gpt-5.5',
37
- reasoningEffort: 'xhigh',
38
- serviceTier: 'default',
39
- modelPreset: 'gpt-5.5:xhigh',
40
- };
41
-
42
- const DEFAULT_CLAUDE_LAUNCH_PROFILE = {
43
- permissionMode: 'default',
44
- model: 'config',
45
- effort: 'config',
46
- };
47
-
48
- const DEFAULT_AGENT_LAUNCH_PROFILES = {
49
- codex: DEFAULT_CODEX_LAUNCH_PROFILE,
50
- claude: DEFAULT_CLAUDE_LAUNCH_PROFILE,
51
- };
52
-
53
- const DEFAULT_LAUNCH_AGENT_NAMES = new Set(['codex', 'claude', 'opencode', 'qoder', 'bash', 'zsh']);
54
-
55
- const DEFAULT_AGENT_HOMES = {
56
- codex: [{ id: 'default', path: '~/.codex' }],
57
- claude: [{ id: 'default', path: '~/.claude' }],
58
- opencode: [{ id: 'default', path: '~/.opencode' }],
59
- qoder: [{ id: 'default', path: '~/.qoder' }],
60
- };
61
-
62
- const DEFAULT_UPDATE_URL = 'https://github.com/zhuwenzhuang/farming/releases/latest';
63
- const LEGACY_DEFAULT_UPDATE_URL = 'https://github.com/zhuwenzhuang/farming/releases/latest/download/manifest.json';
64
- const API_DEFAULT_UPDATE_URL = 'https://api.github.com/repos/zhuwenzhuang/farming/releases/latest';
65
- const LEGACY_DEFAULT_WORKSPACE_FILE_SEARCH_TIMEOUT_MS = 3000;
66
- const DEFAULT_SEARCH_TIMEOUT_MS = 15000;
67
- const MIN_SEARCH_TIMEOUT_MS = 3000;
68
- const MAX_SEARCH_TIMEOUT_MS = 180000;
69
- const DEFAULT_CRT_TERMINAL_FONT_SIZE = 15;
70
- const MIN_CRT_TERMINAL_FONT_SIZE = 10;
71
- const MAX_CRT_TERMINAL_FONT_SIZE = 20;
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}$/;
75
-
76
- const PERSISTED_SETTING_KEYS = new Set([
77
- 'workspace',
78
- 'lastMainWorkspace',
79
- 'workspaceHistory',
80
- 'projectWorkspaces',
81
- 'pinnedProjectWorkspaces',
82
- 'projectNames',
83
- 'projectOperations',
84
- 'instanceName',
85
- 'theme',
86
- 'appearance',
87
- 'language',
88
- 'restReminderIntervalSeconds',
89
- 'heartbeatInterval',
90
- 'dangerouslySkipAgentPermissionsByDefault',
91
- 'browserExtensionEnabled',
92
- 'browserSource',
93
- 'browserExecutablePath',
94
- 'browserExternalCdpUrl',
95
- 'crtSkinEffectsEnabled',
96
- 'crtDynamicHeatEnabled',
97
- 'crtTerminalFontSize',
98
- 'defaultLaunchAgent',
99
- 'agentLaunchProfiles',
100
- 'agentHomes',
101
- 'updateUrl',
102
- 'searchTimeoutMs',
103
- 'codexApprovalMode',
104
- 'codexModel',
105
- 'codexReasoningEffort',
106
- 'codexServiceTier',
107
- 'codexModelPreset',
108
- 'version',
109
- ]);
110
-
111
- function cloneLaunchProfile(profile) {
112
- return { ...profile };
113
- }
114
-
115
- function cloneAgentHomes(agentHomes) {
116
- const cloned = {};
117
- Object.entries(agentHomes || {}).forEach(([provider, homes]) => {
118
- cloned[provider] = Array.isArray(homes)
119
- ? homes.map(home => ({ ...home }))
120
- : [];
121
- });
122
- return cloned;
123
- }
124
-
125
- class ConfigManager {
126
- constructor(options = {}) {
127
- this.farmingDir = options.configDir || storageLayout.farmingConfigDir();
128
- this.settingsFile = storageLayout.settingsFile(this.farmingDir);
129
- this.sessionStore = new FarmingSessionStore(this.farmingDir, {
130
- normalizeMainPageSessionKeys: keys => this.normalizeMainPageSessionKeys(keys),
131
- });
132
- this.runHistoryStore = new RunHistoryStore(this.farmingDir, {
133
- normalizeTaskHistory: entries => this.normalizeTaskHistory(entries),
134
- });
135
- this.writeJson = typeof options.writeJson === 'function' ? options.writeJson : atomicWriteJson;
136
- this.settings = null;
137
- }
138
-
139
- expandWorkspacePath(workspace) {
140
- if (typeof workspace !== 'string') return '';
141
- const value = workspace.trim();
142
- if (!value) return '';
143
- if (value === '~') return os.homedir();
144
- if (value.startsWith('~/')) return path.join(os.homedir(), value.slice(2));
145
- return value;
146
- }
147
-
148
- isTemporaryWorkspace(workspace) {
149
- const resolved = path.resolve(this.expandWorkspacePath(workspace));
150
- return resolved === '/tmp'
151
- || resolved.startsWith('/tmp/')
152
- || resolved === '/private/tmp'
153
- || resolved.startsWith('/private/tmp/')
154
- || resolved === '/var/tmp'
155
- || resolved.startsWith('/var/tmp/')
156
- || resolved === '/private/var/tmp'
157
- || resolved.startsWith('/private/var/tmp/')
158
- || resolved === '/var/folders'
159
- || resolved.startsWith('/var/folders/')
160
- || resolved === '/private/var/folders'
161
- || resolved.startsWith('/private/var/folders/');
162
- }
163
-
164
- isUsableWorkspace(workspace) {
165
- const expanded = this.expandWorkspacePath(workspace);
166
- if (!expanded || this.isTemporaryWorkspace(expanded)) return false;
167
-
168
- try {
169
- return fs.statSync(expanded).isDirectory();
170
- } catch {
171
- return false;
172
- }
173
- }
174
-
175
- isInternalWorkspace(workspace) {
176
- const expanded = this.expandWorkspacePath(workspace);
177
- if (!expanded) return false;
178
-
179
- const resolvedWorkspace = path.resolve(expanded);
180
- const resolvedFarmingDir = path.resolve(this.farmingDir);
181
- return resolvedWorkspace === resolvedFarmingDir || path.basename(resolvedWorkspace) === '.farming';
182
- }
183
-
184
- normalizeMainWorkspace(workspace, fallback = this.farmingDir) {
185
- const expanded = this.expandWorkspacePath(workspace);
186
- if (this.isUsableWorkspace(expanded)) {
187
- return expanded;
188
- }
189
-
190
- const expandedFallback = this.expandWorkspacePath(fallback);
191
- if (this.isUsableWorkspace(expandedFallback)) {
192
- return expandedFallback;
193
- }
194
-
195
- return this.farmingDir;
196
- }
197
-
198
- normalizeInstanceName(value) {
199
- if (typeof value !== 'string') return '';
200
- return value
201
- .replace(/[\x00-\x1f\x7f]/g, ' ')
202
- .replace(/\s+/g, ' ')
203
- .trim()
204
- .slice(0, MAX_INSTANCE_NAME_LENGTH);
205
- }
206
-
207
- getInstanceName() {
208
- return this.settings?.instanceName || this.normalizeInstanceName(os.hostname()) || 'Farming';
209
- }
210
-
211
- normalizeWorkspaceHistory(history) {
212
- const entries = Array.isArray(history) ? history : [];
213
- const result = [];
214
- const seen = new Set();
215
-
216
- for (const entry of entries) {
217
- const expanded = this.expandWorkspacePath(entry);
218
- if (!this.isUsableWorkspace(expanded) || this.isInternalWorkspace(expanded) || seen.has(expanded)) continue;
219
- seen.add(expanded);
220
- result.push(expanded);
221
- }
222
-
223
- return result.slice(0, 5);
224
- }
225
-
226
- normalizeProjectWorkspaces(projects) {
227
- const entries = Array.isArray(projects) ? projects : [];
228
- const result = [];
229
- const seen = new Set();
230
-
231
- for (const entry of entries) {
232
- const expanded = this.expandWorkspacePath(entry);
233
- if (!expanded) continue;
234
- const resolved = path.resolve(expanded);
235
- if (this.isInternalWorkspace(resolved)) continue;
236
- let canonical = resolved;
237
- try {
238
- canonical = fs.realpathSync(resolved);
239
- } catch {
240
- // Project membership is durable. A temporarily unavailable path remains
241
- // until the user explicitly removes it.
242
- }
243
- if (this.isInternalWorkspace(canonical)) continue;
244
- if (seen.has(canonical)) continue;
245
- seen.add(canonical);
246
- result.push(canonical);
247
- }
248
-
249
- return result.slice(0, 200);
250
- }
251
-
252
- normalizeMainPageSessionKeys(keys) {
253
- const entries = Array.isArray(keys) ? keys : [];
254
- const result = [];
255
- const seen = new Set();
256
-
257
- for (const entry of entries) {
258
- if (typeof entry !== 'string') continue;
259
- const value = entry.trim();
260
- if (!/^agent-session:[a-z][a-z0-9_-]*:.+$/i.test(value)) continue;
261
- const sessionId = value.replace(/^agent-session:[^:]+:/i, '');
262
- if (sessionId.startsWith('-')) continue;
263
- if (isTemporaryProviderSessionId(sessionId)) continue;
264
- if (seen.has(value)) continue;
265
- seen.add(value);
266
- result.push(value);
267
- }
268
-
269
- return result.slice(0, MAX_MAIN_PAGE_SESSION_KEYS);
270
- }
271
-
272
- normalizeTaskHistory(history) {
273
- const entries = Array.isArray(history) ? history : [];
274
- const normalized = [];
275
- for (const entry of entries) {
276
- if (!entry || typeof entry !== 'object') continue;
277
- if (typeof entry.id !== 'string' || !entry.id) continue;
278
- if (typeof entry.agentId !== 'string' || !entry.agentId) continue;
279
- if (typeof entry.reason !== 'string' || !entry.reason) continue;
280
- if (typeof entry.archivedAt !== 'number' || !Number.isFinite(entry.archivedAt)) continue;
281
- if (!isSupportedHistoryAgent(entry.command)) continue;
282
- normalized.push({
283
- id: entry.id,
284
- agentId: entry.agentId,
285
- command: typeof entry.command === 'string' ? entry.command : '',
286
- cwd: typeof entry.cwd === 'string' ? entry.cwd : '',
287
- projectWorkspace: typeof entry.projectWorkspace === 'string' ? entry.projectWorkspace : '',
288
- title: typeof entry.title === 'string' ? entry.title : '',
289
- customTitle: typeof entry.customTitle === 'string' ? entry.customTitle.trim().slice(0, 80) : '',
290
- task: typeof entry.task === 'string' ? entry.task : '',
291
- workflowTemplate: typeof entry.workflowTemplate === 'string' ? entry.workflowTemplate : '',
292
- source: typeof entry.source === 'string' ? entry.source : 'ui',
293
- reason: entry.reason,
294
- status: typeof entry.status === 'string' ? entry.status : 'stopped',
295
- startedAt: typeof entry.startedAt === 'number' ? entry.startedAt : null,
296
- lastActivity: typeof entry.lastActivity === 'number' ? entry.lastActivity : null,
297
- archivedAt: entry.archivedAt,
298
- });
299
- }
300
- return normalized
301
- .sort((a, b) => b.archivedAt - a.archivedAt)
302
- .slice(0, 200);
303
- }
304
-
305
- init() {
306
- if (!fs.existsSync(this.farmingDir)) {
307
- fs.mkdirSync(this.farmingDir, { recursive: true });
308
- console.log('Created farming directory:', this.farmingDir);
309
- }
310
-
311
- if (!fs.existsSync(this.settingsFile)) {
312
- const defaultSettings = {
313
- workspace: this.farmingDir,
314
- lastMainWorkspace: this.farmingDir,
315
- workspaceHistory: [],
316
- projectWorkspaces: [],
317
- pinnedProjectWorkspaces: [],
318
- projectNames: {},
319
- projectOperations: {},
320
- instanceName: '',
321
- theme: 'terminal',
322
- appearance: 'system',
323
- language: 'en',
324
- restReminderIntervalSeconds: null,
325
- heartbeatInterval: 1000,
326
- dangerouslySkipAgentPermissionsByDefault: false,
327
- browserExtensionEnabled: false,
328
- browserSource: process.env.FARMING_BROWSER_CDP_URL ? 'external-cdp' : 'system',
329
- browserExecutablePath: process.env.FARMING_BROWSER_EXECUTABLE || '',
330
- browserExternalCdpUrl: process.env.FARMING_BROWSER_CDP_URL || 'http://127.0.0.1:9222',
331
- crtSkinEffectsEnabled: true,
332
- crtDynamicHeatEnabled: false,
333
- crtTerminalFontSize: DEFAULT_CRT_TERMINAL_FONT_SIZE,
334
- defaultLaunchAgent: 'codex',
335
- agentLaunchProfiles: {
336
- codex: cloneLaunchProfile(DEFAULT_CODEX_LAUNCH_PROFILE),
337
- claude: cloneLaunchProfile(DEFAULT_CLAUDE_LAUNCH_PROFILE),
338
- },
339
- agentHomes: cloneAgentHomes(DEFAULT_AGENT_HOMES),
340
- updateUrl: DEFAULT_UPDATE_URL,
341
- searchTimeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,
342
- codexApprovalMode: 'approve',
343
- codexModel: 'gpt-5.5',
344
- codexReasoningEffort: 'xhigh',
345
- codexServiceTier: 'default',
346
- codexModelPreset: 'gpt-5.5:xhigh',
347
- version: '2'
348
- };
349
- this.writeSettingsFile(defaultSettings);
350
- console.log('Created default settings:', this.settingsFile);
351
- }
352
-
353
- const rawSettings = JSON.parse(fs.readFileSync(this.settingsFile, 'utf8'));
354
- this.settings = {
355
- workspace: this.farmingDir,
356
- lastMainWorkspace: this.farmingDir,
357
- workspaceHistory: [],
358
- projectWorkspaces: [],
359
- pinnedProjectWorkspaces: [],
360
- projectNames: {},
361
- projectOperations: {},
362
- instanceName: '',
363
- theme: 'terminal',
364
- appearance: 'system',
365
- language: 'en',
366
- restReminderIntervalSeconds: null,
367
- heartbeatInterval: 1000,
368
- dangerouslySkipAgentPermissionsByDefault: false,
369
- browserExtensionEnabled: false,
370
- browserSource: process.env.FARMING_BROWSER_CDP_URL ? 'external-cdp' : 'system',
371
- browserExecutablePath: process.env.FARMING_BROWSER_EXECUTABLE || '',
372
- browserExternalCdpUrl: process.env.FARMING_BROWSER_CDP_URL || 'http://127.0.0.1:9222',
373
- crtSkinEffectsEnabled: true,
374
- crtDynamicHeatEnabled: false,
375
- crtTerminalFontSize: DEFAULT_CRT_TERMINAL_FONT_SIZE,
376
- defaultLaunchAgent: 'codex',
377
- agentLaunchProfiles: {
378
- codex: cloneLaunchProfile(DEFAULT_CODEX_LAUNCH_PROFILE),
379
- claude: cloneLaunchProfile(DEFAULT_CLAUDE_LAUNCH_PROFILE),
380
- },
381
- agentHomes: cloneAgentHomes(DEFAULT_AGENT_HOMES),
382
- updateUrl: DEFAULT_UPDATE_URL,
383
- searchTimeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,
384
- codexApprovalMode: 'approve',
385
- codexModel: 'gpt-5.5',
386
- codexReasoningEffort: 'xhigh',
387
- codexServiceTier: 'default',
388
- codexModelPreset: 'gpt-5.5:xhigh',
389
- version: '2',
390
- ...rawSettings
391
- };
392
- if (rawSettings.searchTimeoutMs === undefined && rawSettings.workspaceFileSearchTimeoutMs !== undefined) {
393
- const legacyTimeoutMs = Number(rawSettings.workspaceFileSearchTimeoutMs);
394
- this.settings.searchTimeoutMs = legacyTimeoutMs === LEGACY_DEFAULT_WORKSPACE_FILE_SEARCH_TIMEOUT_MS
395
- ? DEFAULT_SEARCH_TIMEOUT_MS
396
- : rawSettings.workspaceFileSearchTimeoutMs;
397
- }
398
- delete this.settings.workspaceFileSearchTimeoutMs;
399
- if (
400
- this.settings.dangerouslySkipAgentPermissionsByDefault === undefined
401
- && this.settings.skipPermissionCheckByDefault !== undefined
402
- ) {
403
- this.settings.dangerouslySkipAgentPermissionsByDefault = this.settings.skipPermissionCheckByDefault === true;
404
- }
405
- delete this.settings.skipPermissionCheckByDefault;
406
- const launchRawSettings = { ...rawSettings };
407
- if (rawSettings.codexApprovalMode === undefined && this.settings.dangerouslySkipAgentPermissionsByDefault === true) {
408
- this.settings.codexApprovalMode = 'full';
409
- launchRawSettings.codexApprovalMode = 'full';
410
- }
411
- this.settings.workspace = this.farmingDir;
412
- this.settings.lastMainWorkspace = this.normalizeMainWorkspace(this.settings.lastMainWorkspace, this.farmingDir);
413
- this.settings.workspaceHistory = this.normalizeWorkspaceHistory(this.settings.workspaceHistory);
414
- this.settings.projectWorkspaces = this.normalizeProjectWorkspaces(this.settings.projectWorkspaces);
415
- this.settings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(this.settings.pinnedProjectWorkspaces);
416
- this.settings.projectNames = this.normalizeProjectNames(this.settings.projectNames);
417
- this.settings.projectOperations = this.normalizeProjectOperations(this.settings.projectOperations);
418
- this.settings.instanceName = this.normalizeInstanceName(this.settings.instanceName);
419
- this.settings.agentHomes = this.normalizeAgentHomes(this.settings.agentHomes);
420
- if (this.settings.updateUrl === LEGACY_DEFAULT_UPDATE_URL || this.settings.updateUrl === API_DEFAULT_UPDATE_URL) {
421
- this.settings.updateUrl = DEFAULT_UPDATE_URL;
422
- }
423
- this.settings.updateUrl = this.normalizeUpdateUrl(this.settings.updateUrl);
424
- this.settings.searchTimeoutMs = this.normalizeSearchTimeoutMs(this.settings.searchTimeoutMs);
425
- delete this.settings.codexRuntimeMode;
426
- const legacyMainPageSessionKeys = this.normalizeMainPageSessionKeys(this.settings.mainPageSessionKeys);
427
- delete this.settings.mainPageSessionKeys;
428
- this.sessionStore.init({ legacyMainPageSessionKeys });
429
- const legacyTaskHistory = this.normalizeTaskHistory(this.settings.taskHistory);
430
- delete this.settings.taskHistory;
431
- this.runHistoryStore.init({ legacyTaskHistory });
432
- this.settings.appearance = this.normalizeAppearance(this.settings.appearance);
433
- this.settings.language = this.normalizeLanguage(this.settings.language);
434
- this.settings.restReminderIntervalSeconds = this.normalizeRestReminderIntervalSeconds(
435
- this.settings.restReminderIntervalSeconds,
436
- );
437
- this.settings.browserExtensionEnabled = this.settings.browserExtensionEnabled === true;
438
- this.settings.browserSource = this.normalizeBrowserSource(this.settings.browserSource);
439
- this.settings.browserExecutablePath = this.normalizeBrowserSetting(this.settings.browserExecutablePath);
440
- this.settings.browserExternalCdpUrl = this.normalizeBrowserSetting(this.settings.browserExternalCdpUrl)
441
- || 'http://127.0.0.1:9222';
442
- this.settings.crtSkinEffectsEnabled = this.settings.crtSkinEffectsEnabled !== false;
443
- this.settings.crtDynamicHeatEnabled = this.settings.crtDynamicHeatEnabled === true;
444
- this.settings.crtTerminalFontSize = this.normalizeCrtTerminalFontSize(this.settings.crtTerminalFontSize);
445
- this.normalizeAgentLaunchSettings(launchRawSettings);
446
- this.pruneUnknownSettings();
447
- ensureMainAgentSkillFiles(this.farmingDir);
448
- ensureFarmingAgentBootstrapFile(this.farmingDir);
449
- this.writeSettingsFile();
450
- console.log('Loaded settings:', this.settings);
451
- }
452
-
453
- pruneUnknownSettings(settings = this.settings) {
454
- for (const key of Object.keys(settings || {})) {
455
- if (!PERSISTED_SETTING_KEYS.has(key)) {
456
- delete settings[key];
457
- }
458
- }
459
- }
460
-
461
- normalizeDefaultLaunchAgent(agentName) {
462
- return DEFAULT_LAUNCH_AGENT_NAMES.has(agentName) ? agentName : 'codex';
463
- }
464
-
465
- normalizeSearchTimeoutMs(value) {
466
- const timeoutMs = Number(value);
467
- if (!Number.isFinite(timeoutMs)) return DEFAULT_SEARCH_TIMEOUT_MS;
468
- return Math.min(
469
- MAX_SEARCH_TIMEOUT_MS,
470
- Math.max(MIN_SEARCH_TIMEOUT_MS, Math.round(timeoutMs))
471
- );
472
- }
473
-
474
- normalizeRestReminderIntervalSeconds(value) {
475
- if (value === null || value === undefined || value === '') return null;
476
- const seconds = Number(value);
477
- if (!Number.isInteger(seconds)) return null;
478
- if (seconds === 0 || seconds === 5) return seconds;
479
- return seconds >= 60 && seconds <= 240 * 60 && seconds % 60 === 0
480
- ? seconds
481
- : null;
482
- }
483
-
484
- normalizeCrtTerminalFontSize(value) {
485
- const fontSize = Number(value);
486
- if (!Number.isFinite(fontSize)) return DEFAULT_CRT_TERMINAL_FONT_SIZE;
487
- return Math.min(
488
- MAX_CRT_TERMINAL_FONT_SIZE,
489
- Math.max(MIN_CRT_TERMINAL_FONT_SIZE, Math.round(fontSize))
490
- );
491
- }
492
-
493
- normalizeAgentHomes(agentHomes) {
494
- const source = agentHomes && typeof agentHomes === 'object' && !Array.isArray(agentHomes)
495
- ? agentHomes
496
- : {};
497
- const normalized = {};
498
-
499
- Object.entries(source).forEach(([rawProvider, rawHomes]) => {
500
- const provider = String(rawProvider || '').trim().toLowerCase();
501
- if (!/^[a-z0-9._-]+$/.test(provider)) return;
502
- if (!Object.prototype.hasOwnProperty.call(DEFAULT_AGENT_HOMES, provider)) return;
503
- if (!Array.isArray(rawHomes)) return;
504
-
505
- const seenIds = new Set();
506
- const homes = [];
507
- rawHomes.forEach(rawHome => {
508
- if (!rawHome || typeof rawHome !== 'object') return;
509
- const id = String(rawHome.id || '').trim();
510
- const homePath = String(rawHome.path || '').trim();
511
- if (!id || !homePath) return;
512
- if (!/^[A-Za-z0-9._-]+$/.test(id)) return;
513
- const idKey = id.toLowerCase();
514
- if (seenIds.has(idKey)) return;
515
- seenIds.add(idKey);
516
- homes.push({ id, path: homePath });
517
- });
518
- if (homes.length > 0) normalized[provider] = homes;
519
- });
520
-
521
- for (const [provider, homes] of Object.entries(DEFAULT_AGENT_HOMES)) {
522
- const defaultHome = homes[0];
523
- const providerHomes = normalized[provider] || [];
524
- if (!providerHomes.some(home => String(home.id || '').toLowerCase() === 'default')) {
525
- normalized[provider] = [{ ...defaultHome }, ...providerHomes];
526
- }
527
- }
528
-
529
- return normalized;
530
- }
531
-
532
- normalizeProjectNames(projectNames) {
533
- if (!projectNames || typeof projectNames !== 'object' || Array.isArray(projectNames)) return {};
534
- const normalized = {};
535
- Object.entries(projectNames).forEach(([workspace, name]) => {
536
- const key = this.expandWorkspacePath(String(workspace || '').trim());
537
- const value = String(name || '').trim().slice(0, 80);
538
- if (!key || !value) return;
539
- normalized[key] = value;
540
- });
541
- return normalized;
542
- }
543
-
544
- normalizeProjectOperations(projectOperations) {
545
- if (!projectOperations || typeof projectOperations !== 'object' || Array.isArray(projectOperations)) return {};
546
- const entries = Object.entries(projectOperations)
547
- .filter(([id, operation]) => (
548
- PROJECT_OPERATION_ID_PATTERN.test(id)
549
- && operation
550
- && typeof operation === 'object'
551
- && ['create-worktree', 'delete-worktree'].includes(operation.type)
552
- && ['pending', 'unknown', 'succeeded', 'failed', 'blocked'].includes(operation.state)
553
- ))
554
- .sort((left, right) => (Number(right[1].updatedAt) || 0) - (Number(left[1].updatedAt) || 0))
555
- .map(([id, operation]) => [id, {
556
- id,
557
- type: operation.type,
558
- state: operation.state,
559
- signature: typeof operation.signature === 'string' ? operation.signature.slice(0, 128) : '',
560
- request: operation.request && typeof operation.request === 'object'
561
- ? JSON.parse(JSON.stringify(operation.request))
562
- : {},
563
- result: operation.result && typeof operation.result === 'object'
564
- ? JSON.parse(JSON.stringify(operation.result))
565
- : null,
566
- error: typeof operation.error === 'string' ? operation.error.slice(0, 2000) : '',
567
- startedAt: Number(operation.startedAt) || 0,
568
- updatedAt: Number(operation.updatedAt) || 0,
569
- finishedAt: Number(operation.finishedAt) || null,
570
- }]);
571
- const unresolved = entries.filter(([, operation]) => (
572
- ['pending', 'unknown', 'blocked'].includes(operation.state)
573
- ));
574
- const terminal = entries.filter(([, operation]) => (
575
- !['pending', 'unknown', 'blocked'].includes(operation.state)
576
- ));
577
- return Object.fromEntries([
578
- ...unresolved,
579
- ...terminal.slice(0, Math.max(0, MAX_PROJECT_OPERATIONS - unresolved.length)),
580
- ]);
581
- }
582
-
583
- setProjectName(workspace, name) {
584
- const normalized = this.normalizeProjectNames({ [workspace]: name });
585
- const entry = Object.entries(normalized)[0];
586
- if (!entry) throw new Error('Project workspace and name are required');
587
- const [normalizedWorkspace, normalizedName] = entry;
588
- const nextSettings = {
589
- ...this.settings,
590
- projectNames: {
591
- ...this.settings.projectNames,
592
- [normalizedWorkspace]: normalizedName,
593
- },
594
- };
595
- this.writeSettingsFile(nextSettings);
596
- this.settings = nextSettings;
597
- return {
598
- workspace: normalizedWorkspace,
599
- name: normalizedName,
600
- };
601
- }
602
-
603
- normalizeAppearance(appearance) {
604
- return ['system', 'light', 'dark'].includes(appearance) ? appearance : 'system';
605
- }
606
-
607
- normalizeLanguage(language) {
608
- return ['en', 'zh'].includes(language) ? language : 'en';
609
- }
610
-
611
- normalizeBrowserSource(source) {
612
- return source === 'external-cdp' ? source : 'system';
613
- }
614
-
615
- normalizeBrowserSetting(value) {
616
- return String(value || '').trim().slice(0, 2000);
617
- }
618
-
619
- normalizeUpdateUrl(value) {
620
- const url = String(value || '').trim();
621
- if (!url) return DEFAULT_UPDATE_URL;
622
- return /^https?:\/\//i.test(url) ? url.slice(0, 2000) : DEFAULT_UPDATE_URL;
623
- }
624
-
625
- normalizeClaudePermissionMode(mode) {
626
- return ['acceptEdits', 'auto', 'bypassPermissions', 'default', 'dontAsk', 'plan'].includes(mode)
627
- ? mode
628
- : 'default';
629
- }
630
-
631
- normalizeClaudeModel(model) {
632
- if (model === 'config') return model;
633
- return normalizeClaudeModelValue(model) || 'config';
634
- }
635
-
636
- normalizeClaudeEffort(effort) {
637
- if (effort === 'config') return effort;
638
- if (['low', 'medium', 'high', 'xhigh', 'max'].includes(effort)) return effort;
639
- return 'config';
640
- }
641
-
642
- normalizeCodexApprovalMode(mode) {
643
- return ['ask', 'approve', 'full', 'custom'].includes(mode) ? mode : 'approve';
644
- }
645
-
646
- normalizeCodexModelPreset(preset) {
647
- if (preset === 'config') return preset;
648
- if (typeof preset !== 'string') return 'gpt-5.5:xhigh';
649
- if (/^[A-Za-z0-9._-]+(?::[A-Za-z0-9._-]+)?$/.test(preset)) return preset;
650
- return 'gpt-5.5:xhigh';
651
- }
652
-
653
- normalizeCodexModelId(model) {
654
- if (model === 'config') return model;
655
- if (typeof model !== 'string') return 'gpt-5.5';
656
- if (/^[A-Za-z0-9._-]+$/.test(model)) return model;
657
- return 'gpt-5.5';
658
- }
659
-
660
- normalizeCodexReasoningEffort(effort) {
661
- if (effort === 'config') return effort;
662
- if (typeof effort !== 'string') return 'xhigh';
663
- if (/^[A-Za-z0-9._-]+$/.test(effort)) return effort;
664
- return 'xhigh';
665
- }
666
-
667
- normalizeCodexServiceTier(tier) {
668
- if (typeof tier !== 'string') return 'default';
669
- if (/^[A-Za-z0-9._-]+$/.test(tier)) return tier;
670
- return 'default';
671
- }
672
-
673
- normalizeCodexModelSettings(rawSettings = {}) {
674
- const codexProfile = this.normalizeCodexLaunchProfile({
675
- approvalMode: this.settings.codexApprovalMode,
676
- model: this.settings.codexModel,
677
- reasoningEffort: this.settings.codexReasoningEffort,
678
- serviceTier: this.settings.codexServiceTier,
679
- modelPreset: this.settings.codexModelPreset,
680
- }, {
681
- approvalMode: rawSettings.codexApprovalMode,
682
- model: rawSettings.codexModel,
683
- reasoningEffort: rawSettings.codexReasoningEffort,
684
- serviceTier: rawSettings.codexServiceTier,
685
- modelPreset: rawSettings.codexModelPreset,
686
- });
687
- this.applyCodexProfileToLegacySettings(codexProfile);
688
- }
689
-
690
- normalizeCodexLaunchProfile(profile = {}, changed = {}) {
691
- const next = {
692
- ...DEFAULT_CODEX_LAUNCH_PROFILE,
693
- ...(profile && typeof profile === 'object' ? profile : {}),
694
- };
695
- next.approvalMode = this.normalizeCodexApprovalMode(next.approvalMode);
696
-
697
- const hasDirectModelChange = changed.model !== undefined || changed.reasoningEffort !== undefined;
698
- const hasPresetChange = changed.modelPreset !== undefined;
699
- const normalizedPreset = this.normalizeCodexModelPreset(next.modelPreset);
700
- if (hasPresetChange && !hasDirectModelChange) {
701
- const fromPreset = splitCodexModelPreset(normalizedPreset);
702
- next.model = fromPreset.model;
703
- next.reasoningEffort = fromPreset.effort;
704
- } else {
705
- next.model = this.normalizeCodexModelId(next.model);
706
- next.reasoningEffort = this.normalizeCodexReasoningEffort(next.reasoningEffort);
707
- }
708
- next.serviceTier = this.normalizeCodexServiceTier(next.serviceTier);
709
- next.modelPreset = joinCodexModelPreset(
710
- next.model,
711
- next.reasoningEffort === 'config' ? '' : next.reasoningEffort
712
- );
713
- return next;
714
- }
715
-
716
- normalizeClaudeLaunchProfile(profile = {}) {
717
- const next = {
718
- ...DEFAULT_CLAUDE_LAUNCH_PROFILE,
719
- ...(profile && typeof profile === 'object' ? profile : {}),
720
- };
721
- return {
722
- permissionMode: this.normalizeClaudePermissionMode(next.permissionMode),
723
- model: this.normalizeClaudeModel(next.model),
724
- effort: this.normalizeClaudeEffort(next.effort),
725
- };
726
- }
727
-
728
- getChangedAgentLaunchProfiles(rawSettings = {}) {
729
- const changedProfiles = {};
730
- if (rawSettings.agentLaunchProfiles && typeof rawSettings.agentLaunchProfiles === 'object') {
731
- for (const [agentName, profile] of Object.entries(rawSettings.agentLaunchProfiles)) {
732
- if (!Object.prototype.hasOwnProperty.call(DEFAULT_AGENT_LAUNCH_PROFILES, agentName)) continue;
733
- if (profile && typeof profile === 'object') changedProfiles[agentName] = profile;
734
- }
735
- }
736
-
737
- const codexChanged = {};
738
- if (rawSettings.codexApprovalMode !== undefined) codexChanged.approvalMode = rawSettings.codexApprovalMode;
739
- if (rawSettings.codexModel !== undefined) codexChanged.model = rawSettings.codexModel;
740
- if (rawSettings.codexReasoningEffort !== undefined) codexChanged.reasoningEffort = rawSettings.codexReasoningEffort;
741
- if (rawSettings.codexServiceTier !== undefined) codexChanged.serviceTier = rawSettings.codexServiceTier;
742
- if (rawSettings.codexModelPreset !== undefined) codexChanged.modelPreset = rawSettings.codexModelPreset;
743
- if (Object.keys(codexChanged).length > 0) {
744
- changedProfiles.codex = {
745
- ...(changedProfiles.codex || {}),
746
- ...codexChanged,
747
- };
748
- }
749
-
750
- return changedProfiles;
751
- }
752
-
753
- mergeAgentLaunchProfiles(existingProfiles = {}, incomingProfiles = {}) {
754
- const merged = {};
755
- for (const [agentName, defaultProfile] of Object.entries(DEFAULT_AGENT_LAUNCH_PROFILES)) {
756
- merged[agentName] = {
757
- ...defaultProfile,
758
- ...(existingProfiles && typeof existingProfiles === 'object' ? existingProfiles[agentName] : {}),
759
- ...(incomingProfiles && typeof incomingProfiles === 'object' ? incomingProfiles[agentName] : {}),
760
- };
761
- }
762
- return merged;
763
- }
764
-
765
- applyCodexProfileToLegacySettings(codexProfile, settings = this.settings) {
766
- settings.codexApprovalMode = codexProfile.approvalMode;
767
- settings.codexModel = codexProfile.model;
768
- settings.codexReasoningEffort = codexProfile.reasoningEffort;
769
- settings.codexServiceTier = codexProfile.serviceTier;
770
- settings.codexModelPreset = codexProfile.modelPreset;
771
- }
772
-
773
- normalizeAgentLaunchSettings(rawSettings = {}, settings = this.settings) {
774
- const changedProfiles = this.getChangedAgentLaunchProfiles(rawSettings);
775
- const mergedProfiles = this.mergeAgentLaunchProfiles(settings.agentLaunchProfiles, changedProfiles);
776
- settings.agentLaunchProfiles = {
777
- codex: this.normalizeCodexLaunchProfile(mergedProfiles.codex, changedProfiles.codex || {}),
778
- claude: this.normalizeClaudeLaunchProfile(mergedProfiles.claude),
779
- };
780
- settings.defaultLaunchAgent = this.normalizeDefaultLaunchAgent(settings.defaultLaunchAgent);
781
- this.applyCodexProfileToLegacySettings(settings.agentLaunchProfiles.codex, settings);
782
- }
783
-
784
- getWorkspace() {
785
- return this.settings ? this.settings.workspace : this.farmingDir;
786
- }
787
-
788
- getHeartbeatInterval() {
789
- return this.settings ? (this.settings.heartbeatInterval || 1000) : 1000;
790
- }
791
-
792
- getDangerouslySkipAgentPermissionsByDefault() {
793
- return this.settings ? this.settings.dangerouslySkipAgentPermissionsByDefault === true : false;
794
- }
795
-
796
- getCodexApprovalMode() {
797
- if (!this.settings) return 'approve';
798
- return this.getAgentLaunchProfile('codex').approvalMode;
799
- }
800
-
801
- getCodexModelPreset() {
802
- if (!this.settings) return 'gpt-5.5:xhigh';
803
- return this.getAgentLaunchProfile('codex').modelPreset;
804
- }
805
-
806
- getCodexModel() {
807
- if (!this.settings) return 'gpt-5.5';
808
- return this.getAgentLaunchProfile('codex').model;
809
- }
810
-
811
- getCodexReasoningEffort() {
812
- if (!this.settings) return 'xhigh';
813
- return this.getAgentLaunchProfile('codex').reasoningEffort;
814
- }
815
-
816
- getCodexServiceTier() {
817
- if (!this.settings) return 'default';
818
- return this.getAgentLaunchProfile('codex').serviceTier;
819
- }
820
-
821
-
822
- getAgentHomes(provider) {
823
- const homes = this.settings && this.settings.agentHomes && this.settings.agentHomes[provider]
824
- ? this.settings.agentHomes[provider]
825
- : [];
826
- return homes.map(home => ({ ...home, path: this.expandWorkspacePath(home.path) }));
827
- }
828
-
829
- getAgentHome(provider, homeId = 'default') {
830
- const normalizedProvider = String(provider || '').trim().toLowerCase();
831
- const normalizedHomeId = String(homeId || 'default').trim();
832
- const homes = this.getAgentHomes(normalizedProvider);
833
- return homes.find(home => home.id === normalizedHomeId) || null;
834
- }
835
-
836
- getDefaultLaunchAgent() {
837
- return this.settings ? this.normalizeDefaultLaunchAgent(this.settings.defaultLaunchAgent) : 'codex';
838
- }
839
-
840
- getAgentLaunchProfiles() {
841
- const profiles = this.settings && this.settings.agentLaunchProfiles
842
- ? this.settings.agentLaunchProfiles
843
- : DEFAULT_AGENT_LAUNCH_PROFILES;
844
- return {
845
- codex: { ...profiles.codex },
846
- claude: { ...profiles.claude },
847
- };
848
- }
849
-
850
- getAgentLaunchProfile(agentName) {
851
- const profiles = this.getAgentLaunchProfiles();
852
- const profile = profiles[agentName] || DEFAULT_AGENT_LAUNCH_PROFILES[agentName];
853
- return profile ? { ...profile } : {};
854
- }
855
-
856
- getSettings() {
857
- const publicSettings = { ...this.settings };
858
- delete publicSettings.projectOperations;
859
- return {
860
- ...publicSettings,
861
- instanceName: this.getInstanceName(),
862
- workspace: this.farmingDir,
863
- mainPageSessionKeys: this.getMainPageSessionKeys(),
864
- taskHistory: this.getTaskHistory(),
865
- };
866
- }
867
-
868
- mountProjectWorkspace(workspace) {
869
- const expanded = this.expandWorkspacePath(workspace);
870
- const resolved = expanded ? path.resolve(expanded) : '';
871
- let canonicalWorkspace = '';
872
- if (resolved) {
873
- try {
874
- canonicalWorkspace = fs.realpathSync(resolved);
875
- if (!fs.statSync(canonicalWorkspace).isDirectory()) canonicalWorkspace = '';
876
- } catch {
877
- canonicalWorkspace = '';
878
- }
879
- }
880
- if (
881
- !canonicalWorkspace
882
- || this.isInternalWorkspace(canonicalWorkspace)
883
- ) {
884
- throw new Error('Project workspace is invalid or unavailable');
885
- }
886
- const current = this.settings.projectWorkspaces || [];
887
- if (!current.includes(canonicalWorkspace)) {
888
- this.commitProjectMembership({
889
- projectWorkspaces: [canonicalWorkspace, ...current],
890
- });
891
- }
892
- return {
893
- workspace: canonicalWorkspace,
894
- projectWorkspaces: [...(this.settings.projectWorkspaces || [])],
895
- pinnedProjectWorkspaces: [...(this.settings.pinnedProjectWorkspaces || [])],
896
- };
897
- }
898
-
899
- removeProjectWorkspace(workspace) {
900
- const expanded = this.expandWorkspacePath(workspace);
901
- if (!expanded) throw new Error('Project workspace is required');
902
- const resolved = path.resolve(expanded);
903
- const candidates = new Set([expanded, resolved]);
904
- try {
905
- candidates.add(fs.realpathSync(resolved));
906
- } catch {
907
- // A deleted worktree can still be removed by its last canonical path.
908
- }
909
- const current = this.settings.projectWorkspaces || [];
910
- const nextProjects = current.filter(entry => !candidates.has(entry));
911
- const currentPinned = this.settings.pinnedProjectWorkspaces || [];
912
- const nextPinned = currentPinned.filter(entry => !candidates.has(entry));
913
- if (nextProjects.length !== current.length || nextPinned.length !== currentPinned.length) {
914
- this.commitProjectMembership({
915
- projectWorkspaces: nextProjects,
916
- pinnedProjectWorkspaces: nextPinned,
917
- });
918
- }
919
- return {
920
- workspace: current.find(entry => candidates.has(entry)) || resolved,
921
- projectWorkspaces: [...(this.settings.projectWorkspaces || [])],
922
- pinnedProjectWorkspaces: [...(this.settings.pinnedProjectWorkspaces || [])],
923
- };
924
- }
925
-
926
- setProjectWorkspacePinned(workspace, pinned) {
927
- const [canonicalWorkspace] = this.normalizeProjectWorkspaces([workspace]);
928
- if (!canonicalWorkspace || !(this.settings.projectWorkspaces || []).includes(canonicalWorkspace)) {
929
- throw new Error('Project does not exist');
930
- }
931
- const current = this.settings.pinnedProjectWorkspaces || [];
932
- const nextPinned = pinned
933
- ? [...current.filter(entry => entry !== canonicalWorkspace), canonicalWorkspace]
934
- : current.filter(entry => entry !== canonicalWorkspace);
935
- if (
936
- nextPinned.length !== current.length
937
- || nextPinned.some((entry, index) => entry !== current[index])
938
- ) {
939
- this.commitProjectMembership({ pinnedProjectWorkspaces: nextPinned });
940
- }
941
- return {
942
- workspace: canonicalWorkspace,
943
- projectWorkspaces: [...(this.settings.projectWorkspaces || [])],
944
- pinnedProjectWorkspaces: [...(this.settings.pinnedProjectWorkspaces || [])],
945
- };
946
- }
947
-
948
- commitProjectMembership(settingsPatch) {
949
- const previousSettings = this.settings;
950
- try {
951
- this.updateSettings(settingsPatch);
952
- } catch (error) {
953
- this.settings = previousSettings;
954
- throw error;
955
- }
956
- }
957
-
958
- getProjectOperation(requestId) {
959
- const id = String(requestId || '').trim();
960
- if (!PROJECT_OPERATION_ID_PATTERN.test(id)) return null;
961
- const operation = this.settings.projectOperations?.[id];
962
- return operation ? JSON.parse(JSON.stringify(operation)) : null;
963
- }
964
-
965
- commitProjectOperation(operation, membership = {}) {
966
- const normalized = this.normalizeProjectOperations({ [operation?.id]: operation });
967
- const nextOperation = normalized[operation?.id];
968
- if (!nextOperation) throw new Error('Project operation is invalid');
969
- const existingOperation = this.settings.projectOperations?.[nextOperation.id];
970
- const unresolvedCount = Object.values(this.settings.projectOperations || {})
971
- .filter(candidate => ['pending', 'unknown', 'blocked'].includes(candidate.state)).length;
972
- if (!existingOperation && nextOperation.state === 'pending' && unresolvedCount >= MAX_PROJECT_OPERATIONS) {
973
- throw new Error('Too many unresolved Project operations require reconciliation');
974
- }
975
- const nextOperations = this.normalizeProjectOperations({
976
- ...this.settings.projectOperations,
977
- [nextOperation.id]: nextOperation,
978
- });
979
- const nextSettings = {
980
- ...this.settings,
981
- projectOperations: nextOperations,
982
- };
983
- if (membership.mountWorkspace) {
984
- const mounted = this.normalizeProjectWorkspaces([
985
- membership.mountWorkspace,
986
- ...(this.settings.projectWorkspaces || []),
987
- ]);
988
- nextSettings.projectWorkspaces = mounted;
989
- nextSettings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(
990
- this.settings.pinnedProjectWorkspaces,
991
- );
992
- }
993
- if (membership.removeWorkspace) {
994
- const expanded = this.expandWorkspacePath(membership.removeWorkspace);
995
- const resolved = expanded ? path.resolve(expanded) : '';
996
- const candidates = new Set([expanded, resolved].filter(Boolean));
997
- try {
998
- candidates.add(fs.realpathSync(resolved));
999
- } catch {
1000
- // A deleted worktree is removed by its last canonical path.
1001
- }
1002
- nextSettings.projectWorkspaces = (this.settings.projectWorkspaces || [])
1003
- .filter(workspace => !candidates.has(workspace));
1004
- nextSettings.pinnedProjectWorkspaces = (this.settings.pinnedProjectWorkspaces || [])
1005
- .filter(workspace => !candidates.has(workspace));
1006
- }
1007
- this.writeSettingsFile(nextSettings);
1008
- this.settings = nextSettings;
1009
- return {
1010
- operation: JSON.parse(JSON.stringify(nextOperation)),
1011
- projectWorkspaces: [...(nextSettings.projectWorkspaces || [])],
1012
- pinnedProjectWorkspaces: [...(nextSettings.pinnedProjectWorkspaces || [])],
1013
- };
1014
- }
1015
-
1016
- getMainPageSessionKeys() {
1017
- return this.sessionStore ? this.sessionStore.getMainPageSessionKeys() : [];
1018
- }
1019
-
1020
- setMainPageSessionKeys(keys) {
1021
- return this.sessionStore ? this.sessionStore.setMainPageSessionKeys(keys) : [];
1022
- }
1023
-
1024
- rememberMainPageSessionKey(sessionKey, patch = {}) {
1025
- return this.sessionStore ? this.sessionStore.rememberMainPageSessionKey(sessionKey, patch) : [];
1026
- }
1027
-
1028
- removeMainPageSessionKey(sessionKey) {
1029
- return this.sessionStore ? this.sessionStore.removeMainPageSessionKey(sessionKey) : false;
1030
- }
1031
-
1032
- removeMainPageSessionKeys(keys) {
1033
- return this.sessionStore ? this.sessionStore.removeMainPageSessionKeys(keys) : [];
1034
- }
1035
-
1036
- ensureAgentSessionRecord(agent, patch = {}) {
1037
- return this.sessionStore ? this.sessionStore.ensureRecordForAgent(agent, patch) : '';
1038
- }
1039
-
1040
- getAgentSessionRecordForProviderSessionKey(sessionKey) {
1041
- return this.sessionStore ? this.sessionStore.getRecordForProviderSessionKey(sessionKey) : null;
1042
- }
1043
-
1044
- setProviderSessionDisplayState(sessionKey, patch = {}) {
1045
- return this.sessionStore ? this.sessionStore.setProviderSessionDisplayState(sessionKey, patch) : '';
1046
- }
1047
-
1048
- listAgentSessionRecords() {
1049
- return this.sessionStore ? this.sessionStore.listAgentRecords() : [];
1050
- }
1051
-
1052
- rememberAgentSessionRecord(agent) {
1053
- return this.sessionStore ? this.sessionStore.rememberAgent(agent) : '';
1054
- }
1055
-
1056
- getTaskHistory() {
1057
- return this.runHistoryStore ? this.runHistoryStore.getEntries() : [];
1058
- }
1059
-
1060
- writeSettingsFile(settings = this.settings) {
1061
- this.writeJson(this.settingsFile, settings);
1062
- }
1063
-
1064
- appendTaskHistory(entry) {
1065
- if (!this.runHistoryStore) return;
1066
- this.runHistoryStore.appendEntry(entry);
1067
- }
1068
-
1069
- updateSettings(newSettings) {
1070
- const incomingMainPageSessionKeys = Object.prototype.hasOwnProperty.call(newSettings || {}, 'mainPageSessionKeys')
1071
- ? newSettings.mainPageSessionKeys
1072
- : undefined;
1073
- const settingsPatch = { ...(newSettings || {}) };
1074
- delete settingsPatch.mainPageSessionKeys;
1075
- delete settingsPatch.projectOperations;
1076
- const incomingTaskHistory = Object.prototype.hasOwnProperty.call(settingsPatch, 'taskHistory')
1077
- ? settingsPatch.taskHistory
1078
- : undefined;
1079
- delete settingsPatch.taskHistory;
1080
- const previousMainWorkspace = this.settings.lastMainWorkspace || this.farmingDir;
1081
- const previousProfiles = this.settings.agentLaunchProfiles || {};
1082
- const incomingProfiles = settingsPatch.agentLaunchProfiles || {};
1083
- const nextSettings = {
1084
- ...this.settings,
1085
- ...settingsPatch,
1086
- agentLaunchProfiles: this.mergeAgentLaunchProfiles(previousProfiles, incomingProfiles),
1087
- workspace: this.farmingDir
1088
- };
1089
- nextSettings.lastMainWorkspace = this.normalizeMainWorkspace(nextSettings.lastMainWorkspace, previousMainWorkspace);
1090
- nextSettings.workspaceHistory = this.normalizeWorkspaceHistory(nextSettings.workspaceHistory);
1091
- nextSettings.projectWorkspaces = this.normalizeProjectWorkspaces(nextSettings.projectWorkspaces);
1092
- nextSettings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(nextSettings.pinnedProjectWorkspaces);
1093
- nextSettings.projectNames = this.normalizeProjectNames(nextSettings.projectNames);
1094
- nextSettings.projectOperations = this.normalizeProjectOperations(nextSettings.projectOperations);
1095
- nextSettings.instanceName = this.normalizeInstanceName(nextSettings.instanceName);
1096
- nextSettings.agentHomes = this.normalizeAgentHomes(nextSettings.agentHomes);
1097
- nextSettings.updateUrl = this.normalizeUpdateUrl(nextSettings.updateUrl);
1098
- nextSettings.searchTimeoutMs = this.normalizeSearchTimeoutMs(nextSettings.searchTimeoutMs);
1099
- delete nextSettings.codexRuntimeMode;
1100
- delete nextSettings.mainPageSessionKeys;
1101
- delete nextSettings.taskHistory;
1102
- if (incomingMainPageSessionKeys !== undefined) {
1103
- this.setMainPageSessionKeys(incomingMainPageSessionKeys);
1104
- }
1105
- if (incomingTaskHistory !== undefined && this.runHistoryStore) {
1106
- this.runHistoryStore.setEntries(incomingTaskHistory);
1107
- }
1108
- nextSettings.appearance = this.normalizeAppearance(nextSettings.appearance);
1109
- nextSettings.language = this.normalizeLanguage(nextSettings.language);
1110
- nextSettings.restReminderIntervalSeconds = this.normalizeRestReminderIntervalSeconds(
1111
- nextSettings.restReminderIntervalSeconds,
1112
- );
1113
- nextSettings.browserExtensionEnabled = nextSettings.browserExtensionEnabled === true;
1114
- nextSettings.browserSource = this.normalizeBrowserSource(nextSettings.browserSource);
1115
- nextSettings.browserExecutablePath = this.normalizeBrowserSetting(nextSettings.browserExecutablePath);
1116
- nextSettings.browserExternalCdpUrl = this.normalizeBrowserSetting(nextSettings.browserExternalCdpUrl)
1117
- || 'http://127.0.0.1:9222';
1118
- nextSettings.crtSkinEffectsEnabled = nextSettings.crtSkinEffectsEnabled !== false;
1119
- nextSettings.crtDynamicHeatEnabled = nextSettings.crtDynamicHeatEnabled === true;
1120
- nextSettings.crtTerminalFontSize = this.normalizeCrtTerminalFontSize(nextSettings.crtTerminalFontSize);
1121
- this.normalizeAgentLaunchSettings(settingsPatch, nextSettings);
1122
- this.pruneUnknownSettings(nextSettings);
1123
- this.writeSettingsFile(nextSettings);
1124
- this.settings = nextSettings;
1125
- }
1126
- }
1127
-
1128
- module.exports = ConfigManager;
1129
- module.exports.DEFAULT_UPDATE_URL = DEFAULT_UPDATE_URL;
1130
- module.exports.DEFAULT_SEARCH_TIMEOUT_MS = DEFAULT_SEARCH_TIMEOUT_MS;
1131
- module.exports.DEFAULT_CRT_TERMINAL_FONT_SIZE = DEFAULT_CRT_TERMINAL_FONT_SIZE;
1132
- module.exports.MIN_CRT_TERMINAL_FONT_SIZE = MIN_CRT_TERMINAL_FONT_SIZE;
1133
- module.exports.MAX_CRT_TERMINAL_FONT_SIZE = MAX_CRT_TERMINAL_FONT_SIZE;