farming-code 2.2.27 → 2.2.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/README.zh_cn.md +9 -2
- package/THIRD_PARTY_NOTICES.md +3 -0
- package/backend/acp-runtime.js +15 -1
- package/backend/agent-manager.js +1054 -94
- package/backend/atomic-json-store.js +37 -0
- package/backend/cli-agents.js +9 -7
- package/backend/config-manager.js +167 -58
- package/backend/control-api.js +2 -1
- package/backend/farming-agent-bootstrap.js +49 -0
- package/backend/farming-agent-bootstrap.zh_cn.md +5 -0
- package/backend/farming-app-cli.js +9 -2
- package/backend/farming-cli.js +55 -0
- package/backend/farming-session-store.js +92 -89
- package/backend/main-agent-skills.js +17 -0
- package/backend/preview-session-manager.js +68 -0
- package/backend/provider-adapters.js +44 -5
- package/backend/review-session-store.js +32 -25
- package/backend/review-state-store.js +13 -14
- package/backend/run-history-store.js +13 -16
- package/backend/server.js +103 -78
- package/backend/storage-layout.js +20 -0
- package/backend/workspace-file-router.js +141 -0
- package/backend/workspace-file-service.js +19 -0
- package/backend/workspace-root-registry.js +6 -4
- package/dist/assets/App-CM7Cy-l4.css +1 -0
- package/dist/assets/App-CPG4WcjO.js +658 -0
- package/dist/assets/{FileEditorMarkdownPreview-Da5jguUs.js → FileEditorMarkdownPreview-DYOMm-b1.js} +5 -5
- package/dist/assets/FileEditorPane-DXXq82aM.js +2 -0
- package/dist/assets/IconGlyphs-DrdPjYXr.js +1 -0
- package/dist/assets/ProjectFilesSection-CP66XVPl.js +12 -0
- package/dist/assets/{ReviewPage-L1vh1Ggs.js → ReviewPage-w21MEPD6.js} +1 -1
- package/dist/assets/{abnfDiagram-VRR7QNED-nnglrXFi.js → abnfDiagram-VRR7QNED-BY1qwq8A.js} +1 -1
- package/dist/assets/api-w2x5QfxB.js +1 -0
- package/dist/assets/{arc-CWoVlxJw.js → arc-DgZRAlwj.js} +1 -1
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-BEXMaFfY.js → architectureDiagram-ZJ3FMSHR-jFn144od.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-1mCezSBk.js → blockDiagram-677ZJIJ3-BmRjlV0H.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-DhTiI6Uv.js → c4Diagram-LMCZKHZV-DUKul6tT.js} +1 -1
- package/dist/assets/{workspace-editor-monaco-DLlws5Ig.js → channel-CI9j3QFD.js} +1 -1
- package/dist/assets/chunk-2Q5K7J3B-87UnWaoh.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-CCdsKd73.js → chunk-32BRIVSS-rGVu23o5.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-Gncjk4LF.js → chunk-52WLFC77-CvFDKgbB.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-Dlw7AXWp.js → chunk-5VM5RSS4-CFgnRW1C.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-ZBRhjLOh.js → chunk-7BUUIJ7U-Cp7bqW6s.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-CiDVUP82.js → chunk-C7G6YPKG-BIS1gjZO.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-z6gXP2_N.js → chunk-EX3LRPZG-BKG-cR9j.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-DMZBccQa.js → chunk-FWX5IMBZ-B8PsTr8a.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-D8tIeoPk.js → chunk-HOUHSVGY-BHFOAiXT.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-b6oQ2Q17.js → chunk-ICXQ74PX-CvLE1J9X.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-DSyBRaRG.js → chunk-JWPE2WC7-D8misks7.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-DAVH_p2a.js → chunk-MOJQB5TN-D-oNgSNH.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-DxoiMCI-.js → chunk-OGEWGWER-C2N-la9e.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-NsOWh7HM.js → chunk-PUDLZKDR-BwI3Jz8q.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-Di4H7L21.js → chunk-Q4XR5HBZ-BuqGfsXA.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-CZA9pvFX.js → chunk-RYQCIY6F-Bq4XZcGt.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-DttpZg9Y.js → chunk-V7JOEXUC-QZLzdTTJ.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-Cb0-kQ9g.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-D-Fmtd4Z.js → chunk-VR4S4FIN-DcZTpML_.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-CUxMtfK2.js → chunk-WYO6CB5R-DCU8wuny.js} +2 -2
- package/dist/assets/chunk-XXDRQBXY-BZAC1Krv.js +1 -0
- package/dist/assets/{chunk-ZGVPDNZ5-CoV2QEl0.js → chunk-ZGVPDNZ5-B7r85QbY.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-DncwlQQc.js → chunk-ZIRB5QZD-BgEnDWhQ.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DcvGOuvi.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-DDYUSofQ.js +1 -0
- package/dist/assets/code-dark-BDjwj7Um.css +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-BNIAz0nN.js → cose-bilkent-JH36ORCC-CThXS2qG.js} +1 -1
- package/dist/assets/{cssMode-DDWxTPm_.js → cssMode-Bdg5RpcJ.js} +1 -1
- package/dist/assets/{cynefinDiagram-TSTJHNR4-0xPI92Lg.js → cynefinDiagram-TSTJHNR4-DxBgzw25.js} +1 -1
- package/dist/assets/{dagre-DXlcHgr3.js → dagre-BM-GvGUZ.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-DfuMG4gU.js → dagre-VKFMJZFB-B7UCRmxR.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-CT00bLZ6.js → diagram-FQU43EPY-CeL2DwKx.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-Xbh7zXUx.js → diagram-G47NLZAW-BEirglCC.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-SRDVPfn7.js → diagram-NH7WQ7WH-C6wcI-Rl.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-CQRli4Np.js → diagram-OA4YK3LP-DpM-XXtJ.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-DMf17WQi.js → diagram-WEI45ONY-BQyaut9k.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-DhpFkgJ5.js → ebnfDiagram-CCIWWBDH-UmAXsUhr.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-1IwxWmJo.js → erDiagram-Q63AITRT-CdYLEOch.js} +1 -1
- package/dist/assets/file-icons-BOlcJ0ZF.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-CO-z9-tq.js +1 -0
- package/dist/assets/{freemarker2-QBsTERH-.js → freemarker2-DfMDJfnE.js} +1 -1
- package/dist/assets/{ganttDiagram-NO4QXBWP-BNCdfyr1.js → ganttDiagram-NO4QXBWP-DgSUNdUB.js} +1 -1
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-pbyWZuiX.js → gitGraphDiagram-IHSO6WYX-DjwjtRtF.js} +1 -1
- package/dist/assets/{handlebars-CuoxPo5A.js → handlebars-BEdPtzMT.js} +1 -1
- package/dist/assets/{html-gX5PEu0Q.js → html-B1fPb1QD.js} +1 -1
- package/dist/assets/html2canvas-DsczWxBa.js +5 -0
- package/dist/assets/{htmlMode-DIWUbUxd.js → htmlMode-CY2ZjHxH.js} +1 -1
- package/dist/assets/{index-CtwKYTiC.js → index-BzQO3pUr.js} +2 -2
- package/dist/assets/{infoDiagram-FWYZ7A6U-BcTOgDbe.js → infoDiagram-FWYZ7A6U-Bi9076l2.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-DCdvGKrn.js → ishikawaDiagram-FXEZZL3T-DaMaNZN7.js} +1 -1
- package/dist/assets/{javascript-BYKGIUGs.js → javascript-BV2OsWA0.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-BZ-1q_IT.js → journeyDiagram-5HDEW3XC-CfDy69EZ.js} +1 -1
- package/dist/assets/{jsonMode-AFmQQP6u.js → jsonMode-zd07aeuX.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-BIgejCjj.js → kanban-definition-HUTT4EX6-XFvZ722B.js} +1 -1
- package/dist/assets/{line-CfptFMmX.js → line-BXK9PKLn.js} +1 -1
- package/dist/assets/{linear-Dld3_ERu.js → linear-CULvmq2Z.js} +1 -1
- package/dist/assets/{liquid-DBIl-f0z.js → liquid-BParI24X.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-DK6tqicV.js → lspLanguageFeatures-BzredkoV.js} +1 -1
- package/dist/assets/main-BlVUXfxa.css +1 -0
- package/dist/assets/{map-LZWWoeWa.js → map-C9Qw9eWh.js} +1 -1
- package/dist/assets/{mdx-DS-bVtZN.js → mdx-vGzUJN98.js} +1 -1
- package/dist/assets/{mermaid.core-gSpX30pV.js → mermaid.core-CzazaIKr.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-BKBaI4LW.js → mindmap-definition-LN4V7U3C-Uoff7hZ3.js} +1 -1
- package/dist/assets/{monaco.contribution-BXz-lfFB.js → monaco.contribution-BmaeBQEc.js} +2 -2
- package/dist/assets/{ordinal-BLrOss5K.js → ordinal-r6pIwRdZ.js} +1 -1
- package/dist/assets/{pegDiagram-2B236MQR-sBvDY3VX.js → pegDiagram-2B236MQR-CCBiHQjk.js} +1 -1
- package/dist/assets/{pieDiagram-ENE6RG2P-DWlWcu08.js → pieDiagram-ENE6RG2P-D61s7l75.js} +1 -1
- package/dist/assets/{python-C93q3xXz.js → python-CUwdLgsI.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-DZutUd3J.js → quadrantDiagram-ABIIQ3AL-D_CWk2DQ.js} +1 -1
- package/dist/assets/{railroadDiagram-RFXS5EU6-DQb3lXGM.js → railroadDiagram-RFXS5EU6-CdlCHtxN.js} +1 -1
- package/dist/assets/{razor-CBifNGXO.js → razor-BScebUxU.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE-DqFGXu2e.js → requirementDiagram-TGXJPOKE-BLpHtkoC.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-d7ECahnO.js → sankeyDiagram-HTMAVEWB-CkhYZN2j.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-DdsbKqct.js → sequenceDiagram-DBY2YBRQ-8bploKJl.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-daTB6OcF.js → sizeCapture-X5ZJPWSS-DtSdkS0d.js} +1 -1
- package/dist/assets/{src-WBW1QxJt.js → src-6yeq6WBA.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-P6iSrgwR.js → stateDiagram-2N3HPSRC-DfmVGpfA.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-B2c9CQ-J.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-BGnZJx1M.js → swimlanes-5IMT3BWC-DRLk2zRF.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-B7_APh_h.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-rA-r3aUR.js → timeline-definition-FHXFAJF6-Cngfy588.js} +1 -1
- package/dist/assets/{tsMode-B0oUTcXQ.js → tsMode-DzUAibXK.js} +1 -1
- package/dist/assets/{typescript-KJKfYO7K.js → typescript-D9EOeM7N.js} +1 -1
- package/dist/assets/{vennDiagram-L72KCM5P-DiVKUjA9.js → vennDiagram-L72KCM5P-DeJn63Lq.js} +1 -1
- package/dist/assets/{wardleyDiagram-EHGQE667-Cfxh7UOn.js → wardleyDiagram-EHGQE667-BH1nzy77.js} +1 -1
- package/dist/assets/{workers-BSQRIkqa.js → workers-DAiomYZM.js} +1 -1
- package/dist/assets/workspace-editor-model-CSGCl21x.js +1 -0
- package/dist/assets/workspace-editor-monaco-CFEfFNcA.js +1 -0
- package/dist/assets/{workspace-editor-monaco-BIpqcWf1.js → workspace-editor-monaco-tXA-udGx.js} +3 -3
- package/dist/assets/workspace-view-state-BS_V8JVs.js +7 -0
- package/dist/assets/{xml-C8FAcN6j.js → xml-wWl1dhkQ.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG--hmryQeL.js → xychartDiagram-FW5EYKEG-SkO2prCU.js} +1 -1
- package/dist/assets/{yaml-BQ4NrRhG.js → yaml-Dc2WDaOZ.js} +1 -1
- package/dist/crt-markdown-renderer.js +46 -46
- package/dist/index.html +1 -1
- package/extensions/browser/backend/agent-capability.js +55 -0
- package/extensions/browser/backend/browser-mcp-server.js +269 -0
- package/extensions/browser/backend/browser-resource-manager.js +524 -0
- package/extensions/browser/backend/browser-resource-store.js +149 -0
- package/extensions/browser/backend/browser-router.js +128 -0
- package/extensions/browser/backend/cdp-browser-runtime.js +648 -0
- package/extensions/browser/backend/cdp-client.js +167 -0
- package/extensions/browser/backend/executable-discovery.js +91 -0
- package/extensions/browser/backend/farming-browser-client.js +83 -0
- package/extensions/browser/backend/index.js +7 -0
- package/extensions/browser/bin/farming-browser +117 -0
- package/extensions/browser/frontend/BrowserSidebarPortals.tsx +362 -0
- package/extensions/browser/frontend/BrowserViewer.tsx +329 -0
- package/extensions/browser/frontend/browser-resource-state.ts +60 -0
- package/extensions/browser/frontend/browser.css +516 -0
- package/extensions/browser/frontend/types.ts +25 -0
- package/extensions/browser/frontend/useBrowserResources.ts +151 -0
- package/frontend/session-bridge.js +7 -6
- package/frontend/skins/crt/app.js +64 -4
- package/package.json +18 -13
- package/shared/browser-protocol.js +1 -1
- package/dist/assets/App-BrP-ENHg.css +0 -1
- package/dist/assets/App-Cm8qTjsc.js +0 -210
- package/dist/assets/FileEditorPane-fFqHA4wW.js +0 -2
- package/dist/assets/IconGlyphs-C2WFcoJS.js +0 -1
- package/dist/assets/ProjectFilesSection-Cyy3Vcn8.js +0 -12
- package/dist/assets/api-D8nyOEbz.js +0 -1
- package/dist/assets/channel-BVWNatUB.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-d5WWh8jo.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-UHNr_yhX.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-BBXwjhUx.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Db0ib5iE.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-Bkf69XF9.js +0 -1
- package/dist/assets/code-dark-BKtvf0Xc.css +0 -1
- package/dist/assets/file-icons-BqiH0rDI.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-DYFo2xmB.js +0 -1
- package/dist/assets/main-XMXgyJJt.css +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-DIYSf_qh.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-BIkrlKrZ.js +0 -8
- package/dist/assets/workspace-editor-model-D0Im34S5.js +0 -1
- package/dist/assets/workspace-view-state-BiuEbmRr.js +0 -7
- /package/dist/assets/{abap-Cc5D5h5i.js → abap-CtX5nWyX.js} +0 -0
- /package/dist/assets/{apex-BKopwLmx.js → apex-DQJRAHwc.js} +0 -0
- /package/dist/assets/{array-HeX70jSN.js → array-BTwzYU0x.js} +0 -0
- /package/dist/assets/{azcli-DI-C34WA.js → azcli-9SMrOQ4q.js} +0 -0
- /package/dist/assets/{bat-Cbp6u42z.js → bat-CBGLUsw1.js} +0 -0
- /package/dist/assets/{bicep-4QA1jTCM.js → bicep-pDx8da1v.js} +0 -0
- /package/dist/assets/{cameligo-Dda_adPs.js → cameligo-hZV3vQ6_.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-Di0sYzi1.js → chunk-Y2CYZVJY-BYi0W5ea.js} +0 -0
- /package/dist/assets/{clojure-CvY8A83L.js → clojure-BhCwU3gq.js} +0 -0
- /package/dist/assets/{coffee-4LX2Sv8A.js → coffee-BVB1PsgH.js} +0 -0
- /package/dist/assets/{core-B9MwRjDE.js → core-vPkV8P_m.js} +0 -0
- /package/dist/assets/{cpp-D4AzSV28.js → cpp-eTjuiNPq.js} +0 -0
- /package/dist/assets/{csharp-C4nWN4Yd.js → csharp-1kP-kKZT.js} +0 -0
- /package/dist/assets/{csp-CiEaaS5Z.js → csp-C_iQqIes.js} +0 -0
- /package/dist/assets/{css-DXxBRsbk.js → css-CxOs7IfP.js} +0 -0
- /package/dist/assets/{cypher-DOMzqyFA.js → cypher-Cd-a9Y82.js} +0 -0
- /package/dist/assets/{cytoscape.esm-Cl8iC3D7.js → cytoscape.esm-OLojuicg.js} +0 -0
- /package/dist/assets/{dart-BWS7MXt_.js → dart-whhXpexn.js} +0 -0
- /package/dist/assets/{defaultLocale-GJwWH1Jr.js → defaultLocale-CPimVhfE.js} +0 -0
- /package/dist/assets/{dist-ClAL-Tv5.js → dist-CLPYXg1u.js} +0 -0
- /package/dist/assets/{dockerfile-Baf4U3xT.js → dockerfile-DibBi8b6.js} +0 -0
- /package/dist/assets/{ecl-CT7udlkQ.js → ecl-DlF1KdoW.js} +0 -0
- /package/dist/assets/{editor.api2-B9h6iFPK.js → editor.api2-D74ufkbr.js} +0 -0
- /package/dist/assets/{elixir-CIbAZw5l.js → elixir-CHQ8uFT3.js} +0 -0
- /package/dist/assets/{flow9-Dqiw45WV.js → flow9-8nUnVKk1.js} +0 -0
- /package/dist/assets/{fsharp-E8E2L9jU.js → fsharp-DNZNZyEE.js} +0 -0
- /package/dist/assets/{go-CouVSN4D.js → go-_kPJjNc_.js} +0 -0
- /package/dist/assets/{graphlib-CbSvZcZU.js → graphlib-CBGF9gA9.js} +0 -0
- /package/dist/assets/{graphql-a6h6h5-t.js → graphql-4HCNVt5g.js} +0 -0
- /package/dist/assets/{hcl-vso3e6N-.js → hcl-C87ymY0o.js} +0 -0
- /package/dist/assets/{ini-SwZZkotR.js → ini-BYrrGNTc.js} +0 -0
- /package/dist/assets/{init-BPLPMQ3Y.js → init-8_PCa3LO.js} +0 -0
- /package/dist/assets/{java-CtRLC4_3.js → java-B211rJbk.js} +0 -0
- /package/dist/assets/{julia-CuJWFKQH.js → julia-DVPsRtBm.js} +0 -0
- /package/dist/assets/{katex-C8DPyI6s.js → katex-C2iYad0m.js} +0 -0
- /package/dist/assets/{kotlin-B_kBhsre.js → kotlin-BYyNerjp.js} +0 -0
- /package/dist/assets/{less-CtrHIfz3.js → less-EC9UblGE.js} +0 -0
- /package/dist/assets/{lexon-yVt1pJLu.js → lexon-B1yuUdqW.js} +0 -0
- /package/dist/assets/{lua-prOwgJ4U.js → lua-Bo6GFzxT.js} +0 -0
- /package/dist/assets/{m3-DhrdTQ84.js → m3-C-Y9cBVI.js} +0 -0
- /package/dist/assets/{markdown-DoI5HwSM.js → markdown-BHu-wLbe.js} +0 -0
- /package/dist/assets/{mermaid-parser.core-BQtepoLd.js → mermaid-parser.core-IxcGtNYG.js} +0 -0
- /package/dist/assets/{mips-Dye5jsBU.js → mips-Dkds26rX.js} +0 -0
- /package/dist/assets/{msdax-TkNOyIL8.js → msdax-PU4g-8_g.js} +0 -0
- /package/dist/assets/{mysql-CEc-RKZF.js → mysql-fPpuGpS7.js} +0 -0
- /package/dist/assets/{objective-c-CqqCsQz0.js → objective-c-Wy1e5JUf.js} +0 -0
- /package/dist/assets/{pascal-DO_pj8yg.js → pascal-BIXwvrqU.js} +0 -0
- /package/dist/assets/{pascaligo-1cbdZdF3.js → pascaligo-DwR0AtL_.js} +0 -0
- /package/dist/assets/{path-YdFzr2W6.js → path-BxQuywGl.js} +0 -0
- /package/dist/assets/{perl-B_N3PYfC.js → perl-CGHAl8my.js} +0 -0
- /package/dist/assets/{pgsql-9iYk1FQ7.js → pgsql-B91M73E2.js} +0 -0
- /package/dist/assets/{php-rO2sgoUM.js → php-C70ttrCx.js} +0 -0
- /package/dist/assets/{pla-Cbgv60kq.js → pla-BNrXaRh0.js} +0 -0
- /package/dist/assets/{postiats-y6xrhy_M.js → postiats-Dv2IAZR9.js} +0 -0
- /package/dist/assets/{powerquery-BaD8gWNE.js → powerquery-CkY5Wq7J.js} +0 -0
- /package/dist/assets/{powershell-BMhG4JVe.js → powershell-uGIYLU3C.js} +0 -0
- /package/dist/assets/{protobuf-CdOP5kN3.js → protobuf-CavfmJu-.js} +0 -0
- /package/dist/assets/{pug-Ck60hNF9.js → pug-Drqnyitx.js} +0 -0
- /package/dist/assets/{qrcode-DV-_rjU8.js → qrcode-7uGsTEmi.js} +0 -0
- /package/dist/assets/{qsharp-BcaKFfP-.js → qsharp-C7yF-Dti.js} +0 -0
- /package/dist/assets/{r-rFNes0iK.js → r-HXLGP0_-.js} +0 -0
- /package/dist/assets/{redis-DkpQ3K6G.js → redis-C4y6mf2p.js} +0 -0
- /package/dist/assets/{redshift-Di9N5TI3.js → redshift-DdQrFPrv.js} +0 -0
- /package/dist/assets/{restructuredtext-By5ZzLt6.js → restructuredtext-CBrf2PNj.js} +0 -0
- /package/dist/assets/{rough.esm-c4PR5shF.js → rough.esm-6CnTHTkH.js} +0 -0
- /package/dist/assets/{ruby-fF5zGiLp.js → ruby-CVtMoX2B.js} +0 -0
- /package/dist/assets/{rust-C5b3AYY6.js → rust-Ckq4sbMP.js} +0 -0
- /package/dist/assets/{sb-CD07UNRs.js → sb-er66OpE3.js} +0 -0
- /package/dist/assets/{scala-jtn1ip9G.js → scala-BdWZz-hH.js} +0 -0
- /package/dist/assets/{scheme-C4vqMkn_.js → scheme-kTV_s2kP.js} +0 -0
- /package/dist/assets/{scss-I4Glxjbz.js → scss-Bymy2VJQ.js} +0 -0
- /package/dist/assets/{shell-DubUcuns.js → shell-bwEP1LQ1.js} +0 -0
- /package/dist/assets/{solidity-CNy2KSl2.js → solidity-DCddeBgL.js} +0 -0
- /package/dist/assets/{sophia-D9_URt84.js → sophia-BMN3AQig.js} +0 -0
- /package/dist/assets/{sparql-DviXpm4C.js → sparql-CSXOLjzi.js} +0 -0
- /package/dist/assets/{sql-vDRbAZgK.js → sql-COg8ewmK.js} +0 -0
- /package/dist/assets/{st-CnpnRqA7.js → st-CIaZtBS_.js} +0 -0
- /package/dist/assets/{swift-D_g8Ganz.js → swift-DXiOhUHu.js} +0 -0
- /package/dist/assets/{systemverilog-OuZa5h1M.js → systemverilog-BTDE6Dr2.js} +0 -0
- /package/dist/assets/{tcl-DBm9ucsV.js → tcl-B0zy9NvV.js} +0 -0
- /package/dist/assets/{twig-BRzEqX5Y.js → twig-D594l4Z1.js} +0 -0
- /package/dist/assets/{typespec-D4ZgGeX8.js → typespec-XKVjaPqo.js} +0 -0
- /package/dist/assets/{useWorkspaceMenuKeyboard-Brws6Ar9.js → useWorkspaceMenuKeyboard-Bpy_s69Z.js} +0 -0
- /package/dist/assets/{vb-DcP4s6WS.js → vb-B2wYoKRV.js} +0 -0
- /package/dist/assets/{wgsl-CnRJ_QUf.js → wgsl-D0Yf2LbK.js} +0 -0
- /package/dist/assets/{workspace-working-copy-D8-s_Sgh.js → workspace-working-copy-C3FSR3N6.js} +0 -0
|
@@ -2,6 +2,7 @@ const crypto = require('crypto');
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const { isDeepStrictEqual } = require('util');
|
|
5
|
+
const { atomicWriteJson } = require('./atomic-json-store');
|
|
5
6
|
const { legacyRuntimeMetadata } = require('./agent-runtime-binding');
|
|
6
7
|
const { lifecycleJournal } = require('./agent-lifecycle-journal');
|
|
7
8
|
const storageLayout = require('./storage-layout');
|
|
@@ -9,6 +10,7 @@ const storageLayout = require('./storage-layout');
|
|
|
9
10
|
const AGENT_RECORD_ID_PREFIX = 'agent';
|
|
10
11
|
const AGENT_RECORD_VERSION = 1;
|
|
11
12
|
const AGENT_STATE_VERSION = 1;
|
|
13
|
+
const SESSION_INDEX_VERSION = 2;
|
|
12
14
|
const MAX_MAIN_PAGE_SESSION_KEYS = 50;
|
|
13
15
|
const AGENT_STATE_FIELDS = [
|
|
14
16
|
'acpState',
|
|
@@ -34,6 +36,7 @@ const AGENT_STATE_FIELDS = [
|
|
|
34
36
|
'readOutputEpoch',
|
|
35
37
|
'readOutputSeq',
|
|
36
38
|
'unread',
|
|
39
|
+
'composerCommands',
|
|
37
40
|
];
|
|
38
41
|
const AGENT_STATE_FIELD_SET = new Set(AGENT_STATE_FIELDS);
|
|
39
42
|
const PRODUCT_STATE_FIELDS = [
|
|
@@ -100,14 +103,6 @@ function withoutUpdatedAt(value) {
|
|
|
100
103
|
return copy;
|
|
101
104
|
}
|
|
102
105
|
|
|
103
|
-
function atomicWriteJson(file, value) {
|
|
104
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
105
|
-
const tmpFile = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
106
|
-
fs.writeFileSync(tmpFile, JSON.stringify(value, null, 2), { mode: 0o600 });
|
|
107
|
-
fs.renameSync(tmpFile, file);
|
|
108
|
-
fs.chmodSync(file, 0o600);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
106
|
function parseProviderSessionKey(key) {
|
|
112
107
|
const match = String(key || '').match(/^agent-session:([^:]+):(.+)$/);
|
|
113
108
|
if (!match) return null;
|
|
@@ -131,28 +126,38 @@ class FarmingSessionStore {
|
|
|
131
126
|
this.normalizeMainPageSessionKeys = typeof options.normalizeMainPageSessionKeys === 'function'
|
|
132
127
|
? options.normalizeMainPageSessionKeys
|
|
133
128
|
: keys => (Array.isArray(keys) ? keys : []).slice(0, MAX_MAIN_PAGE_SESSION_KEYS);
|
|
129
|
+
this.writeJson = typeof options.writeJson === 'function'
|
|
130
|
+
? options.writeJson
|
|
131
|
+
: (file, value) => atomicWriteJson(file, value, { mode: 0o600 });
|
|
134
132
|
this.index = null;
|
|
133
|
+
this.legacyProviderSessionRecords = {};
|
|
134
|
+
this.providerSessionRecords = new Map();
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
init({ legacyMainPageSessionKeys = [] } = {}) {
|
|
138
138
|
fs.mkdirSync(this.sessionsDir, { recursive: true });
|
|
139
139
|
this.index = this.readIndex();
|
|
140
140
|
this.reconcileProviderSessionIndex();
|
|
141
|
+
let nextMainPageSessionKeys = this.index.mainPageSessionKeys;
|
|
141
142
|
if (!Array.isArray(this.index.mainPageSessionKeys) || this.index.mainPageSessionKeys.length === 0) {
|
|
142
143
|
const migrated = this.filterRecoverableMainPageSessionKeys(legacyMainPageSessionKeys);
|
|
143
144
|
if (migrated.length > 0) {
|
|
144
|
-
|
|
145
|
-
return;
|
|
145
|
+
nextMainPageSessionKeys = migrated;
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
nextMainPageSessionKeys = this.filterRecoverableMainPageSessionKeys(nextMainPageSessionKeys);
|
|
149
|
+
nextMainPageSessionKeys.forEach(sessionKey => {
|
|
150
|
+
if (this.getRecordForProviderSessionKey(sessionKey)) return;
|
|
151
|
+
this.ensureRecordForProviderSessionKey(sessionKey, {
|
|
152
|
+
archived: false,
|
|
153
|
+
lastSeenAt: now(),
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
this.writeIndex({ ...this.index, mainPageSessionKeys: nextMainPageSessionKeys });
|
|
157
|
+
this.legacyProviderSessionRecords = {};
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
reconcileProviderSessionIndex() {
|
|
155
|
-
const index = this.ensureIndex();
|
|
156
161
|
const recordsByProviderKey = new Map();
|
|
157
162
|
const records = this.listStoredAgentRecords();
|
|
158
163
|
const successors = this.legacySuccessors(records);
|
|
@@ -166,16 +171,23 @@ class FarmingSessionStore {
|
|
|
166
171
|
}
|
|
167
172
|
|
|
168
173
|
for (const [sessionKey, records] of recordsByProviderKey) {
|
|
169
|
-
const indexedId = index.providerSessionRecords[sessionKey];
|
|
170
|
-
const indexedRecord = indexedId ? records.find(record => record.id === indexedId) : null;
|
|
171
174
|
if (records.length > 1) {
|
|
172
175
|
const ids = records.map(record => record.id).sort().join(', ');
|
|
173
176
|
throw new Error(`Conflicting Farming session records for ${sessionKey}: ${ids}`);
|
|
174
177
|
}
|
|
175
|
-
|
|
176
|
-
|
|
178
|
+
recordsByProviderKey.set(sessionKey, records[0].id);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
for (const [sessionKey, id] of Object.entries(this.legacyProviderSessionRecords)) {
|
|
182
|
+
if (recordsByProviderKey.has(sessionKey)) continue;
|
|
183
|
+
const record = this.readRecord(id);
|
|
184
|
+
if (!record || successors.has(record.id)) continue;
|
|
185
|
+
if (record.providerSessionKey && record.providerSessionKey !== sessionKey) {
|
|
186
|
+
throw new Error(`Farming session ${id} is indexed as ${sessionKey} but bound to ${record.providerSessionKey}`);
|
|
177
187
|
}
|
|
188
|
+
recordsByProviderKey.set(sessionKey, record.id);
|
|
178
189
|
}
|
|
190
|
+
this.providerSessionRecords = recordsByProviderKey;
|
|
179
191
|
}
|
|
180
192
|
|
|
181
193
|
filterRecoverableMainPageSessionKeys(keys) {
|
|
@@ -197,6 +209,7 @@ class FarmingSessionStore {
|
|
|
197
209
|
try {
|
|
198
210
|
if (fs.existsSync(this.indexFile)) {
|
|
199
211
|
const parsed = JSON.parse(fs.readFileSync(this.indexFile, 'utf8'));
|
|
212
|
+
this.legacyProviderSessionRecords = this.normalizeProviderSessionRecords(parsed?.providerSessionRecords);
|
|
200
213
|
return this.normalizeIndex(parsed);
|
|
201
214
|
}
|
|
202
215
|
} catch (error) {
|
|
@@ -206,22 +219,25 @@ class FarmingSessionStore {
|
|
|
206
219
|
}
|
|
207
220
|
|
|
208
221
|
normalizeIndex(index) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
:
|
|
222
|
+
return {
|
|
223
|
+
version: SESSION_INDEX_VERSION,
|
|
224
|
+
mainPageSessionKeys: this.normalizeMainPageSessionKeys(index?.mainPageSessionKeys),
|
|
225
|
+
updatedAt: typeof index?.updatedAt === 'number' ? index.updatedAt : now(),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
normalizeProviderSessionRecords(providerSessionRecords) {
|
|
212
230
|
const normalizedProviderSessionRecords = {};
|
|
213
|
-
Object.entries(
|
|
231
|
+
Object.entries(
|
|
232
|
+
providerSessionRecords && typeof providerSessionRecords === 'object' && !Array.isArray(providerSessionRecords)
|
|
233
|
+
? providerSessionRecords
|
|
234
|
+
: {},
|
|
235
|
+
).forEach(([key, id]) => {
|
|
214
236
|
if (!parseProviderSessionKey(key)) return;
|
|
215
237
|
if (!safeSessionFileName(id)) return;
|
|
216
238
|
normalizedProviderSessionRecords[key] = id;
|
|
217
239
|
});
|
|
218
|
-
|
|
219
|
-
return {
|
|
220
|
-
version: 1,
|
|
221
|
-
mainPageSessionKeys: this.normalizeMainPageSessionKeys(index?.mainPageSessionKeys),
|
|
222
|
-
providerSessionRecords: normalizedProviderSessionRecords,
|
|
223
|
-
updatedAt: typeof index?.updatedAt === 'number' ? index.updatedAt : now(),
|
|
224
|
-
};
|
|
240
|
+
return normalizedProviderSessionRecords;
|
|
225
241
|
}
|
|
226
242
|
|
|
227
243
|
ensureIndex() {
|
|
@@ -229,10 +245,11 @@ class FarmingSessionStore {
|
|
|
229
245
|
return this.index;
|
|
230
246
|
}
|
|
231
247
|
|
|
232
|
-
writeIndex() {
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
248
|
+
writeIndex(index = this.ensureIndex()) {
|
|
249
|
+
const nextIndex = this.normalizeIndex({ ...index, updatedAt: now() });
|
|
250
|
+
this.writeJson(this.indexFile, nextIndex);
|
|
251
|
+
this.index = nextIndex;
|
|
252
|
+
return nextIndex;
|
|
236
253
|
}
|
|
237
254
|
|
|
238
255
|
sessionFile(id) {
|
|
@@ -308,10 +325,10 @@ class FarmingSessionStore {
|
|
|
308
325
|
}
|
|
309
326
|
|
|
310
327
|
promoteIndexRecordId(previousId, nextId) {
|
|
311
|
-
if (!
|
|
312
|
-
|
|
313
|
-
if (id === previousId) this.
|
|
314
|
-
}
|
|
328
|
+
if (!previousId || previousId === nextId) return;
|
|
329
|
+
for (const [key, id] of this.providerSessionRecords) {
|
|
330
|
+
if (id === previousId) this.providerSessionRecords.set(key, nextId);
|
|
331
|
+
}
|
|
315
332
|
}
|
|
316
333
|
|
|
317
334
|
writeRecord(record) {
|
|
@@ -335,11 +352,11 @@ class FarmingSessionStore {
|
|
|
335
352
|
|| !sameJson(withoutUpdatedAt(existingState), withoutUpdatedAt(state));
|
|
336
353
|
if (stateChanged) {
|
|
337
354
|
state.updatedAt = now();
|
|
338
|
-
|
|
355
|
+
this.writeJson(this.agentStateFile(id), state);
|
|
339
356
|
}
|
|
340
357
|
if (metadataChanged) {
|
|
341
358
|
metadata.updatedAt = now();
|
|
342
|
-
|
|
359
|
+
this.writeJson(this.sessionFile(id), metadata);
|
|
343
360
|
}
|
|
344
361
|
if (promoted) this.promoteIndexRecordId(previousId, id);
|
|
345
362
|
return id;
|
|
@@ -397,6 +414,8 @@ class FarmingSessionStore {
|
|
|
397
414
|
projectWorkspace: typeof agent.projectWorkspace === 'string' ? agent.projectWorkspace : '',
|
|
398
415
|
mainWorkspace: typeof agent.mainWorkspace === 'string' ? agent.mainWorkspace : '',
|
|
399
416
|
source: typeof agent.source === 'string' ? agent.source : '',
|
|
417
|
+
parentAgentId: typeof agent.parentAgentId === 'string' ? agent.parentAgentId : '',
|
|
418
|
+
forkRequestId: typeof agent.forkRequestId === 'string' ? agent.forkRequestId : '',
|
|
400
419
|
provider: parsed ? parsed.provider : (typeof agent.providerSessionProvider === 'string' ? agent.providerSessionProvider : ''),
|
|
401
420
|
providerHomeId: parsed ? parsed.providerHomeId : (typeof agent.providerHomeId === 'string' ? agent.providerHomeId : ''),
|
|
402
421
|
providerHomePath: typeof agent.providerHomePath === 'string' ? agent.providerHomePath : '',
|
|
@@ -407,6 +426,9 @@ class FarmingSessionStore {
|
|
|
407
426
|
providerSessionResolvedAt: typeof agent.providerSessionResolvedAt === 'number' ? agent.providerSessionResolvedAt : null,
|
|
408
427
|
providerSessionTitle: typeof agent.providerSessionTitle === 'string' ? agent.providerSessionTitle : '',
|
|
409
428
|
providerSessionWorkspace: typeof agent.providerSessionWorkspace === 'string' ? agent.providerSessionWorkspace : '',
|
|
429
|
+
forkedFromProviderSessionId: typeof agent.forkedFromProviderSessionId === 'string'
|
|
430
|
+
? agent.forkedFromProviderSessionId
|
|
431
|
+
: '',
|
|
410
432
|
terminalInputReceived: agent.terminalInputReceived === true,
|
|
411
433
|
structuredRuntimeProcess: agent.structuredRuntimeProcess
|
|
412
434
|
&& typeof agent.structuredRuntimeProcess === 'object'
|
|
@@ -435,6 +457,9 @@ class FarmingSessionStore {
|
|
|
435
457
|
attentionOutputSeq: typeof agent.attentionOutputSeq === 'number' ? agent.attentionOutputSeq : null,
|
|
436
458
|
readOutputEpoch: typeof agent.readOutputEpoch === 'string' ? agent.readOutputEpoch : '',
|
|
437
459
|
readOutputSeq: typeof agent.readOutputSeq === 'number' ? agent.readOutputSeq : null,
|
|
460
|
+
composerCommands: Array.isArray(agent.composerCommands)
|
|
461
|
+
? cloneJson(agent.composerCommands)
|
|
462
|
+
: [],
|
|
438
463
|
archived: agent.archived === true,
|
|
439
464
|
archivedAt: typeof agent.archivedAt === 'number' ? agent.archivedAt : null,
|
|
440
465
|
...(typeof agent.customTitle === 'string' && agent.customTitle
|
|
@@ -452,8 +477,8 @@ class FarmingSessionStore {
|
|
|
452
477
|
ensureRecordForProviderSessionKey(sessionKey, patch = {}, preferredId = '') {
|
|
453
478
|
const parsed = parseProviderSessionKey(sessionKey);
|
|
454
479
|
if (!parsed) return '';
|
|
455
|
-
|
|
456
|
-
const existingId =
|
|
480
|
+
this.ensureIndex();
|
|
481
|
+
const existingId = this.providerSessionRecords.get(sessionKey);
|
|
457
482
|
const normalizedPreferredId = safeSessionFileName(preferredId) ? preferredId : '';
|
|
458
483
|
const preferredRecord = normalizedPreferredId ? this.readRecord(normalizedPreferredId) : null;
|
|
459
484
|
if (
|
|
@@ -485,15 +510,15 @@ class FarmingSessionStore {
|
|
|
485
510
|
providerSessionTemporary: false,
|
|
486
511
|
updatedAt: now(),
|
|
487
512
|
};
|
|
513
|
+
delete record.visibleOnMainPage;
|
|
488
514
|
if (typeof record.customTitle === 'string' && record.customTitle) {
|
|
489
515
|
record.title = record.customTitle;
|
|
490
516
|
}
|
|
491
|
-
Object.entries(index.providerSessionRecords).forEach(([key, recordId]) => {
|
|
492
|
-
if (key !== sessionKey && recordId === id) delete index.providerSessionRecords[key];
|
|
493
|
-
});
|
|
494
517
|
const writtenId = this.writeRecord(record);
|
|
495
|
-
|
|
496
|
-
|
|
518
|
+
for (const [key, recordId] of this.providerSessionRecords) {
|
|
519
|
+
if (key !== sessionKey && recordId === writtenId) this.providerSessionRecords.delete(key);
|
|
520
|
+
}
|
|
521
|
+
this.providerSessionRecords.set(sessionKey, writtenId);
|
|
497
522
|
return writtenId;
|
|
498
523
|
}
|
|
499
524
|
|
|
@@ -536,7 +561,7 @@ class FarmingSessionStore {
|
|
|
536
561
|
mergedInto: id,
|
|
537
562
|
updatedAt: now(),
|
|
538
563
|
});
|
|
539
|
-
if (mergedId && mergedId !== previousId) this.
|
|
564
|
+
if (mergedId && mergedId !== previousId) this.promoteIndexRecordId(previousId, mergedId);
|
|
540
565
|
}
|
|
541
566
|
}
|
|
542
567
|
return id;
|
|
@@ -569,23 +594,21 @@ class FarmingSessionStore {
|
|
|
569
594
|
rememberMainPageSessionKey(sessionKey, patch = {}) {
|
|
570
595
|
const id = this.ensureRecordForProviderSessionKey(sessionKey, {
|
|
571
596
|
...patch,
|
|
572
|
-
visibleOnMainPage: true,
|
|
573
597
|
archived: false,
|
|
574
598
|
lastSeenAt: now(),
|
|
575
599
|
});
|
|
576
600
|
if (!id) return this.getMainPageSessionKeys();
|
|
577
601
|
const index = this.ensureIndex();
|
|
578
|
-
|
|
602
|
+
const nextIndex = this.writeIndex({ ...index, mainPageSessionKeys: this.normalizeMainPageSessionKeys([
|
|
579
603
|
sessionKey,
|
|
580
604
|
...index.mainPageSessionKeys.filter(key => key !== sessionKey),
|
|
581
|
-
]);
|
|
582
|
-
|
|
583
|
-
return index.mainPageSessionKeys.slice();
|
|
605
|
+
]) });
|
|
606
|
+
return nextIndex.mainPageSessionKeys.slice();
|
|
584
607
|
}
|
|
585
608
|
|
|
586
609
|
rememberAgent(agent) {
|
|
587
610
|
const providerSessionKey = this.providerSessionKeyForAgent(agent);
|
|
588
|
-
const id = this.ensureRecordForAgent(agent, providerSessionKey ? {
|
|
611
|
+
const id = this.ensureRecordForAgent(agent, providerSessionKey ? { archived: false } : {});
|
|
589
612
|
if (providerSessionKey) {
|
|
590
613
|
this.rememberMainPageSessionKey(providerSessionKey, this.recordPatchFromAgent(agent));
|
|
591
614
|
}
|
|
@@ -595,54 +618,33 @@ class FarmingSessionStore {
|
|
|
595
618
|
setMainPageSessionKeys(keys) {
|
|
596
619
|
const normalized = this.normalizeMainPageSessionKeys(keys);
|
|
597
620
|
const index = this.ensureIndex();
|
|
598
|
-
const visible = new Set(normalized);
|
|
599
621
|
normalized.forEach(key => {
|
|
600
622
|
this.ensureRecordForProviderSessionKey(key, {
|
|
601
|
-
visibleOnMainPage: true,
|
|
602
623
|
archived: false,
|
|
603
624
|
lastSeenAt: now(),
|
|
604
625
|
});
|
|
605
626
|
});
|
|
606
|
-
index.mainPageSessionKeys.
|
|
607
|
-
if (visible.has(key)) return;
|
|
608
|
-
const id = index.providerSessionRecords[key];
|
|
609
|
-
const existing = this.readRecord(id);
|
|
610
|
-
if (existing) {
|
|
611
|
-
const writtenId = this.writeRecord({
|
|
612
|
-
...existing,
|
|
613
|
-
visibleOnMainPage: false,
|
|
614
|
-
updatedAt: now(),
|
|
615
|
-
});
|
|
616
|
-
if (writtenId) index.providerSessionRecords[key] = writtenId;
|
|
617
|
-
}
|
|
618
|
-
});
|
|
619
|
-
index.mainPageSessionKeys = normalized;
|
|
620
|
-
this.writeIndex();
|
|
621
|
-
return normalized.slice();
|
|
627
|
+
return this.writeIndex({ ...index, mainPageSessionKeys: normalized }).mainPageSessionKeys.slice();
|
|
622
628
|
}
|
|
623
629
|
|
|
624
630
|
removeMainPageSessionKey(sessionKey) {
|
|
625
631
|
const index = this.ensureIndex();
|
|
626
632
|
if (!index.mainPageSessionKeys.includes(sessionKey)) return false;
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
const writtenId = this.writeRecord({
|
|
632
|
-
...existing,
|
|
633
|
-
visibleOnMainPage: false,
|
|
634
|
-
updatedAt: now(),
|
|
635
|
-
});
|
|
636
|
-
if (writtenId) index.providerSessionRecords[sessionKey] = writtenId;
|
|
637
|
-
}
|
|
638
|
-
this.writeIndex();
|
|
633
|
+
this.writeIndex({
|
|
634
|
+
...index,
|
|
635
|
+
mainPageSessionKeys: index.mainPageSessionKeys.filter(key => key !== sessionKey),
|
|
636
|
+
});
|
|
639
637
|
return true;
|
|
640
638
|
}
|
|
641
639
|
|
|
642
640
|
removeMainPageSessionKeys(keys) {
|
|
643
|
-
const
|
|
644
|
-
|
|
645
|
-
|
|
641
|
+
const index = this.ensureIndex();
|
|
642
|
+
const requested = new Set(Array.isArray(keys) ? keys : []);
|
|
643
|
+
const removed = index.mainPageSessionKeys.filter(key => requested.has(key));
|
|
644
|
+
if (removed.length === 0) return [];
|
|
645
|
+
this.writeIndex({
|
|
646
|
+
...index,
|
|
647
|
+
mainPageSessionKeys: index.mainPageSessionKeys.filter(key => !requested.has(key)),
|
|
646
648
|
});
|
|
647
649
|
return removed;
|
|
648
650
|
}
|
|
@@ -652,8 +654,8 @@ class FarmingSessionStore {
|
|
|
652
654
|
}
|
|
653
655
|
|
|
654
656
|
getRecordForProviderSessionKey(sessionKey) {
|
|
655
|
-
|
|
656
|
-
const id =
|
|
657
|
+
this.ensureIndex();
|
|
658
|
+
const id = this.providerSessionRecords.get(sessionKey);
|
|
657
659
|
return safeSessionFileName(id) ? this.readRecord(id) : null;
|
|
658
660
|
}
|
|
659
661
|
|
|
@@ -670,5 +672,6 @@ module.exports = {
|
|
|
670
672
|
AGENT_STATE_VERSION,
|
|
671
673
|
FarmingSessionStore,
|
|
672
674
|
MAX_MAIN_PAGE_SESSION_KEYS,
|
|
675
|
+
SESSION_INDEX_VERSION,
|
|
673
676
|
parseProviderSessionKey,
|
|
674
677
|
};
|
|
@@ -57,6 +57,22 @@ const MAIN_AGENT_OPERATING_GUIDE = [
|
|
|
57
57
|
];
|
|
58
58
|
|
|
59
59
|
const MAIN_AGENT_SKILLS = [
|
|
60
|
+
{
|
|
61
|
+
id: 'browser-resource',
|
|
62
|
+
name: '系统浏览器操作',
|
|
63
|
+
trigger: '用户要求打开、查看或操作 Farming Project 下的 Browser Resource,或者需要绕过静态 HTML Viewer 限制验证真实网页时',
|
|
64
|
+
summary: '通过 Farming Browser ID 操作用户当前看到的同一个 Headless 系统浏览器;先 Snapshot 获取当前 Ref,再进行点击或输入,页面变化后重新 Snapshot。',
|
|
65
|
+
commands: [
|
|
66
|
+
'farming browser list --workspace <repo>',
|
|
67
|
+
'farming browser start <browser-id>',
|
|
68
|
+
'farming browser snapshot <browser-id>',
|
|
69
|
+
'farming browser navigate <browser-id> <url>',
|
|
70
|
+
'farming browser click <browser-id> <ref-or-css=selector>',
|
|
71
|
+
'farming browser fill <browser-id> <ref-or-css=selector> <text>',
|
|
72
|
+
'farming browser screenshot <browser-id> <output.png>',
|
|
73
|
+
'farming browser stop <browser-id>',
|
|
74
|
+
],
|
|
75
|
+
},
|
|
60
76
|
{
|
|
61
77
|
id: 'memory-report',
|
|
62
78
|
name: '记忆读取总结',
|
|
@@ -137,6 +153,7 @@ function renderMainAgentSkills() {
|
|
|
137
153
|
});
|
|
138
154
|
|
|
139
155
|
lines.push('Rules:');
|
|
156
|
+
lines.push('- Use `farming browser` only for Browser Resources already in the user-selected Project scope; take a new snapshot after navigation or DOM-changing actions.');
|
|
140
157
|
lines.push('- Use `farming memory report` when you need recent context from local agent memories.');
|
|
141
158
|
lines.push('- Use “牧场除虫计划” when the user asks for systematic bug hunting across a directory or module tree.');
|
|
142
159
|
lines.push('- Before spawning child agents for pest control, map modules and module protocols first; do not send overlapping or vague tasks.');
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const crypto = require('crypto');
|
|
2
|
+
|
|
3
|
+
const DEFAULT_PREVIEW_SESSION_TTL_MS = 30 * 60 * 1000;
|
|
4
|
+
const DEFAULT_MAX_PREVIEW_SESSIONS = 128;
|
|
5
|
+
|
|
6
|
+
class PreviewSessionManager {
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.ttlMs = Math.max(1_000, Number(options.ttlMs) || DEFAULT_PREVIEW_SESSION_TTL_MS);
|
|
9
|
+
this.maxSessions = Math.max(1, Number(options.maxSessions) || DEFAULT_MAX_PREVIEW_SESSIONS);
|
|
10
|
+
this.now = options.now || (() => Date.now());
|
|
11
|
+
this.randomUUID = options.randomUUID || (() => crypto.randomUUID());
|
|
12
|
+
this.sessions = new Map();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
createStatic(input) {
|
|
16
|
+
this.cleanupExpired();
|
|
17
|
+
while (this.sessions.size >= this.maxSessions) {
|
|
18
|
+
const oldestId = this.sessions.keys().next().value;
|
|
19
|
+
if (!oldestId) break;
|
|
20
|
+
this.sessions.delete(oldestId);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const now = this.now();
|
|
24
|
+
const session = Object.freeze({
|
|
25
|
+
id: this.randomUUID(),
|
|
26
|
+
kind: 'static',
|
|
27
|
+
rootId: input.rootId,
|
|
28
|
+
workspaceRoot: input.workspaceRoot,
|
|
29
|
+
authorizedRoot: input.authorizedRoot,
|
|
30
|
+
entryPath: input.entryPath,
|
|
31
|
+
baseDirectory: input.baseDirectory,
|
|
32
|
+
createdAt: now,
|
|
33
|
+
expiresAt: now + this.ttlMs,
|
|
34
|
+
});
|
|
35
|
+
this.sessions.set(session.id, session);
|
|
36
|
+
return session;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get(sessionId) {
|
|
40
|
+
const session = this.sessions.get(String(sessionId || ''));
|
|
41
|
+
if (!session) return null;
|
|
42
|
+
if (session.expiresAt <= this.now()) {
|
|
43
|
+
this.sessions.delete(session.id);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return session;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
delete(sessionId) {
|
|
50
|
+
return this.sessions.delete(String(sessionId || ''));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
cleanupExpired() {
|
|
54
|
+
const now = this.now();
|
|
55
|
+
for (const [sessionId, session] of this.sessions) {
|
|
56
|
+
if (session.expiresAt <= now) this.sessions.delete(sessionId);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
dispose() {
|
|
61
|
+
this.sessions.clear();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = {
|
|
66
|
+
DEFAULT_PREVIEW_SESSION_TTL_MS,
|
|
67
|
+
PreviewSessionManager,
|
|
68
|
+
};
|
|
@@ -201,6 +201,12 @@ function codexAcpEnvironment(options = {}) {
|
|
|
201
201
|
if (options.model && options.model !== 'config') config.model = options.model;
|
|
202
202
|
if (options.reasoningEffort && options.reasoningEffort !== 'config') config.model_reasoning_effort = options.reasoningEffort;
|
|
203
203
|
if (options.serviceTier && !['config', 'default'].includes(options.serviceTier)) config.service_tier = options.serviceTier;
|
|
204
|
+
if (typeof options.farmingSystemPrompt === 'string' && options.farmingSystemPrompt.trim()) {
|
|
205
|
+
config.developer_instructions = [
|
|
206
|
+
typeof config.developer_instructions === 'string' ? config.developer_instructions.trim() : '',
|
|
207
|
+
options.farmingSystemPrompt.trim(),
|
|
208
|
+
].filter(Boolean).join('\n\n');
|
|
209
|
+
}
|
|
204
210
|
if (Object.keys(config).length > 0) env.CODEX_CONFIG = JSON.stringify(config);
|
|
205
211
|
const initialMode = { ask: 'read-only', approve: 'agent', full: 'agent-full-access' }[options.approvalMode];
|
|
206
212
|
if (initialMode) env.INITIAL_AGENT_MODE = initialMode;
|
|
@@ -221,7 +227,13 @@ const PROVIDER_ADAPTERS = Object.freeze([
|
|
|
221
227
|
terminalResumeArgs: (args, sessionId) => ['resume', sessionId, ...args],
|
|
222
228
|
acp: { packageName: '@agentclientprotocol/codex-acp', version: '1.1.4' },
|
|
223
229
|
prepareAcpEnvironment: codexAcpEnvironment,
|
|
224
|
-
capabilities: {
|
|
230
|
+
capabilities: {
|
|
231
|
+
runtimeSwitch: true,
|
|
232
|
+
terminalProfile: true,
|
|
233
|
+
goals: false,
|
|
234
|
+
goalSubmission: { terminal: { kind: 'prompt' }, acp: { kind: 'prompt' } },
|
|
235
|
+
sessionFork: true,
|
|
236
|
+
},
|
|
225
237
|
},
|
|
226
238
|
{
|
|
227
239
|
id: 'claude',
|
|
@@ -238,7 +250,13 @@ const PROVIDER_ADAPTERS = Object.freeze([
|
|
|
238
250
|
version: '0.59.0',
|
|
239
251
|
forkMode: 'target-process',
|
|
240
252
|
},
|
|
241
|
-
capabilities: {
|
|
253
|
+
capabilities: {
|
|
254
|
+
runtimeSwitch: true,
|
|
255
|
+
terminalProfile: false,
|
|
256
|
+
goals: false,
|
|
257
|
+
goalSubmission: { terminal: { kind: 'command', prefix: '/goal' }, acp: { kind: 'prompt' } },
|
|
258
|
+
sessionFork: true,
|
|
259
|
+
},
|
|
242
260
|
},
|
|
243
261
|
{
|
|
244
262
|
id: 'opencode',
|
|
@@ -267,7 +285,13 @@ const PROVIDER_ADAPTERS = Object.freeze([
|
|
|
267
285
|
args: ['acp', '--cwd', path.resolve(options.cwd || process.cwd())],
|
|
268
286
|
}),
|
|
269
287
|
},
|
|
270
|
-
capabilities: {
|
|
288
|
+
capabilities: {
|
|
289
|
+
runtimeSwitch: true,
|
|
290
|
+
terminalProfile: false,
|
|
291
|
+
goals: false,
|
|
292
|
+
goalSubmission: { terminal: { kind: 'prompt' }, acp: { kind: 'prompt' } },
|
|
293
|
+
sessionFork: true,
|
|
294
|
+
},
|
|
271
295
|
},
|
|
272
296
|
{
|
|
273
297
|
id: 'qoder',
|
|
@@ -281,9 +305,23 @@ const PROVIDER_ADAPTERS = Object.freeze([
|
|
|
281
305
|
planSession: (rawArgs, launchArgs) => explicitSessionPlan('qoder', rawArgs, launchArgs),
|
|
282
306
|
acp: {
|
|
283
307
|
version: 'native',
|
|
284
|
-
launch: options => ({
|
|
308
|
+
launch: options => ({
|
|
309
|
+
command: options.executable || 'qodercli',
|
|
310
|
+
args: [
|
|
311
|
+
...(typeof options.farmingSystemPrompt === 'string' && options.farmingSystemPrompt.trim()
|
|
312
|
+
? ['--append-system-prompt', options.farmingSystemPrompt.trim()]
|
|
313
|
+
: []),
|
|
314
|
+
'--acp',
|
|
315
|
+
],
|
|
316
|
+
}),
|
|
317
|
+
},
|
|
318
|
+
capabilities: {
|
|
319
|
+
runtimeSwitch: true,
|
|
320
|
+
terminalProfile: false,
|
|
321
|
+
goals: false,
|
|
322
|
+
goalSubmission: { terminal: { kind: 'command', prefix: '/goal set' }, acp: { kind: 'prompt' } },
|
|
323
|
+
sessionFork: true,
|
|
285
324
|
},
|
|
286
|
-
capabilities: { runtimeSwitch: true, terminalProfile: false, goals: false, sessionFork: true },
|
|
287
325
|
},
|
|
288
326
|
]);
|
|
289
327
|
|
|
@@ -313,6 +351,7 @@ function providerCapabilities(provider) {
|
|
|
313
351
|
runtimeSwitch: adapter?.capabilities?.runtimeSwitch === true,
|
|
314
352
|
terminalProfile: adapter?.capabilities?.terminalProfile === true,
|
|
315
353
|
goals: adapter?.capabilities?.goals === true,
|
|
354
|
+
goalSubmission: adapter?.capabilities?.goalSubmission || null,
|
|
316
355
|
sessionFork: adapter?.capabilities?.sessionFork === true,
|
|
317
356
|
...(adapter
|
|
318
357
|
? chatCapabilitiesForProvider(provider)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const crypto = require('crypto');
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
|
+
const { atomicWriteJson } = require('./atomic-json-store');
|
|
4
5
|
const storageLayout = require('./storage-layout');
|
|
5
6
|
|
|
6
7
|
const REVIEW_ID_PATTERN = /^review-[a-f0-9]{32}$/;
|
|
@@ -10,13 +11,6 @@ function clone(value) {
|
|
|
10
11
|
return JSON.parse(JSON.stringify(value));
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
function atomicWriteJson(file, value) {
|
|
14
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
15
|
-
const temporaryFile = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
16
|
-
fs.writeFileSync(temporaryFile, `${JSON.stringify(value, null, 2)}\n`);
|
|
17
|
-
fs.renameSync(temporaryFile, file);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
14
|
function validRevision(value) {
|
|
21
15
|
return value
|
|
22
16
|
&& typeof value === 'object'
|
|
@@ -70,6 +64,9 @@ function normalizeState(value) {
|
|
|
70
64
|
class ReviewSessionStore {
|
|
71
65
|
constructor(configDir, options = {}) {
|
|
72
66
|
this.file = options.file || storageLayout.reviewSessionsFile(configDir);
|
|
67
|
+
this.writeJson = typeof options.writeJson === 'function'
|
|
68
|
+
? options.writeJson
|
|
69
|
+
: (file, value) => atomicWriteJson(file, value, { trailingNewline: true });
|
|
73
70
|
this.state = null;
|
|
74
71
|
}
|
|
75
72
|
|
|
@@ -100,8 +97,8 @@ class ReviewSessionStore {
|
|
|
100
97
|
if (!REVIEW_ID_PATTERN.test(id) || !path.isAbsolute(root) || !OBJECT_ID_PATTERN.test(base) || !OBJECT_ID_PATTERN.test(tree)) {
|
|
101
98
|
throw new TypeError('invalid review session');
|
|
102
99
|
}
|
|
103
|
-
const
|
|
104
|
-
if (
|
|
100
|
+
const currentState = this.ensureState();
|
|
101
|
+
if (currentState.sessions[id]) throw new TypeError('review session already exists');
|
|
105
102
|
const session = {
|
|
106
103
|
base,
|
|
107
104
|
createdAt,
|
|
@@ -113,27 +110,37 @@ class ReviewSessionStore {
|
|
|
113
110
|
...(Array.isArray(paths) ? { paths: [...paths] } : {}),
|
|
114
111
|
updatedAt: createdAt,
|
|
115
112
|
};
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
const nextState = {
|
|
114
|
+
sessions: { ...currentState.sessions, [id]: session },
|
|
115
|
+
};
|
|
116
|
+
this.writeJson(this.file, nextState);
|
|
117
|
+
this.state = nextState;
|
|
118
118
|
return clone(session);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
appendRevision(reviewId, tree, createdAt = new Date().toISOString()) {
|
|
122
122
|
if (!OBJECT_ID_PATTERN.test(tree)) throw new TypeError('invalid review revision');
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
if (!
|
|
126
|
-
const previous =
|
|
127
|
-
if (previous.tree === tree) return { added: false, session: clone(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
123
|
+
const currentState = this.ensureState();
|
|
124
|
+
const currentSession = currentState.sessions[reviewId];
|
|
125
|
+
if (!currentSession) throw new TypeError('review session not found');
|
|
126
|
+
const previous = currentSession.revisions[currentSession.revisions.length - 1];
|
|
127
|
+
if (previous.tree === tree) return { added: false, session: clone(currentSession) };
|
|
128
|
+
const nextSession = {
|
|
129
|
+
...currentSession,
|
|
130
|
+
revisions: [...currentSession.revisions, {
|
|
131
|
+
createdAt,
|
|
132
|
+
number: previous.number + 1,
|
|
133
|
+
previousTree: previous.tree,
|
|
134
|
+
tree,
|
|
135
|
+
}],
|
|
136
|
+
updatedAt: createdAt,
|
|
137
|
+
};
|
|
138
|
+
const nextState = {
|
|
139
|
+
sessions: { ...currentState.sessions, [reviewId]: nextSession },
|
|
140
|
+
};
|
|
141
|
+
this.writeJson(this.file, nextState);
|
|
142
|
+
this.state = nextState;
|
|
143
|
+
return { added: true, session: clone(nextSession) };
|
|
137
144
|
}
|
|
138
145
|
}
|
|
139
146
|
|