farming-code 2.2.23 → 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/native-pty-host-client.js +99 -7
- package/backend/native-pty-host-path.js +20 -0
- package/backend/native-pty-host.js +6 -5
- 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 +171 -6
- 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-KbnE8VC8.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-DhTUO8DA.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-BbNBDA__.js +0 -210
- package/dist/assets/App-BrP-ENHg.css +0 -1
- package/dist/assets/FileEditorPane-5_HUejjd.js +0 -2
- package/dist/assets/IconGlyphs-C2WFcoJS.js +0 -1
- package/dist/assets/ProjectFilesSection-C1RAJWOE.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-CHWt5nSy.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-BqB4HM7r.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.');
|
|
@@ -4,7 +4,10 @@ const crypto = require('crypto');
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const net = require('net');
|
|
6
6
|
const path = require('path');
|
|
7
|
-
const {
|
|
7
|
+
const {
|
|
8
|
+
nativePtyHostPrivateSocketNamePattern,
|
|
9
|
+
nativePtyHostSocketPath,
|
|
10
|
+
} = require('./native-pty-host-path');
|
|
8
11
|
const {
|
|
9
12
|
nativePtyHostRuntimeIdentity,
|
|
10
13
|
nativePtyHostRuntimeIdentityMatches,
|
|
@@ -17,6 +20,7 @@ const {
|
|
|
17
20
|
const { isTemporaryProviderSessionId } = require('./provider-session-id');
|
|
18
21
|
const storageLayout = require('./storage-layout');
|
|
19
22
|
const { deserializeTerminalState } = require('./terminal-state-serialization');
|
|
23
|
+
const { probeUnixSocket } = require('./terminal-runtime-cleanup');
|
|
20
24
|
|
|
21
25
|
const DEFAULT_CONNECT_RETRIES = 300;
|
|
22
26
|
const DEFAULT_CONNECT_RETRY_MS = 50;
|
|
@@ -184,6 +188,7 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
184
188
|
this.controllerIdentityReady = null;
|
|
185
189
|
this.hostRotationTimeoutMs = options.hostRotationTimeoutMs || DEFAULT_HOST_ROTATION_TIMEOUT_MS;
|
|
186
190
|
this.connectedHostInfo = null;
|
|
191
|
+
this.connectedSocketPath = '';
|
|
187
192
|
this.runtimeRotationInfo = null;
|
|
188
193
|
this.socket = null;
|
|
189
194
|
this.socketGeneration = 0;
|
|
@@ -235,7 +240,85 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
235
240
|
|
|
236
241
|
canConnectWithoutStartingHost() {
|
|
237
242
|
if (process.platform === 'win32') return true;
|
|
238
|
-
return fs.existsSync(this.socketPath);
|
|
243
|
+
return fs.existsSync(this.socketPath) || this.privateSocketCandidates().length > 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
privateSocketCandidates() {
|
|
247
|
+
if (process.platform === 'win32') return [];
|
|
248
|
+
const directory = path.dirname(this.socketPath);
|
|
249
|
+
const pattern = nativePtyHostPrivateSocketNamePattern(this.socketPath);
|
|
250
|
+
try {
|
|
251
|
+
return fs.readdirSync(directory)
|
|
252
|
+
.filter(name => pattern.test(name))
|
|
253
|
+
.map(name => path.join(directory, name));
|
|
254
|
+
} catch (error) {
|
|
255
|
+
if (error?.code === 'ENOENT') return [];
|
|
256
|
+
throw error;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
connectedPrivateSocketPath(hostInfo = {}) {
|
|
261
|
+
if (process.platform === 'win32') return '';
|
|
262
|
+
if (typeof hostInfo.privateSocketPath === 'string' && hostInfo.privateSocketPath) {
|
|
263
|
+
return hostInfo.privateSocketPath;
|
|
264
|
+
}
|
|
265
|
+
if (!this.connectedSocketPath || this.connectedSocketPath !== this.socketPath) {
|
|
266
|
+
return this.connectedSocketPath;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
let publicIdentity;
|
|
270
|
+
try {
|
|
271
|
+
const stat = fs.statSync(this.socketPath, { bigint: true });
|
|
272
|
+
publicIdentity = { dev: stat.dev, ino: stat.ino };
|
|
273
|
+
} catch (error) {
|
|
274
|
+
if (error?.code === 'ENOENT') return '';
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const matching = this.privateSocketCandidates().filter((candidate) => {
|
|
279
|
+
try {
|
|
280
|
+
const stat = fs.statSync(candidate, { bigint: true });
|
|
281
|
+
return stat.dev === publicIdentity.dev && stat.ino === publicIdentity.ino;
|
|
282
|
+
} catch (error) {
|
|
283
|
+
if (error?.code === 'ENOENT') return false;
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
return matching.length === 1 ? matching[0] : '';
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async resolveConnectSocketPath() {
|
|
291
|
+
if (process.platform === 'win32' || fs.existsSync(this.socketPath)) {
|
|
292
|
+
return this.socketPath;
|
|
293
|
+
}
|
|
294
|
+
const active = [];
|
|
295
|
+
for (const candidate of this.privateSocketCandidates()) {
|
|
296
|
+
const probe = await probeUnixSocket(candidate);
|
|
297
|
+
if (probe.active) active.push(candidate);
|
|
298
|
+
}
|
|
299
|
+
if (active.length > 1) {
|
|
300
|
+
const error = new Error('Multiple live native PTY hosts were found for this Farming config');
|
|
301
|
+
error.code = 'FARMING_NATIVE_HOST_AMBIGUOUS';
|
|
302
|
+
error.socketPaths = active;
|
|
303
|
+
throw error;
|
|
304
|
+
}
|
|
305
|
+
return active[0] || this.socketPath;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
restorePublicSocketPath(connectedPath) {
|
|
309
|
+
if (
|
|
310
|
+
process.platform === 'win32'
|
|
311
|
+
|| !connectedPath
|
|
312
|
+
|| connectedPath === this.socketPath
|
|
313
|
+
|| fs.existsSync(this.socketPath)
|
|
314
|
+
) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
try {
|
|
318
|
+
fs.linkSync(connectedPath, this.socketPath);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
if (!error || error.code !== 'EEXIST') throw error;
|
|
321
|
+
}
|
|
239
322
|
}
|
|
240
323
|
|
|
241
324
|
spawnHost() {
|
|
@@ -288,9 +371,10 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
288
371
|
});
|
|
289
372
|
}
|
|
290
373
|
|
|
291
|
-
connectOnce() {
|
|
374
|
+
async connectOnce() {
|
|
375
|
+
const connectedPath = await this.resolveConnectSocketPath();
|
|
292
376
|
return new Promise((resolve, reject) => {
|
|
293
|
-
const socket = net.createConnection(
|
|
377
|
+
const socket = net.createConnection(connectedPath);
|
|
294
378
|
const onError = (error) => {
|
|
295
379
|
socket.destroy();
|
|
296
380
|
reject(error);
|
|
@@ -298,6 +382,8 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
298
382
|
socket.once('error', onError);
|
|
299
383
|
socket.once('connect', () => {
|
|
300
384
|
socket.off('error', onError);
|
|
385
|
+
this.restorePublicSocketPath(connectedPath);
|
|
386
|
+
this.connectedSocketPath = connectedPath;
|
|
301
387
|
this.attachSocket(socket);
|
|
302
388
|
resolve();
|
|
303
389
|
});
|
|
@@ -373,6 +459,9 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
373
459
|
if (error && error.code === 'FARMING_NATIVE_HOST_RUNTIME_MISMATCH') {
|
|
374
460
|
throw error;
|
|
375
461
|
}
|
|
462
|
+
if (error && error.code === 'FARMING_NATIVE_HOST_AMBIGUOUS') {
|
|
463
|
+
throw error;
|
|
464
|
+
}
|
|
376
465
|
if (this.hostStartError) {
|
|
377
466
|
lastError = this.hostStartError;
|
|
378
467
|
}
|
|
@@ -427,7 +516,7 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
427
516
|
return this.controllerIdentityReady;
|
|
428
517
|
}
|
|
429
518
|
|
|
430
|
-
async waitForHostRelease() {
|
|
519
|
+
async waitForHostRelease(privateSocketPath = '') {
|
|
431
520
|
const deadline = Date.now() + this.hostRotationTimeoutMs;
|
|
432
521
|
if (process.platform === 'win32') {
|
|
433
522
|
await delay(Math.min(250, this.hostRotationTimeoutMs));
|
|
@@ -437,7 +526,8 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
437
526
|
const childReleased = !this.hostChild ||
|
|
438
527
|
this.hostChild.exitCode !== null ||
|
|
439
528
|
this.hostChild.signalCode !== null;
|
|
440
|
-
|
|
529
|
+
const privateReleased = !privateSocketPath || !fs.existsSync(privateSocketPath);
|
|
530
|
+
if (!fs.existsSync(this.socketPath) && privateReleased && childReleased) return;
|
|
441
531
|
await delay(50);
|
|
442
532
|
}
|
|
443
533
|
const error = new Error('Timed out waiting for the previous native PTY host to stop');
|
|
@@ -589,6 +679,7 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
589
679
|
throw mismatchError;
|
|
590
680
|
}
|
|
591
681
|
|
|
682
|
+
const privateSocketPath = this.connectedPrivateSocketPath(hostInfo);
|
|
592
683
|
const socket = this.socket;
|
|
593
684
|
if (socket) this.suppressedDisconnectSockets.add(socket);
|
|
594
685
|
let shutdownUncertain = false;
|
|
@@ -622,7 +713,7 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
622
713
|
}
|
|
623
714
|
|
|
624
715
|
try {
|
|
625
|
-
await this.waitForHostRelease();
|
|
716
|
+
await this.waitForHostRelease(privateSocketPath || this.connectedSocketPath);
|
|
626
717
|
} catch (error) {
|
|
627
718
|
if (shutdownUncertain) {
|
|
628
719
|
try {
|
|
@@ -674,6 +765,7 @@ class NativePtyHostClient extends EventEmitter {
|
|
|
674
765
|
this.socket = null;
|
|
675
766
|
this.buffer = '';
|
|
676
767
|
this.connectedHostInfo = null;
|
|
768
|
+
this.connectedSocketPath = '';
|
|
677
769
|
if (this.disposed) return;
|
|
678
770
|
const error = new Error('Native pty host disconnected');
|
|
679
771
|
error.code = 'ECONNRESET';
|
|
@@ -17,6 +17,26 @@ function nativePtyHostSocketPath(configDir) {
|
|
|
17
17
|
return path.join(os.tmpdir(), `farming-native-pty-${process.getuid ? process.getuid() : 'user'}-${hash}.sock`);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function nativePtyHostPrivateSocketHash(socketPath) {
|
|
21
|
+
return crypto.createHash('sha256').update(socketPath).digest('hex').slice(0, 8);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function nativePtyHostPrivateSocketPath(socketPath, options = {}) {
|
|
25
|
+
const pid = Number(options.pid || process.pid);
|
|
26
|
+
const nonce = String(options.nonce || crypto.randomBytes(4).toString('hex'));
|
|
27
|
+
return path.join(
|
|
28
|
+
path.dirname(socketPath),
|
|
29
|
+
`.fpty-${pid}-${nativePtyHostPrivateSocketHash(socketPath)}-${nonce}.sock`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function nativePtyHostPrivateSocketNamePattern(socketPath) {
|
|
34
|
+
const hash = nativePtyHostPrivateSocketHash(socketPath);
|
|
35
|
+
return new RegExp(`^\\.fpty-\\d+-${hash}-[a-f0-9]+\\.sock$`);
|
|
36
|
+
}
|
|
37
|
+
|
|
20
38
|
module.exports = {
|
|
39
|
+
nativePtyHostPrivateSocketNamePattern,
|
|
40
|
+
nativePtyHostPrivateSocketPath,
|
|
21
41
|
nativePtyHostSocketPath,
|
|
22
42
|
};
|
|
@@ -7,7 +7,10 @@ const os = require('os');
|
|
|
7
7
|
const path = require('path');
|
|
8
8
|
|
|
9
9
|
const TerminalScreenWorkerPool = require('./terminal-screen-worker-pool');
|
|
10
|
-
const {
|
|
10
|
+
const {
|
|
11
|
+
nativePtyHostPrivateSocketPath,
|
|
12
|
+
nativePtyHostSocketPath,
|
|
13
|
+
} = require('./native-pty-host-path');
|
|
11
14
|
const { terminalInputToPtyString } = require('./input-parts');
|
|
12
15
|
const { normalizeInteractiveTerminalEnv } = require('./agent-env');
|
|
13
16
|
const {
|
|
@@ -95,10 +98,7 @@ class NativePtyHost {
|
|
|
95
98
|
this.exitOnShutdown = options.exitOnShutdown !== false;
|
|
96
99
|
this.boundSocketPath = process.platform === 'win32'
|
|
97
100
|
? this.socketPath
|
|
98
|
-
:
|
|
99
|
-
path.dirname(this.socketPath),
|
|
100
|
-
`.fpty-${process.pid}-${crypto.createHash('sha256').update(this.socketPath).digest('hex').slice(0, 8)}-${crypto.randomBytes(4).toString('hex')}.sock`,
|
|
101
|
-
);
|
|
101
|
+
: nativePtyHostPrivateSocketPath(this.socketPath);
|
|
102
102
|
this.boundSocketIdentity = null;
|
|
103
103
|
this.sessions = new Map();
|
|
104
104
|
this.clients = new Set();
|
|
@@ -347,6 +347,7 @@ class NativePtyHost {
|
|
|
347
347
|
return {
|
|
348
348
|
ok: true,
|
|
349
349
|
pid: process.pid,
|
|
350
|
+
privateSocketPath: process.platform === 'win32' ? '' : this.boundSocketPath,
|
|
350
351
|
runtimeIdentity: this.runtimeIdentity,
|
|
351
352
|
};
|
|
352
353
|
case 'registerController':
|