@shawnstack/quickforge 1.7.4 → 1.7.5
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/dist/assets/AgentProfilesPage-XNjuqJs7.js +1 -0
- package/dist/assets/ChatPanelHost-CuF-PZpc.js +292 -0
- package/dist/assets/CloudAccountSettingsPage-GJSoi6sO.js +1 -0
- package/dist/assets/PluginsPage-BQgp0qN-.js +1 -0
- package/dist/assets/ScheduledTasksPage-DdekATzq.js +2 -0
- package/dist/assets/{SettingsWorkspacePage-B53_eDf2.js → SettingsWorkspacePage-Cb54Ic91.js} +389 -378
- package/dist/assets/ShareLinksSettingsPage-C75WJpaF.js +1 -0
- package/dist/assets/SharedConversationPage-CjMtSQTW.js +1 -0
- package/dist/assets/{TerminalDock-Dgg-_ZmU.js → TerminalDock-D4zJBJc4.js} +2 -2
- package/dist/assets/WorkspaceInspector-D9kdnLDd.js +36 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-Dy7veffk.js → abnfDiagram-VRR7QNED-CMhVoYUh.js} +1 -1
- package/dist/assets/{arc-Bo3p2lGy.js → arc-w21O0TLn.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-DMwFMHxq.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-Cwx8qOvu.js → architectureDiagram-ZJ3FMSHR-C52qL6Hg.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-BiuaAOFa.js → blockDiagram-677ZJIJ3-CM3XbLol.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-BTcGfhK2.js → c4Diagram-LMCZKHZV-D7Bh1ui1.js} +1 -1
- package/dist/assets/channel-Duu1CuH9.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-B6rHWc4S.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-B9PuF_RF.js → chunk-32BRIVSS-xgrtbT8e.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-3zGItfIM.js → chunk-52WLFC77-CDbaHw80.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-DQ66qlmt.js → chunk-5FCAYU7R-CcSvVbPc.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-CLqTO-VF.js → chunk-5HE753X5-erFpzzgx.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-Csxv1jr6.js → chunk-5JV3BV7I-rEhN9F6G.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-BCQttpBr.js → chunk-5TONJI2A-D8L-QTwD.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DEWJGSTb.js → chunk-5VM5RSS4-CjlfMBbM.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-DNorm9MM.js → chunk-7BUUIJ7U-CCcsI9XE.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-DgvY_BOT.js → chunk-BIQX33UG-FSqFbmb3.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-DMvn9IPs.js → chunk-C7G6YPKG-ZMLUvfLy.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-Dq2duUgr.js → chunk-CQNSW5MT-DZuBpk25.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-BovYyc4Y.js → chunk-CYSBUYHQ-CB26wsG0.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-BMDOpuYN.js → chunk-EMLP6XTP-BbsM8oRw.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-6eP2UPOf.js → chunk-EX3LRPZG-BcQhaqt7.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-D4q-wTSy.js → chunk-FWX5IMBZ-DrnrdrSu.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-XjIcuzH7.js → chunk-HOUHSVGY-tdc-Z9eW.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-YBXbanq9.js → chunk-ICXQ74PX-Cd7igVGt.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-CcN3uNXF.js → chunk-JG7HCLWE-iXXGW8nf.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-Cwg6AUAt.js → chunk-JWPE2WC7-BZ87mXEv.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-NNspcGIU.js → chunk-MOJQB5TN-CLTjV5ov.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-pMJ_jMos.js → chunk-MOZMSUNE-B3SCBrRH.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-CJy-3Ldv.js → chunk-OGEWGWER-TgvkXkFX.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-D7cLHHOA.js → chunk-OSBZ3O6U-B9E2E5v1.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-D5YBi1Pi.js → chunk-PUDLZKDR-C5GMVYup.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-DYmqQdIf.js → chunk-Q4XR5HBZ-fo5-HsqY.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-Bfcx00X0.js → chunk-QBLGF6JB-Dwfg8sKc.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-oXzadpZY.js → chunk-R7FJI6CG-DpBrv4ni.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-Dt3-8yUh.js → chunk-RYQCIY6F-DzzmTl11.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-B55eSvpx.js → chunk-U6XO7XAA-Dw6aviKa.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-Btk4JwCt.js → chunk-V7JOEXUC-CEDazV6w.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-CWYjg8zE.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-DgaSiVOY.js → chunk-VR4S4FIN-C_-eEj-9.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-rRDZ_Tta.js → chunk-WYO6CB5R-NF-MsJJR.js} +3 -3
- package/dist/assets/chunk-XXDRQBXY-DzTwx8ZH.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-BnFxj5o4.js → chunk-YOTPTUD7-DqzqtdII.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-CrnlPlmJ.js → chunk-ZGVPDNZ5-CRrAYi4g.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-BYTiATIH.js → chunk-ZIRB5QZD-Dc1s5bLM.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Cc63fLWP.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-CoXU0qT6.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-BORKJRwF.js → cose-bilkent-JH36ORCC-cL247pHg.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-C8yCvH_o.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-BXKeaSl8.js → cynefinDiagram-TSTJHNR4-D4sZ7LYI.js} +1 -1
- package/dist/assets/{dagre-CrA0XVwJ.js → dagre-DmHb3Ctt.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-ouq_lA1a.js → dagre-VKFMJZFB-BlsnSh-Q.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-BxR5kUiQ.js → diagram-FQU43EPY-DW1yQiRO.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-DWonk1sL.js → diagram-G47NLZAW-BTUAsFjb.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-fmV_wV5e.js → diagram-NH7WQ7WH-BcaomqSd.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-DvOSRRiV.js → diagram-OA4YK3LP-DDLX7Xwr.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-Bp-xb3uS.js → diagram-WEI45ONY-CIave0An.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-BTlnwneA.js → ebnfDiagram-CCIWWBDH-Cr1Y6lPu.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-C3fFWGCm.js → erDiagram-Q63AITRT-D3EgiVVH.js} +1 -1
- package/dist/assets/{esm-oa69b5u4.js → esm-Df4edDpj.js} +2 -2
- package/dist/assets/eventmodeling-45OFAUF4-DO1vRTM0.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-BS7KXcqn.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-DzAiojNi.js → ganttDiagram-NO4QXBWP-B0oyDIqK.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-m5F5ef09.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-Cv57oNEA.js → gitGraphDiagram-IHSO6WYX-uQtr6IqK.js} +1 -1
- package/dist/assets/icons-CXPP1fFT.js +1 -0
- package/dist/assets/index-_ZhK6bvp.js +65 -0
- package/dist/assets/index-iVV2bP_f.css +3 -0
- package/dist/assets/info-DKCQHKI2-CZxPlQJ0.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-B5Z_O3Ro.js → infoDiagram-FWYZ7A6U-B_GzlLIM.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-CKTK_TKV.js → ishikawaDiagram-FXEZZL3T-CKQIsSdU.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-Cm9k4ywW.js → journeyDiagram-5HDEW3XC-DrrvzZL1.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-DzNteLwx.js → kanban-definition-HUTT4EX6-CJQRTdXz.js} +1 -1
- package/dist/assets/{line-BG78c_WJ.js → line-B4DxX7tC.js} +1 -1
- package/dist/assets/{linear-1X20_EGu.js → linear-U-nKUhyW.js} +1 -1
- package/dist/assets/{map-CCI8WZkS.js → map-BneTM-ri.js} +1 -1
- package/dist/assets/{mcp-servers-dialog-GXXD9K0U.js → mcp-servers-dialog-BUSPvaqI.js} +2 -2
- package/dist/assets/{mermaid-parser.core-Bb8HI_OS.js → mermaid-parser.core-BlKWrEdZ.js} +2 -2
- package/dist/assets/{mermaid-renderer-PIaNiXAz.js → mermaid-renderer-jEbqFaTe.js} +2 -2
- package/dist/assets/{mermaid.core-DUHOIwL5.js → mermaid.core-DWpShXCs.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-Tnbszo7b.js → mindmap-definition-LN4V7U3C-CEVwZD78.js} +1 -1
- package/dist/assets/model-identity-CgA6_Pbm.js +1 -0
- package/dist/assets/model-reference-o41fJ6jQ.js +1 -0
- package/dist/assets/{monaco-BVtCspYZ.js → monaco-D6OhXgjg.js} +1 -1
- package/dist/assets/{ordinal-v4prQcuq.js → ordinal-B2r5L1v4.js} +1 -1
- package/dist/assets/{otel-D1LswXpM.js → otel-BFnphzjt.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-zIioIZVN.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-CX824Kd0.js → pegDiagram-2B236MQR-CBLkBdnQ.js} +1 -1
- package/dist/assets/{pi-ai-DAJlO9ZB.js → pi-ai-Cr2ee4a0.js} +2 -2
- package/dist/assets/{pi-web-ui-B-RJSxjR.js → pi-web-ui-DV5jKjSg.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-GGWijBvB.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-BT04VWPQ.js → pieDiagram-ENE6RG2P-8tCnwtWS.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-BvOZxkBr.js → quadrantDiagram-ABIIQ3AL-CWd28cHF.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-yvwFH3RV.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-BVadlswB.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-B7R-p_2-.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-BnbJxPug.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-Ci3DcEuQ.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-DnTU--BV.js → railroadDiagram-RFXS5EU6-CI4ouOBs.js} +1 -1
- package/dist/assets/{react-vendor-eWH0QhNU.js → react-vendor-1KC5PyRx.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE--MZX_yEv.js → requirementDiagram-TGXJPOKE-DtFz7sw4.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-SEZkHhYn.js → sankeyDiagram-HTMAVEWB--VeOwwk9.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-BhC2OHiz.js → sequenceDiagram-DBY2YBRQ-B8AHk5Oe.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-Ci5LeToV.js → sizeCapture-X5ZJPWSS-vV_ArM8D.js} +1 -1
- package/dist/assets/{skills-dialog-DDh1h8eH.js → skills-dialog-BThnIUBs.js} +3 -3
- package/dist/assets/{src-CovulcRC.js → src-PYsDme0X.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-DKK5tFT4.js → stateDiagram-2N3HPSRC-etXnJ8X8.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-Dms3pICj.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-DxxGCk67.js → swimlanes-5IMT3BWC-pabIKAmn.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-B14aWjv6.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-BPXB3Sue.js → timeline-definition-FHXFAJF6-C55MKm3L.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-Cru9B2zv.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-DNOVHFaJ.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-CxcBCKye.js → vennDiagram-L72KCM5P-CgNf1Q9W.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-E3m1BOJQ.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-DEL6Yes5.js → wardleyDiagram-EHGQE667-Drt5ytec.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG-N8cPbcjC.js → xychartDiagram-FW5EYKEG-hhoEo_Ar.js} +1 -1
- package/dist/index.html +9 -8
- package/package.json +3 -1
- package/plugins/{openai-documents → documents}/plugin.json +2 -2
- package/plugins/{openai-presentations → presentations}/plugin.json +2 -2
- package/plugins/{openai-spreadsheets → spreadsheets}/plugin.json +2 -2
- package/server/acp/server.mjs +36 -26
- package/server/agent-manager.mjs +130 -28
- package/server/agent-profile-files.mjs +8 -4
- package/server/agent-profile-schema.mjs +47 -23
- package/server/agent-profiles.mjs +1 -1
- package/server/ai-http-logger.mjs +98 -12
- package/server/cloud/chat-idempotency-store.mjs +96 -0
- package/server/cloud/client.mjs +102 -0
- package/server/cloud/config.mjs +53 -0
- package/server/cloud/credential-store.mjs +193 -0
- package/server/cloud/identity.mjs +355 -0
- package/server/cloud/index.mjs +7 -0
- package/server/cloud/models.mjs +80 -0
- package/server/cloud/runtime.mjs +129 -0
- package/server/cloud/service-config.mjs +77 -0
- package/server/index.mjs +28 -11
- package/server/model-catalog.mjs +262 -0
- package/server/plugins/registry.mjs +29 -5
- package/server/routes/agent-profiles.mjs +41 -7
- package/server/routes/agent.mjs +20 -11
- package/server/routes/backup.mjs +7 -1
- package/server/routes/cloud.mjs +227 -0
- package/server/routes/models.mjs +7 -1
- package/server/routes/scheduled-tasks.mjs +38 -8
- package/server/routes/shared-conversation.mjs +62 -58
- package/server/routes/shares.mjs +76 -1
- package/server/routes/storage.mjs +24 -1
- package/server/routes/workspace.mjs +6 -4
- package/server/share-store.mjs +168 -13
- package/server/skills.mjs +30 -3
- package/server/storage.mjs +7 -1
- package/server/subagents.mjs +3 -3
- package/server/tools/definitions.mjs +1 -1
- package/server/tools/index.mjs +2 -2
- package/server/utils/network.mjs +9 -0
- package/server/utils/response.mjs +8 -1
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +485 -0
- package/skills/skill-creator/UPSTREAM.md +6 -0
- package/skills/skill-creator/agents/analyzer.md +274 -0
- package/skills/skill-creator/agents/comparator.md +202 -0
- package/skills/skill-creator/agents/grader.md +223 -0
- package/skills/skill-creator/assets/eval_review.html +146 -0
- package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/skill-creator/references/schemas.md +430 -0
- package/skills/skill-creator/scripts/__init__.py +0 -0
- package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/skill-creator/scripts/generate_report.py +326 -0
- package/skills/skill-creator/scripts/improve_description.py +247 -0
- package/skills/skill-creator/scripts/package_skill.py +136 -0
- package/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/skills/skill-creator/scripts/run_eval.py +310 -0
- package/skills/skill-creator/scripts/run_loop.py +328 -0
- package/skills/skill-creator/scripts/utils.py +47 -0
- package/dist/assets/AgentProfilesPage-B84w-r9S.js +0 -1
- package/dist/assets/ChatPanelHost-CyO8fEoj.js +0 -288
- package/dist/assets/PluginsPage-D2862wul.js +0 -1
- package/dist/assets/ScheduledTasksPage-GqbiJDPX.js +0 -2
- package/dist/assets/SharedConversationPage-Cw2QFnbC.js +0 -1
- package/dist/assets/WorkspaceInspector-3uLiu6Bv.js +0 -13
- package/dist/assets/architecture-TIHT7OUA-7FQo5GbP.js +0 -1
- package/dist/assets/channel-DToA8d-4.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-D_Wxpk-T.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-CIZseNLi.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-Do-XYxat.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Bu24Sy-k.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-DKhh5HSW.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-oyiAgYC4.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-YB_0MefX.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-Bc73xdBd.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-Bvp27L0n.js +0 -1
- package/dist/assets/icons-cTkqD_Gi.js +0 -1
- package/dist/assets/index-B48prgLL.js +0 -65
- package/dist/assets/index-DQhwHHer.css +0 -3
- package/dist/assets/info-DKCQHKI2-BsLOivgq.js +0 -1
- package/dist/assets/packet-7NZHBO7P-BKQkXRtk.js +0 -1
- package/dist/assets/pie-RZYD4A2V-BTiTN5Ge.js +0 -1
- package/dist/assets/radar-I7S5WNFK-BU-oVjKM.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-7H2hxNbL.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-Mx6wf6XQ.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-BgXSKhYy.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-DTEl2rAC.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-D8x3mkni.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-C4nOBNp8.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-DOE6NSdf.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-Ca7QD_b4.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-D9O4RKRm.js +0 -1
- /package/dist/assets/{array-DqLCdDFv.js → array-B9UHiPd-.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-s7Qq-R3i.js → chunk-KEIR6QF5-jrz1pRUS.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-BgISNSiw.js → chunk-Y2CYZVJY-D6N-CrJv.js} +0 -0
- /package/dist/assets/{cytoscape.esm-iekjSZ2n.js → cytoscape.esm-DyfqweF2.js} +0 -0
- /package/dist/assets/{defaultLocale-CrJzLgRD.js → defaultLocale-5eAKkKJC.js} +0 -0
- /package/dist/assets/{dist-zzfqk5hx.js → dist-CLg13NtV.js} +0 -0
- /package/dist/assets/{graphlib-CIz_CfxW.js → graphlib-DJkmx0Cq.js} +0 -0
- /package/dist/assets/{init-C0r9Gk5G.js → init-DlZdxViB.js} +0 -0
- /package/dist/assets/{path-DIKpVbHL.js → path-6uRLdFF7.js} +0 -0
- /package/dist/assets/{plugin-api-C8hMT5W6.js → plugin-api-Uu2xAB4d.js} +0 -0
- /package/dist/assets/{rough.esm-BMOtDaaS.js → rough.esm-Bud4g4fh.js} +0 -0
- /package/dist/assets/{web-RgX7H-OH.js → web-DoV8MSMn.js} +0 -0
- /package/dist/assets/{xterm-BFzZ1FH4.js → xterm-Bm_IbozX.js} +0 -0
- /package/plugins/{openai-documents → documents}/commands/document.md +0 -0
- /package/plugins/{openai-documents → documents}/skills/documents/SKILL.md +0 -0
- /package/plugins/{openai-presentations → presentations}/commands/presentation.md +0 -0
- /package/plugins/{openai-presentations → presentations}/skills/presentations/SKILL.md +0 -0
- /package/plugins/{openai-spreadsheets → spreadsheets}/commands/spreadsheet.md +0 -0
- /package/plugins/{openai-spreadsheets → spreadsheets}/skills/spreadsheets/SKILL.md +0 -0
|
@@ -94,7 +94,7 @@ async function readIndexedValues(store, indexName, direction, scope, projectId,
|
|
|
94
94
|
return values
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
export async function handleStorageApi(req, res, url) {
|
|
97
|
+
export async function handleStorageApi(req, res, url, context = {}) {
|
|
98
98
|
const parts = url.pathname.split('/').filter(Boolean)
|
|
99
99
|
|
|
100
100
|
if (req.method === 'GET' && url.pathname === '/api/storage/quota') {
|
|
@@ -116,6 +116,29 @@ export async function handleStorageApi(req, res, url) {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
const store = decodeSegment(parts[2])
|
|
119
|
+
const remotelySensitiveStores = new Set([
|
|
120
|
+
'provider-keys',
|
|
121
|
+
'custom-providers',
|
|
122
|
+
'mcp',
|
|
123
|
+
'plugins',
|
|
124
|
+
'scheduled-tasks',
|
|
125
|
+
'agent-profile-overrides',
|
|
126
|
+
'custom-agents',
|
|
127
|
+
])
|
|
128
|
+
if (context.isLocalRequest === false && remotelySensitiveStores.has(store)) {
|
|
129
|
+
const error = new Error('This storage area is available only on this computer.')
|
|
130
|
+
error.statusCode = 403
|
|
131
|
+
error.errorCode = 'storage_local_only'
|
|
132
|
+
throw error
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const remotelyReadOnlyStores = new Set(['sessions', 'sessions-metadata'])
|
|
136
|
+
if (context.isLocalRequest === false && remotelyReadOnlyStores.has(store) && req.method !== 'GET') {
|
|
137
|
+
const error = new Error('Remote clients must modify conversations through the Agent API.')
|
|
138
|
+
error.statusCode = 403
|
|
139
|
+
error.errorCode = 'storage_remote_read_only'
|
|
140
|
+
throw error
|
|
141
|
+
}
|
|
119
142
|
|
|
120
143
|
if (req.method === 'GET' && parts[3] === 'keys') {
|
|
121
144
|
const prefix = url.searchParams.get('prefix') || ''
|
|
@@ -2,6 +2,7 @@ import { promises as fs } from 'node:fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { spawn } from 'node:child_process'
|
|
4
4
|
import { streamSimpleWithAiHttpLogging } from '../ai-http-logger.mjs'
|
|
5
|
+
import { resolveModelBinding } from '../model-catalog.mjs'
|
|
5
6
|
import { DEFAULT_AI_MAX_RETRIES } from '../ai-provider-options.mjs'
|
|
6
7
|
import { sendJson, readJsonBody } from '../utils/response.mjs'
|
|
7
8
|
import { projectContextFromId } from '../project-config.mjs'
|
|
@@ -1080,9 +1081,10 @@ async function contextFromGitBody(req) {
|
|
|
1080
1081
|
return { context: await projectContextFromId(projectId), body }
|
|
1081
1082
|
}
|
|
1082
1083
|
|
|
1083
|
-
async function handleGitGenerateCommitMessage(req, res) {
|
|
1084
|
+
async function handleGitGenerateCommitMessage(req, res, requestContext = {}) {
|
|
1084
1085
|
const { context, body } = await contextFromGitBody(req)
|
|
1085
|
-
const
|
|
1086
|
+
const binding = await resolveModelBinding(body, { context: requestContext, legacySnapshot: body?.model })
|
|
1087
|
+
const message = await generateGitCommitMessage(context, binding.model, body?.thinkingLevel, Boolean(body?.includeUnstaged))
|
|
1086
1088
|
sendJson(res, 200, { message })
|
|
1087
1089
|
}
|
|
1088
1090
|
|
|
@@ -1178,7 +1180,7 @@ export async function handleWorkspaceApi(req, res, url, requestContext = {}) {
|
|
|
1178
1180
|
throw error
|
|
1179
1181
|
}
|
|
1180
1182
|
|
|
1181
|
-
export async function handleGitApi(req, res, url) {
|
|
1183
|
+
export async function handleGitApi(req, res, url, requestContext = {}) {
|
|
1182
1184
|
if (req.method === 'GET' && url.pathname === '/api/git/status') {
|
|
1183
1185
|
await handleGitStatus(req, res, url)
|
|
1184
1186
|
return
|
|
@@ -1204,7 +1206,7 @@ export async function handleGitApi(req, res, url) {
|
|
|
1204
1206
|
return
|
|
1205
1207
|
}
|
|
1206
1208
|
if (req.method === 'POST' && url.pathname === '/api/git/generate-commit-message') {
|
|
1207
|
-
await handleGitGenerateCommitMessage(req, res)
|
|
1209
|
+
await handleGitGenerateCommitMessage(req, res, requestContext)
|
|
1208
1210
|
return
|
|
1209
1211
|
}
|
|
1210
1212
|
if (req.method === 'POST' && url.pathname === '/api/git/stage') {
|
package/server/share-store.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto'
|
|
2
|
+
import { EventEmitter } from 'node:events'
|
|
2
3
|
import { promises as fs } from 'node:fs'
|
|
3
4
|
import path from 'node:path'
|
|
4
5
|
import { ensureStorage, storageDir } from './storage.mjs'
|
|
@@ -10,6 +11,25 @@ const SHARES_DIR = path.join(storageDir, 'shares')
|
|
|
10
11
|
const SHARES_FILE = path.join(SHARES_DIR, 'conversation-shares.json')
|
|
11
12
|
const writeQueueName = 'conversation-shares'
|
|
12
13
|
const writeQueues = new Map()
|
|
14
|
+
const shareLifecycleEvents = new EventEmitter()
|
|
15
|
+
shareLifecycleEvents.setMaxListeners(0)
|
|
16
|
+
|
|
17
|
+
export function onConversationShareInvalidated(listener) {
|
|
18
|
+
shareLifecycleEvents.on('invalidated', listener)
|
|
19
|
+
return () => shareLifecycleEvents.removeListener('invalidated', listener)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function emitConversationShareInvalidated(shareId, reason) {
|
|
23
|
+
shareLifecycleEvents.emit('invalidated', { shareId, reason })
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function clearShareTokens(record) {
|
|
27
|
+
record.authVersion = (record.authVersion || 1) + 1
|
|
28
|
+
record.tokens = []
|
|
29
|
+
record.tokenHash = undefined
|
|
30
|
+
record.tokenIssuedAt = undefined
|
|
31
|
+
record.tokenExpiresAt = undefined
|
|
32
|
+
}
|
|
13
33
|
|
|
14
34
|
function enqueueWrite(queueName, operation) {
|
|
15
35
|
const previous = writeQueues.get(queueName) || Promise.resolve()
|
|
@@ -64,6 +84,7 @@ function publicShareRecord(record) {
|
|
|
64
84
|
accessCount: record.accessCount || 0,
|
|
65
85
|
lastAccessedAt: record.lastAccessedAt,
|
|
66
86
|
hasPassword: Boolean(record.passwordHash),
|
|
87
|
+
allowCloudUsage: record.allowCloudUsage === true,
|
|
67
88
|
}
|
|
68
89
|
}
|
|
69
90
|
|
|
@@ -195,6 +216,7 @@ export async function createConversationShare({
|
|
|
195
216
|
permission,
|
|
196
217
|
password,
|
|
197
218
|
expiresAt,
|
|
219
|
+
allowCloudUsage = false,
|
|
198
220
|
titleSnapshot,
|
|
199
221
|
scope,
|
|
200
222
|
projectId,
|
|
@@ -233,14 +255,13 @@ export async function createConversationShare({
|
|
|
233
255
|
}
|
|
234
256
|
|
|
235
257
|
for (const stale of existingRecords.filter((record) => record?.id !== existing?.id)) {
|
|
258
|
+
const newlySuperseded = !stale.supersededAt
|
|
236
259
|
stale.supersededAt = stale.supersededAt || now
|
|
237
260
|
stale.revokedAt = stale.revokedAt || now
|
|
238
261
|
stale.updatedAt = now
|
|
239
|
-
stale
|
|
240
|
-
stale.tokenHash = undefined
|
|
241
|
-
stale.tokenIssuedAt = undefined
|
|
242
|
-
stale.tokenExpiresAt = undefined
|
|
262
|
+
clearShareTokens(stale)
|
|
243
263
|
data[stale.id] = stale
|
|
264
|
+
if (newlySuperseded) emitConversationShareInvalidated(stale.id, 'superseded')
|
|
244
265
|
}
|
|
245
266
|
|
|
246
267
|
if (existing?.id) {
|
|
@@ -251,6 +272,7 @@ export async function createConversationShare({
|
|
|
251
272
|
updatedAt: now,
|
|
252
273
|
supersededAt: undefined,
|
|
253
274
|
expiresAt: expiresAt || undefined,
|
|
275
|
+
allowCloudUsage: permission === 'operate' && allowCloudUsage === true,
|
|
254
276
|
revokedAt: undefined,
|
|
255
277
|
titleSnapshot: titleSnapshot || existing.titleSnapshot || 'New chat',
|
|
256
278
|
scope: scope === 'project' ? 'project' : 'global',
|
|
@@ -264,19 +286,20 @@ export async function createConversationShare({
|
|
|
264
286
|
tokenExpiresAt: existing.tokenExpiresAt,
|
|
265
287
|
}
|
|
266
288
|
if (passwordProvided) {
|
|
267
|
-
record
|
|
268
|
-
record.tokens = []
|
|
269
|
-
record.tokenHash = undefined
|
|
270
|
-
record.tokenIssuedAt = undefined
|
|
271
|
-
record.tokenExpiresAt = undefined
|
|
289
|
+
clearShareTokens(record)
|
|
272
290
|
}
|
|
273
291
|
if (passwordProvided && !passwordInfo.passwordHash) {
|
|
274
292
|
record.passwordHash = undefined
|
|
275
293
|
record.passwordSalt = undefined
|
|
276
294
|
record.passwordVersion = undefined
|
|
277
295
|
}
|
|
296
|
+
const lifecycleChanged = Boolean(existing.revokedAt)
|
|
297
|
+
|| String(existing.expiresAt || '') !== String(record.expiresAt || '')
|
|
298
|
+
|| existing.allowCloudUsage === true !== (record.allowCloudUsage === true)
|
|
299
|
+
|| (passwordProvided && existing.authVersion !== record.authVersion)
|
|
278
300
|
data[record.id] = record
|
|
279
301
|
await writeShareStoreFile(data)
|
|
302
|
+
if (lifecycleChanged) emitConversationShareInvalidated(record.id, 'updated')
|
|
280
303
|
return publicShareRecord(record)
|
|
281
304
|
}
|
|
282
305
|
|
|
@@ -292,6 +315,7 @@ export async function createConversationShare({
|
|
|
292
315
|
updatedAt: now,
|
|
293
316
|
supersededAt: undefined,
|
|
294
317
|
expiresAt: expiresAt || undefined,
|
|
318
|
+
allowCloudUsage: permission === 'operate' && allowCloudUsage === true,
|
|
295
319
|
revokedAt: undefined,
|
|
296
320
|
titleSnapshot: titleSnapshot || 'New chat',
|
|
297
321
|
scope: scope === 'project' ? 'project' : 'global',
|
|
@@ -335,18 +359,149 @@ export async function revokeConversationShare(shareId) {
|
|
|
335
359
|
error.statusCode = 404
|
|
336
360
|
throw error
|
|
337
361
|
}
|
|
362
|
+
const wasActive = !record.revokedAt
|
|
338
363
|
record.revokedAt = record.revokedAt || new Date().toISOString()
|
|
339
364
|
record.updatedAt = record.revokedAt
|
|
340
|
-
record
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
365
|
+
clearShareTokens(record)
|
|
366
|
+
data[shareId] = record
|
|
367
|
+
await writeShareStoreFile(data)
|
|
368
|
+
if (wasActive) emitConversationShareInvalidated(shareId, 'revoked')
|
|
369
|
+
return publicShareRecord(record)
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export async function restoreConversationShare(shareId, expiresAt) {
|
|
374
|
+
assertSafeShareId(shareId)
|
|
375
|
+
if (expiresAt && (Number.isNaN(Date.parse(expiresAt)) || Date.parse(expiresAt) <= Date.now())) {
|
|
376
|
+
const error = new Error('Expiration time must be in the future')
|
|
377
|
+
error.statusCode = 400
|
|
378
|
+
throw error
|
|
379
|
+
}
|
|
380
|
+
return enqueueWrite(writeQueueName, async () => {
|
|
381
|
+
const data = await readShareStoreFile()
|
|
382
|
+
const record = data[shareId]
|
|
383
|
+
if (!record) {
|
|
384
|
+
const error = new Error('Share not found')
|
|
385
|
+
error.statusCode = 404
|
|
386
|
+
throw error
|
|
387
|
+
}
|
|
388
|
+
if (record.supersededAt) {
|
|
389
|
+
const error = new Error('Superseded shares cannot be restored')
|
|
390
|
+
error.statusCode = 409
|
|
391
|
+
throw error
|
|
392
|
+
}
|
|
393
|
+
record.revokedAt = undefined
|
|
394
|
+
record.expiresAt = expiresAt || undefined
|
|
395
|
+
record.updatedAt = new Date().toISOString()
|
|
396
|
+
clearShareTokens(record)
|
|
344
397
|
data[shareId] = record
|
|
345
398
|
await writeShareStoreFile(data)
|
|
346
399
|
return publicShareRecord(record)
|
|
347
400
|
})
|
|
348
401
|
}
|
|
349
402
|
|
|
403
|
+
export async function updateConversationShareExpiration(shareId, expiresAt) {
|
|
404
|
+
assertSafeShareId(shareId)
|
|
405
|
+
if (expiresAt && (Number.isNaN(Date.parse(expiresAt)) || Date.parse(expiresAt) <= Date.now())) {
|
|
406
|
+
const error = new Error('Expiration time must be in the future')
|
|
407
|
+
error.statusCode = 400
|
|
408
|
+
throw error
|
|
409
|
+
}
|
|
410
|
+
return enqueueWrite(writeQueueName, async () => {
|
|
411
|
+
const data = await readShareStoreFile()
|
|
412
|
+
const record = data[shareId]
|
|
413
|
+
if (!record) {
|
|
414
|
+
const error = new Error('Share not found')
|
|
415
|
+
error.statusCode = 404
|
|
416
|
+
throw error
|
|
417
|
+
}
|
|
418
|
+
if (record.supersededAt) {
|
|
419
|
+
const error = new Error('Superseded shares cannot be updated')
|
|
420
|
+
error.statusCode = 409
|
|
421
|
+
throw error
|
|
422
|
+
}
|
|
423
|
+
assertShareActive(record)
|
|
424
|
+
record.expiresAt = expiresAt || undefined
|
|
425
|
+
record.updatedAt = new Date().toISOString()
|
|
426
|
+
data[shareId] = record
|
|
427
|
+
await writeShareStoreFile(data)
|
|
428
|
+
emitConversationShareInvalidated(shareId, 'updated')
|
|
429
|
+
return publicShareRecord(record)
|
|
430
|
+
})
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export async function updateConversationShare(shareId, { permission, password, expiresAt, allowCloudUsage } = {}) {
|
|
434
|
+
assertSafeShareId(shareId)
|
|
435
|
+
const passwordProvided = typeof password === 'string'
|
|
436
|
+
const normalizedPassword = passwordProvided ? password.trim() : undefined
|
|
437
|
+
if (expiresAt && (Number.isNaN(Date.parse(expiresAt)) || Date.parse(expiresAt) <= Date.now())) {
|
|
438
|
+
const error = new Error('Expiration time must be in the future')
|
|
439
|
+
error.statusCode = 400
|
|
440
|
+
throw error
|
|
441
|
+
}
|
|
442
|
+
const passwordInfo = passwordProvided ? await hashSharePassword(normalizedPassword) : {}
|
|
443
|
+
return enqueueWrite(writeQueueName, async () => {
|
|
444
|
+
const data = await readShareStoreFile()
|
|
445
|
+
const record = data[shareId]
|
|
446
|
+
if (!record) {
|
|
447
|
+
const error = new Error('Share not found')
|
|
448
|
+
error.statusCode = 404
|
|
449
|
+
throw error
|
|
450
|
+
}
|
|
451
|
+
if (record.supersededAt) {
|
|
452
|
+
const error = new Error('Superseded shares cannot be updated')
|
|
453
|
+
error.statusCode = 409
|
|
454
|
+
throw error
|
|
455
|
+
}
|
|
456
|
+
assertShareActive(record)
|
|
457
|
+
const nextPermission = permission === undefined ? record.permission : permission
|
|
458
|
+
assertValidPermission(nextPermission)
|
|
459
|
+
const willHavePassword = passwordProvided ? Boolean(normalizedPassword) : Boolean(record.passwordHash)
|
|
460
|
+
if (nextPermission === 'operate' && !willHavePassword) {
|
|
461
|
+
const error = new Error('Editable shares require a non-empty password')
|
|
462
|
+
error.statusCode = 400
|
|
463
|
+
throw error
|
|
464
|
+
}
|
|
465
|
+
const nextAllowCloudUsage = nextPermission === 'operate'
|
|
466
|
+
&& (allowCloudUsage === undefined ? record.allowCloudUsage === true : allowCloudUsage === true)
|
|
467
|
+
const lifecycleChanged = nextPermission !== record.permission
|
|
468
|
+
|| nextAllowCloudUsage !== (record.allowCloudUsage === true)
|
|
469
|
+
|| (expiresAt !== undefined && String(record.expiresAt || '') !== String(expiresAt || ''))
|
|
470
|
+
|| passwordProvided
|
|
471
|
+
if (passwordProvided) {
|
|
472
|
+
record.passwordHash = passwordInfo.passwordHash
|
|
473
|
+
record.passwordSalt = passwordInfo.passwordSalt
|
|
474
|
+
record.passwordVersion = passwordInfo.passwordVersion
|
|
475
|
+
clearShareTokens(record)
|
|
476
|
+
}
|
|
477
|
+
record.permission = nextPermission
|
|
478
|
+
record.allowCloudUsage = nextAllowCloudUsage
|
|
479
|
+
if (expiresAt !== undefined) record.expiresAt = expiresAt || undefined
|
|
480
|
+
record.updatedAt = new Date().toISOString()
|
|
481
|
+
data[shareId] = record
|
|
482
|
+
await writeShareStoreFile(data)
|
|
483
|
+
if (lifecycleChanged) emitConversationShareInvalidated(shareId, 'updated')
|
|
484
|
+
return publicShareRecord(record)
|
|
485
|
+
})
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
export async function deleteConversationShare(shareId) {
|
|
489
|
+
assertSafeShareId(shareId)
|
|
490
|
+
return enqueueWrite(writeQueueName, async () => {
|
|
491
|
+
const data = await readShareStoreFile()
|
|
492
|
+
const record = data[shareId]
|
|
493
|
+
if (!record) {
|
|
494
|
+
const error = new Error('Share not found')
|
|
495
|
+
error.statusCode = 404
|
|
496
|
+
throw error
|
|
497
|
+
}
|
|
498
|
+
delete data[shareId]
|
|
499
|
+
await writeShareStoreFile(data)
|
|
500
|
+
emitConversationShareInvalidated(shareId, 'deleted')
|
|
501
|
+
return publicShareRecord(record)
|
|
502
|
+
})
|
|
503
|
+
}
|
|
504
|
+
|
|
350
505
|
export async function issueConversationShareToken(shareId) {
|
|
351
506
|
assertSafeShareId(shareId)
|
|
352
507
|
return enqueueWrite(writeQueueName, async () => {
|
package/server/skills.mjs
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { existsSync, promises as fs } from 'node:fs'
|
|
2
2
|
import os from 'node:os'
|
|
3
3
|
import path from 'node:path'
|
|
4
|
-
import {
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { atomicProjectConfigUpdate, configDir, dataDir } from './storage.mjs'
|
|
5
6
|
import { getEnabledPluginSkillSources } from './plugins/registry.mjs'
|
|
6
7
|
import { logger } from './utils/logger.mjs'
|
|
7
8
|
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
10
|
+
const bundledSkillsDir = path.resolve(__dirname, '..', 'skills')
|
|
8
11
|
const userSkillsDir = path.join(dataDir, 'skills')
|
|
9
12
|
const sharedUserSkillsDir = path.join(os.homedir(), '.agents', 'skills')
|
|
10
13
|
const claudeUserSkillsDir = path.join(os.homedir(), '.claude', 'skills')
|
|
11
14
|
const opencodeUserSkillsDir = path.join(os.homedir(), '.opencode', 'skills')
|
|
15
|
+
const defaultSkillsMarkerFile = path.join(configDir, '.default-skills-v1')
|
|
16
|
+
const defaultGlobalSkillNames = ['skill-creator']
|
|
12
17
|
const defaultEntry = 'SKILL.md'
|
|
13
|
-
const resourceDirs = ['scripts', 'references', 'assets']
|
|
18
|
+
const resourceDirs = ['scripts', 'references', 'assets', 'agents', 'eval-viewer']
|
|
14
19
|
const maxResourceFiles = 200
|
|
15
20
|
|
|
16
21
|
function isValidSkillName(value) {
|
|
@@ -421,7 +426,7 @@ export function mergeSkills(...skillLists) {
|
|
|
421
426
|
}
|
|
422
427
|
|
|
423
428
|
export const skillSearchPaths = {
|
|
424
|
-
global: searchDirsForList([claudeUserSkillsDir, opencodeUserSkillsDir, sharedUserSkillsDir, userSkillsDir]),
|
|
429
|
+
global: searchDirsForList([bundledSkillsDir, claudeUserSkillsDir, opencodeUserSkillsDir, sharedUserSkillsDir, userSkillsDir]),
|
|
425
430
|
project: ['<project>/.claude/skills', '<project>/.opencode/skills', '<project>/.agents/skills', '<project>/.quickforge/skills'],
|
|
426
431
|
}
|
|
427
432
|
|
|
@@ -444,6 +449,7 @@ async function loadPluginSkills(workspaceRoot) {
|
|
|
444
449
|
|
|
445
450
|
export async function loadGlobalSkills() {
|
|
446
451
|
return loadSkillsFromSources([
|
|
452
|
+
{ dir: bundledSkillsDir, name: 'builtin' },
|
|
447
453
|
{ dir: claudeUserSkillsDir, name: 'user-claude' },
|
|
448
454
|
{ dir: opencodeUserSkillsDir, name: 'user-opencode' },
|
|
449
455
|
{ dir: sharedUserSkillsDir, name: 'user-shared' },
|
|
@@ -451,6 +457,27 @@ export async function loadGlobalSkills() {
|
|
|
451
457
|
])
|
|
452
458
|
}
|
|
453
459
|
|
|
460
|
+
export async function ensureDefaultGlobalSkills() {
|
|
461
|
+
if (existsSync(defaultSkillsMarkerFile)) return false
|
|
462
|
+
|
|
463
|
+
const known = new Set((await loadGlobalSkills()).map((skill) => skill.name))
|
|
464
|
+
const defaults = defaultGlobalSkillNames.filter((name) => known.has(name))
|
|
465
|
+
if (defaults.length === 0) return false
|
|
466
|
+
|
|
467
|
+
await atomicProjectConfigUpdate((config) => {
|
|
468
|
+
config.globalSkills = normalizeSkillNames([
|
|
469
|
+
...(Array.isArray(config.globalSkills) ? config.globalSkills : []),
|
|
470
|
+
...defaults,
|
|
471
|
+
])
|
|
472
|
+
return config
|
|
473
|
+
})
|
|
474
|
+
await fs.mkdir(configDir, { recursive: true })
|
|
475
|
+
await fs.writeFile(defaultSkillsMarkerFile, `${new Date().toISOString()}\n`, { flag: 'wx' }).catch((error) => {
|
|
476
|
+
if (error?.code !== 'EEXIST') throw error
|
|
477
|
+
})
|
|
478
|
+
return true
|
|
479
|
+
}
|
|
480
|
+
|
|
454
481
|
export async function loadProjectSkills(workspaceRoot) {
|
|
455
482
|
const pluginSkills = await loadPluginSkills(workspaceRoot)
|
|
456
483
|
const projectSkills = await loadSkillsFromSources([
|
package/server/storage.mjs
CHANGED
|
@@ -618,10 +618,16 @@ export async function atomicSessionValueUpdate(sessionId, updateFn) {
|
|
|
618
618
|
export async function deleteSessionValue(sessionId) {
|
|
619
619
|
return enqueueWrite('sessions', async () => {
|
|
620
620
|
const bucket = await findSessionBucket(sessionId)
|
|
621
|
-
if (!bucket)
|
|
621
|
+
if (!bucket) {
|
|
622
|
+
const { deleteCloudChatIdempotencySession } = await import('./cloud/chat-idempotency-store.mjs')
|
|
623
|
+
await deleteCloudChatIdempotencySession(sessionId)
|
|
624
|
+
return
|
|
625
|
+
}
|
|
622
626
|
await fs.rm(sessionDataFile(sessionId, bucket), { force: true })
|
|
623
627
|
const { deleteSessionAssets } = await import('./session-assets.mjs')
|
|
624
628
|
await deleteSessionAssets(bucket, sessionId)
|
|
629
|
+
const { deleteCloudChatIdempotencySession } = await import('./cloud/chat-idempotency-store.mjs')
|
|
630
|
+
await deleteCloudChatIdempotencySession(sessionId)
|
|
625
631
|
sessionBucketIndex.delete(sessionId)
|
|
626
632
|
})
|
|
627
633
|
}
|
package/server/subagents.mjs
CHANGED
|
@@ -32,7 +32,7 @@ export const subagentDefinitions = [
|
|
|
32
32
|
model: { mode: 'inherit' },
|
|
33
33
|
lifecycle: 'builtin',
|
|
34
34
|
allowFileMutations: true,
|
|
35
|
-
maxRuntimeMs:
|
|
35
|
+
maxRuntimeMs: 60 * 60 * 1000,
|
|
36
36
|
maxToolCalls: 300,
|
|
37
37
|
systemPrompt: `You are General, a general-purpose subagent for bounded complex multi-step implementation tasks and broader independent work. You may inspect, edit, write files, and run commands using the built-in workspace tools when needed. You do not have MCP tools or Agent Skills. Prefer Explore for focused read-only repository discovery, source search, call-chain lookup, tests/docs discovery, and impact analysis. Make focused, minimal changes that satisfy the delegated task, and verify your changes when appropriate.`,
|
|
38
38
|
},
|
|
@@ -46,7 +46,7 @@ export const subagentDefinitions = [
|
|
|
46
46
|
model: { mode: 'inherit' },
|
|
47
47
|
lifecycle: 'builtin',
|
|
48
48
|
allowFileMutations: false,
|
|
49
|
-
maxRuntimeMs:
|
|
49
|
+
maxRuntimeMs: 60 * 60 * 1000,
|
|
50
50
|
maxToolCalls: 300,
|
|
51
51
|
systemPrompt: `You are Explore, the preferred read-only repository research subagent. Investigate the delegated question using read_file, grep_files, and safe read-only run_command calls, and report only findings grounded in repository evidence. Do not design solutions or propose implementation, architecture, refactoring, or code changes. Cite relevant file paths, symbols, and line ranges when practical. Clearly separate verified facts, reasonable inferences, and unknowns, and never present an inference as a verified fact. Unless the parent Agent explicitly requests them, do not provide an implementation plan, recommendations, or suggested next steps. You cannot modify files.`,
|
|
52
52
|
},
|
|
@@ -82,7 +82,7 @@ capabilityPolicy: ${definition.capabilityPolicy || 'review-only'}
|
|
|
82
82
|
tools: ${definition.allowedTools.join(', ')}
|
|
83
83
|
model:
|
|
84
84
|
mode: inherit
|
|
85
|
-
max-runtime-ms: ${definition.maxRuntimeMs ||
|
|
85
|
+
max-runtime-ms: ${definition.maxRuntimeMs || 60 * 60 * 1000}
|
|
86
86
|
max-tool-calls: ${definition.maxToolCalls || 300}
|
|
87
87
|
---
|
|
88
88
|
${body}
|
|
@@ -111,7 +111,7 @@ export const workspaceTools = [
|
|
|
111
111
|
description: 'Run a shell command in the project bound to this chat. Use this for lint, build, tests, git status, and diagnostics.',
|
|
112
112
|
parameters: Type.Object({
|
|
113
113
|
command: Type.String({ description: 'Command to execute in the workspace.' }),
|
|
114
|
-
timeoutMs: Type.Optional(Type.Number({ description: 'Command timeout in milliseconds. Defaults to
|
|
114
|
+
timeoutMs: Type.Optional(Type.Number({ description: 'Command timeout in milliseconds. Defaults to 1 hour and is clamped to the supported range.', default: 3600000 })),
|
|
115
115
|
description: Type.Optional(Type.String({ description: 'Short explanation of why this command is being run.' })),
|
|
116
116
|
}),
|
|
117
117
|
executionMode: 'sequential',
|
package/server/tools/index.mjs
CHANGED
|
@@ -709,9 +709,9 @@ export async function toolPresentFiles(params, context) {
|
|
|
709
709
|
}
|
|
710
710
|
|
|
711
711
|
// --- run_command ---
|
|
712
|
-
const DEFAULT_RUN_COMMAND_TIMEOUT_MS =
|
|
712
|
+
const DEFAULT_RUN_COMMAND_TIMEOUT_MS = 60 * 60 * 1000
|
|
713
713
|
const MIN_RUN_COMMAND_TIMEOUT_MS = 1000
|
|
714
|
-
const MAX_RUN_COMMAND_TIMEOUT_MS =
|
|
714
|
+
const MAX_RUN_COMMAND_TIMEOUT_MS = 60 * 60 * 1000
|
|
715
715
|
const COMMAND_PREVIEW_LINES = 200
|
|
716
716
|
const COMMAND_PREVIEW_TOTAL_CHARS = 10000
|
|
717
717
|
|
package/server/utils/network.mjs
CHANGED
|
@@ -8,6 +8,15 @@ export function isPrivateIpv4(hostname) {
|
|
|
8
8
|
return a === 10 || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168)
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
export function isTailscaleAddress(address) {
|
|
12
|
+
if (!address) return false
|
|
13
|
+
const normalized = String(address).replace(/^::ffff:/i, '')
|
|
14
|
+
if (!/^\d{1,3}(?:\.\d{1,3}){3}$/.test(normalized)) return false
|
|
15
|
+
const parts = normalized.split('.').map((part) => Number(part))
|
|
16
|
+
if (parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) return false
|
|
17
|
+
return parts[0] === 100 && parts[1] >= 64 && parts[1] <= 127
|
|
18
|
+
}
|
|
19
|
+
|
|
11
20
|
export function isLoopbackAddress(address) {
|
|
12
21
|
if (!address) return false
|
|
13
22
|
const normalized = address.replace(/^::ffff:/, '')
|
|
@@ -15,7 +15,14 @@ export function sendError(res, error) {
|
|
|
15
15
|
return
|
|
16
16
|
}
|
|
17
17
|
const status = error?.statusCode || 500
|
|
18
|
-
|
|
18
|
+
const payload = { error: error?.message || 'Internal server error' }
|
|
19
|
+
const code = typeof error?.errorCode === 'string' && error.errorCode
|
|
20
|
+
? error.errorCode
|
|
21
|
+
: typeof error?.code === 'string' && error.code
|
|
22
|
+
? error.code
|
|
23
|
+
: undefined
|
|
24
|
+
if (code) payload.code = code
|
|
25
|
+
sendJson(res, status, payload)
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
export async function readJsonBody(req, maxBodyBytes = DEFAULT_MAX_BODY_BYTES) {
|