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,953 +0,0 @@
1
- const fs = require('fs');
2
- const fsp = require('fs/promises');
3
- const os = require('os');
4
- const path = require('path');
5
- const readline = require('readline');
6
- const { execFile } = require('child_process');
7
- const {
8
- formatAutomationRRuleLabel,
9
- hasTemporaryWorkspaceReference,
10
- isTemporaryWorkspace,
11
- listCodexSessions,
12
- } = require('./codex-session-history');
13
- const { isSafeProviderSessionId } = require('./provider-session-id');
14
-
15
- const DEFAULT_LIMIT = 60;
16
- const DEFAULT_SCAN_LIMIT = 500;
17
- const MAX_AGENT_SESSION_HISTORY_LIMIT = 5000;
18
- const MAX_AGENT_SESSION_SCAN_LIMIT = 5000;
19
- const CLAUDE_HISTORY_TAIL_BYTES = 2 * 1024 * 1024;
20
- const QODER_HISTORY_TAIL_BYTES = 2 * 1024 * 1024;
21
- const MAX_RECENT_FILE_SCAN_DIRECTORIES = 2000;
22
- const PROVIDERS = new Set(['codex', 'claude', 'opencode', 'qoder']);
23
-
24
- function quoteCommandArg(value) {
25
- return `'${String(value).replace(/'/g, `'\\''`)}'`;
26
- }
27
-
28
- function tomlStringAssignment(line, key) {
29
- const match = String(line || '').match(new RegExp(`^\\s*${key}\\s*=\\s*("(?:[^"\\\\]|\\\\.)*"|'[^']*')\\s*(?:#.*)?$`));
30
- if (!match) return '';
31
- const literal = match[1];
32
- if (literal.startsWith('"')) {
33
- try {
34
- return JSON.parse(literal).trim();
35
- } catch {
36
- return '';
37
- }
38
- }
39
- return literal.slice(1, -1).trim();
40
- }
41
-
42
- function codexProfileNameForSection(section) {
43
- const match = String(section || '').trim().match(/^profiles\.(?:"([^"]+)"|'([^']+)'|([A-Za-z0-9_-]+))$/);
44
- return match ? (match[1] || match[2] || match[3] || '') : '';
45
- }
46
-
47
- function resolveCodexResumeModelProvider(codexHome) {
48
- const home = normalizePathValue(codexHome)
49
- || normalizePathValue(process.env.CODEX_HOME)
50
- || path.join(os.homedir(), '.codex');
51
- let config = '';
52
- try {
53
- config = fs.readFileSync(path.join(home, 'config.toml'), 'utf8');
54
- } catch {
55
- return 'openai';
56
- }
57
-
58
- let section = '';
59
- let activeProfile = '';
60
- let topLevelProvider = '';
61
- const profileProviders = new Map();
62
- for (const line of config.split(/\r?\n/)) {
63
- const sectionMatch = line.match(/^\s*\[([^\]]+)]\s*(?:#.*)?$/);
64
- if (sectionMatch) {
65
- section = sectionMatch[1].trim();
66
- continue;
67
- }
68
- if (!section) {
69
- activeProfile = tomlStringAssignment(line, 'profile') || activeProfile;
70
- topLevelProvider = tomlStringAssignment(line, 'model_provider') || topLevelProvider;
71
- continue;
72
- }
73
- const profileName = codexProfileNameForSection(section);
74
- if (profileName) {
75
- const provider = tomlStringAssignment(line, 'model_provider');
76
- if (provider) profileProviders.set(profileName, provider);
77
- }
78
- }
79
-
80
- return (activeProfile && profileProviders.get(activeProfile)) || topLevelProvider || 'openai';
81
- }
82
-
83
- function normalizePathValue(value) {
84
- if (typeof value !== 'string') return '';
85
- const trimmed = value.trim();
86
- if (!trimmed || trimmed === path.sep) return trimmed;
87
- return trimmed.replace(/[\\/]+$/, '');
88
- }
89
-
90
- function timestampMs(value) {
91
- const parsed = Date.parse(value || '');
92
- return Number.isFinite(parsed) ? parsed : 0;
93
- }
94
-
95
- function agentSessionIdentity(session) {
96
- return [
97
- String(session?.provider || ''),
98
- String(session?.providerHomeId || 'default'),
99
- String(session?.id || ''),
100
- ].join('\u0000');
101
- }
102
-
103
- function compareAgentSessions(a, b) {
104
- const timeDelta = timestampMs(b?.updatedAt || b?.createdAt) - timestampMs(a?.updatedAt || a?.createdAt);
105
- return timeDelta || agentSessionIdentity(a).localeCompare(agentSessionIdentity(b));
106
- }
107
-
108
- function encodeAgentSessionCursor(session) {
109
- if (!session?.provider || !session?.id) return '';
110
- return Buffer.from(JSON.stringify({
111
- version: 1,
112
- provider: String(session.provider),
113
- providerHomeId: String(session.providerHomeId || 'default'),
114
- id: String(session.id),
115
- updatedAt: String(session.updatedAt || session.createdAt || ''),
116
- })).toString('base64url');
117
- }
118
-
119
- function decodeAgentSessionCursor(value) {
120
- try {
121
- const parsed = JSON.parse(Buffer.from(String(value || ''), 'base64url').toString('utf8'));
122
- if (parsed?.version !== 1 || !parsed.provider || !parsed.id) return null;
123
- return {
124
- provider: String(parsed.provider),
125
- providerHomeId: String(parsed.providerHomeId || 'default'),
126
- id: String(parsed.id),
127
- updatedAt: String(parsed.updatedAt || ''),
128
- };
129
- } catch {
130
- return null;
131
- }
132
- }
133
-
134
- function paginateAgentSessions(sessions, options = {}) {
135
- const limit = Number.isFinite(options.limit)
136
- ? Math.max(1, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
137
- : DEFAULT_LIMIT;
138
- const cursorValue = String(options.cursor || '').trim();
139
- let start = 0;
140
- if (cursorValue) {
141
- const cursor = decodeAgentSessionCursor(cursorValue);
142
- if (!cursor) return { sessions: [], nextCursor: '', hasMore: false, invalidCursor: true };
143
- const exactIndex = sessions.findIndex(session => agentSessionIdentity(session) === agentSessionIdentity(cursor));
144
- if (exactIndex >= 0) {
145
- start = exactIndex + 1;
146
- } else {
147
- const nextIndex = sessions.findIndex(session => compareAgentSessions(session, cursor) > 0);
148
- start = nextIndex >= 0 ? nextIndex : sessions.length;
149
- }
150
- }
151
- const page = sessions.slice(start, start + limit);
152
- const hasMore = start + page.length < sessions.length;
153
- return {
154
- sessions: page,
155
- nextCursor: hasMore && page.length > 0 ? encodeAgentSessionCursor(page[page.length - 1]) : '',
156
- hasMore,
157
- invalidCursor: false,
158
- };
159
- }
160
-
161
- function searchAgentSessions(sessions, query, options = {}) {
162
- const normalizedQuery = String(query || '').trim().toLowerCase();
163
- const limit = Number.isFinite(options.limit)
164
- ? Math.max(1, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
165
- : DEFAULT_LIMIT;
166
- if (!normalizedQuery) {
167
- return { sessions: [], total: 0, query: '', scope: 'title-project' };
168
- }
169
-
170
- const projectNames = options.projectNames && typeof options.projectNames === 'object'
171
- ? options.projectNames
172
- : {};
173
- const matches = sessions.filter(session => {
174
- const projectPaths = [session?.workspace, session?.cwd];
175
- return [
176
- session?.title,
177
- ...projectPaths,
178
- ...projectPaths.map(workspace => projectNames[String(workspace || '')]),
179
- ].some(value => String(value || '').toLowerCase().includes(normalizedQuery));
180
- });
181
-
182
- return {
183
- sessions: matches.slice(0, limit),
184
- total: matches.length,
185
- query: normalizedQuery,
186
- scope: 'title-project',
187
- };
188
- }
189
-
190
- function isAgentManagedWorktree(workspace) {
191
- const value = normalizePathValue(workspace);
192
- return value.includes(`${path.sep}.codex${path.sep}worktrees${path.sep}`)
193
- || value.includes(`${path.sep}.claude${path.sep}worktrees${path.sep}`);
194
- }
195
-
196
- function isDefaultClaudeSessionTitle(title) {
197
- return String(title || '').trim().toLowerCase() === 'claude session';
198
- }
199
-
200
- function firstTrimmedString(...values) {
201
- for (const value of values) {
202
- if (typeof value !== 'string') continue;
203
- const trimmed = value.trim();
204
- if (trimmed) return trimmed;
205
- }
206
- return '';
207
- }
208
-
209
- function extractClaudeModel(event) {
210
- return firstTrimmedString(
211
- event?.model,
212
- event?.message?.model,
213
- event?.metadata?.model,
214
- event?.message?.metadata?.model,
215
- event?.request?.model,
216
- event?.options?.model
217
- );
218
- }
219
-
220
- function extractClaudeEffort(event) {
221
- return firstTrimmedString(
222
- event?.effort,
223
- event?.message?.effort,
224
- event?.metadata?.effort,
225
- event?.message?.metadata?.effort,
226
- event?.request?.effort,
227
- event?.options?.effort
228
- );
229
- }
230
-
231
- function extractQoderModel(event) {
232
- return firstTrimmedString(
233
- event?.model,
234
- event?.message?.model,
235
- event?.metadata?.model,
236
- event?.message?.metadata?.model
237
- );
238
- }
239
-
240
- function extractQoderEffort(event) {
241
- return firstTrimmedString(
242
- event?.reasoningEffort,
243
- event?.reasoning_effort,
244
- event?.effort,
245
- event?.metadata?.reasoningEffort,
246
- event?.metadata?.reasoning_effort,
247
- event?.message?.metadata?.reasoningEffort,
248
- event?.message?.metadata?.reasoning_effort
249
- );
250
- }
251
-
252
- function isoTimestamp(value) {
253
- if (typeof value === 'string') {
254
- const parsed = Date.parse(value);
255
- return Number.isFinite(parsed) ? new Date(parsed).toISOString() : '';
256
- }
257
- if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
258
- try {
259
- const date = new Date(value);
260
- return Number.isFinite(date.getTime()) ? date.toISOString() : '';
261
- } catch {
262
- return '';
263
- }
264
- }
265
- return '';
266
- }
267
-
268
- function qoderTextFromMessage(message) {
269
- if (typeof message === 'string') return message.trim();
270
- if (!message || typeof message !== 'object') return '';
271
- const content = message.content;
272
- if (typeof content === 'string') return content.trim();
273
- if (!Array.isArray(content)) return '';
274
- return content
275
- .map(part => {
276
- if (typeof part === 'string') return part;
277
- if (!part || typeof part !== 'object') return '';
278
- if (typeof part.text === 'string') return part.text;
279
- if (typeof part.content === 'string') return part.content;
280
- return '';
281
- })
282
- .join('\n')
283
- .trim();
284
- }
285
-
286
- function isVisibleAgentSession(session) {
287
- const provider = String(session?.provider || '').trim().toLowerCase();
288
- if (provider === 'claude') {
289
- if (isDefaultClaudeSessionTitle(session?.title)) return false;
290
- if (isAgentManagedWorktree(session?.cwd) || isAgentManagedWorktree(session?.workspace)) return false;
291
- }
292
-
293
- return !isTemporaryWorkspace(session?.cwd)
294
- && !isTemporaryWorkspace(session?.workspace)
295
- && !hasTemporaryWorkspaceReference(session?.title);
296
- }
297
-
298
- function activeScheduleFromMetadata(value, sessionId = '') {
299
- if (!value || typeof value !== 'object') return null;
300
- const rrule = typeof value.rrule === 'string' ? value.rrule.trim() : '';
301
- if (!rrule) return null;
302
-
303
- const targetThreadId = typeof value.target_thread_id === 'string'
304
- ? value.target_thread_id.trim()
305
- : typeof value.targetThreadId === 'string'
306
- ? value.targetThreadId.trim()
307
- : '';
308
- if (targetThreadId && sessionId && targetThreadId !== sessionId) return null;
309
-
310
- const rawStatus = typeof value.status === 'string' ? value.status.trim().toUpperCase() : '';
311
- const enabled = value.enabled !== false && value.active !== false;
312
- if (rawStatus && !['ACTIVE', 'ENABLED'].includes(rawStatus)) return null;
313
- if (!enabled) return null;
314
-
315
- return {
316
- id: typeof value.id === 'string' ? value.id.trim() : '',
317
- kind: typeof value.kind === 'string' ? value.kind.trim() : '',
318
- name: typeof value.name === 'string' ? value.name.trim() : '',
319
- status: rawStatus || 'ACTIVE',
320
- rrule,
321
- label: formatAutomationRRuleLabel(rrule),
322
- };
323
- }
324
-
325
- function scheduleFromClaudeEvent(event, sessionId) {
326
- const candidates = [
327
- event?.automation,
328
- event?.schedule,
329
- event?.metadata?.automation,
330
- event?.metadata?.schedule,
331
- event?.message?.metadata?.automation,
332
- event?.message?.metadata?.schedule,
333
- ];
334
-
335
- for (const candidate of candidates) {
336
- const schedule = activeScheduleFromMetadata(candidate, sessionId);
337
- if (schedule) return schedule;
338
- }
339
-
340
- return null;
341
- }
342
-
343
- async function collectRecentFiles(root, extension, limit, acceptFile = () => true) {
344
- const directories = [root];
345
- let files = [];
346
- let visitedDirectories = 0;
347
-
348
- while (directories.length > 0 && visitedDirectories < MAX_RECENT_FILE_SCAN_DIRECTORIES) {
349
- const directory = directories.pop();
350
- let entries = [];
351
- try {
352
- entries = await fsp.readdir(directory, { withFileTypes: true });
353
- } catch {
354
- continue;
355
- }
356
- visitedDirectories += 1;
357
- entries.sort((a, b) => {
358
- if (a.isDirectory() !== b.isDirectory()) return a.isDirectory() ? -1 : 1;
359
- return a.name.localeCompare(b.name);
360
- });
361
-
362
- for (const entry of entries) {
363
- const fullPath = path.join(directory, entry.name);
364
- if (entry.isDirectory()) {
365
- directories.push(fullPath);
366
- } else if (entry.isFile() && entry.name.endsWith(extension) && acceptFile(fullPath)) {
367
- let mtimeMs = 0;
368
- try {
369
- mtimeMs = (await fsp.stat(fullPath)).mtimeMs;
370
- } catch {
371
- mtimeMs = 0;
372
- }
373
- files.push({ filePath: fullPath, mtimeMs });
374
- if (files.length > limit * 2) {
375
- files = files.sort((a, b) => b.mtimeMs - a.mtimeMs).slice(0, limit);
376
- }
377
- }
378
- }
379
- }
380
-
381
- return files.sort((a, b) => b.mtimeMs - a.mtimeMs).slice(0, limit);
382
- }
383
-
384
- async function readTextTail(filePath, maxBytes) {
385
- let handle = null;
386
- try {
387
- const stat = await fsp.stat(filePath);
388
- const start = Math.max(0, stat.size - maxBytes);
389
- const length = stat.size - start;
390
- const buffer = Buffer.alloc(length);
391
- handle = await fsp.open(filePath, 'r');
392
- await handle.read(buffer, 0, length, start);
393
- const text = buffer.toString('utf8');
394
- return start > 0 ? text.replace(/^[^\n]*(\n|$)/, '') : text;
395
- } catch {
396
- return '';
397
- } finally {
398
- if (handle) {
399
- await handle.close().catch(() => {});
400
- }
401
- }
402
- }
403
-
404
- async function readClaudePromptHistory(claudeHome) {
405
- const historyPath = path.join(claudeHome, 'history.jsonl');
406
- const entries = new Map();
407
-
408
- const lines = (await readTextTail(historyPath, CLAUDE_HISTORY_TAIL_BYTES)).split('\n').filter(Boolean);
409
- for (const line of lines) {
410
- try {
411
- const entry = JSON.parse(line);
412
- if (!entry || typeof entry.sessionId !== 'string') continue;
413
- entries.set(entry.sessionId, {
414
- title: typeof entry.display === 'string' ? entry.display.trim() : '',
415
- workspace: typeof entry.project === 'string' ? normalizePathValue(entry.project) : '',
416
- updatedAt: typeof entry.timestamp === 'string' ? entry.timestamp : '',
417
- });
418
- } catch {
419
- // Ignore individual corrupt prompt history lines.
420
- }
421
- }
422
-
423
- return entries;
424
- }
425
-
426
- function claudeSessionIdFromFilePath(filePath) {
427
- const match = path.basename(filePath).match(/^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i);
428
- return match ? match[1] : '';
429
- }
430
-
431
- async function readClaudeSessionMetadata(filePath, promptHistory, maxLines = 160) {
432
- const stream = fs.createReadStream(filePath, { encoding: 'utf8' });
433
- const reader = readline.createInterface({ input: stream, crlfDelay: Infinity });
434
- const fileSessionId = claudeSessionIdFromFilePath(filePath);
435
- const metadata = {
436
- filePath,
437
- id: fileSessionId,
438
- title: '',
439
- cwd: '',
440
- workspace: '',
441
- createdAt: '',
442
- updatedAt: '',
443
- model: '',
444
- effort: '',
445
- source: '',
446
- schedule: null,
447
- };
448
- let lineCount = 0;
449
-
450
- try {
451
- for await (const line of reader) {
452
- if (!line) continue;
453
- lineCount += 1;
454
-
455
- try {
456
- const event = JSON.parse(line);
457
- if (typeof event.sessionId === 'string') {
458
- metadata.id = event.sessionId;
459
- }
460
- if (typeof event.timestamp === 'string') {
461
- metadata.updatedAt = event.timestamp;
462
- metadata.createdAt = metadata.createdAt || event.timestamp;
463
- }
464
- if (typeof event.cwd === 'string' && event.cwd.trim()) {
465
- metadata.cwd = normalizePathValue(event.cwd);
466
- }
467
- if (typeof event.entrypoint === 'string' && event.entrypoint.trim()) {
468
- metadata.source = event.entrypoint.trim();
469
- }
470
- if (event.type === 'ai-title' && typeof event.aiTitle === 'string' && event.aiTitle.trim()) {
471
- metadata.title = event.aiTitle.trim();
472
- }
473
- metadata.model = extractClaudeModel(event) || metadata.model;
474
- metadata.effort = extractClaudeEffort(event) || metadata.effort;
475
- if (!metadata.schedule) {
476
- metadata.schedule = scheduleFromClaudeEvent(event, metadata.id || fileSessionId);
477
- }
478
- } catch {
479
- // Ignore individual corrupt session lines.
480
- }
481
-
482
- if (lineCount >= maxLines || (metadata.id && metadata.title && metadata.cwd && metadata.model)) {
483
- break;
484
- }
485
- }
486
- } finally {
487
- reader.close();
488
- stream.destroy();
489
- }
490
-
491
- if (!metadata.id) return null;
492
-
493
- const indexed = promptHistory.get(metadata.id);
494
- metadata.title = metadata.title || indexed?.title || 'Claude session';
495
- metadata.workspace = normalizePathValue(indexed?.workspace || metadata.cwd || '');
496
- metadata.updatedAt = metadata.updatedAt || indexed?.updatedAt || '';
497
- metadata.source = metadata.source || 'claude';
498
-
499
- return metadata;
500
- }
501
-
502
- async function listClaudeSessions(options = {}) {
503
- const claudeHome = options.claudeHome || path.join(os.homedir(), '.claude');
504
- const limit = Number.isFinite(options.limit)
505
- ? Math.max(0, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
506
- : DEFAULT_LIMIT;
507
- const scanLimit = Number.isFinite(options.scanLimit)
508
- ? Math.max(limit, Math.min(MAX_AGENT_SESSION_SCAN_LIMIT, Math.floor(options.scanLimit)))
509
- : DEFAULT_SCAN_LIMIT;
510
- const promptHistory = await readClaudePromptHistory(claudeHome);
511
- const sessionFiles = await collectRecentFiles(path.join(claudeHome, 'projects'), '.jsonl', scanLimit);
512
-
513
- const sessions = [];
514
- for (const { filePath, mtimeMs } of sessionFiles) {
515
- const metadata = await readClaudeSessionMetadata(filePath, promptHistory);
516
- if (!metadata) continue;
517
- const mtimeIso = mtimeMs > 0 ? new Date(mtimeMs).toISOString() : '';
518
- const updatedAt = timestampMs(mtimeIso) > timestampMs(metadata.updatedAt)
519
- ? mtimeIso
520
- : (metadata.updatedAt || mtimeIso);
521
- const session = {
522
- provider: 'claude',
523
- providerName: 'Claude',
524
- id: metadata.id,
525
- title: metadata.title,
526
- cwd: metadata.cwd,
527
- workspace: metadata.workspace,
528
- updatedAt,
529
- createdAt: metadata.createdAt,
530
- archived: false,
531
- pinned: false,
532
- unread: false,
533
- projectless: !metadata.workspace,
534
- model: metadata.model,
535
- effort: metadata.effort,
536
- source: metadata.source,
537
- schedule: metadata.schedule || undefined,
538
- capabilities: ['resume', 'fork'],
539
- };
540
- if (isVisibleAgentSession(session)) {
541
- sessions.push(session);
542
- }
543
- }
544
-
545
- return sessions
546
- .sort((a, b) => timestampMs(b.updatedAt) - timestampMs(a.updatedAt))
547
- .slice(0, limit);
548
- }
549
-
550
- function qoderSessionIdFromFilePath(filePath) {
551
- const match = path.basename(filePath).match(/^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i);
552
- return match ? match[1] : '';
553
- }
554
-
555
- function applyQoderSessionEvent(metadata, event, fileSessionId) {
556
- if (!event || typeof event !== 'object') return;
557
- const eventSessionId = typeof event.sessionId === 'string'
558
- ? event.sessionId
559
- : typeof event.session_id === 'string'
560
- ? event.session_id
561
- : '';
562
- if (eventSessionId && isSafeProviderSessionId(eventSessionId)) {
563
- metadata.id = eventSessionId;
564
- }
565
-
566
- const timestamp = isoTimestamp(event.timestamp);
567
- if (timestamp) {
568
- metadata.updatedAt = timestamp;
569
- metadata.createdAt = metadata.createdAt || timestamp;
570
- }
571
-
572
- if (typeof event.cwd === 'string' && event.cwd.trim()) {
573
- metadata.cwd = normalizePathValue(event.cwd);
574
- }
575
- if (typeof event.entrypoint === 'string' && event.entrypoint.trim()) {
576
- metadata.source = event.entrypoint.trim();
577
- }
578
- if (event.type === 'system' && typeof event.qodercli_version === 'string') {
579
- metadata.cliVersion = event.qodercli_version.trim();
580
- }
581
- if (typeof event.version === 'string' && event.version.trim()) {
582
- metadata.cliVersion = event.version.trim();
583
- }
584
- if (event.type === 'runtime-config' && typeof event.version === 'string') {
585
- metadata.cliVersion = event.version.trim();
586
- }
587
- if (event.type === 'ai-title' && typeof event.aiTitle === 'string' && event.aiTitle.trim()) {
588
- metadata.title = event.aiTitle.trim();
589
- }
590
- if (event.type === 'last-prompt' && typeof event.lastPrompt === 'string' && event.lastPrompt.trim()) {
591
- metadata.lastPrompt = event.lastPrompt.trim();
592
- }
593
- if (!metadata.firstPrompt && event.type === 'user') {
594
- metadata.firstPrompt = qoderTextFromMessage(event.message);
595
- }
596
-
597
- metadata.model = extractQoderModel(event) || metadata.model;
598
- metadata.effort = extractQoderEffort(event) || metadata.effort;
599
-
600
- if (!metadata.id && fileSessionId) {
601
- metadata.id = fileSessionId;
602
- }
603
- }
604
-
605
- async function readQoderSessionMetadata(filePath, maxLines = 160) {
606
- const fileSessionId = qoderSessionIdFromFilePath(filePath);
607
- const metadata = {
608
- filePath,
609
- id: fileSessionId,
610
- title: '',
611
- lastPrompt: '',
612
- firstPrompt: '',
613
- cwd: '',
614
- workspace: '',
615
- createdAt: '',
616
- updatedAt: '',
617
- model: '',
618
- effort: '',
619
- source: '',
620
- cliVersion: '',
621
- };
622
-
623
- const stream = fs.createReadStream(filePath, { encoding: 'utf8' });
624
- const reader = readline.createInterface({ input: stream, crlfDelay: Infinity });
625
- let lineCount = 0;
626
-
627
- try {
628
- for await (const line of reader) {
629
- if (!line) continue;
630
- lineCount += 1;
631
- try {
632
- applyQoderSessionEvent(metadata, JSON.parse(line), fileSessionId);
633
- } catch {
634
- // Ignore individual corrupt session lines.
635
- }
636
- if (lineCount >= maxLines || (metadata.id && metadata.cwd && metadata.model && metadata.title)) {
637
- break;
638
- }
639
- }
640
- } finally {
641
- reader.close();
642
- stream.destroy();
643
- }
644
-
645
- const tail = await readTextTail(filePath, QODER_HISTORY_TAIL_BYTES);
646
- for (const line of tail.split('\n').filter(Boolean)) {
647
- try {
648
- applyQoderSessionEvent(metadata, JSON.parse(line), fileSessionId);
649
- } catch {
650
- // Ignore individual corrupt session lines.
651
- }
652
- }
653
-
654
- if (!metadata.id || !isSafeProviderSessionId(metadata.id)) return null;
655
- metadata.title = firstTrimmedString(metadata.title, metadata.lastPrompt, metadata.firstPrompt, 'Qoder session');
656
- metadata.workspace = normalizePathValue(metadata.cwd || '');
657
- metadata.source = metadata.source || 'qodercli';
658
-
659
- return metadata;
660
- }
661
-
662
- async function listQoderSessions(options = {}) {
663
- const qoderHome = options.qoderHome || path.join(os.homedir(), '.qoder');
664
- const limit = Number.isFinite(options.limit)
665
- ? Math.max(0, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
666
- : DEFAULT_LIMIT;
667
- const scanLimit = Number.isFinite(options.scanLimit)
668
- ? Math.max(limit, Math.min(MAX_AGENT_SESSION_SCAN_LIMIT, Math.floor(options.scanLimit)))
669
- : DEFAULT_SCAN_LIMIT;
670
- const projectsRoot = path.join(qoderHome, 'projects');
671
- // Child-agent transcripts live deeper under <project>/<session-id>/subagents
672
- // and may repeat the parent id, so only count direct project session files.
673
- const sessionFiles = await collectRecentFiles(
674
- projectsRoot,
675
- '.jsonl',
676
- scanLimit,
677
- filePath => path.relative(projectsRoot, filePath).split(path.sep).length === 2
678
- );
679
-
680
- const sessions = [];
681
- for (const { filePath, mtimeMs } of sessionFiles) {
682
- const metadata = await readQoderSessionMetadata(filePath);
683
- if (!metadata) continue;
684
- const mtimeIso = mtimeMs > 0 ? new Date(mtimeMs).toISOString() : '';
685
- const updatedAt = timestampMs(mtimeIso) > timestampMs(metadata.updatedAt)
686
- ? mtimeIso
687
- : (metadata.updatedAt || mtimeIso);
688
- const session = {
689
- provider: 'qoder',
690
- providerName: 'Qoder',
691
- id: metadata.id,
692
- title: metadata.title,
693
- cwd: metadata.cwd,
694
- workspace: metadata.workspace,
695
- updatedAt,
696
- createdAt: metadata.createdAt,
697
- archived: false,
698
- pinned: false,
699
- unread: false,
700
- projectless: !metadata.workspace,
701
- model: metadata.model,
702
- effort: metadata.effort,
703
- source: metadata.source,
704
- cliVersion: metadata.cliVersion,
705
- capabilities: ['resume', 'fork'],
706
- };
707
- if (isVisibleAgentSession(session)) {
708
- sessions.push(session);
709
- }
710
- }
711
-
712
- return sessions
713
- .sort((a, b) => timestampMs(b.updatedAt) - timestampMs(a.updatedAt))
714
- .slice(0, limit);
715
- }
716
-
717
- function runOpenCodeSessionList(options = {}) {
718
- const executable = options.opencodeBin || process.env.FARMING_OPENCODE_BIN || 'opencode';
719
- const maxCount = Number.isFinite(options.maxCount) ? Math.max(1, Math.floor(options.maxCount)) : DEFAULT_SCAN_LIMIT;
720
- const env = { ...process.env };
721
- if (options.opencodeHome) env.OPENCODE_CONFIG_DIR = options.opencodeHome;
722
- return new Promise((resolve, reject) => {
723
- execFile(executable, ['session', 'list', '--format', 'json', '--max-count', String(maxCount)], {
724
- env,
725
- maxBuffer: 4 * 1024 * 1024,
726
- timeout: 15_000,
727
- }, (error, stdout) => {
728
- if (error) {
729
- reject(error);
730
- return;
731
- }
732
- resolve(stdout);
733
- });
734
- });
735
- }
736
-
737
- async function listOpenCodeSessions(options = {}) {
738
- const limit = Number.isFinite(options.limit)
739
- ? Math.max(0, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
740
- : DEFAULT_LIMIT;
741
- const scanLimit = Number.isFinite(options.scanLimit)
742
- ? Math.max(limit, Math.min(MAX_AGENT_SESSION_SCAN_LIMIT, Math.floor(options.scanLimit)))
743
- : DEFAULT_SCAN_LIMIT;
744
- const listCommand = options.runOpenCodeSessionList || runOpenCodeSessionList;
745
- let rawSessions = [];
746
- try {
747
- const output = await listCommand({
748
- maxCount: scanLimit,
749
- opencodeBin: options.opencodeBin,
750
- opencodeHome: options.opencodeHome,
751
- });
752
- rawSessions = JSON.parse(String(output || '[]'));
753
- } catch {
754
- return [];
755
- }
756
- if (!Array.isArray(rawSessions)) return [];
757
-
758
- return rawSessions
759
- .map(raw => {
760
- const id = firstTrimmedString(raw?.id);
761
- const cwd = normalizePathValue(raw?.directory || '');
762
- if (!id || !isSafeProviderSessionId(id)) return null;
763
- return {
764
- provider: 'opencode',
765
- providerName: 'OpenCode',
766
- id,
767
- title: firstTrimmedString(raw?.title, 'OpenCode session'),
768
- cwd,
769
- workspace: cwd,
770
- updatedAt: isoTimestamp(raw?.updated),
771
- createdAt: isoTimestamp(raw?.created),
772
- archived: false,
773
- pinned: false,
774
- unread: false,
775
- projectless: !cwd,
776
- source: 'opencode',
777
- capabilities: ['resume', 'fork'],
778
- };
779
- })
780
- .filter(session => session && isVisibleAgentSession(session))
781
- .sort((a, b) => timestampMs(b.updatedAt) - timestampMs(a.updatedAt))
782
- .slice(0, limit);
783
- }
784
-
785
- function normalizeCodexSession(session) {
786
- return {
787
- provider: 'codex',
788
- providerName: 'Codex',
789
- ...session,
790
- capabilities: ['resume', 'fork'],
791
- };
792
- }
793
-
794
- function normalizeProvider(provider) {
795
- const normalized = String(provider || '').trim().toLowerCase();
796
- return PROVIDERS.has(normalized) ? normalized : '';
797
- }
798
-
799
- function isSafeSessionId(sessionId) {
800
- return isSafeProviderSessionId(sessionId);
801
- }
802
-
803
- function buildAgentSessionResumeCommand(provider, sessionId, options = {}) {
804
- const normalizedProvider = normalizeProvider(provider);
805
- const normalizedSessionId = String(sessionId || '').trim();
806
- if (!normalizedProvider || !isSafeSessionId(normalizedSessionId)) return '';
807
-
808
- if (normalizedProvider === 'codex') {
809
- const cwd = normalizePathValue(options.cwd);
810
- const modelProvider = String(
811
- options.modelProvider
812
- || (Object.prototype.hasOwnProperty.call(options, 'providerHomePath')
813
- ? resolveCodexResumeModelProvider(options.providerHomePath)
814
- : '')
815
- ).trim();
816
- const providerArgs = modelProvider
817
- ? ` -c ${quoteCommandArg(`model_provider=${JSON.stringify(modelProvider)}`)}`
818
- : '';
819
- const cwdArgs = cwd ? ` -C ${quoteCommandArg(cwd)}` : '';
820
- return `codex ${options.fork === true ? 'fork' : 'resume'}${providerArgs}${cwdArgs} ${normalizedSessionId}`;
821
- }
822
-
823
- if (normalizedProvider === 'claude') {
824
- return options.fork === true
825
- ? `claude --resume ${normalizedSessionId} --fork-session`
826
- : `claude --resume ${normalizedSessionId}`;
827
- }
828
-
829
- if (normalizedProvider === 'qoder') {
830
- return options.fork === true
831
- ? `qodercli --resume ${normalizedSessionId} --fork-session`
832
- : `qodercli --resume ${normalizedSessionId}`;
833
- }
834
-
835
- if (normalizedProvider === 'opencode') {
836
- return `opencode --session ${normalizedSessionId}${options.fork === true ? ' --fork' : ''}`;
837
- }
838
-
839
- return '';
840
- }
841
-
842
- async function listAgentSessions(options = {}) {
843
- const limit = Number.isFinite(options.limit)
844
- ? Math.max(0, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
845
- : DEFAULT_LIMIT;
846
- const requestedProviders = Array.isArray(options.providers)
847
- ? options.providers.map(normalizeProvider).filter(Boolean)
848
- : ['codex', 'claude', 'opencode', 'qoder'];
849
- const providers = Array.from(new Set(requestedProviders));
850
- const sessions = [];
851
-
852
- const providerHomes = options.providerHomes && typeof options.providerHomes === 'object'
853
- ? options.providerHomes
854
- : {};
855
-
856
- async function listForHomes(provider, homes, fallbackHomeKey, listFn, homeOptionKey, normalize = session => session) {
857
- const configuredHomes = Array.isArray(homes) && homes.length > 0
858
- ? homes
859
- : [{ id: 'default', path: options[fallbackHomeKey] }];
860
- const perHomeLimit = Number.isFinite(options.providerLimit)
861
- ? Math.max(0, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.providerLimit)))
862
- : limit;
863
- for (const home of configuredHomes) {
864
- const providerHomeId = String(home && home.id || 'default').trim() || 'default';
865
- const providerHomePath = String(home && home.path || '').trim();
866
- const listOptions = {
867
- limit: perHomeLimit,
868
- scanLimit: options.scanLimit,
869
- opencodeBin: options.opencodeBin,
870
- runOpenCodeSessionList: options.runOpenCodeSessionList,
871
- };
872
- if (providerHomePath) listOptions[homeOptionKey] = providerHomePath;
873
- const homeSessions = await listFn(listOptions);
874
- sessions.push(...homeSessions.map(session => normalize({
875
- ...session,
876
- providerHomeId,
877
- providerHomePath,
878
- })).filter(isVisibleAgentSession));
879
- }
880
- }
881
-
882
- if (providers.includes('codex')) {
883
- await listForHomes('codex', providerHomes.codex, 'codexHome', listCodexSessions, 'codexHome', normalizeCodexSession);
884
- }
885
-
886
- if (providers.includes('claude')) {
887
- await listForHomes('claude', providerHomes.claude, 'claudeHome', listClaudeSessions, 'claudeHome');
888
- }
889
-
890
- if (providers.includes('qoder')) {
891
- await listForHomes('qoder', providerHomes.qoder, 'qoderHome', listQoderSessions, 'qoderHome');
892
- }
893
-
894
- if (providers.includes('opencode')) {
895
- const configuredHomes = Array.isArray(providerHomes.opencode) && providerHomes.opencode.length > 0
896
- ? providerHomes.opencode
897
- : [{ id: 'default', path: options.opencodeHome }];
898
- const home = configuredHomes.find(candidate => String(candidate?.id || '') === 'default') || configuredHomes[0];
899
- const providerHomeId = String(home?.id || 'default').trim() || 'default';
900
- const providerHomePath = String(home?.path || '').trim();
901
- const homeSessions = await listOpenCodeSessions({
902
- limit: Number.isFinite(options.providerLimit) ? options.providerLimit : limit,
903
- scanLimit: options.scanLimit,
904
- opencodeBin: options.opencodeBin,
905
- opencodeHome: providerHomePath,
906
- runOpenCodeSessionList: options.runOpenCodeSessionList,
907
- });
908
- sessions.push(...homeSessions.map(session => ({
909
- ...session,
910
- providerHomeId,
911
- providerHomePath,
912
- })));
913
- }
914
-
915
- return sessions
916
- .sort(compareAgentSessions)
917
- .slice(0, limit);
918
- }
919
-
920
- async function findAgentSession(provider, sessionId, options = {}) {
921
- const normalizedProvider = normalizeProvider(provider);
922
- const normalizedSessionId = String(sessionId || '').trim();
923
- if (!normalizedProvider || !isSafeSessionId(normalizedSessionId)) return null;
924
-
925
- const sessions = await listAgentSessions({
926
- ...options,
927
- providers: [normalizedProvider],
928
- limit: options.limit || 200,
929
- providerLimit: options.providerLimit || 200,
930
- });
931
- const requestedHomeId = typeof options.providerHomeId === 'string' ? options.providerHomeId.trim() : '';
932
- return sessions.find(session => session.id === normalizedSessionId && (!requestedHomeId || (session.providerHomeId || 'default') === requestedHomeId)) || null;
933
- }
934
-
935
- module.exports = {
936
- buildAgentSessionResumeCommand,
937
- compareAgentSessions,
938
- findAgentSession,
939
- hasTemporaryWorkspaceReference,
940
- isAgentManagedWorktree,
941
- isDefaultClaudeSessionTitle,
942
- isSafeSessionId,
943
- isTemporaryWorkspace,
944
- isVisibleAgentSession,
945
- listAgentSessions,
946
- listClaudeSessions,
947
- listOpenCodeSessions,
948
- listQoderSessions,
949
- normalizeProvider,
950
- paginateAgentSessions,
951
- resolveCodexResumeModelProvider,
952
- searchAgentSessions,
953
- };