@shadowob/cloud 1.1.6-dev.311
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +509 -0
- package/dist/agent-browser-CERTMCDL.js +117 -0
- package/dist/agent-browser-CIRZRIY4.js +118 -0
- package/dist/agent-pack-LF3O5TR4.js +1236 -0
- package/dist/agent-pack-RQT27V7R.js +1235 -0
- package/dist/airtable-BG2Q75G2.js +82 -0
- package/dist/airtable-JCQXFM5D.js +83 -0
- package/dist/alipay-MZX2XCDB.js +52 -0
- package/dist/alipay-TZQI34RB.js +51 -0
- package/dist/amap-5RQB3VGC.js +45 -0
- package/dist/amap-KPCLZYYL.js +44 -0
- package/dist/atlassian-LGOEWYC7.js +54 -0
- package/dist/atlassian-TVS2A4IU.js +55 -0
- package/dist/baidu-appbuilder-6UMESXHW.js +41 -0
- package/dist/baidu-appbuilder-QRRL3ETM.js +42 -0
- package/dist/baidu-maps-HEPMVP5D.js +44 -0
- package/dist/baidu-maps-HXC4FBVP.js +45 -0
- package/dist/baidu-netdisk-G5Q6B5NH.js +45 -0
- package/dist/baidu-netdisk-RS2K5W2M.js +44 -0
- package/dist/baidu-smartprogram-EWTK5WKK.js +41 -0
- package/dist/baidu-smartprogram-JHD3XWF6.js +40 -0
- package/dist/browserbase-IUIYVYI7.js +67 -0
- package/dist/browserbase-JFO2PCIA.js +68 -0
- package/dist/canva-3YOFL7JS.js +62 -0
- package/dist/canva-FMYN65SM.js +61 -0
- package/dist/chunk-6P2K6QZR.js +529 -0
- package/dist/chunk-7VMRQ7MG.js +90 -0
- package/dist/chunk-AD3JTIU3.js +17 -0
- package/dist/chunk-BF6CV2Y4.js +64 -0
- package/dist/chunk-CTNUKOQE.js +439 -0
- package/dist/chunk-EEFMJYKB.js +97 -0
- package/dist/chunk-EJKFQ35I.js +739 -0
- package/dist/chunk-HUICDC56.js +62 -0
- package/dist/chunk-JUPAE5IA.js +527 -0
- package/dist/chunk-JY2HTT7Q.js +437 -0
- package/dist/chunk-KEPTCLUO.js +121 -0
- package/dist/chunk-KKK5H7YX.js +3622 -0
- package/dist/chunk-POSVEKIY.js +210 -0
- package/dist/chunk-QET4LT4J.js +5769 -0
- package/dist/chunk-QV4XWO3P.js +30 -0
- package/dist/chunk-R52J3PH2.js +120 -0
- package/dist/chunk-R5U7XKVJ.js +16 -0
- package/dist/chunk-RECNVWMT.js +212 -0
- package/dist/chunk-RTPBU5HF.js +92 -0
- package/dist/chunk-SUZ2ATT6.js +5774 -0
- package/dist/chunk-SVMXSIMG.js +98 -0
- package/dist/chunk-TV3CBM7R.js +28 -0
- package/dist/chunk-V2LU736V.js +3495 -0
- package/dist/chunk-ZUYL3W53.js +741 -0
- package/dist/claude-plugin-577TAQVS.js +1463 -0
- package/dist/claude-plugin-L3MXJJ6J.js +1464 -0
- package/dist/cli.js +7021 -0
- package/dist/cloudflare-HBBABPK6.js +114 -0
- package/dist/cloudflare-RDFPKMM5.js +115 -0
- package/dist/cnb-FLP3QX46.js +44 -0
- package/dist/cnb-YAVVEYFB.js +45 -0
- package/dist/console/index.html +12 -0
- package/dist/console/logo.png +0 -0
- package/dist/console/static/css/5079.f9e0918d.css +1 -0
- package/dist/console/static/css/index.7f91f806.css +1 -0
- package/dist/console/static/font/codicon.5b7d6fac.ttf +0 -0
- package/dist/console/static/js/5079.72a51ca2.js +699 -0
- package/dist/console/static/js/5079.72a51ca2.js.LICENSE.txt +35 -0
- package/dist/console/static/js/7426.f8d483ea.js +1 -0
- package/dist/console/static/js/async/1008.4df521b7.js +1 -0
- package/dist/console/static/js/async/102.1d473ec7.js +1 -0
- package/dist/console/static/js/async/1134.3f9fd9e7.js +1 -0
- package/dist/console/static/js/async/1318.4b8e48e7.js +1 -0
- package/dist/console/static/js/async/1360.5606da88.js +7 -0
- package/dist/console/static/js/async/1546.045f484f.js +1 -0
- package/dist/console/static/js/async/1562.187de2a8.js +1 -0
- package/dist/console/static/js/async/168.456d4813.js +1 -0
- package/dist/console/static/js/async/1750.e6dc2664.js +1 -0
- package/dist/console/static/js/async/1994.3fc86066.js +1 -0
- package/dist/console/static/js/async/2348.613ae3d9.js +1 -0
- package/dist/console/static/js/async/2390.1b890b9d.js +1 -0
- package/dist/console/static/js/async/2414.9d040212.js +1 -0
- package/dist/console/static/js/async/2454.4c1784ab.js +1 -0
- package/dist/console/static/js/async/2498.f5f92030.js +1 -0
- package/dist/console/static/js/async/2924.b823cd1a.js +1 -0
- package/dist/console/static/js/async/3062.63fddea6.js +1 -0
- package/dist/console/static/js/async/3078.dd712008.js +1 -0
- package/dist/console/static/js/async/3198.1f307065.js +1 -0
- package/dist/console/static/js/async/3246.3d5a899f.js +1 -0
- package/dist/console/static/js/async/3286.871676eb.js +1 -0
- package/dist/console/static/js/async/342.10bf3b90.js +1 -0
- package/dist/console/static/js/async/3446.9681a4d7.js +1 -0
- package/dist/console/static/js/async/3698.ccfaabec.js +1 -0
- package/dist/console/static/js/async/3790.2a1106a6.js +1 -0
- package/dist/console/static/js/async/4231.b29784d4.js +1 -0
- package/dist/console/static/js/async/4551.515bd41d.js +1 -0
- package/dist/console/static/js/async/4596.40f6e71b.js +1 -0
- package/dist/console/static/js/async/4600.4aaebe6d.js +1 -0
- package/dist/console/static/js/async/4718.1aae022f.js +1 -0
- package/dist/console/static/js/async/4846.a347c020.js +1 -0
- package/dist/console/static/js/async/4860.83dadf89.js +1 -0
- package/dist/console/static/js/async/500.fcfa37cb.js +1 -0
- package/dist/console/static/js/async/5096.b360203d.js +1 -0
- package/dist/console/static/js/async/5222.043274fe.js +1 -0
- package/dist/console/static/js/async/5362.f498001c.js +1 -0
- package/dist/console/static/js/async/54.c94f0755.js +1 -0
- package/dist/console/static/js/async/5478.50dd9ef0.js +2 -0
- package/dist/console/static/js/async/5478.50dd9ef0.js.LICENSE.txt +3 -0
- package/dist/console/static/js/async/5507.a6a1f793.js +1 -0
- package/dist/console/static/js/async/5638.bc6b102d.js +1 -0
- package/dist/console/static/js/async/5722.e0029049.js +1 -0
- package/dist/console/static/js/async/5942.74635c6b.js +1 -0
- package/dist/console/static/js/async/5994.1c5629c1.js +1 -0
- package/dist/console/static/js/async/6054.6bddf720.js +1 -0
- package/dist/console/static/js/async/6118.45e754e5.js +1 -0
- package/dist/console/static/js/async/6127.adcbcbb6.js +1 -0
- package/dist/console/static/js/async/614.3f434c20.js +1 -0
- package/dist/console/static/js/async/6234.ba3b002d.js +1 -0
- package/dist/console/static/js/async/6310.6546a9ba.js +1 -0
- package/dist/console/static/js/async/6378.9f805419.js +1 -0
- package/dist/console/static/js/async/6380.e4433c49.js +1 -0
- package/dist/console/static/js/async/6418.f23bcfda.js +1 -0
- package/dist/console/static/js/async/6428.77c86114.js +1 -0
- package/dist/console/static/js/async/6443.83318a6c.js +1 -0
- package/dist/console/static/js/async/6508.2b445d62.js +3 -0
- package/dist/console/static/js/async/6542.e82a26c8.js +1 -0
- package/dist/console/static/js/async/6544.62111ecb.js +1 -0
- package/dist/console/static/js/async/6612.a0c9fcf4.js +1 -0
- package/dist/console/static/js/async/6740.695aebf0.js +1 -0
- package/dist/console/static/js/async/6822.dbbb32bc.js +1 -0
- package/dist/console/static/js/async/6824.ad3540ab.js +1 -0
- package/dist/console/static/js/async/6930.585dab94.js +1 -0
- package/dist/console/static/js/async/6982.c81b95e6.js +1 -0
- package/dist/console/static/js/async/7046.ab2378c1.js +1 -0
- package/dist/console/static/js/async/7110.a603277f.js +1 -0
- package/dist/console/static/js/async/7142.4a21366f.js +1 -0
- package/dist/console/static/js/async/7348.15cc6148.js +1373 -0
- package/dist/console/static/js/async/7348.15cc6148.js.LICENSE.txt +14 -0
- package/dist/console/static/js/async/7374.b1ac5c44.js +1 -0
- package/dist/console/static/js/async/742.847f17ca.js +1 -0
- package/dist/console/static/js/async/7446.743954d8.js +1 -0
- package/dist/console/static/js/async/7673.59bbbaac.js +1 -0
- package/dist/console/static/js/async/7684.c5760c8c.js +1 -0
- package/dist/console/static/js/async/7714.c30d0f94.js +1 -0
- package/dist/console/static/js/async/8118.36d5a3bf.js +298 -0
- package/dist/console/static/js/async/8145.4bcf043a.js +1 -0
- package/dist/console/static/js/async/8246.408de938.js +1 -0
- package/dist/console/static/js/async/8390.bdae1f7d.js +1 -0
- package/dist/console/static/js/async/8422.fd94dbe1.js +1 -0
- package/dist/console/static/js/async/8434.94a0e2ae.js +1 -0
- package/dist/console/static/js/async/8518.3158de13.js +1 -0
- package/dist/console/static/js/async/8564.fc2eb841.js +1 -0
- package/dist/console/static/js/async/8678.73af4c9b.js +1 -0
- package/dist/console/static/js/async/8694.79747168.js +1 -0
- package/dist/console/static/js/async/8756.1de37b83.js +1 -0
- package/dist/console/static/js/async/8804.7fe6bdf9.js +3 -0
- package/dist/console/static/js/async/8883.e717ee94.js +1 -0
- package/dist/console/static/js/async/8886.fe6e876c.js +1 -0
- package/dist/console/static/js/async/9030.fc1ae402.js +1 -0
- package/dist/console/static/js/async/9094.5598d084.js +1 -0
- package/dist/console/static/js/async/9218.ee7b84b7.js +1 -0
- package/dist/console/static/js/async/94.9b80bc35.js +1 -0
- package/dist/console/static/js/async/9526.92aba34c.js +1 -0
- package/dist/console/static/js/async/9762.f83bc4f3.js +1 -0
- package/dist/console/static/js/async/984.e11c113a.js +1 -0
- package/dist/console/static/js/async/9846.246653cd.js +1 -0
- package/dist/console/static/js/index.4487e1ff.js +1 -0
- package/dist/console/static/js/lib-react.15d7ca9a.js +2 -0
- package/dist/console/static/js/lib-react.15d7ca9a.js.LICENSE.txt +49 -0
- package/dist/coze-C6PMDPBI.js +49 -0
- package/dist/coze-E6VGRNLV.js +48 -0
- package/dist/dashboard.command-J7XOZNXU.js +8 -0
- package/dist/dashboard.command-RV2NHDKW.js +7 -0
- package/dist/dingtalk-JNRNRN7E.js +77 -0
- package/dist/dingtalk-WZGGIAHJ.js +76 -0
- package/dist/douyin-miniprogram-AIJPPIZH.js +41 -0
- package/dist/douyin-miniprogram-HCYZ5NBW.js +42 -0
- package/dist/figma-2YYNSCDX.js +103 -0
- package/dist/figma-RYOBMENP.js +102 -0
- package/dist/firebase-2IJDDBXX.js +112 -0
- package/dist/firebase-OYSY6HPT.js +111 -0
- package/dist/firecrawl-2T3SBUW7.js +66 -0
- package/dist/firecrawl-IYYXLAZM.js +65 -0
- package/dist/flyai-7FJ4TRAG.js +81 -0
- package/dist/flyai-QS5Q6FJR.js +82 -0
- package/dist/gitagent-MWI75OIX.js +725 -0
- package/dist/gitagent-YBMWY7NZ.js +726 -0
- package/dist/gitee-3N7OFOM7.js +53 -0
- package/dist/gitee-KVNK6KLZ.js +54 -0
- package/dist/github-LUEC2LID.js +143 -0
- package/dist/github-XRO5Z3GC.js +142 -0
- package/dist/google-ads-A3QAJI4D.js +88 -0
- package/dist/google-ads-VPKWTX67.js +89 -0
- package/dist/google-analytics-C4UR5ZR2.js +50 -0
- package/dist/google-analytics-XDYZA2B7.js +49 -0
- package/dist/google-workspace-LL3EWVHH.js +320 -0
- package/dist/google-workspace-YX35SHHX.js +321 -0
- package/dist/huawei-xiaoyi-6BSMGJHR.js +40 -0
- package/dist/huawei-xiaoyi-KPWLTSHB.js +41 -0
- package/dist/hubspot-DIUHGEDI.js +45 -0
- package/dist/hubspot-FTIEMNZO.js +44 -0
- package/dist/huggingface-MJCOXA7E.js +116 -0
- package/dist/huggingface-UUXK2RHK.js +117 -0
- package/dist/index.d.ts +3013 -0
- package/dist/index.js +15649 -0
- package/dist/inference-ai-image-generation-CMI6R5T3.js +106 -0
- package/dist/inference-ai-image-generation-PXV6IG4U.js +107 -0
- package/dist/inference-sh-7AZOLEFI.js +94 -0
- package/dist/inference-sh-ABQOD3YF.js +95 -0
- package/dist/init.command-6E24K4H3.js +9 -0
- package/dist/init.command-O4HG4HKR.js +10 -0
- package/dist/klaviyo-6K5YEFNH.js +45 -0
- package/dist/klaviyo-LDPBWBSS.js +44 -0
- package/dist/kuaidi100-HGFM5VK2.js +42 -0
- package/dist/kuaidi100-UHPFCVXP.js +41 -0
- package/dist/lark-6LNA3LUQ.js +103 -0
- package/dist/lark-URVBZNS4.js +102 -0
- package/dist/linear-7QFSFPOD.js +57 -0
- package/dist/linear-T4ORUP7N.js +56 -0
- package/dist/lovart-PDUXRUHJ.js +99 -0
- package/dist/lovart-QO3SK55T.js +100 -0
- package/dist/meta-ads-SCNFI45S.js +42 -0
- package/dist/meta-ads-V6XPZWX3.js +41 -0
- package/dist/miclaw-5CNTW7VV.js +36 -0
- package/dist/miclaw-TPPPS2WN.js +35 -0
- package/dist/model-provider-AVSFJSZP.js +393 -0
- package/dist/model-provider-KFB76XV5.js +392 -0
- package/dist/notion-FZK76MN2.js +69 -0
- package/dist/notion-WFA7KGZZ.js +70 -0
- package/dist/oceanengine-3JZUS3PP.js +43 -0
- package/dist/oceanengine-5BRIJVJE.js +42 -0
- package/dist/opencli-PFXHGCS2.js +81 -0
- package/dist/opencli-VIGRJTGH.js +80 -0
- package/dist/paypal-33UADIPR.js +54 -0
- package/dist/paypal-Z5JYHIWD.js +55 -0
- package/dist/playwright-MG5WHK47.js +58 -0
- package/dist/playwright-SQAQ3DZG.js +59 -0
- package/dist/plugins-HZBWK3WQ.js +120 -0
- package/dist/plugins-I4GD5SZX.js +121 -0
- package/dist/posthog-MU5MAJOQ.js +79 -0
- package/dist/posthog-RJRRKDWB.js +80 -0
- package/dist/salesforce-34FVIJTG.js +82 -0
- package/dist/salesforce-3QZ6OFVO.js +83 -0
- package/dist/sentry-MCIRMACU.js +111 -0
- package/dist/sentry-PIWW46VA.js +110 -0
- package/dist/seo-suite-4SQ3I67Q.js +54 -0
- package/dist/seo-suite-WJXMA3S4.js +55 -0
- package/dist/serve.command-5FMIPQRY.js +10 -0
- package/dist/serve.command-DNE6GPMK.js +9 -0
- package/dist/shadowob-JELOWHWX.js +1068 -0
- package/dist/shadowob-PRSMI5MW.js +1069 -0
- package/dist/sherlock-2PKY2E2Y.js +66 -0
- package/dist/sherlock-C5ZWPPVT.js +67 -0
- package/dist/shopify-GL3NFVGE.js +94 -0
- package/dist/shopify-R4G3UXM6.js +93 -0
- package/dist/skill-discovery-7INAUP4D.js +77 -0
- package/dist/skill-discovery-YPXXV622.js +78 -0
- package/dist/state-7MCZBTR5.js +17 -0
- package/dist/state-FGOFLFBE.js +18 -0
- package/dist/stripe-C22RR4ZS.js +83 -0
- package/dist/stripe-LJNPQ3CQ.js +82 -0
- package/dist/supabase-IRNQ54FJ.js +98 -0
- package/dist/supabase-N4ONFJNQ.js +97 -0
- package/dist/taobao-aipaas-LRR4GMO3.js +45 -0
- package/dist/taobao-aipaas-RVKORSF4.js +46 -0
- package/dist/tapd-3JPVJ7XH.js +46 -0
- package/dist/tapd-TMQRSMFG.js +47 -0
- package/dist/tencent-ads-IGD33LO7.js +42 -0
- package/dist/tencent-ads-UHC6OPBV.js +43 -0
- package/dist/tencent-docs-C3A4J3CJ.js +47 -0
- package/dist/tencent-docs-O2SC4FHL.js +48 -0
- package/dist/tencent-maps-HMMWMNF4.js +37 -0
- package/dist/tencent-maps-OQOKHVW2.js +36 -0
- package/dist/vercel-KOXDDTHX.js +73 -0
- package/dist/vercel-OLNVDWMG.js +74 -0
- package/dist/webflow-FULU5Q2I.js +114 -0
- package/dist/webflow-OMJKZM54.js +115 -0
- package/dist/wechat-miniprogram-skyline-KYCDMQNW.js +74 -0
- package/dist/wechat-miniprogram-skyline-VR4FVIQL.js +75 -0
- package/dist/wechat-pay-BCMAJ6UW.js +50 -0
- package/dist/wechat-pay-YQQKXVUI.js +51 -0
- package/dist/wonda-NGWIORYN.js +81 -0
- package/dist/wonda-RBABXFNM.js +82 -0
- package/dist/wordpress-woocommerce-RDIUTHYT.js +57 -0
- package/dist/wordpress-woocommerce-RNA5HB3N.js +58 -0
- package/dist/wps-DAEFQHDE.js +47 -0
- package/dist/wps-LUWHMZQQ.js +48 -0
- package/dist/yuque-HCHTJWNI.js +72 -0
- package/dist/yuque-KRH5O74J.js +71 -0
- package/images/RUNNERS.md +270 -0
- package/images/cc-connect-runner/entrypoint.mjs +311 -0
- package/images/claude-runner/Dockerfile +88 -0
- package/images/claude-runner/RUNNER.md +222 -0
- package/images/claude-runner/entrypoint.mjs +2 -0
- package/images/codex-runner/Dockerfile +87 -0
- package/images/codex-runner/RUNNER.md +226 -0
- package/images/codex-runner/entrypoint.mjs +2 -0
- package/images/gemini-runner/Dockerfile +87 -0
- package/images/gemini-runner/RUNNER.md +218 -0
- package/images/gemini-runner/entrypoint.mjs +2 -0
- package/images/hermes-runner/Dockerfile +74 -0
- package/images/hermes-runner/RUNNER.md +243 -0
- package/images/hermes-runner/entrypoint.mjs +283 -0
- package/images/openclaw-runner/Dockerfile +212 -0
- package/images/openclaw-runner/RUNNER.md +170 -0
- package/images/openclaw-runner/entrypoint.mjs +1113 -0
- package/images/openclaw-runner/warm-runtime-deps.mjs +95 -0
- package/images/opencode-runner/Dockerfile +87 -0
- package/images/opencode-runner/RUNNER.md +202 -0
- package/images/opencode-runner/entrypoint.mjs +2 -0
- package/package.json +121 -0
- package/templates/agent-marketplace-buddy.template.json +131 -0
- package/templates/ai-werewolf.template.json +92 -0
- package/templates/bmad-method-buddy.template.json +123 -0
- package/templates/brain-fix.template.json +92 -0
- package/templates/claude-ads-buddy.template.json +123 -0
- package/templates/claude-financial-services-buddy.template.json +111 -0
- package/templates/claude-seo-buddy.template.json +123 -0
- package/templates/code-arena.template.json +92 -0
- package/templates/daily-brief.template.json +92 -0
- package/templates/e-wife.template.json +92 -0
- package/templates/everything-claude-code-buddy.template.json +125 -0
- package/templates/financial-freedom.template.json +92 -0
- package/templates/gitstory.template.json +92 -0
- package/templates/google-workspace-buddy.template.json +88 -0
- package/templates/gsd-buddy.template.json +119 -0
- package/templates/gstack-buddy.template.json +143 -0
- package/templates/gstack.template.json +92 -0
- package/templates/little-match-girl.template.json +114 -0
- package/templates/lovart-buddy.template.json +110 -0
- package/templates/marketingskills-buddy.template.json +102 -0
- package/templates/retire-buddy.template.json +92 -0
- package/templates/scientific-skills-buddy.template.json +119 -0
- package/templates/seomachine-buddy.template.json +113 -0
- package/templates/shadow-server-app-demo.template.json +105 -0
- package/templates/slavingia-skills-buddy.template.json +102 -0
- package/templates/superclaude-buddy.template.json +146 -0
- package/templates/superpowers-buddy.template.json +108 -0
- package/templates/world-pulse.template.json +92 -0
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/plugins/agent-pack/indexer-script.ts
|
|
4
|
+
var AGENT_PACK_SLASH_INDEXER_SCRIPT = String.raw`
|
|
5
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
|
|
6
|
+
import { basename, dirname, extname, join, relative } from 'node:path'
|
|
7
|
+
|
|
8
|
+
function readArg(name, fallback) {
|
|
9
|
+
const idx = process.argv.indexOf(name)
|
|
10
|
+
return idx >= 0 && process.argv[idx + 1] ? process.argv[idx + 1] : fallback
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function listChildDirs(dir) {
|
|
14
|
+
try {
|
|
15
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
16
|
+
.filter((d) => d.isDirectory())
|
|
17
|
+
.map((d) => join(dir, d.name))
|
|
18
|
+
} catch {
|
|
19
|
+
return []
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function listFiles(dir, suffix) {
|
|
24
|
+
try {
|
|
25
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
26
|
+
.filter((d) => d.isFile() && d.name.endsWith(suffix))
|
|
27
|
+
.map((d) => join(dir, d.name))
|
|
28
|
+
} catch {
|
|
29
|
+
return []
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function listFilesRecursive(dir, maxDepth, depth = 0) {
|
|
34
|
+
if (depth > maxDepth) return []
|
|
35
|
+
try {
|
|
36
|
+
const entries = readdirSync(dir, { withFileTypes: true })
|
|
37
|
+
const out = []
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
if (entry.name.startsWith('.')) continue
|
|
40
|
+
const path = join(dir, entry.name)
|
|
41
|
+
if (entry.isDirectory()) {
|
|
42
|
+
if (['node_modules', 'dist', 'build', 'vendor', 'coverage', '__pycache__'].includes(entry.name)) {
|
|
43
|
+
continue
|
|
44
|
+
}
|
|
45
|
+
out.push(...listFilesRecursive(path, maxDepth, depth + 1))
|
|
46
|
+
} else if (entry.isFile()) {
|
|
47
|
+
out.push(path)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return out
|
|
51
|
+
} catch {
|
|
52
|
+
return []
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function readMaybe(path) {
|
|
57
|
+
try {
|
|
58
|
+
return readFileSync(path, 'utf-8')
|
|
59
|
+
} catch {
|
|
60
|
+
return ''
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function normalizeSlashCommandName(value) {
|
|
65
|
+
if (typeof value !== 'string') return null
|
|
66
|
+
const name = value.trim().replace(/^\/+/, '')
|
|
67
|
+
return /^[a-zA-Z][a-zA-Z0-9._-]{0,63}$/.test(name) ? name : null
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function parseFrontmatterList(value) {
|
|
71
|
+
if (typeof value !== 'string') return []
|
|
72
|
+
const trimmed = value.trim()
|
|
73
|
+
const unwrapped =
|
|
74
|
+
trimmed.startsWith('[') && trimmed.endsWith(']') ? trimmed.slice(1, -1) : trimmed
|
|
75
|
+
return unwrapped
|
|
76
|
+
.split(',')
|
|
77
|
+
.map((item) => item.trim().replace(/^['"]|['"]$/g, ''))
|
|
78
|
+
.filter(Boolean)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function parseFrontmatter(text) {
|
|
82
|
+
if (!text.startsWith('---')) return { data: {}, body: text }
|
|
83
|
+
const end = text.indexOf('\n---', 3)
|
|
84
|
+
if (end === -1) return { data: {}, body: text }
|
|
85
|
+
|
|
86
|
+
const raw = text.slice(3, end).trim()
|
|
87
|
+
const data = {}
|
|
88
|
+
const lines = raw.split('\n')
|
|
89
|
+
for (let i = 0; i < lines.length; i++) {
|
|
90
|
+
const line = lines[i]
|
|
91
|
+
const match = line.match(/^([a-zA-Z0-9_.-]+):\s*(.*)$/)
|
|
92
|
+
if (!match) continue
|
|
93
|
+
const key = match[1]
|
|
94
|
+
const value = match[2].trim().replace(/^['"]|['"]$/g, '')
|
|
95
|
+
|
|
96
|
+
if (value === '|') {
|
|
97
|
+
const block = []
|
|
98
|
+
while (i + 1 < lines.length) {
|
|
99
|
+
const next = lines[i + 1]
|
|
100
|
+
if (next && !/^\s/.test(next)) break
|
|
101
|
+
block.push(next.replace(/^\s{2}/, ''))
|
|
102
|
+
i++
|
|
103
|
+
}
|
|
104
|
+
data[key] = block.join('\n').trim()
|
|
105
|
+
continue
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (value) {
|
|
109
|
+
data[key] = value
|
|
110
|
+
continue
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const items = []
|
|
114
|
+
while (i + 1 < lines.length) {
|
|
115
|
+
const itemMatch = lines[i + 1].match(/^\s*-\s*(.+)$/)
|
|
116
|
+
if (!itemMatch) break
|
|
117
|
+
items.push(itemMatch[1].trim().replace(/^['"]|['"]$/g, ''))
|
|
118
|
+
i++
|
|
119
|
+
}
|
|
120
|
+
data[key] = items.length > 0 ? items.join(',') : value
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return { data, body: text.slice(end + 4).trimStart() }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function parseFrontmatterJson(value) {
|
|
127
|
+
if (typeof value !== 'string') return undefined
|
|
128
|
+
const trimmed = value.trim()
|
|
129
|
+
if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) return undefined
|
|
130
|
+
try {
|
|
131
|
+
return JSON.parse(trimmed)
|
|
132
|
+
} catch {
|
|
133
|
+
return undefined
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function normalizeInteractionItems(value, max) {
|
|
138
|
+
if (!Array.isArray(value)) return undefined
|
|
139
|
+
const items = value
|
|
140
|
+
.filter((item) => item && typeof item === 'object' && !Array.isArray(item))
|
|
141
|
+
.map((item, index) => {
|
|
142
|
+
const label =
|
|
143
|
+
typeof item.label === 'string' && item.label.trim()
|
|
144
|
+
? item.label.trim()
|
|
145
|
+
: typeof item.value === 'string' && item.value.trim()
|
|
146
|
+
? item.value.trim()
|
|
147
|
+
: 'Option ' + (index + 1)
|
|
148
|
+
const id =
|
|
149
|
+
typeof item.id === 'string' && item.id.trim()
|
|
150
|
+
? item.id.trim()
|
|
151
|
+
: typeof item.value === 'string' && item.value.trim()
|
|
152
|
+
? item.value.trim()
|
|
153
|
+
: label
|
|
154
|
+
return {
|
|
155
|
+
id,
|
|
156
|
+
label,
|
|
157
|
+
...(typeof item.value === 'string' && item.value.trim()
|
|
158
|
+
? { value: item.value.trim() }
|
|
159
|
+
: {}),
|
|
160
|
+
...(item.style === 'primary' || item.style === 'secondary' || item.style === 'destructive'
|
|
161
|
+
? { style: item.style }
|
|
162
|
+
: {}),
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
.filter((item) => item.id && item.label)
|
|
166
|
+
return items.length > 0 ? items.slice(0, max) : undefined
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function normalizeSlashInteraction(value) {
|
|
170
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined
|
|
171
|
+
const kind = typeof value.kind === 'string' ? value.kind.trim().toLowerCase() : ''
|
|
172
|
+
if (!['buttons', 'select', 'form', 'approval'].includes(kind)) return undefined
|
|
173
|
+
|
|
174
|
+
const out = { kind }
|
|
175
|
+
for (const key of ['id', 'prompt', 'submitLabel', 'responsePrompt', 'approvalCommentLabel']) {
|
|
176
|
+
if (typeof value[key] === 'string' && value[key].trim()) out[key] = value[key].trim()
|
|
177
|
+
}
|
|
178
|
+
if (typeof value.oneShot === 'boolean') out.oneShot = value.oneShot
|
|
179
|
+
|
|
180
|
+
const buttons = normalizeInteractionItems(value.buttons, 8)
|
|
181
|
+
const options = normalizeInteractionItems(value.options, 20)?.map((option) => ({
|
|
182
|
+
id: option.id,
|
|
183
|
+
label: option.label,
|
|
184
|
+
value: option.value ?? option.id,
|
|
185
|
+
}))
|
|
186
|
+
if (buttons) out.buttons = buttons
|
|
187
|
+
if (options) out.options = options
|
|
188
|
+
|
|
189
|
+
if (Array.isArray(value.fields)) {
|
|
190
|
+
out.fields = value.fields
|
|
191
|
+
.filter((field) => field && typeof field === 'object' && !Array.isArray(field))
|
|
192
|
+
.map((field, index) => ({
|
|
193
|
+
id:
|
|
194
|
+
typeof field.id === 'string' && field.id.trim() ? field.id.trim() : 'field_' + (index + 1),
|
|
195
|
+
kind:
|
|
196
|
+
typeof field.kind === 'string' &&
|
|
197
|
+
['text', 'textarea', 'number', 'checkbox', 'select'].includes(field.kind)
|
|
198
|
+
? field.kind
|
|
199
|
+
: 'text',
|
|
200
|
+
label:
|
|
201
|
+
typeof field.label === 'string' && field.label.trim()
|
|
202
|
+
? field.label.trim()
|
|
203
|
+
: 'Field ' + (index + 1),
|
|
204
|
+
...(typeof field.placeholder === 'string' && field.placeholder.trim()
|
|
205
|
+
? { placeholder: field.placeholder.trim() }
|
|
206
|
+
: {}),
|
|
207
|
+
...(typeof field.defaultValue === 'string' ? { defaultValue: field.defaultValue } : {}),
|
|
208
|
+
...(typeof field.required === 'boolean' ? { required: field.required } : {}),
|
|
209
|
+
...(typeof field.maxLength === 'number' ? { maxLength: field.maxLength } : {}),
|
|
210
|
+
...(typeof field.min === 'number' ? { min: field.min } : {}),
|
|
211
|
+
...(typeof field.max === 'number' ? { max: field.max } : {}),
|
|
212
|
+
}))
|
|
213
|
+
.slice(0, 12)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return out
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function frontmatterInteraction(data) {
|
|
220
|
+
const direct = normalizeSlashInteraction(
|
|
221
|
+
parseFrontmatterJson(data.interaction) ?? parseFrontmatterJson(data.interactive),
|
|
222
|
+
)
|
|
223
|
+
if (direct) return direct
|
|
224
|
+
|
|
225
|
+
const kind = data['interaction.kind'] ?? data['interactive.kind']
|
|
226
|
+
if (!kind) return undefined
|
|
227
|
+
const oneShotRaw = data['interaction.oneShot'] ?? data['interactive.oneShot']
|
|
228
|
+
return normalizeSlashInteraction({
|
|
229
|
+
kind,
|
|
230
|
+
id: data['interaction.id'] ?? data['interactive.id'],
|
|
231
|
+
prompt: data['interaction.prompt'] ?? data['interactive.prompt'],
|
|
232
|
+
submitLabel: data['interaction.submitLabel'] ?? data['interactive.submitLabel'],
|
|
233
|
+
responsePrompt: data['interaction.responsePrompt'] ?? data['interactive.responsePrompt'],
|
|
234
|
+
approvalCommentLabel:
|
|
235
|
+
data['interaction.approvalCommentLabel'] ?? data['interactive.approvalCommentLabel'],
|
|
236
|
+
...(oneShotRaw !== undefined ? { oneShot: oneShotRaw === 'true' } : {}),
|
|
237
|
+
buttons: parseFrontmatterJson(data['interaction.buttons'] ?? data['interactive.buttons']),
|
|
238
|
+
options: parseFrontmatterJson(data['interaction.options'] ?? data['interactive.options']),
|
|
239
|
+
fields: parseFrontmatterJson(data['interaction.fields'] ?? data['interactive.fields']),
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function derivePackId(path, mountPath) {
|
|
244
|
+
const mountParts = mountPath.split('/').filter(Boolean)
|
|
245
|
+
const parts = path.split('/').filter(Boolean)
|
|
246
|
+
if (mountParts.length > 0) {
|
|
247
|
+
for (let i = 0; i <= parts.length - mountParts.length - 1; i++) {
|
|
248
|
+
let matches = true
|
|
249
|
+
for (let j = 0; j < mountParts.length; j++) {
|
|
250
|
+
if (parts[i + j] !== mountParts[j]) {
|
|
251
|
+
matches = false
|
|
252
|
+
break
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (matches && parts[i + mountParts.length]) return parts[i + mountParts.length]
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const idx = parts.lastIndexOf('agent-packs')
|
|
260
|
+
if (idx >= 0 && parts[idx + 1]) return parts[idx + 1]
|
|
261
|
+
return undefined
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function deriveSlashDescription(body, frontmatter) {
|
|
265
|
+
const fmDescription =
|
|
266
|
+
typeof frontmatter.description === 'string' ? frontmatter.description.trim() : ''
|
|
267
|
+
if (fmDescription) return fmDescription.slice(0, 240)
|
|
268
|
+
|
|
269
|
+
for (const line of body.split('\n')) {
|
|
270
|
+
const text = line.replace(/^#+\s*/, '').trim()
|
|
271
|
+
if (text) return text.slice(0, 240)
|
|
272
|
+
}
|
|
273
|
+
return undefined
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function asStringArray(value) {
|
|
277
|
+
if (typeof value === 'string') return [value]
|
|
278
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === 'string') : []
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function matchesSlashCommandRule(rule, command, context) {
|
|
282
|
+
const match = rule.match
|
|
283
|
+
if (!match || typeof match !== 'object') return true
|
|
284
|
+
if (typeof match.packId === 'string' && match.packId !== context.packId) return false
|
|
285
|
+
|
|
286
|
+
const names = [...asStringArray(match.name), ...asStringArray(match.names)]
|
|
287
|
+
if (
|
|
288
|
+
names.length > 0 &&
|
|
289
|
+
!names.some((name) => name.toLowerCase() === command.name.toLowerCase())
|
|
290
|
+
) {
|
|
291
|
+
return false
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (typeof match.namePattern === 'string' && match.namePattern.trim()) {
|
|
295
|
+
try {
|
|
296
|
+
if (!new RegExp(match.namePattern).test(command.name)) return false
|
|
297
|
+
} catch (err) {
|
|
298
|
+
console.warn('[agent-pack] Ignoring invalid slash command rule pattern: ' + err.message)
|
|
299
|
+
return false
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const pathIncludes = asStringArray(match.sourcePathIncludes)
|
|
304
|
+
return pathIncludes.length === 0 || pathIncludes.some((needle) => context.path.includes(needle))
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function applySlashCommandRules(command, context, rules) {
|
|
308
|
+
for (const rule of rules) {
|
|
309
|
+
if (!matchesSlashCommandRule(rule, command, context)) continue
|
|
310
|
+
|
|
311
|
+
const aliases = asStringArray(rule.aliases)
|
|
312
|
+
.map(normalizeSlashCommandName)
|
|
313
|
+
.filter(Boolean)
|
|
314
|
+
.filter((alias) => alias.toLowerCase() !== command.name.toLowerCase())
|
|
315
|
+
if (aliases.length > 0) {
|
|
316
|
+
command.aliases = [...new Set([...(command.aliases ?? []), ...aliases])]
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const interaction = normalizeSlashInteraction(rule.interaction)
|
|
320
|
+
if (interaction && !command.interaction) command.interaction = interaction
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return command
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function stripMarkdownInline(value) {
|
|
327
|
+
return value
|
|
328
|
+
.replace(new RegExp('[' + String.fromCharCode(96) + '*_~]', 'g'), '')
|
|
329
|
+
.replace(/\s+/g, ' ')
|
|
330
|
+
.trim()
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function extractAskLine(block) {
|
|
334
|
+
const quoted = block.match(/\*\*Ask:\*\*\s*"([\s\S]*?)"/)
|
|
335
|
+
if (quoted?.[1]) return stripMarkdownInline(quoted[1])
|
|
336
|
+
|
|
337
|
+
const line = block.match(/\*\*Ask:\*\*\s*(.+)/)
|
|
338
|
+
if (line?.[1]) return stripMarkdownInline(line[1].replace(/^"|"$/g, ''))
|
|
339
|
+
|
|
340
|
+
return ''
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function slugifyFieldId(value, fallback) {
|
|
344
|
+
const slug = value
|
|
345
|
+
.toLowerCase()
|
|
346
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
347
|
+
.replace(/^_+|_+$/g, '')
|
|
348
|
+
.slice(0, 64)
|
|
349
|
+
return slug || fallback
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function deriveAskFieldsFromMarkdown(markdown) {
|
|
353
|
+
const questionHeadingRegex = /^#{2,6}\s+Q(\d+)\s*:\s*(.+?)\s*$/gm
|
|
354
|
+
const matches = [...markdown.matchAll(questionHeadingRegex)]
|
|
355
|
+
const fields = []
|
|
356
|
+
|
|
357
|
+
for (let i = 0; i < matches.length && fields.length < 12; i++) {
|
|
358
|
+
const current = matches[i]
|
|
359
|
+
const next = matches[i + 1]
|
|
360
|
+
const qNumber = current[1]
|
|
361
|
+
const title = stripMarkdownInline(current[2] ?? 'Question ' + (fields.length + 1))
|
|
362
|
+
const blockStart = (current.index ?? 0) + current[0].length
|
|
363
|
+
const blockEnd = next?.index ?? markdown.length
|
|
364
|
+
const ask = extractAskLine(markdown.slice(blockStart, blockEnd))
|
|
365
|
+
if (!ask) continue
|
|
366
|
+
fields.push({
|
|
367
|
+
id: slugifyFieldId('q' + qNumber + '_' + title, 'q' + (fields.length + 1)),
|
|
368
|
+
kind: 'textarea',
|
|
369
|
+
label: 'Q' + qNumber + ': ' + title,
|
|
370
|
+
placeholder: ask,
|
|
371
|
+
required: true,
|
|
372
|
+
maxLength: 2000,
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (fields.length > 0) return fields
|
|
377
|
+
|
|
378
|
+
const askLines = [...markdown.matchAll(/\*\*Ask:\*\*\s*"?(.+?)"?\s*$/gm)]
|
|
379
|
+
for (let i = 0; i < askLines.length && fields.length < 12; i++) {
|
|
380
|
+
const ask = stripMarkdownInline(askLines[i][1] ?? '')
|
|
381
|
+
if (!ask) continue
|
|
382
|
+
fields.push({
|
|
383
|
+
id: 'q' + (i + 1),
|
|
384
|
+
kind: 'textarea',
|
|
385
|
+
label: 'Q' + (i + 1),
|
|
386
|
+
placeholder: ask,
|
|
387
|
+
required: true,
|
|
388
|
+
maxLength: 2000,
|
|
389
|
+
})
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return fields
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function inferInteractionFromMarkdown(command, inferInteractions) {
|
|
396
|
+
if (!inferInteractions || !command.body) return undefined
|
|
397
|
+
const fields = deriveAskFieldsFromMarkdown(command.body)
|
|
398
|
+
if (fields.length < 2) return undefined
|
|
399
|
+
|
|
400
|
+
return {
|
|
401
|
+
id: 'slash:' + (command.packId ?? 'pack') + ':' + command.name + ':auto-form',
|
|
402
|
+
kind: 'form',
|
|
403
|
+
prompt:
|
|
404
|
+
command.description ?? '/' + command.name + ' needs a few answers before the Buddy can continue.',
|
|
405
|
+
oneShot: true,
|
|
406
|
+
responsePrompt:
|
|
407
|
+
'Use the submitted values as answers to this slash command, then continue from the source command definition. Produce the requested artifact before asking for approval.',
|
|
408
|
+
fields,
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function deriveAliasCandidates(name, packId) {
|
|
413
|
+
const candidates = new Set()
|
|
414
|
+
let base = name
|
|
415
|
+
|
|
416
|
+
if (packId && base.startsWith(packId + '-')) {
|
|
417
|
+
base = base.slice(packId.length + 1)
|
|
418
|
+
if (normalizeSlashCommandName(base)) candidates.add(base)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
for (const prefix of ['openclaw-', 'claude-', 'claude-code-', 'codex-', 'cursor-']) {
|
|
422
|
+
if (base.startsWith(prefix)) {
|
|
423
|
+
const stripped = base.slice(prefix.length)
|
|
424
|
+
if (normalizeSlashCommandName(stripped)) candidates.add(stripped)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
for (const candidate of [...candidates]) {
|
|
429
|
+
if (candidate.endsWith('-hours')) candidates.add(candidate.replace(/-hours$/, '-hour'))
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return [...candidates].filter((alias) => alias.toLowerCase() !== name.toLowerCase())
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function addInferredAliases(command, context) {
|
|
436
|
+
const aliases = new Set(command.aliases ?? [])
|
|
437
|
+
for (const alias of deriveAliasCandidates(command.name, context.packId)) aliases.add(alias)
|
|
438
|
+
if (aliases.size > 0) command.aliases = [...aliases]
|
|
439
|
+
return command
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const SCRIPT_EXTENSIONS = new Set(['', '.sh', '.bash', '.js', '.mjs', '.cjs', '.py', '.rb', '.pl'])
|
|
443
|
+
const SCRIPT_EXCLUDED_EXTENSIONS = new Set([
|
|
444
|
+
'.ts',
|
|
445
|
+
'.tsx',
|
|
446
|
+
'.json',
|
|
447
|
+
'.md',
|
|
448
|
+
'.mdx',
|
|
449
|
+
'.txt',
|
|
450
|
+
'.png',
|
|
451
|
+
'.jpg',
|
|
452
|
+
'.jpeg',
|
|
453
|
+
'.gif',
|
|
454
|
+
'.svg',
|
|
455
|
+
'.icns',
|
|
456
|
+
'.map',
|
|
457
|
+
'.lock',
|
|
458
|
+
])
|
|
459
|
+
const SCRIPT_EXCLUDED_NAMES = new Set([
|
|
460
|
+
'package.json',
|
|
461
|
+
'package-lock.json',
|
|
462
|
+
'pnpm-lock.yaml',
|
|
463
|
+
'yarn.lock',
|
|
464
|
+
'bun.lockb',
|
|
465
|
+
])
|
|
466
|
+
|
|
467
|
+
function readScriptHead(path) {
|
|
468
|
+
try {
|
|
469
|
+
return readFileSync(path, 'utf-8').slice(0, 12000)
|
|
470
|
+
} catch {
|
|
471
|
+
return ''
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function isLikelyScript(path) {
|
|
476
|
+
const name = basename(path)
|
|
477
|
+
if (!name || name.startsWith('.') || SCRIPT_EXCLUDED_NAMES.has(name)) return false
|
|
478
|
+
const ext = extname(name).toLowerCase()
|
|
479
|
+
if (SCRIPT_EXCLUDED_EXTENSIONS.has(ext)) return false
|
|
480
|
+
if (!SCRIPT_EXTENSIONS.has(ext)) return false
|
|
481
|
+
|
|
482
|
+
try {
|
|
483
|
+
const stat = statSync(path)
|
|
484
|
+
if (!stat.isFile() || stat.size <= 0 || stat.size > 512 * 1024) return false
|
|
485
|
+
} catch {
|
|
486
|
+
return false
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (ext === '') return true
|
|
490
|
+
const head = readScriptHead(path)
|
|
491
|
+
return head.startsWith('#!') || /(^|\n)\s*(Usage:|USAGE:|export\s+default|if\s+\(__name__\s*==)/.test(head)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function commandNameFromScriptPath(path) {
|
|
495
|
+
const ext = extname(path)
|
|
496
|
+
const raw = ext ? basename(path, ext) : basename(path)
|
|
497
|
+
const normalized = raw.replace(/[^A-Za-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '')
|
|
498
|
+
return normalizeSlashCommandName(normalized)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function deriveScriptDescription(path, packId) {
|
|
502
|
+
const head = readScriptHead(path)
|
|
503
|
+
const lines = head.split('\n').slice(0, 60)
|
|
504
|
+
for (const rawLine of lines) {
|
|
505
|
+
const line = rawLine
|
|
506
|
+
.replace(/^#!.*$/, '')
|
|
507
|
+
.replace(/^\s*(#|\/\/)\s?/, '')
|
|
508
|
+
.trim()
|
|
509
|
+
if (!line) continue
|
|
510
|
+
if (/^(usage|env overrides?|set -|shellcheck|eslint|biome)/i.test(line)) continue
|
|
511
|
+
return stripMarkdownInline(line).slice(0, 180)
|
|
512
|
+
}
|
|
513
|
+
return 'Run a helper script from the ' + packId + ' agent pack.'
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function scriptSkillMarkdown(params) {
|
|
517
|
+
const rel = params.relPath
|
|
518
|
+
const description = params.description
|
|
519
|
+
const path = params.path
|
|
520
|
+
return [
|
|
521
|
+
'---',
|
|
522
|
+
'name: ' + JSON.stringify(params.name),
|
|
523
|
+
'description: ' + JSON.stringify(description),
|
|
524
|
+
'---',
|
|
525
|
+
'',
|
|
526
|
+
'# ' + params.name,
|
|
527
|
+
'',
|
|
528
|
+
'This capability is backed by a mounted helper script from the ' + params.packId + ' agent pack.',
|
|
529
|
+
'',
|
|
530
|
+
'- Script path: ' + path,
|
|
531
|
+
'- Pack script: ' + rel,
|
|
532
|
+
'',
|
|
533
|
+
'When this skill is relevant:',
|
|
534
|
+
'',
|
|
535
|
+
'1. Inspect usage first by running the script with --help, or read the script if help is not supported.',
|
|
536
|
+
'2. Run the script with explicit user-provided arguments, using the absolute script path above.',
|
|
537
|
+
'3. Summarize stdout, stderr, exit status, and any files created or changed.',
|
|
538
|
+
'4. For destructive, credentialed, long-running, or network-heavy actions, explain the exact action before running it unless the user explicitly requested that action.',
|
|
539
|
+
].join('\n')
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function discoverPackDirs(mountPath) {
|
|
543
|
+
return listChildDirs(mountPath).filter((packDir) => !packDir.endsWith('/.shadow'))
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function discoverPackScripts(packDir, maxPerPack) {
|
|
547
|
+
const scriptsDir = join(packDir, 'scripts')
|
|
548
|
+
if (!existsSync(scriptsDir)) return []
|
|
549
|
+
const seenNames = new Set()
|
|
550
|
+
const scripts = []
|
|
551
|
+
for (const path of listFilesRecursive(scriptsDir, 4)) {
|
|
552
|
+
if (!isLikelyScript(path)) continue
|
|
553
|
+
const name = commandNameFromScriptPath(path)
|
|
554
|
+
if (!name || seenNames.has(name.toLowerCase())) continue
|
|
555
|
+
seenNames.add(name.toLowerCase())
|
|
556
|
+
scripts.push({
|
|
557
|
+
name,
|
|
558
|
+
path,
|
|
559
|
+
relPath: relative(scriptsDir, path),
|
|
560
|
+
})
|
|
561
|
+
if (scripts.length >= maxPerPack) break
|
|
562
|
+
}
|
|
563
|
+
return scripts
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function generateScriptSkillWrappers(mountPath, options) {
|
|
567
|
+
if (!options.includeScripts || !options.generateScriptSkills) return
|
|
568
|
+
for (const packDir of discoverPackDirs(mountPath)) {
|
|
569
|
+
const packId = basename(packDir)
|
|
570
|
+
const skillsDir = join(packDir, 'skills')
|
|
571
|
+
mkdirSync(skillsDir, { recursive: true })
|
|
572
|
+
|
|
573
|
+
for (const script of discoverPackScripts(packDir, options.maxScriptCommandsPerPack)) {
|
|
574
|
+
const skillDir = join(skillsDir, script.name)
|
|
575
|
+
const skillPath = join(skillDir, 'SKILL.md')
|
|
576
|
+
if (existsSync(skillPath)) continue
|
|
577
|
+
const description = deriveScriptDescription(script.path, packId)
|
|
578
|
+
mkdirSync(skillDir, { recursive: true })
|
|
579
|
+
writeFileSync(
|
|
580
|
+
skillPath,
|
|
581
|
+
scriptSkillMarkdown({
|
|
582
|
+
...script,
|
|
583
|
+
packId,
|
|
584
|
+
description,
|
|
585
|
+
}),
|
|
586
|
+
'utf-8',
|
|
587
|
+
)
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function discoverScriptCommands(mountPath, options) {
|
|
593
|
+
if (!options.includeScripts) return []
|
|
594
|
+
const commands = []
|
|
595
|
+
for (const packDir of discoverPackDirs(mountPath)) {
|
|
596
|
+
const packId = basename(packDir)
|
|
597
|
+
for (const script of discoverPackScripts(packDir, options.maxScriptCommandsPerPack)) {
|
|
598
|
+
const description = deriveScriptDescription(script.path, packId)
|
|
599
|
+
commands.push({
|
|
600
|
+
name: script.name,
|
|
601
|
+
description,
|
|
602
|
+
packId,
|
|
603
|
+
sourcePath: script.path,
|
|
604
|
+
body: scriptSkillMarkdown({
|
|
605
|
+
...script,
|
|
606
|
+
packId,
|
|
607
|
+
description,
|
|
608
|
+
}),
|
|
609
|
+
})
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return commands
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function readSlashCommand(path, fallbackName, options) {
|
|
616
|
+
const text = readMaybe(path).trim()
|
|
617
|
+
if (!text) return null
|
|
618
|
+
const { data, body } = parseFrontmatter(text)
|
|
619
|
+
const name = normalizeSlashCommandName(data.name ?? fallbackName)
|
|
620
|
+
if (!name) return null
|
|
621
|
+
const packId = derivePackId(path, options.mountPath)
|
|
622
|
+
const aliases = parseFrontmatterList(data.aliases)
|
|
623
|
+
.map(normalizeSlashCommandName)
|
|
624
|
+
.filter(Boolean)
|
|
625
|
+
.filter((alias) => alias.toLowerCase() !== name.toLowerCase())
|
|
626
|
+
const description = deriveSlashDescription(body, data)
|
|
627
|
+
const interaction = frontmatterInteraction(data)
|
|
628
|
+
|
|
629
|
+
let command = {
|
|
630
|
+
name,
|
|
631
|
+
...(description ? { description } : {}),
|
|
632
|
+
...(aliases.length > 0 ? { aliases: [...new Set(aliases)] } : {}),
|
|
633
|
+
...(packId ? { packId } : {}),
|
|
634
|
+
...(interaction ? { interaction } : {}),
|
|
635
|
+
sourcePath: path,
|
|
636
|
+
body: text.slice(0, 20000),
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
const context = { path, packId, body, frontmatter: data }
|
|
640
|
+
command = addInferredAliases(command, context)
|
|
641
|
+
command = applySlashCommandRules(command, context, options.rules)
|
|
642
|
+
|
|
643
|
+
if (!command.interaction) {
|
|
644
|
+
const inferred = inferInteractionFromMarkdown(command, options.inferInteractions)
|
|
645
|
+
if (inferred) command.interaction = inferred
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return command
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function discoverSlashCommands(commandsDirs, options) {
|
|
652
|
+
const commands = []
|
|
653
|
+
const seen = new Set()
|
|
654
|
+
for (const dir of commandsDirs) {
|
|
655
|
+
for (const file of listFiles(dir, '.md')) {
|
|
656
|
+
const fallbackName = file.split('/').pop().replace(/\.md$/, '')
|
|
657
|
+
const command = readSlashCommand(file, fallbackName, options)
|
|
658
|
+
if (!command) continue
|
|
659
|
+
const key = command.name.toLowerCase()
|
|
660
|
+
if (seen.has(key)) continue
|
|
661
|
+
seen.add(key)
|
|
662
|
+
commands.push(command)
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
for (const childDir of listChildDirs(dir)) {
|
|
666
|
+
const fallbackName = childDir.split('/').pop()
|
|
667
|
+
for (const candidate of ['SKILL.md', 'COMMAND.md', 'README.md']) {
|
|
668
|
+
const path = join(childDir, candidate)
|
|
669
|
+
if (!existsSync(path)) continue
|
|
670
|
+
const command = readSlashCommand(path, fallbackName, options)
|
|
671
|
+
if (!command) break
|
|
672
|
+
const key = command.name.toLowerCase()
|
|
673
|
+
if (!seen.has(key)) {
|
|
674
|
+
seen.add(key)
|
|
675
|
+
commands.push(command)
|
|
676
|
+
}
|
|
677
|
+
break
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
return commands.slice(0, 200)
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function commandDirsFromMountRoot(mountPath) {
|
|
685
|
+
const dirs = []
|
|
686
|
+
for (const packDir of listChildDirs(mountPath)) {
|
|
687
|
+
if (packDir.endsWith('/.shadow')) continue
|
|
688
|
+
for (const kind of ['commands', 'skills']) {
|
|
689
|
+
const dir = join(packDir, kind)
|
|
690
|
+
if (existsSync(dir)) dirs.push(dir)
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return [...new Set(dirs)]
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
const mountPath = readArg('--mount-path', '/agent-packs')
|
|
697
|
+
const output = readArg('--output', mountPath + '/.shadow/slash-commands.json')
|
|
698
|
+
const rulesRaw = readArg('--rules-json', '[]')
|
|
699
|
+
const inferInteractions = readArg('--infer-interactions', 'true') !== 'false'
|
|
700
|
+
const includeScripts = readArg('--include-scripts', 'true') !== 'false'
|
|
701
|
+
const generateScriptSkills = readArg('--generate-script-skills', 'true') !== 'false'
|
|
702
|
+
const maxScriptCommandsPerPack = Math.max(
|
|
703
|
+
0,
|
|
704
|
+
Number.parseInt(readArg('--max-script-commands-per-pack', '80'), 10) || 80,
|
|
705
|
+
)
|
|
706
|
+
let rules = []
|
|
707
|
+
try {
|
|
708
|
+
const parsed = JSON.parse(rulesRaw)
|
|
709
|
+
if (Array.isArray(parsed)) rules = parsed
|
|
710
|
+
} catch (err) {
|
|
711
|
+
console.warn('[agent-pack] Ignoring invalid slash command rules JSON: ' + err.message)
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const options = {
|
|
715
|
+
inferInteractions,
|
|
716
|
+
includeScripts,
|
|
717
|
+
generateScriptSkills,
|
|
718
|
+
maxScriptCommandsPerPack,
|
|
719
|
+
rules,
|
|
720
|
+
mountPath,
|
|
721
|
+
}
|
|
722
|
+
generateScriptSkillWrappers(mountPath, options)
|
|
723
|
+
|
|
724
|
+
const seenCommands = new Set()
|
|
725
|
+
const commands = [
|
|
726
|
+
...discoverSlashCommands(commandDirsFromMountRoot(mountPath), options),
|
|
727
|
+
...discoverScriptCommands(mountPath, options),
|
|
728
|
+
].filter((command) => {
|
|
729
|
+
const key = command.name.toLowerCase()
|
|
730
|
+
if (seenCommands.has(key)) return false
|
|
731
|
+
seenCommands.add(key)
|
|
732
|
+
return true
|
|
733
|
+
}).slice(0, 200)
|
|
734
|
+
mkdirSync(dirname(output), { recursive: true })
|
|
735
|
+
writeFileSync(output, JSON.stringify(commands, null, 2), 'utf-8')
|
|
736
|
+
console.log('[agent-pack] Wrote ' + commands.length + ' slash command(s) to ' + output)
|
|
737
|
+
`;
|
|
738
|
+
|
|
739
|
+
export {
|
|
740
|
+
AGENT_PACK_SLASH_INDEXER_SCRIPT
|
|
741
|
+
};
|