squidclaw 3.0.2 → 3.0.3
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/{accounts-LA308FHj.js → accounts-CK_sHUyT.js} +2 -2
- package/dist/{accounts-CL_NXliB.js → accounts-CkF7YwoF.js} +17 -17
- package/dist/{accounts-F7tGwezI.js → accounts-DbloMfwT.js} +2 -2
- package/dist/{active-listener-DJv1FZqf.js → active-listener-AepfNSUY.js} +2 -2
- package/dist/{agents-DdixSPs3.js → agents-JnnOlm2G.js} +5 -5
- package/dist/{agents.config-Cn_vTN1v.js → agents.config-BeGeS2jv.js} +1 -1
- package/dist/{agents.config-C6KTwnde.js → agents.config-DHJBQ7uA.js} +1 -1
- package/dist/{plugin-sdk/api-key-rotation-DE4gr5YM.js → api-key-rotation-BHFJiYbw.js} +2 -2
- package/dist/{audio-preflight-AEM744TY.js → audio-preflight-BTYxAJjy.js} +32 -32
- package/dist/{audio-preflight-DpCWFB4z.js → audio-preflight-Dkl6Z32z.js} +4 -4
- package/dist/{audio-transcription-runner-CItniQDZ.js → audio-transcription-runner-DBkDgluo.js} +12 -12
- package/dist/{audio-transcription-runner-B2BdTEps.js → audio-transcription-runner-Gi_h5HEE.js} +1 -1
- package/dist/{audit-membership-runtime-w23FnNAN.js → audit-membership-runtime-DyLj-uhz.js} +4 -4
- package/dist/{auth-choice-7WVhiM9J.js → auth-choice-DQbCl-4F.js} +2 -2
- package/dist/{auth-choice-17U1cGPH.js → auth-choice-xwYK6txn.js} +2 -2
- package/dist/{banner-CJTrU-HC.js → banner-BxibaqUz.js} +1 -1
- package/dist/build-info.json +3 -3
- package/dist/bundled/boot-md/handler.js +51 -51
- package/dist/bundled/bootstrap-extra-files/handler.js +6 -6
- package/dist/bundled/command-logger/handler.js +2 -2
- package/dist/bundled/session-memory/handler.js +51 -51
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/{channel-activity-DPrXawu4.js → channel-activity-C5kTj83_.js} +3 -3
- package/dist/{channel-options-x47KAgAV.js → channel-options-BKsCYdHu.js} +1 -1
- package/dist/{channel-options-BM7IEY5X.js → channel-options-FdCN4cFo.js} +1 -1
- package/dist/{channel-web-B48pVgke.js → channel-web-BFUPrpIe.js} +1 -1
- package/dist/{channel-web-HM1q5FP_.js → channel-web-BkYtM8H5.js} +1 -1
- package/dist/{channels-cli-iPiD6449.js → channels-cli-BxhfVD-R.js} +7 -7
- package/dist/{channels-cli-y66ZCzYf.js → channels-cli-CZzGaGvG.js} +7 -7
- package/dist/{chrome-BQDCalPp.js → chrome-CAd6FQEn.js} +8 -8
- package/dist/{chrome-BFfAGQtd.js → chrome-pBkBuWci.js} +26 -26
- package/dist/cli/daemon-cli.js +1 -1
- package/dist/{cli-C-neGkM4.js → cli-GSev2Q95.js} +2 -2
- package/dist/{cli-BzpBs_KI.js → cli-bXiYaLre.js} +2 -2
- package/dist/{command-registry-BL80-JCV.js → command-registry-CvgCFxfY.js} +9 -9
- package/dist/{commands-registry-C2t2bcZ6.js → commands-registry-D6ZOTo1C.js} +4 -4
- package/dist/{completion-cli-CJ_L_gYr.js → completion-cli-BGM1V6EN.js} +2 -2
- package/dist/{completion-cli-Bi2s1mq8.js → completion-cli-OrgUDc2S.js} +1 -1
- package/dist/{config-cli-FhKX7MOY.js → config-cli-DbBvjvpS.js} +1 -1
- package/dist/{config-cli-BVpzzhoY.js → config-cli-uIP4r17f.js} +1 -1
- package/dist/{configure-ChiLGQo6.js → configure-BGvoAfbs.js} +6 -6
- package/dist/{configure-t9fm4x9H.js → configure-BOsTXjBw.js} +6 -6
- package/dist/{daemon-cli-DK8fQgAw.js → daemon-cli-CNi-QjEX.js} +1 -1
- package/dist/{daemon-cli-CO09shIt.js → daemon-cli-DN2TnjHQ.js} +1 -1
- package/dist/{deliver-aL8yOYS1.js → deliver-BJuiq0GS.js} +1 -1
- package/dist/{deliver-neVJ7AU9.js → deliver-DBXe-ZmL.js} +21 -21
- package/dist/{deliver-runtime-ChVR6sR3.js → deliver-runtime-DHKcNQzq.js} +3 -3
- package/dist/deliver-runtime-GlnBJNCj.js +36 -0
- package/dist/deps-send-discord.runtime-BRE0s2nz.js +26 -0
- package/dist/deps-send-imessage.runtime-DbIRBnmD.js +25 -0
- package/dist/deps-send-signal.runtime-B4h6X3o4.js +24 -0
- package/dist/deps-send-slack.runtime-BWXOnOxS.js +22 -0
- package/dist/deps-send-telegram.runtime-YvauJtgv.js +27 -0
- package/dist/{deps-send-whatsapp.runtime-WND2o1Mr.js → deps-send-whatsapp.runtime-BcxCalPD.js} +4 -4
- package/dist/deps-send-whatsapp.runtime-CslTuV47.js +60 -0
- package/dist/{deps-send-whatsapp.runtime-CZj97m5A.js → deps-send-whatsapp.runtime-DdxKewuy.js} +7 -7
- package/dist/{deps-send-whatsapp.runtime-DSbrPzxG.js → deps-send-whatsapp.runtime-Dl4ro-Df.js} +4 -4
- package/dist/{diagnostic-DoguEiWW.js → diagnostic-ySwZga6c.js} +2 -2
- package/dist/{doctor-completion-CKaQEebJ.js → doctor-completion-42wcUATu.js} +1 -1
- package/dist/{doctor-completion-Ctqsu6Y2.js → doctor-completion-D6RGDBD5.js} +1 -1
- package/dist/entry.js +2 -2
- package/dist/{plugin-sdk/errors-9oVz7reJ.js → errors-kkRuS2Cs.js} +1 -1
- package/dist/extensionAPI.js +6 -6
- package/dist/{fetch-DdiB5_OX.js → fetch-BLS7EMnx.js} +5 -5
- package/dist/{fetch-guard-CEV5qBHc.js → fetch-guard-D0fXNJls.js} +2 -2
- package/dist/{frontmatter-CjKtFduT.js → frontmatter-Cq1TcIQ2.js} +3 -3
- package/dist/{fs-safe-CwHbZdFH.js → fs-safe-BoB4X3GD.js} +4 -4
- package/dist/{gateway-cli-CSIyrhFg.js → gateway-cli-BbPfLLT6.js} +10 -10
- package/dist/{gateway-cli-xX1CTw9n.js → gateway-cli-CG3mshpO.js} +10 -10
- package/dist/{github-copilot-token-Cw3tAXM9.js → github-copilot-token-B5cPlwaz.js} +7 -7
- package/dist/{health-D9Pie2kF.js → health-CJgEuWuG.js} +1 -1
- package/dist/{health-D7mPTab_.js → health-dZqyhpdR.js} +1 -1
- package/dist/{hooks-cli-C6aI9HU7.js → hooks-cli-BD4Ww1dF.js} +3 -3
- package/dist/{hooks-cli-_1zdKcZA.js → hooks-cli-C0wWJOBW.js} +3 -3
- package/dist/{image-ecaECpjT.js → image-j_UomzVG.js} +6 -6
- package/dist/{image-ops-bdrMTILs.js → image-ops-CdgypS_g.js} +2 -2
- package/dist/image-runtime-BNh3IfMj.js +29 -0
- package/dist/{image-runtime-poRypm-b.js → image-runtime-SUtf9jqh.js} +3 -3
- package/dist/{image-DKZCmkET.js → image-sRW3RpTY.js} +1 -1
- package/dist/index.js +7 -7
- package/dist/{ir-D_GD01cg.js → ir-BvisJWXv.js} +8 -8
- package/dist/{legacy-names-B0wgIP0Q.js → legacy-names-aGJJuzM_.js} +1 -1
- package/dist/llm-slug-generator.js +51 -51
- package/dist/{logger-oGKcCLZ5.js → logger-CnTSBL7T.js} +7 -7
- package/dist/{login-gJWPqN66.js → login-BMeLPUiO.js} +5 -5
- package/dist/{login-qr-CgmlF7zK.js → login-qr-B2B67qqQ.js} +10 -10
- package/dist/{manager-CD69uguS.js → manager-DdxMYEDd.js} +13 -13
- package/dist/manager-runtime-BMygJEz3.js +18 -0
- package/dist/{model-selection-DMjtmGZP.js → model-selection-ag9BmVct.js} +43 -43
- package/dist/{models-BviRe-_7.js → models-BXT0s4KJ.js} +3 -3
- package/dist/{models-cli-BM5yo_mo.js → models-cli-BtLc9uPC.js} +3 -3
- package/dist/{models-cli-pvYVl1i-.js → models-cli-BwPFxWK2.js} +4 -4
- package/dist/{npm-resolution-DMM9Hopy.js → npm-resolution-DWpNPsBF.js} +1 -1
- package/dist/{npm-resolution-BTFMooVS.js → npm-resolution-Djbuzx6o.js} +1 -1
- package/dist/{onboard-DVuhj8ub.js → onboard-1KfKwvMR.js} +3 -3
- package/dist/{onboard-DTsgFKIa.js → onboard-ChxvwUze.js} +3 -3
- package/dist/{onboard-channels-W9UHiBQg.js → onboard-channels-CHrtFmhi.js} +2 -2
- package/dist/{onboard-channels-B1D9LqV_.js → onboard-channels-CXjnFvP1.js} +2 -2
- package/dist/{onboard-helpers-DVaF21TE.js → onboard-helpers-Bvpkyuwm.js} +6 -6
- package/dist/{onboard-helpers-PRhg7ZY5.js → onboard-helpers-ByttGRIZ.js} +6 -6
- package/dist/{onboard-remote-h-aHSDJ1.js → onboard-remote-Cfx2v9OI.js} +1 -1
- package/dist/{onboard-remote-DkIrV4Hx.js → onboard-remote-DxBaaS6o.js} +1 -1
- package/dist/{onboard-skills-fFSuiv21.js → onboard-skills-B7pHg1lN.js} +1 -1
- package/dist/{onboard-skills-fgrVmjJP.js → onboard-skills-PCnCZ6Od.js} +1 -1
- package/dist/{onboarding-D1nCnc_t.js → onboarding-D6kMb3yv.js} +7 -7
- package/dist/{onboarding-CYWs766P.js → onboarding-DuUMPrqA.js} +7 -7
- package/dist/{onboarding.finalize-Bcan6_vA.js → onboarding.finalize-KTOhO1-l.js} +7 -7
- package/dist/{onboarding.finalize-bAiXf9D6.js → onboarding.finalize-bphDUwZy.js} +6 -6
- package/dist/{onboarding.gateway-config-61E9xXYF.js → onboarding.gateway-config-DDdX0W74.js} +1 -1
- package/dist/{onboarding.gateway-config-Dyaqc_M7.js → onboarding.gateway-config-DNUJ0seU.js} +1 -1
- package/dist/{outbound-Cboz5UyH.js → outbound-DHDBvGLA.js} +6 -6
- package/dist/{outbound-attachment-PwEbEhAL.js → outbound-attachment-CqXiWbKN.js} +2 -2
- package/dist/{path-alias-guards-Cpsiv2KL.js → path-alias-guards-DORgbZ1w.js} +1 -1
- package/dist/{paths-CSdAWKDO.js → paths-DA5srn0U.js} +5 -5
- package/dist/{paths-CXClY8zC.js → paths-DSd911Oe.js} +4 -4
- package/dist/{pi-embedded-MktS4l8v.js → pi-embedded-BGz_qdCc.js} +24 -24
- package/dist/{pi-embedded-CkTlmTq8.js → pi-embedded-BP2UlUm_.js} +171 -171
- package/dist/{pi-embedded-helpers-DYWYzEOC.js → pi-embedded-helpers-BruaFB5l.js} +3 -3
- package/dist/{pi-embedded-helpers-Bfm_CvEb.js → pi-embedded-helpers-CmLnmKlb.js} +52 -52
- package/dist/{pi-model-discovery-DEps5Exd.js → pi-model-discovery-DAzuqPoG.js} +7 -7
- package/dist/pi-model-discovery-runtime-Dpu7Jm2L.js +11 -0
- package/dist/{pi-tools.before-tool-call.runtime-4wPdP7Br.js → pi-tools.before-tool-call.runtime-2Sp1jmlg.js} +9 -9
- package/dist/{plugin-registry-CvMvSI8O.js → plugin-registry-CLEhrKYA.js} +1 -1
- package/dist/{plugin-registry-DL2ClHLQ.js → plugin-registry-DtuxmgWx.js} +1 -1
- package/dist/plugin-sdk/{accounts-kr-Gz1hk.js → accounts-DghIDNk2.js} +2 -2
- package/dist/plugin-sdk/{accounts-CxUSDHsT.js → accounts-YTdQYQFr.js} +3 -3
- package/dist/plugin-sdk/{accounts-PSzw-z3S.js → accounts-h__dTrLK.js} +2 -2
- package/dist/plugin-sdk/{active-listener-BQNrTcR3.js → active-listener-_PRYjtJv.js} +2 -2
- package/dist/plugin-sdk/{api-key-rotation-Bhck7wki.js → api-key-rotation-mVDSAkKQ.js} +2 -2
- package/dist/plugin-sdk/{audio-preflight-_xgGaeho.js → audio-preflight-BZlQM-qX.js} +26 -26
- package/dist/plugin-sdk/{audio-transcription-runner-Dwc0Eh-B.js → audio-transcription-runner-CrYTX8py.js} +11 -11
- package/dist/plugin-sdk/{audit-membership-runtime-DHQDvH4u.js → audit-membership-runtime-Xl20kCBe.js} +2 -2
- package/dist/plugin-sdk/{channel-activity-XajEg_DL.js → channel-activity-gwxRn4wF.js} +3 -3
- package/dist/plugin-sdk/{channel-web-KtqCp4mz.js → channel-web-1WF-Nabe.js} +18 -18
- package/dist/plugin-sdk/{chrome-diV5m81I.js → chrome-BXbYwXRH.js} +6 -6
- package/dist/plugin-sdk/{commands-registry-DwZAJuut.js → commands-registry-0w-aZenK.js} +4 -4
- package/dist/plugin-sdk/{common-CqnO92P8.js → common-DBOCt6Yv.js} +2 -2
- package/dist/plugin-sdk/{config-DYbtdrsT.js → config-pRtEoVyZ.js} +7 -7
- package/dist/plugin-sdk/{deliver-DG_7Uagn.js → deliver-FjlJrtZk.js} +10 -10
- package/dist/plugin-sdk/deliver-runtime-DEzvpBW1.js +32 -0
- package/dist/plugin-sdk/deps-send-discord.runtime-Bhusa_Hi.js +23 -0
- package/dist/plugin-sdk/deps-send-imessage.runtime-bmakPm5f.js +22 -0
- package/dist/plugin-sdk/deps-send-signal.runtime-n00sfFto.js +21 -0
- package/dist/plugin-sdk/deps-send-slack.runtime-BvM3Z-Mr.js +19 -0
- package/dist/plugin-sdk/deps-send-telegram.runtime-CPuMkcmo.js +24 -0
- package/dist/plugin-sdk/deps-send-whatsapp.runtime-BzO6S-KX.js +57 -0
- package/dist/plugin-sdk/{diagnostic-CT7v_kM2.js → diagnostic-Dt2i3afe.js} +2 -2
- package/dist/plugin-sdk/{errors-B8oJXuCF.js → errors-CgRPdp3o.js} +1 -1
- package/dist/plugin-sdk/{fetch-guard-Or5BCq0E.js → fetch-guard-DyPZh8r2.js} +2 -2
- package/dist/plugin-sdk/{fs-safe-DFbwq9CS.js → fs-safe-DqCO1D4C.js} +3 -3
- package/dist/plugin-sdk/{image-rycGCqJO.js → image-CQ9TZ9vq.js} +6 -6
- package/dist/plugin-sdk/{image-ops-CMsocOob.js → image-ops-sw0uZ0GN.js} +2 -2
- package/dist/plugin-sdk/image-runtime-17_mTqsy.js +25 -0
- package/dist/plugin-sdk/index.js +50 -50
- package/dist/plugin-sdk/{ir-DihI2SIz.js → ir-BVZ5kUMb.js} +7 -7
- package/dist/plugin-sdk/{local-roots-1xVosTZ4.js → local-roots-fO3ZgW3G.js} +4 -4
- package/dist/plugin-sdk/{logger-Bg4vIUJn.js → logger-DIb2cGHp.js} +2 -2
- package/dist/plugin-sdk/{login-YhFrVUWo.js → login-Dg5cxB_3.js} +4 -4
- package/dist/plugin-sdk/{login-qr-SpUTuwYv.js → login-qr-C3Vn30cq.js} +5 -5
- package/dist/plugin-sdk/{manager-DrzOPeMD.js → manager-BR-TwWTH.js} +8 -8
- package/dist/plugin-sdk/manager-runtime-CvI9wF8N.js +15 -0
- package/dist/plugin-sdk/{outbound-Cc4cUn9K.js → outbound-1a3Z_QJ2.js} +5 -5
- package/dist/plugin-sdk/{outbound-attachment-Dtp3hQgc.js → outbound-attachment-BTQjD4YE.js} +2 -2
- package/dist/plugin-sdk/{path-alias-guards-DA0MhfkG.js → path-alias-guards-TnxupPQC.js} +1 -1
- package/dist/plugin-sdk/{paths-CP67O8eN.js → paths-B7_75Pdr.js} +1 -1
- package/dist/plugin-sdk/{pi-embedded-helpers-BDJ_4Plh.js → pi-embedded-helpers-DZRNadD8.js} +16 -16
- package/dist/plugin-sdk/{pi-model-discovery-Mk0GTDJl.js → pi-model-discovery-DGh6xekX.js} +1 -1
- package/dist/plugin-sdk/pi-model-discovery-runtime-DjjBdPYt.js +8 -0
- package/dist/plugin-sdk/{pi-tools.before-tool-call.runtime-DV72wTDb.js → pi-tools.before-tool-call.runtime-BZ9XgG_x.js} +4 -4
- package/dist/plugin-sdk/{plugins-DSs2-fnK.js → plugins-B8pWVYug.js} +4 -4
- package/dist/plugin-sdk/{proxy-env-Ib4-LUh-.js → proxy-env-BOlkiW1-.js} +1 -1
- package/dist/plugin-sdk/{proxy-fetch-ZPEvp58f.js → proxy-fetch-Dt5BedH8.js} +1 -1
- package/dist/plugin-sdk/{pw-ai-DIx2wpkY.js → pw-ai-C17A1o4w.js} +9 -9
- package/dist/plugin-sdk/{qmd-manager-Ov9ElEfG.js → qmd-manager-Bei6TaFq.js} +7 -7
- package/dist/plugin-sdk/{query-expansion-CzjwW461.js → query-expansion-POz2za8a.js} +4 -4
- package/dist/plugin-sdk/{redact-BoNEjbpF.js → redact-9WsNyb7S.js} +1 -1
- package/dist/plugin-sdk/{reply-CWWUd_JS.js → reply-BFbijn6_.js} +73 -73
- package/dist/plugin-sdk/{resolve-outbound-target-BOkvxZtM.js → resolve-outbound-target-B9iFEh0y.js} +2 -2
- package/dist/plugin-sdk/{run-with-concurrency-kVooFCVo.js → run-with-concurrency-DmTrN5JG.js} +1 -1
- package/dist/plugin-sdk/runtime-whatsapp-login.runtime-DzhkSmLi.js +10 -0
- package/dist/plugin-sdk/runtime-whatsapp-outbound.runtime-DyILWezU.js +19 -0
- package/dist/plugin-sdk/{send-BP1fSEBR.js → send-BGZo6HW1.js} +5 -5
- package/dist/plugin-sdk/{send-D9CSOGul.js → send-BisREGBZ.js} +6 -6
- package/dist/plugin-sdk/{send-BeLBlAsQ.js → send-BqkUDZed.js} +13 -13
- package/dist/plugin-sdk/{send-DLKxJJYV.js → send-D6_nNvi0.js} +8 -8
- package/dist/plugin-sdk/{send-XZ6IXCtL.js → send-Dj7XEcZN.js} +7 -7
- package/dist/plugin-sdk/{session-DtLUYWvY.js → session-D4KDs7Hq.js} +3 -3
- package/dist/plugin-sdk/{skill-commands-Bv7EZypt.js → skill-commands-D_xeseiI.js} +4 -4
- package/dist/plugin-sdk/{skills-BzXN4uev.js → skills-Bs2b3JfV.js} +6 -6
- package/dist/plugin-sdk/slash-commands.runtime-CUb5sqqf.js +13 -0
- package/dist/plugin-sdk/slash-dispatch.runtime-DCB6bGjB.js +52 -0
- package/dist/plugin-sdk/slash-skill-commands.runtime-BqEweE4K.js +16 -0
- package/dist/plugin-sdk/{store-DnJhFFW5.js → store-B7ESm9_L.js} +2 -2
- package/dist/plugin-sdk/subagent-registry-runtime-CCUW4SbM.js +52 -0
- package/dist/plugin-sdk/{tables-CpmqssLF.js → tables-1vhBJPK_.js} +1 -1
- package/dist/plugin-sdk/{thinking-1UCPuD9d.js → thinking-DjaClmzi.js} +7 -7
- package/dist/plugin-sdk/{tokens-DAL_5WHL.js → tokens-CLE20fRI.js} +1 -1
- package/dist/plugin-sdk/{tool-images-RX4QTMnt.js → tool-images-B95xcwiR.js} +2 -2
- package/dist/plugin-sdk/web-DeRmHQ4_.js +56 -0
- package/dist/plugin-sdk/{whatsapp-actions-BF6ih4Gi.js → whatsapp-actions-BYpcWkTN.js} +17 -17
- package/dist/plugin-sdk/whatsapp.js +50 -50
- package/dist/{plugins-CmdmAU0K.js → plugins-DXkm70nK.js} +11 -11
- package/dist/{plugins-cli-DBtLtIsQ.js → plugins-cli-Cs3UUJew.js} +3 -3
- package/dist/{plugins-cli-BMPvpwSo.js → plugins-cli-KPz6APX0.js} +3 -3
- package/dist/{program-context-KSeqVkRM.js → program-context-J_FyEsaS.js} +18 -18
- package/dist/{program-C6sTShRB.js → program-xNEHPhT8.js} +8 -8
- package/dist/{prompt-select-styled-Ba5fC0g1.js → prompt-select-styled-B1LjjgQ0.js} +5 -5
- package/dist/{prompt-select-styled-DFhJPiqx.js → prompt-select-styled-BRiogP_P.js} +5 -5
- package/dist/{provider-auth-helpers-S2rdI85T.js → provider-auth-helpers-CxUWqt95.js} +1 -1
- package/dist/{provider-auth-helpers-BPvZ8xkJ.js → provider-auth-helpers-hhFVhZdv.js} +1 -1
- package/dist/{proxy-env-QUJz9VEJ.js → proxy-env-D75CWSOo.js} +1 -1
- package/dist/{proxy-fetch-C2v-Utgg.js → proxy-fetch-lH6RsRTE.js} +1 -1
- package/dist/{push-apns-BQEPMPtG.js → push-apns-BBkpZyNR.js} +1 -1
- package/dist/{push-apns-CGibQhps.js → push-apns-BQjV_93G.js} +1 -1
- package/dist/{pw-ai-SYjuzbV6.js → pw-ai-7kHgUGj0.js} +14 -14
- package/dist/{pw-ai-zFPBSxaL.js → pw-ai-BmGrTicP.js} +1 -1
- package/dist/{qmd-manager-CO-shcLU.js → qmd-manager-BN0siR2Z.js} +10 -10
- package/dist/{query-expansion-DlQOkf-g.js → query-expansion-Dzxt6kXo.js} +6 -6
- package/dist/{redact-NmPEVjIo.js → redact-DvzicBMu.js} +1 -1
- package/dist/{register.agent-DP_2xCaO.js → register.agent-DYq06QHS.js} +8 -8
- package/dist/{register.agent-BwhWwpRX.js → register.agent-reU63wQ5.js} +7 -7
- package/dist/{register.configure-D8TE-yQn.js → register.configure-C4p9ad2q.js} +10 -10
- package/dist/{register.configure-C5i661J4.js → register.configure-DezZ4Q1p.js} +10 -10
- package/dist/{register.maintenance-BS2i3S5V.js → register.maintenance-CTvFmkAm.js} +9 -9
- package/dist/{register.maintenance-BA4UOg2_.js → register.maintenance-CzMKTC2a.js} +8 -8
- package/dist/{register.message-oFI2Mzrd.js → register.message-BmsovYS6.js} +3 -3
- package/dist/{register.message-D9hVI5b6.js → register.message-Bp4SDXWk.js} +3 -3
- package/dist/{register.onboard-D6wqijOl.js → register.onboard-C39xhpv1.js} +3 -3
- package/dist/{register.onboard-OaKr3SnU.js → register.onboard-DZt2kSAg.js} +3 -3
- package/dist/{register.setup-DsK_7zih.js → register.setup-04L_8wfA.js} +3 -3
- package/dist/{register.setup-Dygx-glo.js → register.setup-DWctFmOd.js} +3 -3
- package/dist/{register.status-health-sessions-C6VfEhho.js → register.status-health-sessions-CBPZoj51.js} +4 -4
- package/dist/{register.status-health-sessions-BmWcbWPR.js → register.status-health-sessions-N6SFc-UY.js} +4 -4
- package/dist/{register.subclis-CLf32krW.js → register.subclis-C3TphbCF.js} +10 -10
- package/dist/{reply-ZWkzBiSb.js → reply-CB1p166g.js} +5 -5
- package/dist/{run-main-asKkGUqy.js → run-main-7tknx04F.js} +15 -15
- package/dist/{run-with-concurrency-FczpX8ng.js → run-with-concurrency-BFR3ReeF.js} +4 -4
- package/dist/runtime-whatsapp-login.runtime-DSR-m0FW.js +13 -0
- package/dist/runtime-whatsapp-outbound.runtime-Blywd_bv.js +22 -0
- package/dist/{send-oS3t6gE6.js → send-C98RfcAb.js} +5 -5
- package/dist/{send-DX_O1OHH.js → send-Co5Bqwuo.js} +6 -6
- package/dist/{send-BNsV-D2Y.js → send-DjL7KlMV.js} +8 -8
- package/dist/{send-C-jb8X9I.js → send-Do7hKDL9.js} +7 -7
- package/dist/{send-D-Rnbdzz.js → send-bW7jDv8D.js} +26 -26
- package/dist/{server-node-events-DV2yeAp-.js → server-node-events-Ctjzvlem.js} +3 -3
- package/dist/{server-node-events-BHv7a_ll.js → server-node-events-DrCKK0J4.js} +3 -3
- package/dist/{session-DRyURckG.js → session-QSn69XeJ.js} +8 -8
- package/dist/{skill-commands-BrlAf_CG.js → skill-commands-Bi_jchJn.js} +9 -9
- package/dist/{skills-DWrRJwa-.js → skills-CTV78w4q.js} +22 -22
- package/dist/slash-commands.runtime-63MUmCBt.js +16 -0
- package/dist/{slash-dispatch.runtime-DkcAYuyK.js → slash-dispatch.runtime-BL3qA1O3.js} +6 -6
- package/dist/{slash-dispatch.runtime-BJOuQOeN.js → slash-dispatch.runtime-DRGqAgwa.js} +2 -2
- package/dist/slash-dispatch.runtime-Dh2L_3Tg.js +56 -0
- package/dist/{slash-dispatch.runtime-CEAbkOCI.js → slash-dispatch.runtime-uqWhoI6q.js} +2 -2
- package/dist/slash-skill-commands.runtime-B3MSSAQ-.js +20 -0
- package/dist/{status-Ck8-aQIF.js → status-BkfSGlOi.js} +3 -3
- package/dist/{status-CMhW6nGs.js → status-DdW571-j.js} +3 -3
- package/dist/{store-BFNH5fXG.js → store-B89Hj8Ub.js} +2 -2
- package/dist/{subagent-registry-DQpeidFk.js → subagent-registry-DGrfQVN3.js} +5 -5
- package/dist/subagent-registry-runtime-BRNDawlJ.js +56 -0
- package/dist/{subagent-registry-runtime-C-jjppV6.js → subagent-registry-runtime-DatTO2LD.js} +2 -2
- package/dist/{subagent-registry-runtime-tRRyFZL8.js → subagent-registry-runtime-Dsrz3yIh.js} +2 -2
- package/dist/{subagent-registry-runtime-BlRAnw80.js → subagent-registry-runtime-MtjBCcgn.js} +6 -6
- package/dist/{subsystem-BaLYRf7D.js → subsystem-6v7sWnAD.js} +14 -14
- package/dist/{tables-CnlmCLb3.js → tables-DGHzaXQz.js} +1 -1
- package/dist/{target-errors-Df1wB-I7.js → target-errors-CweAa7L9.js} +2 -2
- package/dist/{thinking-CTpcVnlx.js → thinking-SdNGqtJE.js} +7 -7
- package/dist/{tokens-D2XhLqIz.js → tokens-DfbMVF9y.js} +1 -1
- package/dist/{tool-images-CElPu2en.js → tool-images-8BKrL7Bn.js} +2 -2
- package/dist/{update-cli-5KzuA6pa.js → update-cli-0UiUaT3q.js} +10 -10
- package/dist/{update-cli-CEghYBNP.js → update-cli-C-uyQcFS.js} +9 -9
- package/dist/{update-runner-C5XgCwj2.js → update-runner-CT9YRLtn.js} +1 -1
- package/dist/{update-runner-C0q8aGFd.js → update-runner-CqVLeGYA.js} +1 -1
- package/dist/{web-DBm_uXOl.js → web-B2qXyOb9.js} +3 -3
- package/dist/{web-DdrUn13G.js → web-B7kbCskR.js} +55 -55
- package/dist/{web-DddJa7ZT.js → web-D1ZoRVB0.js} +6 -6
- package/dist/{web-O2WkG3cH.js → web-FqoNMI-k.js} +3 -3
- package/dist/{whatsapp-actions-DPszRJ8b.js → whatsapp-actions-BDkbnZVH.js} +21 -21
- package/dist/{workspace-TqfVSQuO.js → workspace-kVMIaBrV.js} +20 -20
- package/package.json +1 -1
- package/dist/api-key-rotation-Dzvqp3Dc.js +0 -181
- package/dist/deliver-runtime-BdUlqV9E.js +0 -36
- package/dist/deps-send-discord.runtime-R8jUd_2I.js +0 -26
- package/dist/deps-send-imessage.runtime-Die0aWtU.js +0 -25
- package/dist/deps-send-signal.runtime-Biux_4v4.js +0 -24
- package/dist/deps-send-slack.runtime-CkUST2Ky.js +0 -22
- package/dist/deps-send-telegram.runtime-CIN5ILBe.js +0 -27
- package/dist/deps-send-whatsapp.runtime-DUff9bWS.js +0 -60
- package/dist/errors-DfgAh2Ml.js +0 -54
- package/dist/image-runtime-irHu11-U.js +0 -29
- package/dist/manager-runtime-BISxj7HK.js +0 -18
- package/dist/pi-model-discovery-runtime-bzJViQLK.js +0 -11
- package/dist/plugin-sdk/accounts-BNuRM3rG.js +0 -288
- package/dist/plugin-sdk/accounts-CGTYP7Rh.js +0 -46
- package/dist/plugin-sdk/accounts-CcS9IAhD.js +0 -35
- package/dist/plugin-sdk/active-listener-CTsLn1AX.js +0 -50
- package/dist/plugin-sdk/audio-preflight-CRGLqp-g.js +0 -69
- package/dist/plugin-sdk/audio-transcription-runner-RXsskMMk.js +0 -2176
- package/dist/plugin-sdk/audit-membership-runtime-B9b-zRwg.js +0 -58
- package/dist/plugin-sdk/channel-activity-gPvD1D7S.js +0 -94
- package/dist/plugin-sdk/channel-web-LGl1zPJt.js +0 -2256
- package/dist/plugin-sdk/chrome-9Y_LcUg1.js +0 -2415
- package/dist/plugin-sdk/commands-registry-CcdEPxVg.js +0 -1125
- package/dist/plugin-sdk/config-CrQ5bCrw.js +0 -17912
- package/dist/plugin-sdk/deliver-D3xr5AkB.js +0 -1694
- package/dist/plugin-sdk/deliver-runtime-B79ZQu69.js +0 -32
- package/dist/plugin-sdk/deliver-runtime-BdTC7uKE.js +0 -32
- package/dist/plugin-sdk/deps-send-discord.runtime-BOQZIqC8.js +0 -23
- package/dist/plugin-sdk/deps-send-discord.runtime-CObCNMt3.js +0 -23
- package/dist/plugin-sdk/deps-send-imessage.runtime-CuHOc9Ka.js +0 -22
- package/dist/plugin-sdk/deps-send-imessage.runtime-DlWgi2DH.js +0 -22
- package/dist/plugin-sdk/deps-send-signal.runtime-Cz7FT8J8.js +0 -21
- package/dist/plugin-sdk/deps-send-signal.runtime-iPynghkE.js +0 -21
- package/dist/plugin-sdk/deps-send-slack.runtime-D4vDoRsg.js +0 -19
- package/dist/plugin-sdk/deps-send-slack.runtime-DNTbE5jS.js +0 -19
- package/dist/plugin-sdk/deps-send-telegram.runtime-7CR-xtCF.js +0 -24
- package/dist/plugin-sdk/deps-send-telegram.runtime-DjTVED_m.js +0 -24
- package/dist/plugin-sdk/deps-send-whatsapp.runtime-CRWOIKRC.js +0 -57
- package/dist/plugin-sdk/deps-send-whatsapp.runtime-bUi8kghi.js +0 -57
- package/dist/plugin-sdk/diagnostic-BXkLYs_9.js +0 -319
- package/dist/plugin-sdk/fetch-guard-C55uvn27.js +0 -156
- package/dist/plugin-sdk/fs-safe-Dqmpk-Fr.js +0 -352
- package/dist/plugin-sdk/image-3xW7IJdq.js +0 -2310
- package/dist/plugin-sdk/image-ops-BjK2qZZn.js +0 -584
- package/dist/plugin-sdk/image-runtime-CZZJJqcW.js +0 -25
- package/dist/plugin-sdk/image-runtime-Cjz368oj.js +0 -25
- package/dist/plugin-sdk/ir-CS7uuQhN.js +0 -1296
- package/dist/plugin-sdk/local-roots-DmOKwiNW.js +0 -186
- package/dist/plugin-sdk/logger-DDdrdbDu.js +0 -1163
- package/dist/plugin-sdk/login-BSEeU27Y.js +0 -57
- package/dist/plugin-sdk/login-qr-BwWJsDSj.js +0 -320
- package/dist/plugin-sdk/manager-DiXPCubI.js +0 -3917
- package/dist/plugin-sdk/manager-runtime-CF55pBNe.js +0 -15
- package/dist/plugin-sdk/manager-runtime-Ct0m9UJC.js +0 -15
- package/dist/plugin-sdk/outbound-attachment-BoFx05zw.js +0 -19
- package/dist/plugin-sdk/outbound-cpqK1GFe.js +0 -212
- package/dist/plugin-sdk/path-alias-guards-gBhrAn14.js +0 -43
- package/dist/plugin-sdk/paths-C6W4VHoa.js +0 -166
- package/dist/plugin-sdk/pi-embedded-helpers-C-B9B6Sp.js +0 -9627
- package/dist/plugin-sdk/pi-model-discovery-BGEeoPzN.js +0 -134
- package/dist/plugin-sdk/pi-model-discovery-runtime-BHZ_Htob.js +0 -8
- package/dist/plugin-sdk/pi-model-discovery-runtime-BrwtJHPU.js +0 -8
- package/dist/plugin-sdk/pi-tools.before-tool-call.runtime-ByN_xThw.js +0 -354
- package/dist/plugin-sdk/plugins-D5cdn70e.js +0 -864
- package/dist/plugin-sdk/proxy-fetch-Cf3IUSDw.js +0 -38
- package/dist/plugin-sdk/pw-ai-C_QOIuin.js +0 -1938
- package/dist/plugin-sdk/qmd-manager-6bozlfFg.js +0 -1448
- package/dist/plugin-sdk/query-expansion-eeVz_aEm.js +0 -1011
- package/dist/plugin-sdk/redact-DfACyt0X.js +0 -319
- package/dist/plugin-sdk/reply-CQUX_haM.js +0 -98828
- package/dist/plugin-sdk/resolve-outbound-target-Dbz0O8cR.js +0 -40
- package/dist/plugin-sdk/run-with-concurrency-5DMu9szx.js +0 -1994
- package/dist/plugin-sdk/runtime-whatsapp-login.runtime-DitS0I1z.js +0 -10
- package/dist/plugin-sdk/runtime-whatsapp-login.runtime-OthrtsLL.js +0 -10
- package/dist/plugin-sdk/runtime-whatsapp-outbound.runtime-CYCr6A3v.js +0 -19
- package/dist/plugin-sdk/runtime-whatsapp-outbound.runtime-Q2HL0zL3.js +0 -19
- package/dist/plugin-sdk/send-BACEu1Un.js +0 -414
- package/dist/plugin-sdk/send-BU4OoR7u.js +0 -2587
- package/dist/plugin-sdk/send-DbxOJ_BC.js +0 -3135
- package/dist/plugin-sdk/send-n932vjT5.js +0 -540
- package/dist/plugin-sdk/send-uCPS53j8.js +0 -503
- package/dist/plugin-sdk/session-DenDKR_-.js +0 -169
- package/dist/plugin-sdk/skill-commands-BK1KDKmS.js +0 -342
- package/dist/plugin-sdk/skills-D4am-zkO.js +0 -1428
- package/dist/plugin-sdk/slash-commands.runtime-Bx1K1iqP.js +0 -13
- package/dist/plugin-sdk/slash-commands.runtime-DWfFqMZw.js +0 -13
- package/dist/plugin-sdk/slash-dispatch.runtime-DVn338JI.js +0 -52
- package/dist/plugin-sdk/slash-dispatch.runtime-pnWH5AjM.js +0 -52
- package/dist/plugin-sdk/slash-skill-commands.runtime-Dbi_YzPO.js +0 -16
- package/dist/plugin-sdk/slash-skill-commands.runtime-DxvNWv_E.js +0 -16
- package/dist/plugin-sdk/ssrf-2WBi1Tzx.js +0 -202
- package/dist/plugin-sdk/store-BKDMuvyn.js +0 -81
- package/dist/plugin-sdk/subagent-registry-runtime-FhP0l-Rw.js +0 -52
- package/dist/plugin-sdk/subagent-registry-runtime-hH9ADku1.js +0 -52
- package/dist/plugin-sdk/tables-CrDYcv_b.js +0 -55
- package/dist/plugin-sdk/target-errors-aOwE-MIU.js +0 -195
- package/dist/plugin-sdk/thinking-D41FMh9T.js +0 -1206
- package/dist/plugin-sdk/tokens-CTIYTLWu.js +0 -52
- package/dist/plugin-sdk/tool-images-CWc54lpI.js +0 -274
- package/dist/plugin-sdk/web-AtEy-48y.js +0 -56
- package/dist/plugin-sdk/web-DjKONHqF.js +0 -56
- package/dist/plugin-sdk/whatsapp-actions-DEZcm_CZ.js +0 -80
- package/dist/runtime-whatsapp-login.runtime-BqOsE5As.js +0 -13
- package/dist/runtime-whatsapp-outbound.runtime-D5S6mxFT.js +0 -22
- package/dist/slash-commands.runtime-JqCsKeu2.js +0 -16
- package/dist/slash-dispatch.runtime-h9I6EDYB.js +0 -56
- package/dist/slash-skill-commands.runtime-C0QZlkpu.js +0 -20
- package/dist/subagent-registry-runtime-BxvwRp_3.js +0 -56
|
@@ -1,1428 +0,0 @@
|
|
|
1
|
-
import { E as resolveSquidClawPackageRootSync, H as normalizeSkillFilter, z as isPathInside } from "./run-with-concurrency-5DMu9szx.js";
|
|
2
|
-
import { $r as isDangerousHostEnvVarName, Sr as isPathInsideWithRealpath, Ur as normalizeResolvedSecretInputString, dt as LEGACY_MANIFEST_KEYS, ft as MANIFEST_KEY, gt as resolveMemorySlotDecision, ht as resolveEffectiveEnableState, mt as normalizePluginsConfig, st as loadPluginManifestRegistry, ti as parseBooleanValue } from "./config-CrQ5bCrw.js";
|
|
3
|
-
import { E as resolveUserPath, X as resolvePreferredSquidClawTmpDir, a as createSubsystemLogger, f as CONFIG_DIR } from "./logger-DDdrdbDu.js";
|
|
4
|
-
import { n as assertNoPathAliasEscape } from "./path-alias-guards-gBhrAn14.js";
|
|
5
|
-
import fs from "node:fs";
|
|
6
|
-
import path from "node:path";
|
|
7
|
-
import os from "node:os";
|
|
8
|
-
import { createHash, timingSafeEqual } from "node:crypto";
|
|
9
|
-
import JSON5 from "json5";
|
|
10
|
-
import { URL as URL$1, fileURLToPath } from "node:url";
|
|
11
|
-
import { formatSkillsForPrompt, loadSkillsFromDir } from "@mariozechner/pi-coding-agent";
|
|
12
|
-
import YAML from "yaml";
|
|
13
|
-
|
|
14
|
-
//#region src/security/secret-equal.ts
|
|
15
|
-
function safeEqualSecret(provided, expected) {
|
|
16
|
-
if (typeof provided !== "string" || typeof expected !== "string") return false;
|
|
17
|
-
const hash = (s) => createHash("sha256").update(s).digest();
|
|
18
|
-
return timingSafeEqual(hash(provided), hash(expected));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region src/shared/config-eval.ts
|
|
23
|
-
function isTruthy(value) {
|
|
24
|
-
if (value === void 0 || value === null) return false;
|
|
25
|
-
if (typeof value === "boolean") return value;
|
|
26
|
-
if (typeof value === "number") return value !== 0;
|
|
27
|
-
if (typeof value === "string") return value.trim().length > 0;
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
function resolveConfigPath(config, pathStr) {
|
|
31
|
-
const parts = pathStr.split(".").filter(Boolean);
|
|
32
|
-
let current = config;
|
|
33
|
-
for (const part of parts) {
|
|
34
|
-
if (typeof current !== "object" || current === null) return;
|
|
35
|
-
current = current[part];
|
|
36
|
-
}
|
|
37
|
-
return current;
|
|
38
|
-
}
|
|
39
|
-
function isConfigPathTruthyWithDefaults(config, pathStr, defaults) {
|
|
40
|
-
const value = resolveConfigPath(config, pathStr);
|
|
41
|
-
if (value === void 0 && pathStr in defaults) return defaults[pathStr] ?? false;
|
|
42
|
-
return isTruthy(value);
|
|
43
|
-
}
|
|
44
|
-
function evaluateRuntimeRequires(params) {
|
|
45
|
-
const requires = params.requires;
|
|
46
|
-
if (!requires) return true;
|
|
47
|
-
const requiredBins = requires.bins ?? [];
|
|
48
|
-
if (requiredBins.length > 0) for (const bin of requiredBins) {
|
|
49
|
-
if (params.hasBin(bin)) continue;
|
|
50
|
-
if (params.hasRemoteBin?.(bin)) continue;
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
const requiredAnyBins = requires.anyBins ?? [];
|
|
54
|
-
if (requiredAnyBins.length > 0) {
|
|
55
|
-
if (!requiredAnyBins.some((bin) => params.hasBin(bin)) && !params.hasAnyRemoteBin?.(requiredAnyBins)) return false;
|
|
56
|
-
}
|
|
57
|
-
const requiredEnv = requires.env ?? [];
|
|
58
|
-
if (requiredEnv.length > 0) {
|
|
59
|
-
for (const envName of requiredEnv) if (!params.hasEnv(envName)) return false;
|
|
60
|
-
}
|
|
61
|
-
const requiredConfig = requires.config ?? [];
|
|
62
|
-
if (requiredConfig.length > 0) {
|
|
63
|
-
for (const configPath of requiredConfig) if (!params.isConfigPathTruthy(configPath)) return false;
|
|
64
|
-
}
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
function evaluateRuntimeEligibility(params) {
|
|
68
|
-
const osList = params.os ?? [];
|
|
69
|
-
const remotePlatforms = params.remotePlatforms ?? [];
|
|
70
|
-
if (osList.length > 0 && !osList.includes(resolveRuntimePlatform()) && !remotePlatforms.some((platform) => osList.includes(platform))) return false;
|
|
71
|
-
if (params.always === true) return true;
|
|
72
|
-
return evaluateRuntimeRequires({
|
|
73
|
-
requires: params.requires,
|
|
74
|
-
hasBin: params.hasBin,
|
|
75
|
-
hasRemoteBin: params.hasRemoteBin,
|
|
76
|
-
hasAnyRemoteBin: params.hasAnyRemoteBin,
|
|
77
|
-
hasEnv: params.hasEnv,
|
|
78
|
-
isConfigPathTruthy: params.isConfigPathTruthy
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
function resolveRuntimePlatform() {
|
|
82
|
-
return process.platform;
|
|
83
|
-
}
|
|
84
|
-
function windowsPathExtensions() {
|
|
85
|
-
const raw = process.env.PATHEXT;
|
|
86
|
-
return ["", ...(raw !== void 0 ? raw.split(";").map((v) => v.trim()) : [
|
|
87
|
-
".EXE",
|
|
88
|
-
".CMD",
|
|
89
|
-
".BAT",
|
|
90
|
-
".COM"
|
|
91
|
-
]).filter(Boolean)];
|
|
92
|
-
}
|
|
93
|
-
let cachedHasBinaryPath;
|
|
94
|
-
let cachedHasBinaryPathExt;
|
|
95
|
-
const hasBinaryCache = /* @__PURE__ */ new Map();
|
|
96
|
-
function hasBinary(bin) {
|
|
97
|
-
const pathEnv = process.env.PATH ?? "";
|
|
98
|
-
const pathExt = process.platform === "win32" ? process.env.PATHEXT ?? "" : "";
|
|
99
|
-
if (cachedHasBinaryPath !== pathEnv || cachedHasBinaryPathExt !== pathExt) {
|
|
100
|
-
cachedHasBinaryPath = pathEnv;
|
|
101
|
-
cachedHasBinaryPathExt = pathExt;
|
|
102
|
-
hasBinaryCache.clear();
|
|
103
|
-
}
|
|
104
|
-
if (hasBinaryCache.has(bin)) return hasBinaryCache.get(bin);
|
|
105
|
-
const parts = pathEnv.split(path.delimiter).filter(Boolean);
|
|
106
|
-
const extensions = process.platform === "win32" ? windowsPathExtensions() : [""];
|
|
107
|
-
for (const part of parts) for (const ext of extensions) {
|
|
108
|
-
const candidate = path.join(part, bin + ext);
|
|
109
|
-
try {
|
|
110
|
-
fs.accessSync(candidate, fs.constants.X_OK);
|
|
111
|
-
hasBinaryCache.set(bin, true);
|
|
112
|
-
return true;
|
|
113
|
-
} catch {}
|
|
114
|
-
}
|
|
115
|
-
hasBinaryCache.set(bin, false);
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
//#endregion
|
|
120
|
-
//#region src/infra/npm-registry-spec.ts
|
|
121
|
-
function validateRegistryNpmSpec(rawSpec) {
|
|
122
|
-
const spec = rawSpec.trim();
|
|
123
|
-
if (!spec) return "missing npm spec";
|
|
124
|
-
if (/\s/.test(spec)) return "unsupported npm spec: whitespace is not allowed";
|
|
125
|
-
if (spec.includes("://")) return "unsupported npm spec: URLs are not allowed";
|
|
126
|
-
if (spec.includes("#")) return "unsupported npm spec: git refs are not allowed";
|
|
127
|
-
if (spec.includes(":")) return "unsupported npm spec: protocol specs are not allowed";
|
|
128
|
-
const at = spec.lastIndexOf("@");
|
|
129
|
-
const hasVersion = at > 0;
|
|
130
|
-
const name = hasVersion ? spec.slice(0, at) : spec;
|
|
131
|
-
const version = hasVersion ? spec.slice(at + 1) : "";
|
|
132
|
-
if (!(name.startsWith("@") ? /^@[a-z0-9][a-z0-9-._~]*\/[a-z0-9][a-z0-9-._~]*$/.test(name) : /^[a-z0-9][a-z0-9-._~]*$/.test(name))) return "unsupported npm spec: expected <name> or <name>@<version> from the npm registry";
|
|
133
|
-
if (hasVersion) {
|
|
134
|
-
if (!version) return "unsupported npm spec: missing version/tag after @";
|
|
135
|
-
if (/[\\/]/.test(version)) return "unsupported npm spec: invalid version/tag";
|
|
136
|
-
}
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
//#endregion
|
|
141
|
-
//#region src/markdown/frontmatter.ts
|
|
142
|
-
function stripQuotes(value) {
|
|
143
|
-
if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1);
|
|
144
|
-
return value;
|
|
145
|
-
}
|
|
146
|
-
function coerceYamlFrontmatterValue(value) {
|
|
147
|
-
if (value === null || value === void 0) return;
|
|
148
|
-
if (typeof value === "string") return {
|
|
149
|
-
value: value.trim(),
|
|
150
|
-
kind: "scalar"
|
|
151
|
-
};
|
|
152
|
-
if (typeof value === "number" || typeof value === "boolean") return {
|
|
153
|
-
value: String(value),
|
|
154
|
-
kind: "scalar"
|
|
155
|
-
};
|
|
156
|
-
if (typeof value === "object") try {
|
|
157
|
-
return {
|
|
158
|
-
value: JSON.stringify(value),
|
|
159
|
-
kind: "structured"
|
|
160
|
-
};
|
|
161
|
-
} catch {
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
function parseYamlFrontmatter(block) {
|
|
166
|
-
try {
|
|
167
|
-
const parsed = YAML.parse(block, { schema: "core" });
|
|
168
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
169
|
-
const result = {};
|
|
170
|
-
for (const [rawKey, value] of Object.entries(parsed)) {
|
|
171
|
-
const key = rawKey.trim();
|
|
172
|
-
if (!key) continue;
|
|
173
|
-
const coerced = coerceYamlFrontmatterValue(value);
|
|
174
|
-
if (!coerced) continue;
|
|
175
|
-
result[key] = coerced;
|
|
176
|
-
}
|
|
177
|
-
return result;
|
|
178
|
-
} catch {
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
function extractMultiLineValue(lines, startIndex) {
|
|
183
|
-
const valueLines = [];
|
|
184
|
-
let i = startIndex + 1;
|
|
185
|
-
while (i < lines.length) {
|
|
186
|
-
const line = lines[i];
|
|
187
|
-
if (line.length > 0 && !line.startsWith(" ") && !line.startsWith(" ")) break;
|
|
188
|
-
valueLines.push(line);
|
|
189
|
-
i += 1;
|
|
190
|
-
}
|
|
191
|
-
return {
|
|
192
|
-
value: valueLines.join("\n").trim(),
|
|
193
|
-
linesConsumed: i - startIndex
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
function parseLineFrontmatter(block) {
|
|
197
|
-
const result = {};
|
|
198
|
-
const lines = block.split("\n");
|
|
199
|
-
let i = 0;
|
|
200
|
-
while (i < lines.length) {
|
|
201
|
-
const match = lines[i].match(/^([\w-]+):\s*(.*)$/);
|
|
202
|
-
if (!match) {
|
|
203
|
-
i += 1;
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
const key = match[1];
|
|
207
|
-
const inlineValue = match[2].trim();
|
|
208
|
-
if (!key) {
|
|
209
|
-
i += 1;
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
if (!inlineValue && i + 1 < lines.length) {
|
|
213
|
-
const nextLine = lines[i + 1];
|
|
214
|
-
if (nextLine.startsWith(" ") || nextLine.startsWith(" ")) {
|
|
215
|
-
const { value, linesConsumed } = extractMultiLineValue(lines, i);
|
|
216
|
-
if (value) result[key] = {
|
|
217
|
-
value,
|
|
218
|
-
kind: "multiline",
|
|
219
|
-
rawInline: inlineValue
|
|
220
|
-
};
|
|
221
|
-
i += linesConsumed;
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
const value = stripQuotes(inlineValue);
|
|
226
|
-
if (value) result[key] = {
|
|
227
|
-
value,
|
|
228
|
-
kind: "inline",
|
|
229
|
-
rawInline: inlineValue
|
|
230
|
-
};
|
|
231
|
-
i += 1;
|
|
232
|
-
}
|
|
233
|
-
return result;
|
|
234
|
-
}
|
|
235
|
-
function lineFrontmatterToPlain(parsed) {
|
|
236
|
-
const result = {};
|
|
237
|
-
for (const [key, entry] of Object.entries(parsed)) result[key] = entry.value;
|
|
238
|
-
return result;
|
|
239
|
-
}
|
|
240
|
-
function isYamlBlockScalarIndicator(value) {
|
|
241
|
-
return /^[|>][+-]?(\d+)?[+-]?$/.test(value);
|
|
242
|
-
}
|
|
243
|
-
function shouldPreferInlineLineValue(params) {
|
|
244
|
-
const { lineEntry, yamlValue } = params;
|
|
245
|
-
if (yamlValue.kind !== "structured") return false;
|
|
246
|
-
if (lineEntry.kind !== "inline") return false;
|
|
247
|
-
if (isYamlBlockScalarIndicator(lineEntry.rawInline)) return false;
|
|
248
|
-
return lineEntry.value.includes(":");
|
|
249
|
-
}
|
|
250
|
-
function extractFrontmatterBlock(content) {
|
|
251
|
-
const normalized = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
252
|
-
if (!normalized.startsWith("---")) return;
|
|
253
|
-
const endIndex = normalized.indexOf("\n---", 3);
|
|
254
|
-
if (endIndex === -1) return;
|
|
255
|
-
return normalized.slice(4, endIndex);
|
|
256
|
-
}
|
|
257
|
-
function parseFrontmatterBlock(content) {
|
|
258
|
-
const block = extractFrontmatterBlock(content);
|
|
259
|
-
if (!block) return {};
|
|
260
|
-
const lineParsed = parseLineFrontmatter(block);
|
|
261
|
-
const yamlParsed = parseYamlFrontmatter(block);
|
|
262
|
-
if (yamlParsed === null) return lineFrontmatterToPlain(lineParsed);
|
|
263
|
-
const merged = {};
|
|
264
|
-
for (const [key, yamlValue] of Object.entries(yamlParsed)) {
|
|
265
|
-
merged[key] = yamlValue.value;
|
|
266
|
-
const lineEntry = lineParsed[key];
|
|
267
|
-
if (!lineEntry) continue;
|
|
268
|
-
if (shouldPreferInlineLineValue({
|
|
269
|
-
lineEntry,
|
|
270
|
-
yamlValue
|
|
271
|
-
})) merged[key] = lineEntry.value;
|
|
272
|
-
}
|
|
273
|
-
for (const [key, lineEntry] of Object.entries(lineParsed)) if (!(key in merged)) merged[key] = lineEntry.value;
|
|
274
|
-
return merged;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
//#endregion
|
|
278
|
-
//#region src/shared/frontmatter.ts
|
|
279
|
-
function normalizeStringList(input) {
|
|
280
|
-
if (!input) return [];
|
|
281
|
-
if (Array.isArray(input)) return input.map((value) => String(value).trim()).filter(Boolean);
|
|
282
|
-
if (typeof input === "string") return input.split(",").map((value) => value.trim()).filter(Boolean);
|
|
283
|
-
return [];
|
|
284
|
-
}
|
|
285
|
-
function getFrontmatterString(frontmatter, key) {
|
|
286
|
-
const raw = frontmatter[key];
|
|
287
|
-
return typeof raw === "string" ? raw : void 0;
|
|
288
|
-
}
|
|
289
|
-
function parseFrontmatterBool(value, fallback) {
|
|
290
|
-
const parsed = parseBooleanValue(value);
|
|
291
|
-
return parsed === void 0 ? fallback : parsed;
|
|
292
|
-
}
|
|
293
|
-
function resolveSquidClawManifestBlock(params) {
|
|
294
|
-
const raw = getFrontmatterString(params.frontmatter, params.key ?? "metadata");
|
|
295
|
-
if (!raw) return;
|
|
296
|
-
try {
|
|
297
|
-
const parsed = JSON5.parse(raw);
|
|
298
|
-
if (!parsed || typeof parsed !== "object") return;
|
|
299
|
-
const manifestKeys = [MANIFEST_KEY, ...LEGACY_MANIFEST_KEYS];
|
|
300
|
-
for (const key of manifestKeys) {
|
|
301
|
-
const candidate = parsed[key];
|
|
302
|
-
if (candidate && typeof candidate === "object") return candidate;
|
|
303
|
-
}
|
|
304
|
-
return;
|
|
305
|
-
} catch {
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
function resolveSquidClawManifestRequires(metadataObj) {
|
|
310
|
-
const requiresRaw = typeof metadataObj.requires === "object" && metadataObj.requires !== null ? metadataObj.requires : void 0;
|
|
311
|
-
if (!requiresRaw) return;
|
|
312
|
-
return {
|
|
313
|
-
bins: normalizeStringList(requiresRaw.bins),
|
|
314
|
-
anyBins: normalizeStringList(requiresRaw.anyBins),
|
|
315
|
-
env: normalizeStringList(requiresRaw.env),
|
|
316
|
-
config: normalizeStringList(requiresRaw.config)
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
function resolveSquidClawManifestInstall(metadataObj, parseInstallSpec) {
|
|
320
|
-
return (Array.isArray(metadataObj.install) ? metadataObj.install : []).map((entry) => parseInstallSpec(entry)).filter((entry) => Boolean(entry));
|
|
321
|
-
}
|
|
322
|
-
function resolveSquidClawManifestOs(metadataObj) {
|
|
323
|
-
return normalizeStringList(metadataObj.os);
|
|
324
|
-
}
|
|
325
|
-
function parseSquidClawManifestInstallBase(input, allowedKinds) {
|
|
326
|
-
if (!input || typeof input !== "object") return;
|
|
327
|
-
const raw = input;
|
|
328
|
-
const kind = (typeof raw.kind === "string" ? raw.kind : typeof raw.type === "string" ? raw.type : "").trim().toLowerCase();
|
|
329
|
-
if (!allowedKinds.includes(kind)) return;
|
|
330
|
-
const spec = {
|
|
331
|
-
raw,
|
|
332
|
-
kind
|
|
333
|
-
};
|
|
334
|
-
if (typeof raw.id === "string") spec.id = raw.id;
|
|
335
|
-
if (typeof raw.label === "string") spec.label = raw.label;
|
|
336
|
-
const bins = normalizeStringList(raw.bins);
|
|
337
|
-
if (bins.length > 0) spec.bins = bins;
|
|
338
|
-
return spec;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
//#endregion
|
|
342
|
-
//#region src/agents/skills/frontmatter.ts
|
|
343
|
-
function parseFrontmatter(content) {
|
|
344
|
-
return parseFrontmatterBlock(content);
|
|
345
|
-
}
|
|
346
|
-
const BREW_FORMULA_PATTERN = /^[A-Za-z0-9][A-Za-z0-9@+._/-]*$/;
|
|
347
|
-
const GO_MODULE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._~+\-/]*(?:@[A-Za-z0-9][A-Za-z0-9._~+\-/]*)?$/;
|
|
348
|
-
const UV_PACKAGE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._\-[\]=<>!~+,]*$/;
|
|
349
|
-
function normalizeSafeBrewFormula(raw) {
|
|
350
|
-
if (typeof raw !== "string") return;
|
|
351
|
-
const formula = raw.trim();
|
|
352
|
-
if (!formula || formula.startsWith("-") || formula.includes("\\") || formula.includes("..")) return;
|
|
353
|
-
if (!BREW_FORMULA_PATTERN.test(formula)) return;
|
|
354
|
-
return formula;
|
|
355
|
-
}
|
|
356
|
-
function normalizeSafeNpmSpec(raw) {
|
|
357
|
-
if (typeof raw !== "string") return;
|
|
358
|
-
const spec = raw.trim();
|
|
359
|
-
if (!spec || spec.startsWith("-")) return;
|
|
360
|
-
if (validateRegistryNpmSpec(spec) !== null) return;
|
|
361
|
-
return spec;
|
|
362
|
-
}
|
|
363
|
-
function normalizeSafeGoModule(raw) {
|
|
364
|
-
if (typeof raw !== "string") return;
|
|
365
|
-
const moduleSpec = raw.trim();
|
|
366
|
-
if (!moduleSpec || moduleSpec.startsWith("-") || moduleSpec.includes("\\") || moduleSpec.includes("://")) return;
|
|
367
|
-
if (!GO_MODULE_PATTERN.test(moduleSpec)) return;
|
|
368
|
-
return moduleSpec;
|
|
369
|
-
}
|
|
370
|
-
function normalizeSafeUvPackage(raw) {
|
|
371
|
-
if (typeof raw !== "string") return;
|
|
372
|
-
const pkg = raw.trim();
|
|
373
|
-
if (!pkg || pkg.startsWith("-") || pkg.includes("\\") || pkg.includes("://")) return;
|
|
374
|
-
if (!UV_PACKAGE_PATTERN.test(pkg)) return;
|
|
375
|
-
return pkg;
|
|
376
|
-
}
|
|
377
|
-
function normalizeSafeDownloadUrl(raw) {
|
|
378
|
-
if (typeof raw !== "string") return;
|
|
379
|
-
const value = raw.trim();
|
|
380
|
-
if (!value || /\s/.test(value)) return;
|
|
381
|
-
try {
|
|
382
|
-
const parsed = new URL(value);
|
|
383
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return;
|
|
384
|
-
return parsed.toString();
|
|
385
|
-
} catch {
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
function parseInstallSpec(input) {
|
|
390
|
-
const parsed = parseSquidClawManifestInstallBase(input, [
|
|
391
|
-
"brew",
|
|
392
|
-
"node",
|
|
393
|
-
"go",
|
|
394
|
-
"uv",
|
|
395
|
-
"download"
|
|
396
|
-
]);
|
|
397
|
-
if (!parsed) return;
|
|
398
|
-
const { raw } = parsed;
|
|
399
|
-
const spec = { kind: parsed.kind };
|
|
400
|
-
if (parsed.id) spec.id = parsed.id;
|
|
401
|
-
if (parsed.label) spec.label = parsed.label;
|
|
402
|
-
if (parsed.bins) spec.bins = parsed.bins;
|
|
403
|
-
const osList = normalizeStringList(raw.os);
|
|
404
|
-
if (osList.length > 0) spec.os = osList;
|
|
405
|
-
const formula = normalizeSafeBrewFormula(raw.formula);
|
|
406
|
-
if (formula) spec.formula = formula;
|
|
407
|
-
const cask = normalizeSafeBrewFormula(raw.cask);
|
|
408
|
-
if (!spec.formula && cask) spec.formula = cask;
|
|
409
|
-
if (spec.kind === "node") {
|
|
410
|
-
const pkg = normalizeSafeNpmSpec(raw.package);
|
|
411
|
-
if (pkg) spec.package = pkg;
|
|
412
|
-
} else if (spec.kind === "uv") {
|
|
413
|
-
const pkg = normalizeSafeUvPackage(raw.package);
|
|
414
|
-
if (pkg) spec.package = pkg;
|
|
415
|
-
}
|
|
416
|
-
const moduleSpec = normalizeSafeGoModule(raw.module);
|
|
417
|
-
if (moduleSpec) spec.module = moduleSpec;
|
|
418
|
-
const downloadUrl = normalizeSafeDownloadUrl(raw.url);
|
|
419
|
-
if (downloadUrl) spec.url = downloadUrl;
|
|
420
|
-
if (typeof raw.archive === "string") spec.archive = raw.archive;
|
|
421
|
-
if (typeof raw.extract === "boolean") spec.extract = raw.extract;
|
|
422
|
-
if (typeof raw.stripComponents === "number") spec.stripComponents = raw.stripComponents;
|
|
423
|
-
if (typeof raw.targetDir === "string") spec.targetDir = raw.targetDir;
|
|
424
|
-
if (spec.kind === "brew" && !spec.formula) return;
|
|
425
|
-
if (spec.kind === "node" && !spec.package) return;
|
|
426
|
-
if (spec.kind === "go" && !spec.module) return;
|
|
427
|
-
if (spec.kind === "uv" && !spec.package) return;
|
|
428
|
-
if (spec.kind === "download" && !spec.url) return;
|
|
429
|
-
return spec;
|
|
430
|
-
}
|
|
431
|
-
function resolveSquidClawMetadata(frontmatter) {
|
|
432
|
-
const metadataObj = resolveSquidClawManifestBlock({ frontmatter });
|
|
433
|
-
if (!metadataObj) return;
|
|
434
|
-
const requires = resolveSquidClawManifestRequires(metadataObj);
|
|
435
|
-
const install = resolveSquidClawManifestInstall(metadataObj, parseInstallSpec);
|
|
436
|
-
const osRaw = resolveSquidClawManifestOs(metadataObj);
|
|
437
|
-
return {
|
|
438
|
-
always: typeof metadataObj.always === "boolean" ? metadataObj.always : void 0,
|
|
439
|
-
emoji: typeof metadataObj.emoji === "string" ? metadataObj.emoji : void 0,
|
|
440
|
-
homepage: typeof metadataObj.homepage === "string" ? metadataObj.homepage : void 0,
|
|
441
|
-
skillKey: typeof metadataObj.skillKey === "string" ? metadataObj.skillKey : void 0,
|
|
442
|
-
primaryEnv: typeof metadataObj.primaryEnv === "string" ? metadataObj.primaryEnv : void 0,
|
|
443
|
-
os: osRaw.length > 0 ? osRaw : void 0,
|
|
444
|
-
requires,
|
|
445
|
-
install: install.length > 0 ? install : void 0
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
function resolveSkillInvocationPolicy(frontmatter) {
|
|
449
|
-
return {
|
|
450
|
-
userInvocable: parseFrontmatterBool(getFrontmatterString(frontmatter, "user-invocable"), true),
|
|
451
|
-
disableModelInvocation: parseFrontmatterBool(getFrontmatterString(frontmatter, "disable-model-invocation"), false)
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
function resolveSkillKey(skill, entry) {
|
|
455
|
-
return entry?.metadata?.skillKey ?? skill.name;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
//#endregion
|
|
459
|
-
//#region src/agents/skills/config.ts
|
|
460
|
-
const DEFAULT_CONFIG_VALUES = {
|
|
461
|
-
"browser.enabled": true,
|
|
462
|
-
"browser.evaluateEnabled": true
|
|
463
|
-
};
|
|
464
|
-
function isConfigPathTruthy(config, pathStr) {
|
|
465
|
-
return isConfigPathTruthyWithDefaults(config, pathStr, DEFAULT_CONFIG_VALUES);
|
|
466
|
-
}
|
|
467
|
-
function resolveSkillConfig(config, skillKey) {
|
|
468
|
-
const skills = config?.skills?.entries;
|
|
469
|
-
if (!skills || typeof skills !== "object") return;
|
|
470
|
-
const entry = skills[skillKey];
|
|
471
|
-
if (!entry || typeof entry !== "object") return;
|
|
472
|
-
return entry;
|
|
473
|
-
}
|
|
474
|
-
function normalizeAllowlist(input) {
|
|
475
|
-
if (!input) return;
|
|
476
|
-
if (!Array.isArray(input)) return;
|
|
477
|
-
const normalized = input.map((entry) => String(entry).trim()).filter(Boolean);
|
|
478
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
479
|
-
}
|
|
480
|
-
const BUNDLED_SOURCES = new Set(["squidclaw-bundled"]);
|
|
481
|
-
function isBundledSkill(entry) {
|
|
482
|
-
return BUNDLED_SOURCES.has(entry.skill.source);
|
|
483
|
-
}
|
|
484
|
-
function isBundledSkillAllowed(entry, allowlist) {
|
|
485
|
-
if (!allowlist || allowlist.length === 0) return true;
|
|
486
|
-
if (!isBundledSkill(entry)) return true;
|
|
487
|
-
const key = resolveSkillKey(entry.skill, entry);
|
|
488
|
-
return allowlist.includes(key) || allowlist.includes(entry.skill.name);
|
|
489
|
-
}
|
|
490
|
-
function shouldIncludeSkill(params) {
|
|
491
|
-
const { entry, config, eligibility } = params;
|
|
492
|
-
const skillConfig = resolveSkillConfig(config, resolveSkillKey(entry.skill, entry));
|
|
493
|
-
const allowBundled = normalizeAllowlist(config?.skills?.allowBundled);
|
|
494
|
-
if (skillConfig?.enabled === false) return false;
|
|
495
|
-
if (!isBundledSkillAllowed(entry, allowBundled)) return false;
|
|
496
|
-
return evaluateRuntimeEligibility({
|
|
497
|
-
os: entry.metadata?.os,
|
|
498
|
-
remotePlatforms: eligibility?.remote?.platforms,
|
|
499
|
-
always: entry.metadata?.always,
|
|
500
|
-
requires: entry.metadata?.requires,
|
|
501
|
-
hasBin: hasBinary,
|
|
502
|
-
hasRemoteBin: eligibility?.remote?.hasBin,
|
|
503
|
-
hasAnyRemoteBin: eligibility?.remote?.hasAnyBin,
|
|
504
|
-
hasEnv: (envName) => Boolean(process.env[envName] || skillConfig?.env?.[envName] || skillConfig?.apiKey && entry.metadata?.primaryEnv === envName),
|
|
505
|
-
isConfigPathTruthy: (configPath) => isConfigPathTruthy(config, configPath)
|
|
506
|
-
});
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
//#endregion
|
|
510
|
-
//#region src/agents/sandbox/sanitize-env-vars.ts
|
|
511
|
-
const BLOCKED_ENV_VAR_PATTERNS = [
|
|
512
|
-
/^ANTHROPIC_API_KEY$/i,
|
|
513
|
-
/^OPENAI_API_KEY$/i,
|
|
514
|
-
/^GEMINI_API_KEY$/i,
|
|
515
|
-
/^OPENROUTER_API_KEY$/i,
|
|
516
|
-
/^MINIMAX_API_KEY$/i,
|
|
517
|
-
/^ELEVENLABS_API_KEY$/i,
|
|
518
|
-
/^SYNTHETIC_API_KEY$/i,
|
|
519
|
-
/^TELEGRAM_BOT_TOKEN$/i,
|
|
520
|
-
/^DISCORD_BOT_TOKEN$/i,
|
|
521
|
-
/^SLACK_(BOT|APP)_TOKEN$/i,
|
|
522
|
-
/^LINE_CHANNEL_SECRET$/i,
|
|
523
|
-
/^LINE_CHANNEL_ACCESS_TOKEN$/i,
|
|
524
|
-
/^SQUIDCLAW_GATEWAY_(TOKEN|PASSWORD)$/i,
|
|
525
|
-
/^AWS_(SECRET_ACCESS_KEY|SECRET_KEY|SESSION_TOKEN)$/i,
|
|
526
|
-
/^(GH|GITHUB)_TOKEN$/i,
|
|
527
|
-
/^(AZURE|AZURE_OPENAI|COHERE|AI_GATEWAY|OPENROUTER)_API_KEY$/i,
|
|
528
|
-
/_?(API_KEY|TOKEN|PASSWORD|PRIVATE_KEY|SECRET)$/i
|
|
529
|
-
];
|
|
530
|
-
const ALLOWED_ENV_VAR_PATTERNS = [
|
|
531
|
-
/^LANG$/,
|
|
532
|
-
/^LC_.*$/i,
|
|
533
|
-
/^PATH$/i,
|
|
534
|
-
/^HOME$/i,
|
|
535
|
-
/^USER$/i,
|
|
536
|
-
/^SHELL$/i,
|
|
537
|
-
/^TERM$/i,
|
|
538
|
-
/^TZ$/i,
|
|
539
|
-
/^NODE_ENV$/i
|
|
540
|
-
];
|
|
541
|
-
function validateEnvVarValue(value) {
|
|
542
|
-
if (value.includes("\0")) return "Contains null bytes";
|
|
543
|
-
if (value.length > 32768) return "Value exceeds maximum length";
|
|
544
|
-
if (/^[A-Za-z0-9+/=]{80,}$/.test(value)) return "Value looks like base64-encoded credential data";
|
|
545
|
-
}
|
|
546
|
-
function matchesAnyPattern$1(value, patterns) {
|
|
547
|
-
return patterns.some((pattern) => pattern.test(value));
|
|
548
|
-
}
|
|
549
|
-
function sanitizeEnvVars(envVars, options = {}) {
|
|
550
|
-
const allowed = {};
|
|
551
|
-
const blocked = [];
|
|
552
|
-
const warnings = [];
|
|
553
|
-
const blockedPatterns = [...BLOCKED_ENV_VAR_PATTERNS, ...options.customBlockedPatterns ?? []];
|
|
554
|
-
const allowedPatterns = [...ALLOWED_ENV_VAR_PATTERNS, ...options.customAllowedPatterns ?? []];
|
|
555
|
-
for (const [rawKey, value] of Object.entries(envVars)) {
|
|
556
|
-
const key = rawKey.trim();
|
|
557
|
-
if (!key) continue;
|
|
558
|
-
if (matchesAnyPattern$1(key, blockedPatterns)) {
|
|
559
|
-
blocked.push(key);
|
|
560
|
-
continue;
|
|
561
|
-
}
|
|
562
|
-
if (options.strictMode && !matchesAnyPattern$1(key, allowedPatterns)) {
|
|
563
|
-
blocked.push(key);
|
|
564
|
-
continue;
|
|
565
|
-
}
|
|
566
|
-
const warning = validateEnvVarValue(value);
|
|
567
|
-
if (warning) {
|
|
568
|
-
if (warning === "Contains null bytes") {
|
|
569
|
-
blocked.push(key);
|
|
570
|
-
continue;
|
|
571
|
-
}
|
|
572
|
-
warnings.push(`${key}: ${warning}`);
|
|
573
|
-
}
|
|
574
|
-
allowed[key] = value;
|
|
575
|
-
}
|
|
576
|
-
return {
|
|
577
|
-
allowed,
|
|
578
|
-
blocked,
|
|
579
|
-
warnings
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
//#endregion
|
|
584
|
-
//#region src/agents/skills/env-overrides.ts
|
|
585
|
-
const log$1 = createSubsystemLogger("env-overrides");
|
|
586
|
-
const SKILL_ALWAYS_BLOCKED_ENV_PATTERNS = [/^OPENSSL_CONF$/i];
|
|
587
|
-
function matchesAnyPattern(value, patterns) {
|
|
588
|
-
return patterns.some((pattern) => pattern.test(value));
|
|
589
|
-
}
|
|
590
|
-
function isAlwaysBlockedSkillEnvKey(key) {
|
|
591
|
-
return isDangerousHostEnvVarName(key) || matchesAnyPattern(key, SKILL_ALWAYS_BLOCKED_ENV_PATTERNS);
|
|
592
|
-
}
|
|
593
|
-
function sanitizeSkillEnvOverrides(params) {
|
|
594
|
-
if (Object.keys(params.overrides).length === 0) return {
|
|
595
|
-
allowed: {},
|
|
596
|
-
blocked: [],
|
|
597
|
-
warnings: []
|
|
598
|
-
};
|
|
599
|
-
const result = sanitizeEnvVars(params.overrides);
|
|
600
|
-
const allowed = {};
|
|
601
|
-
const blocked = /* @__PURE__ */ new Set();
|
|
602
|
-
const warnings = [...result.warnings];
|
|
603
|
-
for (const [key, value] of Object.entries(result.allowed)) {
|
|
604
|
-
if (isAlwaysBlockedSkillEnvKey(key)) {
|
|
605
|
-
blocked.add(key);
|
|
606
|
-
continue;
|
|
607
|
-
}
|
|
608
|
-
allowed[key] = value;
|
|
609
|
-
}
|
|
610
|
-
for (const key of result.blocked) {
|
|
611
|
-
if (isAlwaysBlockedSkillEnvKey(key) || !params.allowedSensitiveKeys.has(key)) {
|
|
612
|
-
blocked.add(key);
|
|
613
|
-
continue;
|
|
614
|
-
}
|
|
615
|
-
const value = params.overrides[key];
|
|
616
|
-
if (!value) continue;
|
|
617
|
-
const warning = validateEnvVarValue(value);
|
|
618
|
-
if (warning) {
|
|
619
|
-
if (warning === "Contains null bytes") {
|
|
620
|
-
blocked.add(key);
|
|
621
|
-
continue;
|
|
622
|
-
}
|
|
623
|
-
warnings.push(`${key}: ${warning}`);
|
|
624
|
-
}
|
|
625
|
-
allowed[key] = value;
|
|
626
|
-
}
|
|
627
|
-
return {
|
|
628
|
-
allowed,
|
|
629
|
-
blocked: [...blocked],
|
|
630
|
-
warnings
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
function applySkillConfigEnvOverrides(params) {
|
|
634
|
-
const { updates, skillConfig, primaryEnv, requiredEnv, skillKey } = params;
|
|
635
|
-
const allowedSensitiveKeys = /* @__PURE__ */ new Set();
|
|
636
|
-
const normalizedPrimaryEnv = primaryEnv?.trim();
|
|
637
|
-
if (normalizedPrimaryEnv) allowedSensitiveKeys.add(normalizedPrimaryEnv);
|
|
638
|
-
for (const envName of requiredEnv ?? []) {
|
|
639
|
-
const trimmedEnv = envName.trim();
|
|
640
|
-
if (trimmedEnv) allowedSensitiveKeys.add(trimmedEnv);
|
|
641
|
-
}
|
|
642
|
-
const pendingOverrides = {};
|
|
643
|
-
if (skillConfig.env) for (const [rawKey, envValue] of Object.entries(skillConfig.env)) {
|
|
644
|
-
const envKey = rawKey.trim();
|
|
645
|
-
if (!envKey || !envValue || process.env[envKey]) continue;
|
|
646
|
-
pendingOverrides[envKey] = envValue;
|
|
647
|
-
}
|
|
648
|
-
const resolvedApiKey = normalizeResolvedSecretInputString({
|
|
649
|
-
value: skillConfig.apiKey,
|
|
650
|
-
path: `skills.entries.${skillKey}.apiKey`
|
|
651
|
-
}) ?? "";
|
|
652
|
-
if (normalizedPrimaryEnv && resolvedApiKey && !process.env[normalizedPrimaryEnv]) {
|
|
653
|
-
if (!pendingOverrides[normalizedPrimaryEnv]) pendingOverrides[normalizedPrimaryEnv] = resolvedApiKey;
|
|
654
|
-
}
|
|
655
|
-
const sanitized = sanitizeSkillEnvOverrides({
|
|
656
|
-
overrides: pendingOverrides,
|
|
657
|
-
allowedSensitiveKeys
|
|
658
|
-
});
|
|
659
|
-
if (sanitized.blocked.length > 0) log$1.warn(`Blocked skill env overrides for ${skillKey}: ${sanitized.blocked.join(", ")}`);
|
|
660
|
-
if (sanitized.warnings.length > 0) log$1.warn(`Suspicious skill env overrides for ${skillKey}: ${sanitized.warnings.join(", ")}`);
|
|
661
|
-
for (const [envKey, envValue] of Object.entries(sanitized.allowed)) {
|
|
662
|
-
if (process.env[envKey]) continue;
|
|
663
|
-
updates.push({
|
|
664
|
-
key: envKey,
|
|
665
|
-
prev: process.env[envKey]
|
|
666
|
-
});
|
|
667
|
-
process.env[envKey] = envValue;
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
function createEnvReverter(updates) {
|
|
671
|
-
return () => {
|
|
672
|
-
for (const update of updates) if (update.prev === void 0) delete process.env[update.key];
|
|
673
|
-
else process.env[update.key] = update.prev;
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
function applySkillEnvOverrides(params) {
|
|
677
|
-
const { skills, config } = params;
|
|
678
|
-
const updates = [];
|
|
679
|
-
for (const entry of skills) {
|
|
680
|
-
const skillKey = resolveSkillKey(entry.skill, entry);
|
|
681
|
-
const skillConfig = resolveSkillConfig(config, skillKey);
|
|
682
|
-
if (!skillConfig) continue;
|
|
683
|
-
applySkillConfigEnvOverrides({
|
|
684
|
-
updates,
|
|
685
|
-
skillConfig,
|
|
686
|
-
primaryEnv: entry.metadata?.primaryEnv,
|
|
687
|
-
requiredEnv: entry.metadata?.requires?.env,
|
|
688
|
-
skillKey
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
return createEnvReverter(updates);
|
|
692
|
-
}
|
|
693
|
-
function applySkillEnvOverridesFromSnapshot(params) {
|
|
694
|
-
const { snapshot, config } = params;
|
|
695
|
-
if (!snapshot) return () => {};
|
|
696
|
-
const updates = [];
|
|
697
|
-
for (const skill of snapshot.skills) {
|
|
698
|
-
const skillConfig = resolveSkillConfig(config, skill.name);
|
|
699
|
-
if (!skillConfig) continue;
|
|
700
|
-
applySkillConfigEnvOverrides({
|
|
701
|
-
updates,
|
|
702
|
-
skillConfig,
|
|
703
|
-
primaryEnv: skill.primaryEnv,
|
|
704
|
-
requiredEnv: skill.requiredEnv,
|
|
705
|
-
skillKey: skill.name
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
return createEnvReverter(updates);
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
//#endregion
|
|
712
|
-
//#region src/agents/sandbox-paths.ts
|
|
713
|
-
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
714
|
-
const HTTP_URL_RE = /^https?:\/\//i;
|
|
715
|
-
const DATA_URL_RE = /^data:/i;
|
|
716
|
-
const SANDBOX_CONTAINER_WORKDIR = "/workspace";
|
|
717
|
-
function normalizeUnicodeSpaces(str) {
|
|
718
|
-
return str.replace(UNICODE_SPACES, " ");
|
|
719
|
-
}
|
|
720
|
-
function normalizeAtPrefix(filePath) {
|
|
721
|
-
return filePath.startsWith("@") ? filePath.slice(1) : filePath;
|
|
722
|
-
}
|
|
723
|
-
function expandPath(filePath) {
|
|
724
|
-
const normalized = normalizeUnicodeSpaces(normalizeAtPrefix(filePath));
|
|
725
|
-
if (normalized === "~") return os.homedir();
|
|
726
|
-
if (normalized.startsWith("~/")) return os.homedir() + normalized.slice(1);
|
|
727
|
-
return normalized;
|
|
728
|
-
}
|
|
729
|
-
function resolveToCwd(filePath, cwd) {
|
|
730
|
-
const expanded = expandPath(filePath);
|
|
731
|
-
if (path.isAbsolute(expanded)) return expanded;
|
|
732
|
-
return path.resolve(cwd, expanded);
|
|
733
|
-
}
|
|
734
|
-
function resolveSandboxInputPath(filePath, cwd) {
|
|
735
|
-
return resolveToCwd(filePath, cwd);
|
|
736
|
-
}
|
|
737
|
-
function resolveSandboxPath(params) {
|
|
738
|
-
const resolved = resolveSandboxInputPath(params.filePath, params.cwd);
|
|
739
|
-
const rootResolved = path.resolve(params.root);
|
|
740
|
-
const relative = path.relative(rootResolved, resolved);
|
|
741
|
-
if (!relative || relative === "") return {
|
|
742
|
-
resolved,
|
|
743
|
-
relative: ""
|
|
744
|
-
};
|
|
745
|
-
if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`Path escapes sandbox root (${shortPath(rootResolved)}): ${params.filePath}`);
|
|
746
|
-
return {
|
|
747
|
-
resolved,
|
|
748
|
-
relative
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
async function assertSandboxPath(params) {
|
|
752
|
-
const resolved = resolveSandboxPath(params);
|
|
753
|
-
const policy = {
|
|
754
|
-
allowFinalSymlinkForUnlink: params.allowFinalSymlinkForUnlink,
|
|
755
|
-
allowFinalHardlinkForUnlink: params.allowFinalHardlinkForUnlink
|
|
756
|
-
};
|
|
757
|
-
await assertNoPathAliasEscape({
|
|
758
|
-
absolutePath: resolved.resolved,
|
|
759
|
-
rootPath: params.root,
|
|
760
|
-
boundaryLabel: "sandbox root",
|
|
761
|
-
policy
|
|
762
|
-
});
|
|
763
|
-
return resolved;
|
|
764
|
-
}
|
|
765
|
-
function assertMediaNotDataUrl(media) {
|
|
766
|
-
const raw = media.trim();
|
|
767
|
-
if (DATA_URL_RE.test(raw)) throw new Error("data: URLs are not supported for media. Use buffer instead.");
|
|
768
|
-
}
|
|
769
|
-
async function resolveSandboxedMediaSource(params) {
|
|
770
|
-
const raw = params.media.trim();
|
|
771
|
-
if (!raw) return raw;
|
|
772
|
-
if (HTTP_URL_RE.test(raw)) return raw;
|
|
773
|
-
let candidate = raw;
|
|
774
|
-
if (/^file:\/\//i.test(candidate)) {
|
|
775
|
-
const workspaceMappedFromUrl = mapContainerWorkspaceFileUrl({
|
|
776
|
-
fileUrl: candidate,
|
|
777
|
-
sandboxRoot: params.sandboxRoot
|
|
778
|
-
});
|
|
779
|
-
if (workspaceMappedFromUrl) candidate = workspaceMappedFromUrl;
|
|
780
|
-
else try {
|
|
781
|
-
candidate = fileURLToPath(candidate);
|
|
782
|
-
} catch {
|
|
783
|
-
throw new Error(`Invalid file:// URL for sandboxed media: ${raw}`);
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
const containerWorkspaceMapped = mapContainerWorkspacePath({
|
|
787
|
-
candidate,
|
|
788
|
-
sandboxRoot: params.sandboxRoot
|
|
789
|
-
});
|
|
790
|
-
if (containerWorkspaceMapped) candidate = containerWorkspaceMapped;
|
|
791
|
-
const tmpMediaPath = await resolveAllowedTmpMediaPath({
|
|
792
|
-
candidate,
|
|
793
|
-
sandboxRoot: params.sandboxRoot
|
|
794
|
-
});
|
|
795
|
-
if (tmpMediaPath) return tmpMediaPath;
|
|
796
|
-
return (await assertSandboxPath({
|
|
797
|
-
filePath: candidate,
|
|
798
|
-
cwd: params.sandboxRoot,
|
|
799
|
-
root: params.sandboxRoot
|
|
800
|
-
})).resolved;
|
|
801
|
-
}
|
|
802
|
-
function mapContainerWorkspaceFileUrl(params) {
|
|
803
|
-
let parsed;
|
|
804
|
-
try {
|
|
805
|
-
parsed = new URL$1(params.fileUrl);
|
|
806
|
-
} catch {
|
|
807
|
-
return;
|
|
808
|
-
}
|
|
809
|
-
if (parsed.protocol !== "file:") return;
|
|
810
|
-
const normalizedPathname = decodeURIComponent(parsed.pathname).replace(/\\/g, "/");
|
|
811
|
-
if (normalizedPathname !== SANDBOX_CONTAINER_WORKDIR && !normalizedPathname.startsWith(`${SANDBOX_CONTAINER_WORKDIR}/`)) return;
|
|
812
|
-
return mapContainerWorkspacePath({
|
|
813
|
-
candidate: normalizedPathname,
|
|
814
|
-
sandboxRoot: params.sandboxRoot
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
function mapContainerWorkspacePath(params) {
|
|
818
|
-
const normalized = params.candidate.replace(/\\/g, "/");
|
|
819
|
-
if (normalized === SANDBOX_CONTAINER_WORKDIR) return path.resolve(params.sandboxRoot);
|
|
820
|
-
const prefix = `${SANDBOX_CONTAINER_WORKDIR}/`;
|
|
821
|
-
if (!normalized.startsWith(prefix)) return;
|
|
822
|
-
const rel = normalized.slice(prefix.length);
|
|
823
|
-
if (!rel) return path.resolve(params.sandboxRoot);
|
|
824
|
-
return path.resolve(params.sandboxRoot, ...rel.split("/").filter(Boolean));
|
|
825
|
-
}
|
|
826
|
-
async function resolveAllowedTmpMediaPath(params) {
|
|
827
|
-
if (!path.isAbsolute(expandPath(params.candidate))) return;
|
|
828
|
-
const resolved = path.resolve(resolveSandboxInputPath(params.candidate, params.sandboxRoot));
|
|
829
|
-
const openClawTmpDir = path.resolve(resolvePreferredSquidClawTmpDir());
|
|
830
|
-
if (!isPathInside(openClawTmpDir, resolved)) return;
|
|
831
|
-
await assertNoTmpAliasEscape({
|
|
832
|
-
filePath: resolved,
|
|
833
|
-
tmpRoot: openClawTmpDir
|
|
834
|
-
});
|
|
835
|
-
return resolved;
|
|
836
|
-
}
|
|
837
|
-
async function assertNoTmpAliasEscape(params) {
|
|
838
|
-
await assertNoPathAliasEscape({
|
|
839
|
-
absolutePath: params.filePath,
|
|
840
|
-
rootPath: params.tmpRoot,
|
|
841
|
-
boundaryLabel: "tmp root"
|
|
842
|
-
});
|
|
843
|
-
}
|
|
844
|
-
function shortPath(value) {
|
|
845
|
-
if (value.startsWith(os.homedir())) return `~${value.slice(os.homedir().length)}`;
|
|
846
|
-
return value;
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
//#endregion
|
|
850
|
-
//#region src/agents/skills/bundled-dir.ts
|
|
851
|
-
function looksLikeSkillsDir(dir) {
|
|
852
|
-
try {
|
|
853
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
854
|
-
for (const entry of entries) {
|
|
855
|
-
if (entry.name.startsWith(".")) continue;
|
|
856
|
-
const fullPath = path.join(dir, entry.name);
|
|
857
|
-
if (entry.isFile() && entry.name.endsWith(".md")) return true;
|
|
858
|
-
if (entry.isDirectory()) {
|
|
859
|
-
if (fs.existsSync(path.join(fullPath, "SKILL.md"))) return true;
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
} catch {
|
|
863
|
-
return false;
|
|
864
|
-
}
|
|
865
|
-
return false;
|
|
866
|
-
}
|
|
867
|
-
function resolveBundledSkillsDir(opts = {}) {
|
|
868
|
-
const override = process.env.SQUIDCLAW_BUNDLED_SKILLS_DIR?.trim();
|
|
869
|
-
if (override) return override;
|
|
870
|
-
try {
|
|
871
|
-
const execPath = opts.execPath ?? process.execPath;
|
|
872
|
-
const execDir = path.dirname(execPath);
|
|
873
|
-
const sibling = path.join(execDir, "skills");
|
|
874
|
-
if (fs.existsSync(sibling)) return sibling;
|
|
875
|
-
} catch {}
|
|
876
|
-
try {
|
|
877
|
-
const moduleUrl = opts.moduleUrl ?? import.meta.url;
|
|
878
|
-
const moduleDir = path.dirname(fileURLToPath(moduleUrl));
|
|
879
|
-
const packageRoot = resolveSquidClawPackageRootSync({
|
|
880
|
-
argv1: opts.argv1 ?? process.argv[1],
|
|
881
|
-
moduleUrl,
|
|
882
|
-
cwd: opts.cwd ?? process.cwd()
|
|
883
|
-
});
|
|
884
|
-
if (packageRoot) {
|
|
885
|
-
const candidate = path.join(packageRoot, "skills");
|
|
886
|
-
if (looksLikeSkillsDir(candidate)) return candidate;
|
|
887
|
-
}
|
|
888
|
-
let current = moduleDir;
|
|
889
|
-
for (let depth = 0; depth < 6; depth += 1) {
|
|
890
|
-
const candidate = path.join(current, "skills");
|
|
891
|
-
if (looksLikeSkillsDir(candidate)) return candidate;
|
|
892
|
-
const next = path.dirname(current);
|
|
893
|
-
if (next === current) break;
|
|
894
|
-
current = next;
|
|
895
|
-
}
|
|
896
|
-
} catch {}
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
//#endregion
|
|
900
|
-
//#region src/agents/skills/plugin-skills.ts
|
|
901
|
-
const log = createSubsystemLogger("skills");
|
|
902
|
-
function resolvePluginSkillDirs(params) {
|
|
903
|
-
const workspaceDir = (params.workspaceDir ?? "").trim();
|
|
904
|
-
if (!workspaceDir) return [];
|
|
905
|
-
const registry = loadPluginManifestRegistry({
|
|
906
|
-
workspaceDir,
|
|
907
|
-
config: params.config
|
|
908
|
-
});
|
|
909
|
-
if (registry.plugins.length === 0) return [];
|
|
910
|
-
const normalizedPlugins = normalizePluginsConfig(params.config?.plugins);
|
|
911
|
-
const acpEnabled = params.config?.acp?.enabled !== false;
|
|
912
|
-
const memorySlot = normalizedPlugins.slots.memory;
|
|
913
|
-
let selectedMemoryPluginId = null;
|
|
914
|
-
const seen = /* @__PURE__ */ new Set();
|
|
915
|
-
const resolved = [];
|
|
916
|
-
for (const record of registry.plugins) {
|
|
917
|
-
if (!record.skills || record.skills.length === 0) continue;
|
|
918
|
-
if (!resolveEffectiveEnableState({
|
|
919
|
-
id: record.id,
|
|
920
|
-
origin: record.origin,
|
|
921
|
-
config: normalizedPlugins,
|
|
922
|
-
rootConfig: params.config
|
|
923
|
-
}).enabled) continue;
|
|
924
|
-
if (!acpEnabled && record.id === "acpx") continue;
|
|
925
|
-
const memoryDecision = resolveMemorySlotDecision({
|
|
926
|
-
id: record.id,
|
|
927
|
-
kind: record.kind,
|
|
928
|
-
slot: memorySlot,
|
|
929
|
-
selectedId: selectedMemoryPluginId
|
|
930
|
-
});
|
|
931
|
-
if (!memoryDecision.enabled) continue;
|
|
932
|
-
if (memoryDecision.selected && record.kind === "memory") selectedMemoryPluginId = record.id;
|
|
933
|
-
for (const raw of record.skills) {
|
|
934
|
-
const trimmed = raw.trim();
|
|
935
|
-
if (!trimmed) continue;
|
|
936
|
-
const candidate = path.resolve(record.rootDir, trimmed);
|
|
937
|
-
if (!fs.existsSync(candidate)) {
|
|
938
|
-
log.warn(`plugin skill path not found (${record.id}): ${candidate}`);
|
|
939
|
-
continue;
|
|
940
|
-
}
|
|
941
|
-
if (!isPathInsideWithRealpath(record.rootDir, candidate, { requireRealpath: true })) {
|
|
942
|
-
log.warn(`plugin skill path escapes plugin root (${record.id}): ${candidate}`);
|
|
943
|
-
continue;
|
|
944
|
-
}
|
|
945
|
-
if (seen.has(candidate)) continue;
|
|
946
|
-
seen.add(candidate);
|
|
947
|
-
resolved.push(candidate);
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
return resolved;
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
//#endregion
|
|
954
|
-
//#region src/agents/skills/serialize.ts
|
|
955
|
-
const SKILLS_SYNC_QUEUE = /* @__PURE__ */ new Map();
|
|
956
|
-
async function serializeByKey(key, task) {
|
|
957
|
-
const next = (SKILLS_SYNC_QUEUE.get(key) ?? Promise.resolve()).then(task, task);
|
|
958
|
-
SKILLS_SYNC_QUEUE.set(key, next);
|
|
959
|
-
try {
|
|
960
|
-
return await next;
|
|
961
|
-
} finally {
|
|
962
|
-
if (SKILLS_SYNC_QUEUE.get(key) === next) SKILLS_SYNC_QUEUE.delete(key);
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
//#endregion
|
|
967
|
-
//#region src/agents/skills/workspace.ts
|
|
968
|
-
const fsp = fs.promises;
|
|
969
|
-
const skillsLogger = createSubsystemLogger("skills");
|
|
970
|
-
const skillCommandDebugOnce = /* @__PURE__ */ new Set();
|
|
971
|
-
/**
|
|
972
|
-
* Replace the user's home directory prefix with `~` in skill file paths
|
|
973
|
-
* to reduce system prompt token usage. Models understand `~` expansion,
|
|
974
|
-
* and the read tool resolves `~` to the home directory.
|
|
975
|
-
*
|
|
976
|
-
* Example: `/Users/alice/.bun/.../skills/github/SKILL.md`
|
|
977
|
-
* → `~/.bun/.../skills/github/SKILL.md`
|
|
978
|
-
*
|
|
979
|
-
* Saves ~5–6 tokens per skill path × N skills ≈ 400–600 tokens total.
|
|
980
|
-
*/
|
|
981
|
-
function compactSkillPaths(skills) {
|
|
982
|
-
const home = os.homedir();
|
|
983
|
-
if (!home) return skills;
|
|
984
|
-
const prefix = home.endsWith(path.sep) ? home : home + path.sep;
|
|
985
|
-
return skills.map((s) => ({
|
|
986
|
-
...s,
|
|
987
|
-
filePath: s.filePath.startsWith(prefix) ? "~/" + s.filePath.slice(prefix.length) : s.filePath
|
|
988
|
-
}));
|
|
989
|
-
}
|
|
990
|
-
function debugSkillCommandOnce(messageKey, message, meta) {
|
|
991
|
-
if (skillCommandDebugOnce.has(messageKey)) return;
|
|
992
|
-
skillCommandDebugOnce.add(messageKey);
|
|
993
|
-
skillsLogger.debug(message, meta);
|
|
994
|
-
}
|
|
995
|
-
function filterSkillEntries(entries, config, skillFilter, eligibility) {
|
|
996
|
-
let filtered = entries.filter((entry) => shouldIncludeSkill({
|
|
997
|
-
entry,
|
|
998
|
-
config,
|
|
999
|
-
eligibility
|
|
1000
|
-
}));
|
|
1001
|
-
if (skillFilter !== void 0) {
|
|
1002
|
-
const normalized = normalizeSkillFilter(skillFilter) ?? [];
|
|
1003
|
-
const label = normalized.length > 0 ? normalized.join(", ") : "(none)";
|
|
1004
|
-
skillsLogger.debug(`Applying skill filter: ${label}`);
|
|
1005
|
-
filtered = normalized.length > 0 ? filtered.filter((entry) => normalized.includes(entry.skill.name)) : [];
|
|
1006
|
-
skillsLogger.debug(`After skill filter: ${filtered.map((entry) => entry.skill.name).join(", ") || "(none)"}`);
|
|
1007
|
-
}
|
|
1008
|
-
return filtered;
|
|
1009
|
-
}
|
|
1010
|
-
const SKILL_COMMAND_MAX_LENGTH = 32;
|
|
1011
|
-
const SKILL_COMMAND_FALLBACK = "skill";
|
|
1012
|
-
const SKILL_COMMAND_DESCRIPTION_MAX_LENGTH = 100;
|
|
1013
|
-
const DEFAULT_MAX_CANDIDATES_PER_ROOT = 300;
|
|
1014
|
-
const DEFAULT_MAX_SKILLS_LOADED_PER_SOURCE = 200;
|
|
1015
|
-
const DEFAULT_MAX_SKILLS_IN_PROMPT = 150;
|
|
1016
|
-
const DEFAULT_MAX_SKILLS_PROMPT_CHARS = 3e4;
|
|
1017
|
-
const DEFAULT_MAX_SKILL_FILE_BYTES = 256e3;
|
|
1018
|
-
function sanitizeSkillCommandName(raw) {
|
|
1019
|
-
return raw.toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").slice(0, SKILL_COMMAND_MAX_LENGTH) || SKILL_COMMAND_FALLBACK;
|
|
1020
|
-
}
|
|
1021
|
-
function resolveUniqueSkillCommandName(base, used) {
|
|
1022
|
-
const normalizedBase = base.toLowerCase();
|
|
1023
|
-
if (!used.has(normalizedBase)) return base;
|
|
1024
|
-
for (let index = 2; index < 1e3; index += 1) {
|
|
1025
|
-
const suffix = `_${index}`;
|
|
1026
|
-
const maxBaseLength = Math.max(1, SKILL_COMMAND_MAX_LENGTH - suffix.length);
|
|
1027
|
-
const candidate = `${base.slice(0, maxBaseLength)}${suffix}`;
|
|
1028
|
-
const candidateKey = candidate.toLowerCase();
|
|
1029
|
-
if (!used.has(candidateKey)) return candidate;
|
|
1030
|
-
}
|
|
1031
|
-
return `${base.slice(0, Math.max(1, SKILL_COMMAND_MAX_LENGTH - 2))}_x`;
|
|
1032
|
-
}
|
|
1033
|
-
function resolveSkillsLimits(config) {
|
|
1034
|
-
const limits = config?.skills?.limits;
|
|
1035
|
-
return {
|
|
1036
|
-
maxCandidatesPerRoot: limits?.maxCandidatesPerRoot ?? DEFAULT_MAX_CANDIDATES_PER_ROOT,
|
|
1037
|
-
maxSkillsLoadedPerSource: limits?.maxSkillsLoadedPerSource ?? DEFAULT_MAX_SKILLS_LOADED_PER_SOURCE,
|
|
1038
|
-
maxSkillsInPrompt: limits?.maxSkillsInPrompt ?? DEFAULT_MAX_SKILLS_IN_PROMPT,
|
|
1039
|
-
maxSkillsPromptChars: limits?.maxSkillsPromptChars ?? DEFAULT_MAX_SKILLS_PROMPT_CHARS,
|
|
1040
|
-
maxSkillFileBytes: limits?.maxSkillFileBytes ?? DEFAULT_MAX_SKILL_FILE_BYTES
|
|
1041
|
-
};
|
|
1042
|
-
}
|
|
1043
|
-
function listChildDirectories(dir) {
|
|
1044
|
-
try {
|
|
1045
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1046
|
-
const dirs = [];
|
|
1047
|
-
for (const entry of entries) {
|
|
1048
|
-
if (entry.name.startsWith(".")) continue;
|
|
1049
|
-
if (entry.name === "node_modules") continue;
|
|
1050
|
-
const fullPath = path.join(dir, entry.name);
|
|
1051
|
-
if (entry.isDirectory()) {
|
|
1052
|
-
dirs.push(entry.name);
|
|
1053
|
-
continue;
|
|
1054
|
-
}
|
|
1055
|
-
if (entry.isSymbolicLink()) try {
|
|
1056
|
-
if (fs.statSync(fullPath).isDirectory()) dirs.push(entry.name);
|
|
1057
|
-
} catch {}
|
|
1058
|
-
}
|
|
1059
|
-
return dirs;
|
|
1060
|
-
} catch {
|
|
1061
|
-
return [];
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
function resolveNestedSkillsRoot(dir, opts) {
|
|
1065
|
-
const nested = path.join(dir, "skills");
|
|
1066
|
-
try {
|
|
1067
|
-
if (!fs.existsSync(nested) || !fs.statSync(nested).isDirectory()) return { baseDir: dir };
|
|
1068
|
-
} catch {
|
|
1069
|
-
return { baseDir: dir };
|
|
1070
|
-
}
|
|
1071
|
-
const nestedDirs = listChildDirectories(nested);
|
|
1072
|
-
const scanLimit = Math.max(0, opts?.maxEntriesToScan ?? 100);
|
|
1073
|
-
const toScan = scanLimit === 0 ? [] : nestedDirs.slice(0, Math.min(nestedDirs.length, scanLimit));
|
|
1074
|
-
for (const name of toScan) {
|
|
1075
|
-
const skillMd = path.join(nested, name, "SKILL.md");
|
|
1076
|
-
if (fs.existsSync(skillMd)) return {
|
|
1077
|
-
baseDir: nested,
|
|
1078
|
-
note: `Detected nested skills root at ${nested}`
|
|
1079
|
-
};
|
|
1080
|
-
}
|
|
1081
|
-
return { baseDir: dir };
|
|
1082
|
-
}
|
|
1083
|
-
function unwrapLoadedSkills(loaded) {
|
|
1084
|
-
if (Array.isArray(loaded)) return loaded;
|
|
1085
|
-
if (loaded && typeof loaded === "object" && "skills" in loaded) {
|
|
1086
|
-
const skills = loaded.skills;
|
|
1087
|
-
if (Array.isArray(skills)) return skills;
|
|
1088
|
-
}
|
|
1089
|
-
return [];
|
|
1090
|
-
}
|
|
1091
|
-
function loadSkillEntries(workspaceDir, opts) {
|
|
1092
|
-
const limits = resolveSkillsLimits(opts?.config);
|
|
1093
|
-
const loadSkills = (params) => {
|
|
1094
|
-
const baseDir = resolveNestedSkillsRoot(params.dir, { maxEntriesToScan: limits.maxCandidatesPerRoot }).baseDir;
|
|
1095
|
-
const rootSkillMd = path.join(baseDir, "SKILL.md");
|
|
1096
|
-
if (fs.existsSync(rootSkillMd)) {
|
|
1097
|
-
try {
|
|
1098
|
-
const size = fs.statSync(rootSkillMd).size;
|
|
1099
|
-
if (size > limits.maxSkillFileBytes) {
|
|
1100
|
-
skillsLogger.warn("Skipping skills root due to oversized SKILL.md.", {
|
|
1101
|
-
dir: baseDir,
|
|
1102
|
-
filePath: rootSkillMd,
|
|
1103
|
-
size,
|
|
1104
|
-
maxSkillFileBytes: limits.maxSkillFileBytes
|
|
1105
|
-
});
|
|
1106
|
-
return [];
|
|
1107
|
-
}
|
|
1108
|
-
} catch {
|
|
1109
|
-
return [];
|
|
1110
|
-
}
|
|
1111
|
-
return unwrapLoadedSkills(loadSkillsFromDir({
|
|
1112
|
-
dir: baseDir,
|
|
1113
|
-
source: params.source
|
|
1114
|
-
}));
|
|
1115
|
-
}
|
|
1116
|
-
const childDirs = listChildDirectories(baseDir);
|
|
1117
|
-
const suspicious = childDirs.length > limits.maxCandidatesPerRoot;
|
|
1118
|
-
const maxCandidates = Math.max(0, limits.maxSkillsLoadedPerSource);
|
|
1119
|
-
const limitedChildren = childDirs.slice().sort().slice(0, maxCandidates);
|
|
1120
|
-
if (suspicious) skillsLogger.warn("Skills root looks suspiciously large, truncating discovery.", {
|
|
1121
|
-
dir: params.dir,
|
|
1122
|
-
baseDir,
|
|
1123
|
-
childDirCount: childDirs.length,
|
|
1124
|
-
maxCandidatesPerRoot: limits.maxCandidatesPerRoot,
|
|
1125
|
-
maxSkillsLoadedPerSource: limits.maxSkillsLoadedPerSource
|
|
1126
|
-
});
|
|
1127
|
-
else if (childDirs.length > maxCandidates) skillsLogger.warn("Skills root has many entries, truncating discovery.", {
|
|
1128
|
-
dir: params.dir,
|
|
1129
|
-
baseDir,
|
|
1130
|
-
childDirCount: childDirs.length,
|
|
1131
|
-
maxSkillsLoadedPerSource: limits.maxSkillsLoadedPerSource
|
|
1132
|
-
});
|
|
1133
|
-
const loadedSkills = [];
|
|
1134
|
-
for (const name of limitedChildren) {
|
|
1135
|
-
const skillDir = path.join(baseDir, name);
|
|
1136
|
-
const skillMd = path.join(skillDir, "SKILL.md");
|
|
1137
|
-
if (!fs.existsSync(skillMd)) continue;
|
|
1138
|
-
try {
|
|
1139
|
-
const size = fs.statSync(skillMd).size;
|
|
1140
|
-
if (size > limits.maxSkillFileBytes) {
|
|
1141
|
-
skillsLogger.warn("Skipping skill due to oversized SKILL.md.", {
|
|
1142
|
-
skill: name,
|
|
1143
|
-
filePath: skillMd,
|
|
1144
|
-
size,
|
|
1145
|
-
maxSkillFileBytes: limits.maxSkillFileBytes
|
|
1146
|
-
});
|
|
1147
|
-
continue;
|
|
1148
|
-
}
|
|
1149
|
-
} catch {
|
|
1150
|
-
continue;
|
|
1151
|
-
}
|
|
1152
|
-
const loaded = loadSkillsFromDir({
|
|
1153
|
-
dir: skillDir,
|
|
1154
|
-
source: params.source
|
|
1155
|
-
});
|
|
1156
|
-
loadedSkills.push(...unwrapLoadedSkills(loaded));
|
|
1157
|
-
if (loadedSkills.length >= limits.maxSkillsLoadedPerSource) break;
|
|
1158
|
-
}
|
|
1159
|
-
if (loadedSkills.length > limits.maxSkillsLoadedPerSource) return loadedSkills.slice().sort((a, b) => a.name.localeCompare(b.name)).slice(0, limits.maxSkillsLoadedPerSource);
|
|
1160
|
-
return loadedSkills;
|
|
1161
|
-
};
|
|
1162
|
-
const managedSkillsDir = opts?.managedSkillsDir ?? path.join(CONFIG_DIR, "skills");
|
|
1163
|
-
const workspaceSkillsDir = path.resolve(workspaceDir, "skills");
|
|
1164
|
-
const bundledSkillsDir = opts?.bundledSkillsDir ?? resolveBundledSkillsDir();
|
|
1165
|
-
const extraDirs = (opts?.config?.skills?.load?.extraDirs ?? []).map((d) => typeof d === "string" ? d.trim() : "").filter(Boolean);
|
|
1166
|
-
const pluginSkillDirs = resolvePluginSkillDirs({
|
|
1167
|
-
workspaceDir,
|
|
1168
|
-
config: opts?.config
|
|
1169
|
-
});
|
|
1170
|
-
const mergedExtraDirs = [...extraDirs, ...pluginSkillDirs];
|
|
1171
|
-
const bundledSkills = bundledSkillsDir ? loadSkills({
|
|
1172
|
-
dir: bundledSkillsDir,
|
|
1173
|
-
source: "squidclaw-bundled"
|
|
1174
|
-
}) : [];
|
|
1175
|
-
const extraSkills = mergedExtraDirs.flatMap((dir) => {
|
|
1176
|
-
return loadSkills({
|
|
1177
|
-
dir: resolveUserPath(dir),
|
|
1178
|
-
source: "squidclaw-extra"
|
|
1179
|
-
});
|
|
1180
|
-
});
|
|
1181
|
-
const managedSkills = loadSkills({
|
|
1182
|
-
dir: managedSkillsDir,
|
|
1183
|
-
source: "squidclaw-managed"
|
|
1184
|
-
});
|
|
1185
|
-
const personalAgentsSkills = loadSkills({
|
|
1186
|
-
dir: path.resolve(os.homedir(), ".agents", "skills"),
|
|
1187
|
-
source: "agents-skills-personal"
|
|
1188
|
-
});
|
|
1189
|
-
const projectAgentsSkills = loadSkills({
|
|
1190
|
-
dir: path.resolve(workspaceDir, ".agents", "skills"),
|
|
1191
|
-
source: "agents-skills-project"
|
|
1192
|
-
});
|
|
1193
|
-
const workspaceSkills = loadSkills({
|
|
1194
|
-
dir: workspaceSkillsDir,
|
|
1195
|
-
source: "squidclaw-workspace"
|
|
1196
|
-
});
|
|
1197
|
-
const merged = /* @__PURE__ */ new Map();
|
|
1198
|
-
for (const skill of extraSkills) merged.set(skill.name, skill);
|
|
1199
|
-
for (const skill of bundledSkills) merged.set(skill.name, skill);
|
|
1200
|
-
for (const skill of managedSkills) merged.set(skill.name, skill);
|
|
1201
|
-
for (const skill of personalAgentsSkills) merged.set(skill.name, skill);
|
|
1202
|
-
for (const skill of projectAgentsSkills) merged.set(skill.name, skill);
|
|
1203
|
-
for (const skill of workspaceSkills) merged.set(skill.name, skill);
|
|
1204
|
-
return Array.from(merged.values()).map((skill) => {
|
|
1205
|
-
let frontmatter = {};
|
|
1206
|
-
try {
|
|
1207
|
-
frontmatter = parseFrontmatter(fs.readFileSync(skill.filePath, "utf-8"));
|
|
1208
|
-
} catch {}
|
|
1209
|
-
return {
|
|
1210
|
-
skill,
|
|
1211
|
-
frontmatter,
|
|
1212
|
-
metadata: resolveSquidClawMetadata(frontmatter),
|
|
1213
|
-
invocation: resolveSkillInvocationPolicy(frontmatter)
|
|
1214
|
-
};
|
|
1215
|
-
});
|
|
1216
|
-
}
|
|
1217
|
-
function applySkillsPromptLimits(params) {
|
|
1218
|
-
const limits = resolveSkillsLimits(params.config);
|
|
1219
|
-
const total = params.skills.length;
|
|
1220
|
-
const byCount = params.skills.slice(0, Math.max(0, limits.maxSkillsInPrompt));
|
|
1221
|
-
let skillsForPrompt = byCount;
|
|
1222
|
-
let truncated = total > byCount.length;
|
|
1223
|
-
let truncatedReason = truncated ? "count" : null;
|
|
1224
|
-
const fits = (skills) => {
|
|
1225
|
-
return formatSkillsForPrompt(skills).length <= limits.maxSkillsPromptChars;
|
|
1226
|
-
};
|
|
1227
|
-
if (!fits(skillsForPrompt)) {
|
|
1228
|
-
let lo = 0;
|
|
1229
|
-
let hi = skillsForPrompt.length;
|
|
1230
|
-
while (lo < hi) {
|
|
1231
|
-
const mid = Math.ceil((lo + hi) / 2);
|
|
1232
|
-
if (fits(skillsForPrompt.slice(0, mid))) lo = mid;
|
|
1233
|
-
else hi = mid - 1;
|
|
1234
|
-
}
|
|
1235
|
-
skillsForPrompt = skillsForPrompt.slice(0, lo);
|
|
1236
|
-
truncated = true;
|
|
1237
|
-
truncatedReason = "chars";
|
|
1238
|
-
}
|
|
1239
|
-
return {
|
|
1240
|
-
skillsForPrompt,
|
|
1241
|
-
truncated,
|
|
1242
|
-
truncatedReason
|
|
1243
|
-
};
|
|
1244
|
-
}
|
|
1245
|
-
function buildWorkspaceSkillSnapshot(workspaceDir, opts) {
|
|
1246
|
-
const { eligible, prompt, resolvedSkills } = resolveWorkspaceSkillPromptState(workspaceDir, opts);
|
|
1247
|
-
const skillFilter = normalizeSkillFilter(opts?.skillFilter);
|
|
1248
|
-
return {
|
|
1249
|
-
prompt,
|
|
1250
|
-
skills: eligible.map((entry) => ({
|
|
1251
|
-
name: entry.skill.name,
|
|
1252
|
-
primaryEnv: entry.metadata?.primaryEnv,
|
|
1253
|
-
requiredEnv: entry.metadata?.requires?.env?.slice()
|
|
1254
|
-
})),
|
|
1255
|
-
...skillFilter === void 0 ? {} : { skillFilter },
|
|
1256
|
-
resolvedSkills,
|
|
1257
|
-
version: opts?.snapshotVersion
|
|
1258
|
-
};
|
|
1259
|
-
}
|
|
1260
|
-
function buildWorkspaceSkillsPrompt(workspaceDir, opts) {
|
|
1261
|
-
return resolveWorkspaceSkillPromptState(workspaceDir, opts).prompt;
|
|
1262
|
-
}
|
|
1263
|
-
function resolveWorkspaceSkillPromptState(workspaceDir, opts) {
|
|
1264
|
-
const eligible = filterSkillEntries(opts?.entries ?? loadSkillEntries(workspaceDir, opts), opts?.config, opts?.skillFilter, opts?.eligibility);
|
|
1265
|
-
const promptEntries = eligible.filter((entry) => entry.invocation?.disableModelInvocation !== true);
|
|
1266
|
-
const remoteNote = opts?.eligibility?.remote?.note?.trim();
|
|
1267
|
-
const resolvedSkills = promptEntries.map((entry) => entry.skill);
|
|
1268
|
-
const { skillsForPrompt, truncated } = applySkillsPromptLimits({
|
|
1269
|
-
skills: resolvedSkills,
|
|
1270
|
-
config: opts?.config
|
|
1271
|
-
});
|
|
1272
|
-
return {
|
|
1273
|
-
eligible,
|
|
1274
|
-
prompt: [
|
|
1275
|
-
remoteNote,
|
|
1276
|
-
truncated ? `⚠️ Skills truncated: included ${skillsForPrompt.length} of ${resolvedSkills.length}. Run \`squidclaw skills check\` to audit.` : "",
|
|
1277
|
-
formatSkillsForPrompt(compactSkillPaths(skillsForPrompt))
|
|
1278
|
-
].filter(Boolean).join("\n"),
|
|
1279
|
-
resolvedSkills
|
|
1280
|
-
};
|
|
1281
|
-
}
|
|
1282
|
-
function resolveSkillsPromptForRun(params) {
|
|
1283
|
-
const snapshotPrompt = params.skillsSnapshot?.prompt?.trim();
|
|
1284
|
-
if (snapshotPrompt) return snapshotPrompt;
|
|
1285
|
-
if (params.entries && params.entries.length > 0) {
|
|
1286
|
-
const prompt = buildWorkspaceSkillsPrompt(params.workspaceDir, {
|
|
1287
|
-
entries: params.entries,
|
|
1288
|
-
config: params.config
|
|
1289
|
-
});
|
|
1290
|
-
return prompt.trim() ? prompt : "";
|
|
1291
|
-
}
|
|
1292
|
-
return "";
|
|
1293
|
-
}
|
|
1294
|
-
function loadWorkspaceSkillEntries(workspaceDir, opts) {
|
|
1295
|
-
return loadSkillEntries(workspaceDir, opts);
|
|
1296
|
-
}
|
|
1297
|
-
function resolveUniqueSyncedSkillDirName(base, used) {
|
|
1298
|
-
if (!used.has(base)) {
|
|
1299
|
-
used.add(base);
|
|
1300
|
-
return base;
|
|
1301
|
-
}
|
|
1302
|
-
for (let index = 2; index < 1e4; index += 1) {
|
|
1303
|
-
const candidate = `${base}-${index}`;
|
|
1304
|
-
if (!used.has(candidate)) {
|
|
1305
|
-
used.add(candidate);
|
|
1306
|
-
return candidate;
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
let fallbackIndex = 1e4;
|
|
1310
|
-
let fallback = `${base}-${fallbackIndex}`;
|
|
1311
|
-
while (used.has(fallback)) {
|
|
1312
|
-
fallbackIndex += 1;
|
|
1313
|
-
fallback = `${base}-${fallbackIndex}`;
|
|
1314
|
-
}
|
|
1315
|
-
used.add(fallback);
|
|
1316
|
-
return fallback;
|
|
1317
|
-
}
|
|
1318
|
-
function resolveSyncedSkillDestinationPath(params) {
|
|
1319
|
-
const sourceDirName = path.basename(params.entry.skill.baseDir).trim();
|
|
1320
|
-
if (!sourceDirName || sourceDirName === "." || sourceDirName === "..") return null;
|
|
1321
|
-
return resolveSandboxPath({
|
|
1322
|
-
filePath: resolveUniqueSyncedSkillDirName(sourceDirName, params.usedDirNames),
|
|
1323
|
-
cwd: params.targetSkillsDir,
|
|
1324
|
-
root: params.targetSkillsDir
|
|
1325
|
-
}).resolved;
|
|
1326
|
-
}
|
|
1327
|
-
async function syncSkillsToWorkspace(params) {
|
|
1328
|
-
const sourceDir = resolveUserPath(params.sourceWorkspaceDir);
|
|
1329
|
-
const targetDir = resolveUserPath(params.targetWorkspaceDir);
|
|
1330
|
-
if (sourceDir === targetDir) return;
|
|
1331
|
-
await serializeByKey(`syncSkills:${targetDir}`, async () => {
|
|
1332
|
-
const targetSkillsDir = path.join(targetDir, "skills");
|
|
1333
|
-
const entries = loadSkillEntries(sourceDir, {
|
|
1334
|
-
config: params.config,
|
|
1335
|
-
managedSkillsDir: params.managedSkillsDir,
|
|
1336
|
-
bundledSkillsDir: params.bundledSkillsDir
|
|
1337
|
-
});
|
|
1338
|
-
await fsp.rm(targetSkillsDir, {
|
|
1339
|
-
recursive: true,
|
|
1340
|
-
force: true
|
|
1341
|
-
});
|
|
1342
|
-
await fsp.mkdir(targetSkillsDir, { recursive: true });
|
|
1343
|
-
const usedDirNames = /* @__PURE__ */ new Set();
|
|
1344
|
-
for (const entry of entries) {
|
|
1345
|
-
let dest = null;
|
|
1346
|
-
try {
|
|
1347
|
-
dest = resolveSyncedSkillDestinationPath({
|
|
1348
|
-
targetSkillsDir,
|
|
1349
|
-
entry,
|
|
1350
|
-
usedDirNames
|
|
1351
|
-
});
|
|
1352
|
-
} catch (error) {
|
|
1353
|
-
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
1354
|
-
skillsLogger.warn(`Failed to resolve safe destination for ${entry.skill.name}: ${message}`);
|
|
1355
|
-
continue;
|
|
1356
|
-
}
|
|
1357
|
-
if (!dest) {
|
|
1358
|
-
skillsLogger.warn(`Failed to resolve safe destination for ${entry.skill.name}: invalid source directory name`);
|
|
1359
|
-
continue;
|
|
1360
|
-
}
|
|
1361
|
-
try {
|
|
1362
|
-
await fsp.cp(entry.skill.baseDir, dest, {
|
|
1363
|
-
recursive: true,
|
|
1364
|
-
force: true
|
|
1365
|
-
});
|
|
1366
|
-
} catch (error) {
|
|
1367
|
-
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
1368
|
-
skillsLogger.warn(`Failed to copy ${entry.skill.name} to sandbox: ${message}`);
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
});
|
|
1372
|
-
}
|
|
1373
|
-
function buildWorkspaceSkillCommandSpecs(workspaceDir, opts) {
|
|
1374
|
-
const userInvocable = filterSkillEntries(opts?.entries ?? loadSkillEntries(workspaceDir, opts), opts?.config, opts?.skillFilter, opts?.eligibility).filter((entry) => entry.invocation?.userInvocable !== false);
|
|
1375
|
-
const used = /* @__PURE__ */ new Set();
|
|
1376
|
-
for (const reserved of opts?.reservedNames ?? []) used.add(reserved.toLowerCase());
|
|
1377
|
-
const specs = [];
|
|
1378
|
-
for (const entry of userInvocable) {
|
|
1379
|
-
const rawName = entry.skill.name;
|
|
1380
|
-
const base = sanitizeSkillCommandName(rawName);
|
|
1381
|
-
if (base !== rawName) debugSkillCommandOnce(`sanitize:${rawName}:${base}`, `Sanitized skill command name "${rawName}" to "/${base}".`, {
|
|
1382
|
-
rawName,
|
|
1383
|
-
sanitized: `/${base}`
|
|
1384
|
-
});
|
|
1385
|
-
const unique = resolveUniqueSkillCommandName(base, used);
|
|
1386
|
-
if (unique !== base) debugSkillCommandOnce(`dedupe:${rawName}:${unique}`, `De-duplicated skill command name for "${rawName}" to "/${unique}".`, {
|
|
1387
|
-
rawName,
|
|
1388
|
-
deduped: `/${unique}`
|
|
1389
|
-
});
|
|
1390
|
-
used.add(unique.toLowerCase());
|
|
1391
|
-
const rawDescription = entry.skill.description?.trim() || rawName;
|
|
1392
|
-
const description = rawDescription.length > SKILL_COMMAND_DESCRIPTION_MAX_LENGTH ? rawDescription.slice(0, SKILL_COMMAND_DESCRIPTION_MAX_LENGTH - 1) + "…" : rawDescription;
|
|
1393
|
-
const dispatch = (() => {
|
|
1394
|
-
const kindRaw = (entry.frontmatter?.["command-dispatch"] ?? entry.frontmatter?.["command_dispatch"] ?? "").trim().toLowerCase();
|
|
1395
|
-
if (!kindRaw) return;
|
|
1396
|
-
if (kindRaw !== "tool") return;
|
|
1397
|
-
const toolName = (entry.frontmatter?.["command-tool"] ?? entry.frontmatter?.["command_tool"] ?? "").trim();
|
|
1398
|
-
if (!toolName) {
|
|
1399
|
-
debugSkillCommandOnce(`dispatch:missingTool:${rawName}`, `Skill command "/${unique}" requested tool dispatch but did not provide command-tool. Ignoring dispatch.`, {
|
|
1400
|
-
skillName: rawName,
|
|
1401
|
-
command: unique
|
|
1402
|
-
});
|
|
1403
|
-
return;
|
|
1404
|
-
}
|
|
1405
|
-
const argModeRaw = (entry.frontmatter?.["command-arg-mode"] ?? entry.frontmatter?.["command_arg_mode"] ?? "").trim().toLowerCase();
|
|
1406
|
-
if (!(!argModeRaw || argModeRaw === "raw" ? "raw" : null)) debugSkillCommandOnce(`dispatch:badArgMode:${rawName}:${argModeRaw}`, `Skill command "/${unique}" requested tool dispatch but has unknown command-arg-mode. Falling back to raw.`, {
|
|
1407
|
-
skillName: rawName,
|
|
1408
|
-
command: unique,
|
|
1409
|
-
argMode: argModeRaw
|
|
1410
|
-
});
|
|
1411
|
-
return {
|
|
1412
|
-
kind: "tool",
|
|
1413
|
-
toolName,
|
|
1414
|
-
argMode: "raw"
|
|
1415
|
-
};
|
|
1416
|
-
})();
|
|
1417
|
-
specs.push({
|
|
1418
|
-
name: unique,
|
|
1419
|
-
skillName: rawName,
|
|
1420
|
-
description,
|
|
1421
|
-
...dispatch ? { dispatch } : {}
|
|
1422
|
-
});
|
|
1423
|
-
}
|
|
1424
|
-
return specs;
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
//#endregion
|
|
1428
|
-
export { syncSkillsToWorkspace as a, assertSandboxPath as c, resolveSandboxedMediaSource as d, applySkillEnvOverrides as f, safeEqualSecret as h, resolveSkillsPromptForRun as i, resolveSandboxInputPath as l, sanitizeEnvVars as m, buildWorkspaceSkillSnapshot as n, resolvePluginSkillDirs as o, applySkillEnvOverridesFromSnapshot as p, loadWorkspaceSkillEntries as r, assertMediaNotDataUrl as s, buildWorkspaceSkillCommandSpecs as t, resolveSandboxPath as u };
|