farming-code 2.2.30 → 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.
- package/THIRD_PARTY_NOTICES.md +7 -0
- package/backend/acp/{client-services.js → client-services.cjs} +132 -134
- package/backend/acp/packaged-claude-acp.cjs +37 -0
- package/backend/acp/packaged-codex-acp.cjs +37 -0
- package/backend/acp/patch-decisions.cjs +182 -0
- package/backend/acp/permission-security.cjs +131 -0
- package/backend/{acp-checkpoint-store.js → acp-checkpoint-store.cjs} +90 -59
- package/backend/{acp-runtime.js → acp-runtime.cjs} +1220 -1112
- package/backend/acp-session-state.cjs +622 -0
- package/backend/acp-transcript.cjs +525 -0
- package/backend/agent-env.cjs +257 -0
- package/backend/agent-extension-discovery.cjs +452 -0
- package/backend/agent-extension-inventory.cjs +116 -0
- package/backend/agent-json-stream.cjs +283 -0
- package/backend/agent-lifecycle-journal.cjs +185 -0
- package/backend/{agent-manager.js → agent-manager.cjs} +3116 -4275
- package/backend/agent-order-transaction.cjs +85 -0
- package/backend/agent-order.cjs +159 -0
- package/backend/agent-provider-session.cjs +98 -0
- package/backend/agent-runtime-binding.cjs +179 -0
- package/backend/agent-session-history.cjs +1022 -0
- package/backend/agent-session-inventory.cjs +291 -0
- package/backend/async-cache.cjs +104 -0
- package/backend/atomic-json-store.cjs +67 -0
- package/backend/auth.cjs +261 -0
- package/backend/authoritative-inventory-cache.cjs +383 -0
- package/backend/business-health.cjs +68 -0
- package/backend/chat-runtime.cjs +50 -0
- package/backend/claude-settings.cjs +132 -0
- package/backend/cli-agents.cjs +435 -0
- package/backend/codex-context-window.cjs +196 -0
- package/backend/codex-models.cjs +228 -0
- package/backend/codex-session-archive.cjs +82 -0
- package/backend/codex-session-history.cjs +590 -0
- package/backend/{codex-terminal-profile.js → codex-terminal-profile.cjs} +149 -155
- package/backend/codex-transcript-sanitizer.cjs +130 -0
- package/backend/codex-transcript.cjs +2107 -0
- package/backend/command-runner-child.cjs +105 -0
- package/backend/config-manager.cjs +1263 -0
- package/backend/control-api.cjs +439 -0
- package/backend/data/LICENSE.cua +21 -0
- package/backend/executable-discovery.cjs +204 -0
- package/backend/farming-agent-bootstrap.cjs +81 -0
- package/backend/farming-agent-bootstrap.zh_cn.md +6 -2
- package/backend/{farming-app-cli.js → farming-app-cli.cjs} +441 -493
- package/backend/farming-cli.cjs +414 -0
- package/backend/farming-net-pass.cjs +319 -0
- package/backend/farming-net-registry.cjs +123 -0
- package/backend/farming-net-server.cjs +309 -0
- package/backend/farming-session-store.cjs +651 -0
- package/backend/git-worktree-info.cjs +181 -0
- package/backend/haiku-token.cjs +828 -0
- package/backend/index-html.cjs +96 -0
- package/backend/input-parts.cjs +68 -0
- package/backend/input-routing.cjs +40 -0
- package/backend/{local-session-engine.js → local-session-engine.cjs} +276 -282
- package/backend/main-agent-skills.cjs +309 -0
- package/backend/main-page-session.cjs +132 -0
- package/backend/native-pty-controller-generation.cjs +139 -0
- package/backend/{native-pty-host-client.js → native-pty-host-client.cjs} +338 -346
- package/backend/native-pty-host-identity.cjs +125 -0
- package/backend/native-pty-host-path.cjs +68 -0
- package/backend/{native-pty-host.js → native-pty-host.cjs} +480 -569
- package/backend/native-session-engine.cjs +296 -0
- package/backend/network.cjs +57 -0
- package/backend/npm-update-helper.cjs +399 -0
- package/backend/packaged-node-pty.cjs +120 -0
- package/backend/preview-session-manager.cjs +89 -0
- package/backend/provider-adapters.cjs +492 -0
- package/backend/provider-home-configuration.cjs +211 -0
- package/backend/provider-session-id.cjs +79 -0
- package/backend/provider-session-service.cjs +333 -0
- package/backend/qr-share-tickets.cjs +119 -0
- package/backend/resource-broadcast-protocol.cjs +50 -0
- package/backend/review-diff-router.cjs +202 -0
- package/backend/review-diff-service.cjs +1267 -0
- package/backend/review-session-router.cjs +93 -0
- package/backend/review-session-service.cjs +470 -0
- package/backend/review-session-store.cjs +161 -0
- package/backend/review-state-router.cjs +132 -0
- package/backend/review-state-store.cjs +299 -0
- package/backend/run-history-store.cjs +97 -0
- package/backend/runtime-dependency-manager.cjs +893 -0
- package/backend/runtime-executable-invocation.cjs +37 -0
- package/backend/runtime-observation.cjs +96 -0
- package/backend/server-process-identity.cjs +70 -0
- package/backend/server.cjs +3356 -0
- package/backend/session-engine-bridge.cjs +144 -0
- package/backend/session-engine-router.cjs +105 -0
- package/backend/session-engine.cjs +64 -0
- package/backend/session-stream-protocol.cjs +181 -0
- package/backend/shell-busy-integration.cjs +442 -0
- package/backend/slash-command-discovery.cjs +423 -0
- package/backend/storage-layout.cjs +263 -0
- package/backend/system-monitor.cjs +96 -0
- package/backend/terminal-attach-checkpoint.cjs +73 -0
- package/backend/terminal-exit-quiescence.cjs +57 -0
- package/backend/{terminal-reducer-flow-control.js → terminal-reducer-flow-control.cjs} +45 -22
- package/backend/terminal-runtime-cleanup.cjs +99 -0
- package/backend/{terminal-screen-state.js → terminal-screen-state.cjs} +100 -108
- package/backend/{terminal-screen-worker-pool.js → terminal-screen-worker-pool.cjs} +89 -79
- package/backend/{terminal-screen-worker-thread.js → terminal-screen-worker-thread.cjs} +64 -65
- package/backend/terminal-screen-worker.cjs +352 -0
- package/backend/terminal-state-serialization.cjs +147 -0
- package/backend/{terminal-status.js → terminal-status.cjs} +137 -187
- package/backend/theme-manager.cjs +185 -0
- package/backend/{update-service.js → update-service.cjs} +258 -248
- package/backend/usage-forecast.cjs +95 -0
- package/backend/{usage-history-client.js → usage-history-client.cjs} +144 -94
- package/backend/usage-history-smoke.cjs +85 -0
- package/backend/usage-history-worker.cjs +60 -0
- package/backend/{usage-monitor.js → usage-monitor.cjs} +363 -390
- package/backend/workspace-directory.cjs +239 -0
- package/backend/workspace-discovery.cjs +271 -0
- package/backend/{workspace-file-router.js → workspace-file-router.cjs} +213 -282
- package/backend/{workspace-file-service.js → workspace-file-service.cjs} +1139 -1318
- package/backend/workspace-root-registry.cjs +192 -0
- package/bin/farming +1 -1
- package/dist/acp/codex-acp-1.1.4.mjs +18 -1
- package/dist/assets/App-BCkdpWB6.css +1 -0
- package/dist/assets/App-CRjKpaGp.js +697 -0
- package/dist/assets/CodeSelect-Ci8sKZPU.js +1 -0
- package/dist/assets/CodeSelect-T2eNzrOc.css +1 -0
- package/dist/assets/{FileEditorMarkdownPreview-Cs9cLv8a.js → FileEditorMarkdownPreview-V06QHlAg.js} +55 -55
- package/dist/assets/FileEditorPane-BX-Wjg9U.js +2 -0
- package/dist/assets/IconGlyphs-YhV7tqd4.js +1 -0
- package/dist/assets/ProjectFilesSection-BDT2_r0o.js +12 -0
- package/dist/assets/ReviewPage-BqAs5sG1.js +3 -0
- package/dist/assets/code-dark-B7eM_9G9.css +1 -0
- package/dist/assets/{cssMode-Bdg5RpcJ.js → cssMode-ADdAlxTO.js} +1 -1
- package/dist/assets/{editor.api2-D74ufkbr.js → editor.api2-BFLAr0YF.js} +162 -162
- package/dist/assets/file-icons-BpeqWkIB.js +1 -0
- package/dist/assets/{freemarker2-DfMDJfnE.js → freemarker2-C90q5jrp.js} +1 -1
- package/dist/assets/{handlebars-BEdPtzMT.js → handlebars-BwUQcEDq.js} +1 -1
- package/dist/assets/{html-B1fPb1QD.js → html-1s3uPKfh.js} +1 -1
- package/dist/assets/{htmlMode-CY2ZjHxH.js → htmlMode-xtKD99de.js} +1 -1
- package/dist/assets/{index-D-zetSol.js → index-C8MchCem.js} +3 -3
- package/dist/assets/{javascript-BV2OsWA0.js → javascript-Ph7ijyny.js} +1 -1
- package/dist/assets/{jsonMode-zd07aeuX.js → jsonMode-D-jGAnFH.js} +1 -1
- package/dist/assets/linkComputer-CbGyI_qx.js +1 -0
- package/dist/assets/{liquid-BParI24X.js → liquid-0IamE_cI.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-BzredkoV.js → lspLanguageFeatures-BxnQunWF.js} +1 -1
- package/dist/assets/main-CLKXa6hf.css +1 -0
- package/dist/assets/{mdx-vGzUJN98.js → mdx-DdNmfivn.js} +1 -1
- package/dist/assets/{monaco.contribution-BmaeBQEc.js → monaco.contribution-B43jsUs1.js} +2 -2
- package/dist/assets/{python-CUwdLgsI.js → python-IAt4X5TS.js} +1 -1
- package/dist/assets/{razor-BScebUxU.js → razor-DRkFYW0S.js} +1 -1
- package/dist/assets/review-C8-oPKXk.css +1 -0
- package/dist/assets/{tsMode-DzUAibXK.js → tsMode-_d_4U2gf.js} +1 -1
- package/dist/assets/{typescript-D9EOeM7N.js → typescript-C7zcMq9l.js} +1 -1
- package/dist/assets/{workers-DAiomYZM.js → workers-D0nOyJzf.js} +1 -1
- package/dist/assets/workspace-editor-model-DND_Y-Bj.js +1 -0
- package/dist/assets/workspace-editor-monaco-BPWhgcIB.js +4 -0
- package/dist/assets/workspace-editor-monaco-N641qPjX.js +1 -0
- package/dist/assets/workspace-view-state-k1bTlJ_Z.js +13 -0
- package/dist/assets/{xml-wWl1dhkQ.js → xml-BR-HvxT8.js} +1 -1
- package/dist/assets/{yaml-Dc2WDaOZ.js → yaml-YtFQwh4q.js} +1 -1
- package/dist/index.html +1 -1
- package/extensions/browser/backend/agent-browser-runtime.cjs +1040 -0
- package/extensions/browser/backend/agent-capability.cjs +85 -0
- package/extensions/browser/backend/browser-mcp-server.cjs +655 -0
- package/extensions/browser/backend/browser-resource-manager.cjs +1486 -0
- package/extensions/browser/backend/browser-resource-store.cjs +228 -0
- package/extensions/browser/backend/browser-router.cjs +203 -0
- package/extensions/browser/backend/executable-discovery.cjs +248 -0
- package/extensions/browser/backend/farming-browser-client.cjs +116 -0
- package/extensions/browser/backend/index.cjs +32 -0
- package/extensions/browser/backend/managed-chromium-installer.cjs +833 -0
- package/extensions/browser/bin/farming-browser +16 -7
- package/extensions/computer/backend/agent-capability.cjs +72 -0
- package/extensions/computer/backend/computer-constants.cjs +59 -0
- package/extensions/computer/backend/computer-mcp-server.cjs +182 -0
- package/extensions/computer/backend/computer-resource-manager.cjs +1219 -0
- package/extensions/computer/backend/computer-resource-store.cjs +190 -0
- package/extensions/computer/backend/computer-router.cjs +257 -0
- package/extensions/computer/backend/cua-tools.json +3067 -0
- package/extensions/computer/backend/farming-computer-client.cjs +84 -0
- package/extensions/computer/backend/index.cjs +35 -0
- package/extensions/computer/backend/isolated-browser-provider.cjs +157 -0
- package/extensions/computer/bin/farming-computer +131 -0
- package/frontend/farming-net/app.js +255 -262
- package/frontend/ghostty-loader.js +24 -20
- package/frontend/reading-anchor.js +210 -193
- package/frontend/runtime-paths.js +24 -26
- package/frontend/session-bridge.js +90 -111
- package/frontend/session-modal-bridge.js +184 -302
- package/frontend/skin-bridge.js +20 -23
- package/frontend/skins/crt/app.js +7686 -7901
- package/frontend/skins/crt/effects.js +7 -6
- package/frontend/skins/crt/index.html +6 -6
- package/frontend/skins/crt/styles/markdown.css +4 -4
- package/frontend/terminal-bridge.js +174 -181
- package/frontend/terminal-replay.js +320 -345
- package/frontend/theme-loader.js +55 -71
- package/package.json +64 -37
- package/shared/backend-connection-status.js +38 -69
- package/shared/browser-protocol.js +235 -110
- package/shared/websocket-liveness.js +40 -0
- package/backend/acp/packaged-claude-acp.js +0 -13
- package/backend/acp/packaged-codex-acp.js +0 -13
- package/backend/acp/patch-decisions.js +0 -153
- package/backend/acp/permission-security.js +0 -108
- package/backend/acp-session-state.js +0 -634
- package/backend/acp-transcript.js +0 -512
- package/backend/agent-env.js +0 -250
- package/backend/agent-json-stream.js +0 -268
- package/backend/agent-lifecycle-journal.js +0 -133
- package/backend/agent-order.js +0 -166
- package/backend/agent-provider-session.js +0 -76
- package/backend/agent-runtime-binding.js +0 -174
- package/backend/agent-session-history.js +0 -986
- package/backend/async-cache.js +0 -94
- package/backend/atomic-json-store.js +0 -37
- package/backend/auth.js +0 -251
- package/backend/chat-runtime.js +0 -28
- package/backend/claude-settings.js +0 -121
- package/backend/cli-agents.js +0 -486
- package/backend/codex-context-window.js +0 -189
- package/backend/codex-models.js +0 -226
- package/backend/codex-session-archive.js +0 -65
- package/backend/codex-session-history.js +0 -647
- package/backend/codex-transcript-sanitizer.js +0 -115
- package/backend/codex-transcript.js +0 -2362
- package/backend/command-runner-child.js +0 -67
- package/backend/config-manager.js +0 -1117
- package/backend/control-api.js +0 -455
- package/backend/executable-discovery.js +0 -216
- package/backend/farming-agent-bootstrap.js +0 -49
- package/backend/farming-cli.js +0 -403
- package/backend/farming-net-pass.js +0 -285
- package/backend/farming-net-registry.js +0 -112
- package/backend/farming-net-server.js +0 -298
- package/backend/farming-session-store.js +0 -677
- package/backend/git-worktree-info.js +0 -181
- package/backend/haiku-token.js +0 -772
- package/backend/index-html.js +0 -80
- package/backend/input-parts.js +0 -54
- package/backend/input-routing.js +0 -24
- package/backend/json-cli-runtime.js +0 -275
- package/backend/main-agent-skills.js +0 -288
- package/backend/main-page-session.js +0 -122
- package/backend/native-pty-controller-generation.js +0 -106
- package/backend/native-pty-host-identity.js +0 -86
- package/backend/native-pty-host-path.js +0 -42
- package/backend/native-session-engine.js +0 -268
- package/backend/network.js +0 -23
- package/backend/npm-update-helper.js +0 -374
- package/backend/packaged-node-pty.js +0 -99
- package/backend/preview-session-manager.js +0 -68
- package/backend/provider-adapters.js +0 -399
- package/backend/provider-session-id.js +0 -47
- package/backend/provider-session-service.js +0 -345
- package/backend/qr-share-tickets.js +0 -100
- package/backend/review-diff-router.js +0 -180
- package/backend/review-diff-service.js +0 -1270
- package/backend/review-session-router.js +0 -74
- package/backend/review-session-service.js +0 -446
- package/backend/review-session-store.js +0 -151
- package/backend/review-state-router.js +0 -116
- package/backend/review-state-store.js +0 -286
- package/backend/run-history-store.js +0 -67
- package/backend/runtime-dependency-manager.js +0 -759
- package/backend/runtime-executable-invocation.js +0 -20
- package/backend/runtime-observation.js +0 -81
- package/backend/server-process-identity.js +0 -47
- package/backend/server.js +0 -3225
- package/backend/session-engine-bridge.js +0 -129
- package/backend/session-engine-router.js +0 -66
- package/backend/session-engine.js +0 -39
- package/backend/session-stream-protocol.js +0 -185
- package/backend/shell-busy-integration.js +0 -472
- package/backend/slash-command-discovery.js +0 -433
- package/backend/storage-layout.js +0 -205
- package/backend/system-monitor.js +0 -77
- package/backend/terminal-attach-checkpoint.js +0 -74
- package/backend/terminal-exit-quiescence.js +0 -39
- package/backend/terminal-runtime-cleanup.js +0 -80
- package/backend/terminal-screen-worker.js +0 -337
- package/backend/terminal-state-serialization.js +0 -127
- package/backend/theme-manager.js +0 -163
- package/backend/usage-forecast.js +0 -86
- package/backend/usage-history-scanner.ts +0 -2718
- package/backend/usage-history-smoke.js +0 -64
- package/backend/usage-history-worker.js +0 -34
- package/backend/workspace-directory.js +0 -232
- package/backend/workspace-discovery.js +0 -311
- package/backend/workspace-root-registry.js +0 -166
- package/dist/assets/App-BKNUILuL.css +0 -1
- package/dist/assets/App-Z1N7T0eM.js +0 -695
- package/dist/assets/FileEditorPane-CNtuGjQ3.js +0 -2
- package/dist/assets/IconGlyphs-BClgag6E.js +0 -1
- package/dist/assets/ProjectFilesSection-K3GHuQ4U.js +0 -12
- package/dist/assets/ReviewPage-BRuxFaH5.js +0 -3
- package/dist/assets/code-dark-kLsQLvpf.css +0 -1
- package/dist/assets/file-icons-BOlcJ0ZF.js +0 -1
- package/dist/assets/main-DUTz-Rd2.css +0 -1
- package/dist/assets/review-BcnwQtJv.css +0 -1
- package/dist/assets/workspace-editor-model-CSGCl21x.js +0 -1
- package/dist/assets/workspace-editor-monaco-CJNwbpCy.js +0 -4
- package/dist/assets/workspace-editor-monaco-CO9w8YV0.js +0 -1
- package/dist/assets/workspace-view-state-BjKPYp0E.js +0 -7
- package/extensions/browser/backend/agent-browser-runtime.js +0 -1041
- package/extensions/browser/backend/agent-capability.js +0 -55
- package/extensions/browser/backend/browser-mcp-server.js +0 -621
- package/extensions/browser/backend/browser-resource-manager.js +0 -1331
- package/extensions/browser/backend/browser-resource-store.js +0 -190
- package/extensions/browser/backend/browser-router.js +0 -141
- package/extensions/browser/backend/executable-discovery.js +0 -238
- package/extensions/browser/backend/farming-browser-client.js +0 -83
- package/extensions/browser/backend/index.js +0 -7
- package/extensions/browser/backend/managed-chromium-installer.js +0 -593
- package/extensions/browser/frontend/BrowserSidebarPortals.tsx +0 -360
- package/extensions/browser/frontend/BrowserViewer.tsx +0 -500
- package/extensions/browser/frontend/browser-resource-state.ts +0 -60
- package/extensions/browser/frontend/browser.css +0 -567
- package/extensions/browser/frontend/types.ts +0 -38
- package/extensions/browser/frontend/useBrowserResources.ts +0 -166
- package/frontend/vendor/ghostty-web/index.d.ts +0 -1842
- package/shared/backend-connection-status.d.ts +0 -37
- package/shared/browser-protocol.d.ts +0 -5
- /package/dist/assets/{api-w2x5QfxB.js → api-ByCV9MEr.js} +0 -0
- /package/dist/assets/{core-vPkV8P_m.js → core-Czwdx12k.js} +0 -0
- /package/dist/assets/{fsharp-DNZNZyEE.js → fsharp-BjPpkoJe.js} +0 -0
- /package/dist/assets/{go-_kPJjNc_.js → go-BkIDmSUP.js} +0 -0
- /package/dist/assets/{graphql-4HCNVt5g.js → graphql-CCJTpqi1.js} +0 -0
- /package/dist/assets/{hcl-C87ymY0o.js → hcl-s4z8lUFg.js} +0 -0
- /package/dist/assets/{ini-BYrrGNTc.js → ini-CyUW1I7Z.js} +0 -0
- /package/dist/assets/{java-B211rJbk.js → java-CFCcGRiM.js} +0 -0
- /package/dist/assets/{julia-DVPsRtBm.js → julia-DQyH_EYb.js} +0 -0
- /package/dist/assets/{kotlin-BYyNerjp.js → kotlin-B8hA5O51.js} +0 -0
- /package/dist/assets/{less-EC9UblGE.js → less-DaVdaas0.js} +0 -0
- /package/dist/assets/{lexon-B1yuUdqW.js → lexon-DLBhPd3y.js} +0 -0
- /package/dist/assets/{lua-Bo6GFzxT.js → lua-gB1c_cif.js} +0 -0
- /package/dist/assets/{m3-C-Y9cBVI.js → m3-C2T3z3gB.js} +0 -0
- /package/dist/assets/{markdown-BHu-wLbe.js → markdown-CKq-Euj1.js} +0 -0
- /package/dist/assets/{mips-Dkds26rX.js → mips-Bcs5qIDX.js} +0 -0
- /package/dist/assets/{msdax-PU4g-8_g.js → msdax-CBP48FHF.js} +0 -0
- /package/dist/assets/{mysql-fPpuGpS7.js → mysql-c7tiPcFj.js} +0 -0
- /package/dist/assets/{objective-c-Wy1e5JUf.js → objective-c-D4BZkeEV.js} +0 -0
- /package/dist/assets/{pascal-BIXwvrqU.js → pascal-CJDZg0MN.js} +0 -0
- /package/dist/assets/{pascaligo-DwR0AtL_.js → pascaligo-Bygi8Ynl.js} +0 -0
- /package/dist/assets/{perl-CGHAl8my.js → perl-aS8bkf7E.js} +0 -0
- /package/dist/assets/{pgsql-B91M73E2.js → pgsql-CzNAYFYl.js} +0 -0
- /package/dist/assets/{php-C70ttrCx.js → php-DOtoEFTT.js} +0 -0
- /package/dist/assets/{pla-BNrXaRh0.js → pla-DugRnao1.js} +0 -0
- /package/dist/assets/{postiats-Dv2IAZR9.js → postiats-DsXwusKh.js} +0 -0
- /package/dist/assets/{powerquery-CkY5Wq7J.js → powerquery-DL3o72oD.js} +0 -0
- /package/dist/assets/{powershell-uGIYLU3C.js → powershell-C1qHekys.js} +0 -0
- /package/dist/assets/{protobuf-CavfmJu-.js → protobuf-DHgsc-cH.js} +0 -0
- /package/dist/assets/{pug-Drqnyitx.js → pug-FZXlE_Iu.js} +0 -0
- /package/dist/assets/{qrcode-7uGsTEmi.js → qrcode-DJDTdjL7.js} +0 -0
- /package/dist/assets/{qsharp-C7yF-Dti.js → qsharp-bLyhI3DT.js} +0 -0
- /package/dist/assets/{r-HXLGP0_-.js → r-DjFGXbAa.js} +0 -0
- /package/dist/assets/{redis-C4y6mf2p.js → redis-DSoZ_V6u.js} +0 -0
- /package/dist/assets/{redshift-DdQrFPrv.js → redshift-CzkdCsrg.js} +0 -0
- /package/dist/assets/{restructuredtext-CBrf2PNj.js → restructuredtext-B_XPrGCQ.js} +0 -0
- /package/dist/assets/{ruby-CVtMoX2B.js → ruby-Cry2RneJ.js} +0 -0
- /package/dist/assets/{rust-Ckq4sbMP.js → rust-CWzdbFq1.js} +0 -0
- /package/dist/assets/{sb-er66OpE3.js → sb-DmofU59h.js} +0 -0
- /package/dist/assets/{scala-BdWZz-hH.js → scala-BUC2l-vN.js} +0 -0
- /package/dist/assets/{scheme-kTV_s2kP.js → scheme-CNIB_72f.js} +0 -0
- /package/dist/assets/{scss-Bymy2VJQ.js → scss-DcL4-NbX.js} +0 -0
- /package/dist/assets/{shell-bwEP1LQ1.js → shell-CgAGvSSA.js} +0 -0
- /package/dist/assets/{solidity-DCddeBgL.js → solidity-DSkt6O_P.js} +0 -0
- /package/dist/assets/{sophia-BMN3AQig.js → sophia--5ytcjDN.js} +0 -0
- /package/dist/assets/{sparql-CSXOLjzi.js → sparql-C1Srr7cD.js} +0 -0
- /package/dist/assets/{sql-COg8ewmK.js → sql-2k_O5fj7.js} +0 -0
- /package/dist/assets/{st-CIaZtBS_.js → st-DCCCPqfz.js} +0 -0
- /package/dist/assets/{swift-DXiOhUHu.js → swift-Dd8mAfOt.js} +0 -0
- /package/dist/assets/{systemverilog-BTDE6Dr2.js → systemverilog-B0-aZYXu.js} +0 -0
- /package/dist/assets/{tcl-B0zy9NvV.js → tcl-CZAZwPVX.js} +0 -0
- /package/dist/assets/{twig-D594l4Z1.js → twig-D-Ag0tdS.js} +0 -0
- /package/dist/assets/{typespec-XKVjaPqo.js → typespec-B7kTFp0Z.js} +0 -0
- /package/dist/assets/{useWorkspaceMenuKeyboard-Bpy_s69Z.js → useWorkspaceMenuKeyboard-uYZpDxhU.js} +0 -0
- /package/dist/assets/{vb-B2wYoKRV.js → vb-20w1JPum.js} +0 -0
- /package/dist/assets/{wgsl-D0Yf2LbK.js → wgsl-CLJfqFt0.js} +0 -0
- /package/dist/assets/{workspace-working-copy-C3FSR3N6.js → workspace-working-copy-Cfz07cOd.js} +0 -0
|
@@ -1,986 +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 dedupeAgentSessions(sessions) {
|
|
109
|
-
const sessionsByIdentity = new Map();
|
|
110
|
-
for (const session of sessions) {
|
|
111
|
-
const identity = agentSessionIdentity(session);
|
|
112
|
-
const current = sessionsByIdentity.get(identity);
|
|
113
|
-
if (!current || timestampMs(session?.updatedAt || session?.createdAt) > timestampMs(current?.updatedAt || current?.createdAt)) {
|
|
114
|
-
sessionsByIdentity.set(identity, session);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return Array.from(sessionsByIdentity.values());
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function encodeAgentSessionCursor(session) {
|
|
121
|
-
if (!session?.provider || !session?.id) return '';
|
|
122
|
-
return Buffer.from(JSON.stringify({
|
|
123
|
-
version: 1,
|
|
124
|
-
provider: String(session.provider),
|
|
125
|
-
providerHomeId: String(session.providerHomeId || 'default'),
|
|
126
|
-
id: String(session.id),
|
|
127
|
-
updatedAt: String(session.updatedAt || session.createdAt || ''),
|
|
128
|
-
})).toString('base64url');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function decodeAgentSessionCursor(value) {
|
|
132
|
-
try {
|
|
133
|
-
const parsed = JSON.parse(Buffer.from(String(value || ''), 'base64url').toString('utf8'));
|
|
134
|
-
if (parsed?.version !== 1 || !parsed.provider || !parsed.id) return null;
|
|
135
|
-
return {
|
|
136
|
-
provider: String(parsed.provider),
|
|
137
|
-
providerHomeId: String(parsed.providerHomeId || 'default'),
|
|
138
|
-
id: String(parsed.id),
|
|
139
|
-
updatedAt: String(parsed.updatedAt || ''),
|
|
140
|
-
};
|
|
141
|
-
} catch {
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function paginateAgentSessions(sessions, options = {}) {
|
|
147
|
-
const limit = Number.isFinite(options.limit)
|
|
148
|
-
? Math.max(1, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
|
|
149
|
-
: DEFAULT_LIMIT;
|
|
150
|
-
const cursorValue = String(options.cursor || '').trim();
|
|
151
|
-
let start = 0;
|
|
152
|
-
if (cursorValue) {
|
|
153
|
-
const cursor = decodeAgentSessionCursor(cursorValue);
|
|
154
|
-
if (!cursor) return { sessions: [], nextCursor: '', hasMore: false, invalidCursor: true };
|
|
155
|
-
const exactIndex = sessions.findIndex(session => (
|
|
156
|
-
agentSessionIdentity(session) === agentSessionIdentity(cursor)
|
|
157
|
-
&& String(session.updatedAt || session.createdAt || '') === cursor.updatedAt
|
|
158
|
-
));
|
|
159
|
-
if (exactIndex >= 0) {
|
|
160
|
-
start = exactIndex + 1;
|
|
161
|
-
} else {
|
|
162
|
-
const nextIndex = sessions.findIndex(session => compareAgentSessions(session, cursor) > 0);
|
|
163
|
-
start = nextIndex >= 0 ? nextIndex : sessions.length;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
const page = sessions.slice(start, start + limit);
|
|
167
|
-
const hasMore = start + page.length < sessions.length;
|
|
168
|
-
return {
|
|
169
|
-
sessions: page,
|
|
170
|
-
nextCursor: hasMore && page.length > 0 ? encodeAgentSessionCursor(page[page.length - 1]) : '',
|
|
171
|
-
hasMore,
|
|
172
|
-
invalidCursor: false,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function searchAgentSessions(sessions, query, options = {}) {
|
|
177
|
-
const normalizedQuery = String(query || '').trim().toLowerCase();
|
|
178
|
-
const limit = Number.isFinite(options.limit)
|
|
179
|
-
? Math.max(1, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
|
|
180
|
-
: DEFAULT_LIMIT;
|
|
181
|
-
if (!normalizedQuery) {
|
|
182
|
-
return { sessions: [], total: 0, query: '', scope: 'id-title-project' };
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const projectNames = options.projectNames && typeof options.projectNames === 'object'
|
|
186
|
-
? options.projectNames
|
|
187
|
-
: {};
|
|
188
|
-
const matches = sessions.filter(session => {
|
|
189
|
-
const projectPaths = [session?.workspace, session?.cwd];
|
|
190
|
-
return [
|
|
191
|
-
session?.id,
|
|
192
|
-
session?.title,
|
|
193
|
-
...projectPaths,
|
|
194
|
-
...projectPaths.map(workspace => projectNames[String(workspace || '')]),
|
|
195
|
-
].some(value => String(value || '').toLowerCase().includes(normalizedQuery));
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
sessions: matches.slice(0, limit),
|
|
200
|
-
total: matches.length,
|
|
201
|
-
query: normalizedQuery,
|
|
202
|
-
scope: 'id-title-project',
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function isAgentManagedWorktree(workspace) {
|
|
207
|
-
const value = normalizePathValue(workspace);
|
|
208
|
-
return value.includes(`${path.sep}.codex${path.sep}worktrees${path.sep}`)
|
|
209
|
-
|| value.includes(`${path.sep}.claude${path.sep}worktrees${path.sep}`);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function isDefaultClaudeSessionTitle(title) {
|
|
213
|
-
return String(title || '').trim().toLowerCase() === 'claude session';
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function firstTrimmedString(...values) {
|
|
217
|
-
for (const value of values) {
|
|
218
|
-
if (typeof value !== 'string') continue;
|
|
219
|
-
const trimmed = value.trim();
|
|
220
|
-
if (trimmed) return trimmed;
|
|
221
|
-
}
|
|
222
|
-
return '';
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function extractClaudeModel(event) {
|
|
226
|
-
return firstTrimmedString(
|
|
227
|
-
event?.model,
|
|
228
|
-
event?.message?.model,
|
|
229
|
-
event?.metadata?.model,
|
|
230
|
-
event?.message?.metadata?.model,
|
|
231
|
-
event?.request?.model,
|
|
232
|
-
event?.options?.model
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function extractClaudeEffort(event) {
|
|
237
|
-
return firstTrimmedString(
|
|
238
|
-
event?.effort,
|
|
239
|
-
event?.message?.effort,
|
|
240
|
-
event?.metadata?.effort,
|
|
241
|
-
event?.message?.metadata?.effort,
|
|
242
|
-
event?.request?.effort,
|
|
243
|
-
event?.options?.effort
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function extractQoderModel(event) {
|
|
248
|
-
return firstTrimmedString(
|
|
249
|
-
event?.model,
|
|
250
|
-
event?.message?.model,
|
|
251
|
-
event?.metadata?.model,
|
|
252
|
-
event?.message?.metadata?.model
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function extractQoderEffort(event) {
|
|
257
|
-
return firstTrimmedString(
|
|
258
|
-
event?.reasoningEffort,
|
|
259
|
-
event?.reasoning_effort,
|
|
260
|
-
event?.effort,
|
|
261
|
-
event?.metadata?.reasoningEffort,
|
|
262
|
-
event?.metadata?.reasoning_effort,
|
|
263
|
-
event?.message?.metadata?.reasoningEffort,
|
|
264
|
-
event?.message?.metadata?.reasoning_effort
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function isoTimestamp(value) {
|
|
269
|
-
if (typeof value === 'string') {
|
|
270
|
-
const parsed = Date.parse(value);
|
|
271
|
-
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : '';
|
|
272
|
-
}
|
|
273
|
-
if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
|
|
274
|
-
try {
|
|
275
|
-
const date = new Date(value);
|
|
276
|
-
return Number.isFinite(date.getTime()) ? date.toISOString() : '';
|
|
277
|
-
} catch {
|
|
278
|
-
return '';
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
return '';
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function qoderTextFromMessage(message) {
|
|
285
|
-
if (typeof message === 'string') return message.trim();
|
|
286
|
-
if (!message || typeof message !== 'object') return '';
|
|
287
|
-
const content = message.content;
|
|
288
|
-
if (typeof content === 'string') return content.trim();
|
|
289
|
-
if (!Array.isArray(content)) return '';
|
|
290
|
-
return content
|
|
291
|
-
.map(part => {
|
|
292
|
-
if (typeof part === 'string') return part;
|
|
293
|
-
if (!part || typeof part !== 'object') return '';
|
|
294
|
-
if (typeof part.text === 'string') return part.text;
|
|
295
|
-
if (typeof part.content === 'string') return part.content;
|
|
296
|
-
return '';
|
|
297
|
-
})
|
|
298
|
-
.join('\n')
|
|
299
|
-
.trim();
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function isVisibleAgentSession(session) {
|
|
303
|
-
const provider = String(session?.provider || '').trim().toLowerCase();
|
|
304
|
-
if (provider === 'claude') {
|
|
305
|
-
if (isDefaultClaudeSessionTitle(session?.title)) return false;
|
|
306
|
-
if (isAgentManagedWorktree(session?.cwd) || isAgentManagedWorktree(session?.workspace)) return false;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return !isTemporaryWorkspace(session?.cwd)
|
|
310
|
-
&& !isTemporaryWorkspace(session?.workspace)
|
|
311
|
-
&& !hasTemporaryWorkspaceReference(session?.title);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function activeScheduleFromMetadata(value, sessionId = '') {
|
|
315
|
-
if (!value || typeof value !== 'object') return null;
|
|
316
|
-
const rrule = typeof value.rrule === 'string' ? value.rrule.trim() : '';
|
|
317
|
-
if (!rrule) return null;
|
|
318
|
-
|
|
319
|
-
const targetThreadId = typeof value.target_thread_id === 'string'
|
|
320
|
-
? value.target_thread_id.trim()
|
|
321
|
-
: typeof value.targetThreadId === 'string'
|
|
322
|
-
? value.targetThreadId.trim()
|
|
323
|
-
: '';
|
|
324
|
-
if (targetThreadId && sessionId && targetThreadId !== sessionId) return null;
|
|
325
|
-
|
|
326
|
-
const rawStatus = typeof value.status === 'string' ? value.status.trim().toUpperCase() : '';
|
|
327
|
-
const enabled = value.enabled !== false && value.active !== false;
|
|
328
|
-
if (rawStatus && !['ACTIVE', 'ENABLED'].includes(rawStatus)) return null;
|
|
329
|
-
if (!enabled) return null;
|
|
330
|
-
|
|
331
|
-
return {
|
|
332
|
-
id: typeof value.id === 'string' ? value.id.trim() : '',
|
|
333
|
-
kind: typeof value.kind === 'string' ? value.kind.trim() : '',
|
|
334
|
-
name: typeof value.name === 'string' ? value.name.trim() : '',
|
|
335
|
-
status: rawStatus || 'ACTIVE',
|
|
336
|
-
rrule,
|
|
337
|
-
label: formatAutomationRRuleLabel(rrule),
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
function scheduleFromClaudeEvent(event, sessionId) {
|
|
342
|
-
const candidates = [
|
|
343
|
-
event?.automation,
|
|
344
|
-
event?.schedule,
|
|
345
|
-
event?.metadata?.automation,
|
|
346
|
-
event?.metadata?.schedule,
|
|
347
|
-
event?.message?.metadata?.automation,
|
|
348
|
-
event?.message?.metadata?.schedule,
|
|
349
|
-
];
|
|
350
|
-
|
|
351
|
-
for (const candidate of candidates) {
|
|
352
|
-
const schedule = activeScheduleFromMetadata(candidate, sessionId);
|
|
353
|
-
if (schedule) return schedule;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
return null;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
async function collectRecentFiles(
|
|
360
|
-
root,
|
|
361
|
-
extension,
|
|
362
|
-
limit,
|
|
363
|
-
acceptFile = () => true,
|
|
364
|
-
descendDirectory = () => true
|
|
365
|
-
) {
|
|
366
|
-
const directories = [root];
|
|
367
|
-
let files = [];
|
|
368
|
-
let visitedDirectories = 0;
|
|
369
|
-
|
|
370
|
-
while (directories.length > 0 && visitedDirectories < MAX_RECENT_FILE_SCAN_DIRECTORIES) {
|
|
371
|
-
const directory = directories.pop();
|
|
372
|
-
let entries = [];
|
|
373
|
-
try {
|
|
374
|
-
entries = await fsp.readdir(directory, { withFileTypes: true });
|
|
375
|
-
} catch {
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
visitedDirectories += 1;
|
|
379
|
-
entries.sort((a, b) => {
|
|
380
|
-
if (a.isDirectory() !== b.isDirectory()) return a.isDirectory() ? -1 : 1;
|
|
381
|
-
return a.name.localeCompare(b.name);
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
for (const entry of entries) {
|
|
385
|
-
const fullPath = path.join(directory, entry.name);
|
|
386
|
-
if (entry.isDirectory()) {
|
|
387
|
-
if (descendDirectory(fullPath)) directories.push(fullPath);
|
|
388
|
-
} else if (entry.isFile() && entry.name.endsWith(extension) && acceptFile(fullPath)) {
|
|
389
|
-
let mtimeMs = 0;
|
|
390
|
-
try {
|
|
391
|
-
mtimeMs = (await fsp.stat(fullPath)).mtimeMs;
|
|
392
|
-
} catch {
|
|
393
|
-
mtimeMs = 0;
|
|
394
|
-
}
|
|
395
|
-
files.push({ filePath: fullPath, mtimeMs });
|
|
396
|
-
if (files.length > limit * 2) {
|
|
397
|
-
files = files.sort((a, b) => b.mtimeMs - a.mtimeMs).slice(0, limit);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
return files.sort((a, b) => b.mtimeMs - a.mtimeMs).slice(0, limit);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
async function readTextTail(filePath, maxBytes) {
|
|
407
|
-
let handle = null;
|
|
408
|
-
try {
|
|
409
|
-
const stat = await fsp.stat(filePath);
|
|
410
|
-
const start = Math.max(0, stat.size - maxBytes);
|
|
411
|
-
const length = stat.size - start;
|
|
412
|
-
const buffer = Buffer.alloc(length);
|
|
413
|
-
handle = await fsp.open(filePath, 'r');
|
|
414
|
-
await handle.read(buffer, 0, length, start);
|
|
415
|
-
const text = buffer.toString('utf8');
|
|
416
|
-
return start > 0 ? text.replace(/^[^\n]*(\n|$)/, '') : text;
|
|
417
|
-
} catch {
|
|
418
|
-
return '';
|
|
419
|
-
} finally {
|
|
420
|
-
if (handle) {
|
|
421
|
-
await handle.close().catch(() => {});
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
async function readClaudePromptHistory(claudeHome) {
|
|
427
|
-
const historyPath = path.join(claudeHome, 'history.jsonl');
|
|
428
|
-
const entries = new Map();
|
|
429
|
-
|
|
430
|
-
const lines = (await readTextTail(historyPath, CLAUDE_HISTORY_TAIL_BYTES)).split('\n').filter(Boolean);
|
|
431
|
-
for (const line of lines) {
|
|
432
|
-
try {
|
|
433
|
-
const entry = JSON.parse(line);
|
|
434
|
-
if (!entry || typeof entry.sessionId !== 'string') continue;
|
|
435
|
-
entries.set(entry.sessionId, {
|
|
436
|
-
title: typeof entry.display === 'string' ? entry.display.trim() : '',
|
|
437
|
-
workspace: typeof entry.project === 'string' ? normalizePathValue(entry.project) : '',
|
|
438
|
-
updatedAt: typeof entry.timestamp === 'string' ? entry.timestamp : '',
|
|
439
|
-
});
|
|
440
|
-
} catch {
|
|
441
|
-
// Ignore individual corrupt prompt history lines.
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
return entries;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
function claudeSessionIdFromFilePath(filePath) {
|
|
449
|
-
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);
|
|
450
|
-
return match ? match[1] : '';
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
async function readClaudeSessionMetadata(filePath, promptHistory, maxLines = 160) {
|
|
454
|
-
const stream = fs.createReadStream(filePath, { encoding: 'utf8' });
|
|
455
|
-
const reader = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
456
|
-
const fileSessionId = claudeSessionIdFromFilePath(filePath);
|
|
457
|
-
const metadata = {
|
|
458
|
-
filePath,
|
|
459
|
-
id: fileSessionId,
|
|
460
|
-
title: '',
|
|
461
|
-
cwd: '',
|
|
462
|
-
workspace: '',
|
|
463
|
-
createdAt: '',
|
|
464
|
-
updatedAt: '',
|
|
465
|
-
model: '',
|
|
466
|
-
effort: '',
|
|
467
|
-
source: '',
|
|
468
|
-
schedule: null,
|
|
469
|
-
};
|
|
470
|
-
let lineCount = 0;
|
|
471
|
-
|
|
472
|
-
try {
|
|
473
|
-
for await (const line of reader) {
|
|
474
|
-
if (!line) continue;
|
|
475
|
-
lineCount += 1;
|
|
476
|
-
|
|
477
|
-
try {
|
|
478
|
-
const event = JSON.parse(line);
|
|
479
|
-
if (typeof event.sessionId === 'string') {
|
|
480
|
-
metadata.id = event.sessionId;
|
|
481
|
-
}
|
|
482
|
-
if (typeof event.timestamp === 'string') {
|
|
483
|
-
metadata.updatedAt = event.timestamp;
|
|
484
|
-
metadata.createdAt = metadata.createdAt || event.timestamp;
|
|
485
|
-
}
|
|
486
|
-
if (typeof event.cwd === 'string' && event.cwd.trim()) {
|
|
487
|
-
metadata.cwd = normalizePathValue(event.cwd);
|
|
488
|
-
}
|
|
489
|
-
if (typeof event.entrypoint === 'string' && event.entrypoint.trim()) {
|
|
490
|
-
metadata.source = event.entrypoint.trim();
|
|
491
|
-
}
|
|
492
|
-
if (event.type === 'ai-title' && typeof event.aiTitle === 'string' && event.aiTitle.trim()) {
|
|
493
|
-
metadata.title = event.aiTitle.trim();
|
|
494
|
-
}
|
|
495
|
-
metadata.model = extractClaudeModel(event) || metadata.model;
|
|
496
|
-
metadata.effort = extractClaudeEffort(event) || metadata.effort;
|
|
497
|
-
if (!metadata.schedule) {
|
|
498
|
-
metadata.schedule = scheduleFromClaudeEvent(event, metadata.id || fileSessionId);
|
|
499
|
-
}
|
|
500
|
-
} catch {
|
|
501
|
-
// Ignore individual corrupt session lines.
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
if (lineCount >= maxLines || (metadata.id && metadata.title && metadata.cwd && metadata.model)) {
|
|
505
|
-
break;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
} finally {
|
|
509
|
-
reader.close();
|
|
510
|
-
stream.destroy();
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
if (!metadata.id) return null;
|
|
514
|
-
|
|
515
|
-
const indexed = promptHistory.get(metadata.id);
|
|
516
|
-
metadata.title = metadata.title || indexed?.title || 'Claude session';
|
|
517
|
-
metadata.workspace = normalizePathValue(indexed?.workspace || metadata.cwd || '');
|
|
518
|
-
metadata.updatedAt = metadata.updatedAt || indexed?.updatedAt || '';
|
|
519
|
-
metadata.source = metadata.source || 'claude';
|
|
520
|
-
|
|
521
|
-
return metadata;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
async function listClaudeSessions(options = {}) {
|
|
525
|
-
const claudeHome = options.claudeHome || path.join(os.homedir(), '.claude');
|
|
526
|
-
const limit = Number.isFinite(options.limit)
|
|
527
|
-
? Math.max(0, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
|
|
528
|
-
: DEFAULT_LIMIT;
|
|
529
|
-
const scanLimit = Number.isFinite(options.scanLimit)
|
|
530
|
-
? Math.max(limit, Math.min(MAX_AGENT_SESSION_SCAN_LIMIT, Math.floor(options.scanLimit)))
|
|
531
|
-
: DEFAULT_SCAN_LIMIT;
|
|
532
|
-
const promptHistory = await readClaudePromptHistory(claudeHome);
|
|
533
|
-
const projectsRoot = path.join(claudeHome, 'projects');
|
|
534
|
-
// Claude child-agent transcripts live below <project>/<session-id>/subagents
|
|
535
|
-
// and inherit the parent session id. Only direct project session files are
|
|
536
|
-
// resumable roots and should count as History entries.
|
|
537
|
-
const sessionFiles = await collectRecentFiles(
|
|
538
|
-
projectsRoot,
|
|
539
|
-
'.jsonl',
|
|
540
|
-
scanLimit,
|
|
541
|
-
filePath => path.relative(projectsRoot, filePath).split(path.sep).length === 2,
|
|
542
|
-
directoryPath => path.relative(projectsRoot, directoryPath).split(path.sep).length === 1
|
|
543
|
-
);
|
|
544
|
-
|
|
545
|
-
const sessions = [];
|
|
546
|
-
for (const { filePath, mtimeMs } of sessionFiles) {
|
|
547
|
-
const metadata = await readClaudeSessionMetadata(filePath, promptHistory);
|
|
548
|
-
if (!metadata) continue;
|
|
549
|
-
const mtimeIso = mtimeMs > 0 ? new Date(mtimeMs).toISOString() : '';
|
|
550
|
-
const updatedAt = timestampMs(mtimeIso) > timestampMs(metadata.updatedAt)
|
|
551
|
-
? mtimeIso
|
|
552
|
-
: (metadata.updatedAt || mtimeIso);
|
|
553
|
-
const session = {
|
|
554
|
-
provider: 'claude',
|
|
555
|
-
providerName: 'Claude',
|
|
556
|
-
id: metadata.id,
|
|
557
|
-
title: metadata.title,
|
|
558
|
-
cwd: metadata.cwd,
|
|
559
|
-
workspace: metadata.workspace,
|
|
560
|
-
updatedAt,
|
|
561
|
-
createdAt: metadata.createdAt,
|
|
562
|
-
archived: false,
|
|
563
|
-
pinned: false,
|
|
564
|
-
unread: false,
|
|
565
|
-
projectless: !metadata.workspace,
|
|
566
|
-
model: metadata.model,
|
|
567
|
-
effort: metadata.effort,
|
|
568
|
-
source: metadata.source,
|
|
569
|
-
schedule: metadata.schedule || undefined,
|
|
570
|
-
capabilities: ['resume', 'fork'],
|
|
571
|
-
};
|
|
572
|
-
if (isVisibleAgentSession(session)) {
|
|
573
|
-
sessions.push(session);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
return dedupeAgentSessions(sessions)
|
|
578
|
-
.sort((a, b) => timestampMs(b.updatedAt) - timestampMs(a.updatedAt))
|
|
579
|
-
.slice(0, limit);
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
function qoderSessionIdFromFilePath(filePath) {
|
|
583
|
-
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);
|
|
584
|
-
return match ? match[1] : '';
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
function applyQoderSessionEvent(metadata, event, fileSessionId) {
|
|
588
|
-
if (!event || typeof event !== 'object') return;
|
|
589
|
-
const eventSessionId = typeof event.sessionId === 'string'
|
|
590
|
-
? event.sessionId
|
|
591
|
-
: typeof event.session_id === 'string'
|
|
592
|
-
? event.session_id
|
|
593
|
-
: '';
|
|
594
|
-
if (eventSessionId && isSafeProviderSessionId(eventSessionId)) {
|
|
595
|
-
metadata.id = eventSessionId;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const timestamp = isoTimestamp(event.timestamp);
|
|
599
|
-
if (timestamp) {
|
|
600
|
-
metadata.updatedAt = timestamp;
|
|
601
|
-
metadata.createdAt = metadata.createdAt || timestamp;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
if (typeof event.cwd === 'string' && event.cwd.trim()) {
|
|
605
|
-
metadata.cwd = normalizePathValue(event.cwd);
|
|
606
|
-
}
|
|
607
|
-
if (typeof event.entrypoint === 'string' && event.entrypoint.trim()) {
|
|
608
|
-
metadata.source = event.entrypoint.trim();
|
|
609
|
-
}
|
|
610
|
-
if (event.type === 'system' && typeof event.qodercli_version === 'string') {
|
|
611
|
-
metadata.cliVersion = event.qodercli_version.trim();
|
|
612
|
-
}
|
|
613
|
-
if (typeof event.version === 'string' && event.version.trim()) {
|
|
614
|
-
metadata.cliVersion = event.version.trim();
|
|
615
|
-
}
|
|
616
|
-
if (event.type === 'runtime-config' && typeof event.version === 'string') {
|
|
617
|
-
metadata.cliVersion = event.version.trim();
|
|
618
|
-
}
|
|
619
|
-
if (event.type === 'ai-title' && typeof event.aiTitle === 'string' && event.aiTitle.trim()) {
|
|
620
|
-
metadata.title = event.aiTitle.trim();
|
|
621
|
-
}
|
|
622
|
-
if (event.type === 'last-prompt' && typeof event.lastPrompt === 'string' && event.lastPrompt.trim()) {
|
|
623
|
-
metadata.lastPrompt = event.lastPrompt.trim();
|
|
624
|
-
}
|
|
625
|
-
if (!metadata.firstPrompt && event.type === 'user') {
|
|
626
|
-
metadata.firstPrompt = qoderTextFromMessage(event.message);
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
metadata.model = extractQoderModel(event) || metadata.model;
|
|
630
|
-
metadata.effort = extractQoderEffort(event) || metadata.effort;
|
|
631
|
-
|
|
632
|
-
if (!metadata.id && fileSessionId) {
|
|
633
|
-
metadata.id = fileSessionId;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
async function readQoderSessionMetadata(filePath, maxLines = 160) {
|
|
638
|
-
const fileSessionId = qoderSessionIdFromFilePath(filePath);
|
|
639
|
-
const metadata = {
|
|
640
|
-
filePath,
|
|
641
|
-
id: fileSessionId,
|
|
642
|
-
title: '',
|
|
643
|
-
lastPrompt: '',
|
|
644
|
-
firstPrompt: '',
|
|
645
|
-
cwd: '',
|
|
646
|
-
workspace: '',
|
|
647
|
-
createdAt: '',
|
|
648
|
-
updatedAt: '',
|
|
649
|
-
model: '',
|
|
650
|
-
effort: '',
|
|
651
|
-
source: '',
|
|
652
|
-
cliVersion: '',
|
|
653
|
-
};
|
|
654
|
-
|
|
655
|
-
const stream = fs.createReadStream(filePath, { encoding: 'utf8' });
|
|
656
|
-
const reader = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
657
|
-
let lineCount = 0;
|
|
658
|
-
|
|
659
|
-
try {
|
|
660
|
-
for await (const line of reader) {
|
|
661
|
-
if (!line) continue;
|
|
662
|
-
lineCount += 1;
|
|
663
|
-
try {
|
|
664
|
-
applyQoderSessionEvent(metadata, JSON.parse(line), fileSessionId);
|
|
665
|
-
} catch {
|
|
666
|
-
// Ignore individual corrupt session lines.
|
|
667
|
-
}
|
|
668
|
-
if (lineCount >= maxLines || (metadata.id && metadata.cwd && metadata.model && metadata.title)) {
|
|
669
|
-
break;
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
} finally {
|
|
673
|
-
reader.close();
|
|
674
|
-
stream.destroy();
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
const tail = await readTextTail(filePath, QODER_HISTORY_TAIL_BYTES);
|
|
678
|
-
for (const line of tail.split('\n').filter(Boolean)) {
|
|
679
|
-
try {
|
|
680
|
-
applyQoderSessionEvent(metadata, JSON.parse(line), fileSessionId);
|
|
681
|
-
} catch {
|
|
682
|
-
// Ignore individual corrupt session lines.
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
if (!metadata.id || !isSafeProviderSessionId(metadata.id)) return null;
|
|
687
|
-
metadata.title = firstTrimmedString(metadata.title, metadata.lastPrompt, metadata.firstPrompt, 'Qoder session');
|
|
688
|
-
metadata.workspace = normalizePathValue(metadata.cwd || '');
|
|
689
|
-
metadata.source = metadata.source || 'qodercli';
|
|
690
|
-
|
|
691
|
-
return metadata;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
async function listQoderSessions(options = {}) {
|
|
695
|
-
const qoderHome = options.qoderHome || path.join(os.homedir(), '.qoder');
|
|
696
|
-
const limit = Number.isFinite(options.limit)
|
|
697
|
-
? Math.max(0, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
|
|
698
|
-
: DEFAULT_LIMIT;
|
|
699
|
-
const scanLimit = Number.isFinite(options.scanLimit)
|
|
700
|
-
? Math.max(limit, Math.min(MAX_AGENT_SESSION_SCAN_LIMIT, Math.floor(options.scanLimit)))
|
|
701
|
-
: DEFAULT_SCAN_LIMIT;
|
|
702
|
-
const projectsRoot = path.join(qoderHome, 'projects');
|
|
703
|
-
// Child-agent transcripts live deeper under <project>/<session-id>/subagents
|
|
704
|
-
// and may repeat the parent id, so only count direct project session files.
|
|
705
|
-
const sessionFiles = await collectRecentFiles(
|
|
706
|
-
projectsRoot,
|
|
707
|
-
'.jsonl',
|
|
708
|
-
scanLimit,
|
|
709
|
-
filePath => path.relative(projectsRoot, filePath).split(path.sep).length === 2,
|
|
710
|
-
directoryPath => path.relative(projectsRoot, directoryPath).split(path.sep).length === 1
|
|
711
|
-
);
|
|
712
|
-
|
|
713
|
-
const sessions = [];
|
|
714
|
-
for (const { filePath, mtimeMs } of sessionFiles) {
|
|
715
|
-
const metadata = await readQoderSessionMetadata(filePath);
|
|
716
|
-
if (!metadata) continue;
|
|
717
|
-
const mtimeIso = mtimeMs > 0 ? new Date(mtimeMs).toISOString() : '';
|
|
718
|
-
const updatedAt = timestampMs(mtimeIso) > timestampMs(metadata.updatedAt)
|
|
719
|
-
? mtimeIso
|
|
720
|
-
: (metadata.updatedAt || mtimeIso);
|
|
721
|
-
const session = {
|
|
722
|
-
provider: 'qoder',
|
|
723
|
-
providerName: 'Qoder',
|
|
724
|
-
id: metadata.id,
|
|
725
|
-
title: metadata.title,
|
|
726
|
-
cwd: metadata.cwd,
|
|
727
|
-
workspace: metadata.workspace,
|
|
728
|
-
updatedAt,
|
|
729
|
-
createdAt: metadata.createdAt,
|
|
730
|
-
archived: false,
|
|
731
|
-
pinned: false,
|
|
732
|
-
unread: false,
|
|
733
|
-
projectless: !metadata.workspace,
|
|
734
|
-
model: metadata.model,
|
|
735
|
-
effort: metadata.effort,
|
|
736
|
-
source: metadata.source,
|
|
737
|
-
cliVersion: metadata.cliVersion,
|
|
738
|
-
capabilities: ['resume', 'fork'],
|
|
739
|
-
};
|
|
740
|
-
if (isVisibleAgentSession(session)) {
|
|
741
|
-
sessions.push(session);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
return dedupeAgentSessions(sessions)
|
|
746
|
-
.sort((a, b) => timestampMs(b.updatedAt) - timestampMs(a.updatedAt))
|
|
747
|
-
.slice(0, limit);
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
function runOpenCodeSessionList(options = {}) {
|
|
751
|
-
const executable = options.opencodeBin || process.env.FARMING_OPENCODE_BIN || 'opencode';
|
|
752
|
-
const maxCount = Number.isFinite(options.maxCount) ? Math.max(1, Math.floor(options.maxCount)) : DEFAULT_SCAN_LIMIT;
|
|
753
|
-
const env = { ...process.env };
|
|
754
|
-
if (options.opencodeHome) env.OPENCODE_CONFIG_DIR = options.opencodeHome;
|
|
755
|
-
return new Promise((resolve, reject) => {
|
|
756
|
-
execFile(executable, ['session', 'list', '--format', 'json', '--max-count', String(maxCount)], {
|
|
757
|
-
env,
|
|
758
|
-
maxBuffer: 4 * 1024 * 1024,
|
|
759
|
-
timeout: 15_000,
|
|
760
|
-
}, (error, stdout) => {
|
|
761
|
-
if (error) {
|
|
762
|
-
reject(error);
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
|
-
resolve(stdout);
|
|
766
|
-
});
|
|
767
|
-
});
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
async function listOpenCodeSessions(options = {}) {
|
|
771
|
-
const limit = Number.isFinite(options.limit)
|
|
772
|
-
? Math.max(0, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
|
|
773
|
-
: DEFAULT_LIMIT;
|
|
774
|
-
const scanLimit = Number.isFinite(options.scanLimit)
|
|
775
|
-
? Math.max(limit, Math.min(MAX_AGENT_SESSION_SCAN_LIMIT, Math.floor(options.scanLimit)))
|
|
776
|
-
: DEFAULT_SCAN_LIMIT;
|
|
777
|
-
const listCommand = options.runOpenCodeSessionList || runOpenCodeSessionList;
|
|
778
|
-
let rawSessions = [];
|
|
779
|
-
try {
|
|
780
|
-
const output = await listCommand({
|
|
781
|
-
maxCount: scanLimit,
|
|
782
|
-
opencodeBin: options.opencodeBin,
|
|
783
|
-
opencodeHome: options.opencodeHome,
|
|
784
|
-
});
|
|
785
|
-
rawSessions = JSON.parse(String(output || '[]'));
|
|
786
|
-
} catch {
|
|
787
|
-
return [];
|
|
788
|
-
}
|
|
789
|
-
if (!Array.isArray(rawSessions)) return [];
|
|
790
|
-
|
|
791
|
-
return dedupeAgentSessions(rawSessions
|
|
792
|
-
.map(raw => {
|
|
793
|
-
const id = firstTrimmedString(raw?.id);
|
|
794
|
-
const cwd = normalizePathValue(raw?.directory || '');
|
|
795
|
-
if (!id || !isSafeProviderSessionId(id)) return null;
|
|
796
|
-
return {
|
|
797
|
-
provider: 'opencode',
|
|
798
|
-
providerName: 'OpenCode',
|
|
799
|
-
id,
|
|
800
|
-
title: firstTrimmedString(raw?.title, 'OpenCode session'),
|
|
801
|
-
cwd,
|
|
802
|
-
workspace: cwd,
|
|
803
|
-
updatedAt: isoTimestamp(raw?.updated),
|
|
804
|
-
createdAt: isoTimestamp(raw?.created),
|
|
805
|
-
archived: false,
|
|
806
|
-
pinned: false,
|
|
807
|
-
unread: false,
|
|
808
|
-
projectless: !cwd,
|
|
809
|
-
source: 'opencode',
|
|
810
|
-
capabilities: ['resume', 'fork'],
|
|
811
|
-
};
|
|
812
|
-
})
|
|
813
|
-
.filter(session => session && isVisibleAgentSession(session)))
|
|
814
|
-
.sort((a, b) => timestampMs(b.updatedAt) - timestampMs(a.updatedAt))
|
|
815
|
-
.slice(0, limit);
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
function normalizeCodexSession(session) {
|
|
819
|
-
return {
|
|
820
|
-
provider: 'codex',
|
|
821
|
-
providerName: 'Codex',
|
|
822
|
-
...session,
|
|
823
|
-
capabilities: ['resume', 'fork'],
|
|
824
|
-
};
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
function normalizeProvider(provider) {
|
|
828
|
-
const normalized = String(provider || '').trim().toLowerCase();
|
|
829
|
-
return PROVIDERS.has(normalized) ? normalized : '';
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
function isSafeSessionId(sessionId) {
|
|
833
|
-
return isSafeProviderSessionId(sessionId);
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
function buildAgentSessionResumeCommand(provider, sessionId, options = {}) {
|
|
837
|
-
const normalizedProvider = normalizeProvider(provider);
|
|
838
|
-
const normalizedSessionId = String(sessionId || '').trim();
|
|
839
|
-
if (!normalizedProvider || !isSafeSessionId(normalizedSessionId)) return '';
|
|
840
|
-
|
|
841
|
-
if (normalizedProvider === 'codex') {
|
|
842
|
-
const cwd = normalizePathValue(options.cwd);
|
|
843
|
-
const modelProvider = String(
|
|
844
|
-
options.modelProvider
|
|
845
|
-
|| (Object.prototype.hasOwnProperty.call(options, 'providerHomePath')
|
|
846
|
-
? resolveCodexResumeModelProvider(options.providerHomePath)
|
|
847
|
-
: '')
|
|
848
|
-
).trim();
|
|
849
|
-
const providerArgs = modelProvider
|
|
850
|
-
? ` -c ${quoteCommandArg(`model_provider=${JSON.stringify(modelProvider)}`)}`
|
|
851
|
-
: '';
|
|
852
|
-
const cwdArgs = cwd ? ` -C ${quoteCommandArg(cwd)}` : '';
|
|
853
|
-
return `codex ${options.fork === true ? 'fork' : 'resume'}${providerArgs}${cwdArgs} ${normalizedSessionId}`;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
if (normalizedProvider === 'claude') {
|
|
857
|
-
return options.fork === true
|
|
858
|
-
? `claude --resume ${normalizedSessionId} --fork-session`
|
|
859
|
-
: `claude --resume ${normalizedSessionId}`;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
if (normalizedProvider === 'qoder') {
|
|
863
|
-
return options.fork === true
|
|
864
|
-
? `qodercli --resume ${normalizedSessionId} --fork-session`
|
|
865
|
-
: `qodercli --resume ${normalizedSessionId}`;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
if (normalizedProvider === 'opencode') {
|
|
869
|
-
return `opencode --session ${normalizedSessionId}${options.fork === true ? ' --fork' : ''}`;
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
return '';
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
async function listAgentSessions(options = {}) {
|
|
876
|
-
const limit = Number.isFinite(options.limit)
|
|
877
|
-
? Math.max(0, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.limit)))
|
|
878
|
-
: DEFAULT_LIMIT;
|
|
879
|
-
const requestedProviders = Array.isArray(options.providers)
|
|
880
|
-
? options.providers.map(normalizeProvider).filter(Boolean)
|
|
881
|
-
: ['codex', 'claude', 'opencode', 'qoder'];
|
|
882
|
-
const providers = Array.from(new Set(requestedProviders));
|
|
883
|
-
const sessions = [];
|
|
884
|
-
|
|
885
|
-
const providerHomes = options.providerHomes && typeof options.providerHomes === 'object'
|
|
886
|
-
? options.providerHomes
|
|
887
|
-
: {};
|
|
888
|
-
|
|
889
|
-
async function listForHomes(provider, homes, fallbackHomeKey, listFn, homeOptionKey, normalize = session => session) {
|
|
890
|
-
const configuredHomes = Array.isArray(homes) && homes.length > 0
|
|
891
|
-
? homes
|
|
892
|
-
: [{ id: 'default', path: options[fallbackHomeKey] }];
|
|
893
|
-
const perHomeLimit = Number.isFinite(options.providerLimit)
|
|
894
|
-
? Math.max(0, Math.min(MAX_AGENT_SESSION_HISTORY_LIMIT, Math.floor(options.providerLimit)))
|
|
895
|
-
: limit;
|
|
896
|
-
for (const home of configuredHomes) {
|
|
897
|
-
const providerHomeId = String(home && home.id || 'default').trim() || 'default';
|
|
898
|
-
const providerHomePath = String(home && home.path || '').trim();
|
|
899
|
-
const listOptions = {
|
|
900
|
-
limit: perHomeLimit,
|
|
901
|
-
scanLimit: options.scanLimit,
|
|
902
|
-
opencodeBin: options.opencodeBin,
|
|
903
|
-
runOpenCodeSessionList: options.runOpenCodeSessionList,
|
|
904
|
-
};
|
|
905
|
-
if (providerHomePath) listOptions[homeOptionKey] = providerHomePath;
|
|
906
|
-
const homeSessions = await listFn(listOptions);
|
|
907
|
-
sessions.push(...homeSessions.map(session => normalize({
|
|
908
|
-
...session,
|
|
909
|
-
providerHomeId,
|
|
910
|
-
providerHomePath,
|
|
911
|
-
})).filter(isVisibleAgentSession));
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
if (providers.includes('codex')) {
|
|
916
|
-
await listForHomes('codex', providerHomes.codex, 'codexHome', listCodexSessions, 'codexHome', normalizeCodexSession);
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
if (providers.includes('claude')) {
|
|
920
|
-
await listForHomes('claude', providerHomes.claude, 'claudeHome', listClaudeSessions, 'claudeHome');
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
if (providers.includes('qoder')) {
|
|
924
|
-
await listForHomes('qoder', providerHomes.qoder, 'qoderHome', listQoderSessions, 'qoderHome');
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
if (providers.includes('opencode')) {
|
|
928
|
-
const configuredHomes = Array.isArray(providerHomes.opencode) && providerHomes.opencode.length > 0
|
|
929
|
-
? providerHomes.opencode
|
|
930
|
-
: [{ id: 'default', path: options.opencodeHome }];
|
|
931
|
-
const home = configuredHomes.find(candidate => String(candidate?.id || '') === 'default') || configuredHomes[0];
|
|
932
|
-
const providerHomeId = String(home?.id || 'default').trim() || 'default';
|
|
933
|
-
const providerHomePath = String(home?.path || '').trim();
|
|
934
|
-
const homeSessions = await listOpenCodeSessions({
|
|
935
|
-
limit: Number.isFinite(options.providerLimit) ? options.providerLimit : limit,
|
|
936
|
-
scanLimit: options.scanLimit,
|
|
937
|
-
opencodeBin: options.opencodeBin,
|
|
938
|
-
opencodeHome: providerHomePath,
|
|
939
|
-
runOpenCodeSessionList: options.runOpenCodeSessionList,
|
|
940
|
-
});
|
|
941
|
-
sessions.push(...homeSessions.map(session => ({
|
|
942
|
-
...session,
|
|
943
|
-
providerHomeId,
|
|
944
|
-
providerHomePath,
|
|
945
|
-
})));
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
return dedupeAgentSessions(sessions)
|
|
949
|
-
.sort(compareAgentSessions)
|
|
950
|
-
.slice(0, limit);
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
async function findAgentSession(provider, sessionId, options = {}) {
|
|
954
|
-
const normalizedProvider = normalizeProvider(provider);
|
|
955
|
-
const normalizedSessionId = String(sessionId || '').trim();
|
|
956
|
-
if (!normalizedProvider || !isSafeSessionId(normalizedSessionId)) return null;
|
|
957
|
-
|
|
958
|
-
const sessions = await listAgentSessions({
|
|
959
|
-
...options,
|
|
960
|
-
providers: [normalizedProvider],
|
|
961
|
-
limit: options.limit || 200,
|
|
962
|
-
providerLimit: options.providerLimit || 200,
|
|
963
|
-
});
|
|
964
|
-
const requestedHomeId = typeof options.providerHomeId === 'string' ? options.providerHomeId.trim() : '';
|
|
965
|
-
return sessions.find(session => session.id === normalizedSessionId && (!requestedHomeId || (session.providerHomeId || 'default') === requestedHomeId)) || null;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
module.exports = {
|
|
969
|
-
buildAgentSessionResumeCommand,
|
|
970
|
-
compareAgentSessions,
|
|
971
|
-
findAgentSession,
|
|
972
|
-
hasTemporaryWorkspaceReference,
|
|
973
|
-
isAgentManagedWorktree,
|
|
974
|
-
isDefaultClaudeSessionTitle,
|
|
975
|
-
isSafeSessionId,
|
|
976
|
-
isTemporaryWorkspace,
|
|
977
|
-
isVisibleAgentSession,
|
|
978
|
-
listAgentSessions,
|
|
979
|
-
listClaudeSessions,
|
|
980
|
-
listOpenCodeSessions,
|
|
981
|
-
listQoderSessions,
|
|
982
|
-
normalizeProvider,
|
|
983
|
-
paginateAgentSessions,
|
|
984
|
-
resolveCodexResumeModelProvider,
|
|
985
|
-
searchAgentSessions,
|
|
986
|
-
};
|