shadow-claw 1.26.0 → 1.27.0
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/.agents/skills/main/skill-creator/SKILL.md +39 -0
- package/.agents/skills/main/skill-creator/references/declarative-pipelines.md +44 -0
- package/.agents/skills/main/skill-creator/references/declarative-tools.md +35 -0
- package/.agents/skills/main/skill-creator/references/frontmatter-spec.md +50 -0
- package/.well-known/agent-skills/index.json +14 -0
- package/README.md +5 -3
- package/bin/build/build.mjs +146 -15
- package/bin/build/build.test.mjs +57 -0
- package/bin/cli.mjs +26 -0
- package/bin/commands/mcp.mjs +277 -55
- package/bin/commands/mcp.test.mjs +275 -1
- package/bin/commands/skills-index.mjs +328 -0
- package/bin/commands/skills-index.test.mjs +161 -0
- package/bin/site-config/utils/custom-elements/get-approved-custom-element-scripts.test.mjs +2 -0
- package/bin/site-config/utils/custom-elements/sanitize-embedded-custom-element-scripts.test.mjs +10 -1
- package/dist/lib/components/index.js +25 -25
- package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
- package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/settings/shadow-claw-git.js +1 -1
- package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
- package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
- package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
- package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
- package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
- package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw-a2ui.js +1 -1
- package/dist/lib/components/shadow-claw-accounts.js +1 -1
- package/dist/lib/components/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/shadow-claw-channels.js +1 -1
- package/dist/lib/components/shadow-claw-chat.js +1 -1
- package/dist/lib/components/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/shadow-claw-conversations.js +1 -1
- package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
- package/dist/lib/components/shadow-claw-files.js +1 -1
- package/dist/lib/components/shadow-claw-git.js +1 -1
- package/dist/lib/components/shadow-claw-integrations.js +1 -1
- package/dist/lib/components/shadow-claw-llm.js +1 -1
- package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
- package/dist/lib/components/shadow-claw-networking.js +1 -1
- package/dist/lib/components/shadow-claw-page-header.js +1 -1
- package/dist/lib/components/shadow-claw-pages.js +1 -1
- package/dist/lib/components/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/shadow-claw-settings.js +1 -1
- package/dist/lib/components/shadow-claw-storage.js +1 -1
- package/dist/lib/components/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/shadow-claw-tasks.js +1 -1
- package/dist/lib/components/shadow-claw-terminal.js +1 -1
- package/dist/lib/components/shadow-claw-tools.js +1 -1
- package/dist/lib/components/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw.js +1 -1
- package/dist/lib/{configurePeerJs-CrlGan0m.js → configurePeerJs-oODzltaC.js} +2 -2
- package/dist/lib/{configurePeerJs-CrlGan0m.js.map → configurePeerJs-oODzltaC.js.map} +1 -1
- package/dist/lib/core/control-plane-client.d.ts +1 -0
- package/dist/lib/{downloadGroupFile-DboUjmp2.js → downloadGroupFile-DmcBQU1n.js} +2 -2
- package/dist/lib/{downloadGroupFile-DboUjmp2.js.map → downloadGroupFile-DmcBQU1n.js.map} +1 -1
- package/dist/lib/{file-viewer-BrK2Wxgh.js → file-viewer-C3YKnq_-.js} +4 -3
- package/dist/lib/{file-viewer-BrK2Wxgh.js.map → file-viewer-C3YKnq_-.js.map} +1 -1
- package/dist/lib/index.js +26 -26
- package/dist/lib/{initControlPlane-CsO4UR6_.js → initControlPlane-C2zURVIS.js} +86 -13
- package/dist/lib/initControlPlane-C2zURVIS.js.map +1 -0
- package/dist/lib/{markdown-eeSTFnMA.js → markdown-C6EHl9zs.js} +3 -3
- package/dist/lib/{markdown-eeSTFnMA.js.map → markdown-C6EHl9zs.js.map} +1 -1
- package/dist/lib/{orchestrator-CJvoC2Uu.js → orchestrator-CACLa_Ro.js} +7 -6
- package/dist/lib/{orchestrator-CJvoC2Uu.js.map → orchestrator-CACLa_Ro.js.map} +1 -1
- package/dist/lib/{orchestrator-DCfomsn9.js → orchestrator-KRjx0eba.js} +6 -534
- package/dist/lib/{orchestrator-DCfomsn9.js.map → orchestrator-KRjx0eba.js.map} +1 -1
- package/dist/lib/parsePath-DwC_YZjw.js +16 -0
- package/dist/lib/parsePath-DwC_YZjw.js.map +1 -0
- package/dist/lib/{peerjs-Dp02bXcG.js → peerjs-DFWOBcXf.js} +4 -4
- package/dist/lib/{peerjs-Dp02bXcG.js.map → peerjs-DFWOBcXf.js.map} +1 -1
- package/dist/lib/{readGroupFileBytes-Bve-e5e_.js → readGroupFileBytes-C8oOe8Iu.js} +3 -16
- package/dist/lib/readGroupFileBytes-C8oOe8Iu.js.map +1 -0
- package/dist/lib/security/custom-element-security.d.ts +8 -0
- package/dist/lib/server/control-plane-types.d.ts +1 -1
- package/dist/lib/{shadow-claw-D8xINM3c.js → shadow-claw-6UHdiy4a.js} +5 -5
- package/dist/lib/{shadow-claw-D8xINM3c.js.map → shadow-claw-6UHdiy4a.js.map} +1 -1
- package/dist/lib/{shadow-claw-a2ui-7rJqG4Ke.js → shadow-claw-a2ui-CpZUTzlh.js} +5 -4
- package/dist/lib/{shadow-claw-a2ui-7rJqG4Ke.js.map → shadow-claw-a2ui-CpZUTzlh.js.map} +1 -1
- package/dist/lib/{shadow-claw-accounts-CdruwN8A.js → shadow-claw-accounts-03oJ__XC.js} +2 -2
- package/dist/lib/{shadow-claw-accounts-CdruwN8A.js.map → shadow-claw-accounts-03oJ__XC.js.map} +1 -1
- package/dist/lib/{shadow-claw-channel-config-Bj0-Nk3t.js → shadow-claw-channel-config-DmfwJc6G.js} +3 -3
- package/dist/lib/{shadow-claw-channel-config-Bj0-Nk3t.js.map → shadow-claw-channel-config-DmfwJc6G.js.map} +1 -1
- package/dist/lib/{shadow-claw-channels-C_jI4KhP.js → shadow-claw-channels-1N6Jl-By.js} +3 -3
- package/dist/lib/{shadow-claw-channels-C_jI4KhP.js.map → shadow-claw-channels-1N6Jl-By.js.map} +1 -1
- package/dist/lib/{shadow-claw-chat-B16MspoP.js → shadow-claw-chat-BMoqQJRK.js} +10 -10
- package/dist/lib/{shadow-claw-chat-B16MspoP.js.map → shadow-claw-chat-BMoqQJRK.js.map} +1 -1
- package/dist/lib/{shadow-claw-control-plane-x8Ldid_h.js → shadow-claw-control-plane-UG0o7pCz.js} +6 -6
- package/dist/lib/{shadow-claw-control-plane-x8Ldid_h.js.map → shadow-claw-control-plane-UG0o7pCz.js.map} +1 -1
- package/dist/lib/{shadow-claw-conversations-Ct1kAYdB.js → shadow-claw-conversations-BwXep3iu.js} +4 -3
- package/dist/lib/{shadow-claw-conversations-Ct1kAYdB.js.map → shadow-claw-conversations-BwXep3iu.js.map} +1 -1
- package/dist/lib/{shadow-claw-file-viewer-BfDHHgpA.js → shadow-claw-file-viewer-DUxzVxDT.js} +14 -10
- package/dist/lib/shadow-claw-file-viewer-DUxzVxDT.js.map +1 -0
- package/dist/lib/{shadow-claw-files-EYhOPYIH.js → shadow-claw-files-DIREEnT2.js} +7 -7
- package/dist/lib/{shadow-claw-files-EYhOPYIH.js.map → shadow-claw-files-DIREEnT2.js.map} +1 -1
- package/dist/lib/{shadow-claw-git-tcSpT-P0.js → shadow-claw-git-Bg1SWgsF.js} +4 -4
- package/dist/lib/{shadow-claw-git-tcSpT-P0.js.map → shadow-claw-git-Bg1SWgsF.js.map} +1 -1
- package/dist/lib/{shadow-claw-integrations-NbcCx_ZI.js → shadow-claw-integrations-Ds-CLPhj.js} +2 -2
- package/dist/lib/{shadow-claw-integrations-NbcCx_ZI.js.map → shadow-claw-integrations-Ds-CLPhj.js.map} +1 -1
- package/dist/lib/{shadow-claw-llm-BazJdD5f.js → shadow-claw-llm-CazBrVpM.js} +3 -3
- package/dist/lib/{shadow-claw-llm-BazJdD5f.js.map → shadow-claw-llm-CazBrVpM.js.map} +1 -1
- package/dist/lib/{shadow-claw-mcp-remote-CYmhpg7a.js → shadow-claw-mcp-remote-CT5Q-54E.js} +2 -2
- package/dist/lib/{shadow-claw-mcp-remote-CYmhpg7a.js.map → shadow-claw-mcp-remote-CT5Q-54E.js.map} +1 -1
- package/dist/lib/{shadow-claw-networking-DImPxe0H.js → shadow-claw-networking-Df85tCbO.js} +2 -2
- package/dist/lib/{shadow-claw-networking-DImPxe0H.js.map → shadow-claw-networking-Df85tCbO.js.map} +1 -1
- package/dist/lib/{shadow-claw-page-header-CcHUfFUx.js → shadow-claw-page-header-Cti2fzf-.js} +2 -2
- package/dist/lib/{shadow-claw-page-header-CcHUfFUx.js.map → shadow-claw-page-header-Cti2fzf-.js.map} +1 -1
- package/dist/lib/{shadow-claw-pages-D54jF1Qq.js → shadow-claw-pages-BgPyIEZO.js} +15 -11
- package/dist/lib/shadow-claw-pages-BgPyIEZO.js.map +1 -0
- package/dist/lib/{shadow-claw-peerjs-B9-T8Nlx.js → shadow-claw-peerjs-xkBXILed.js} +3 -3
- package/dist/lib/{shadow-claw-peerjs-B9-T8Nlx.js.map → shadow-claw-peerjs-xkBXILed.js.map} +1 -1
- package/dist/lib/{shadow-claw-settings-Bt1VAe-1.js → shadow-claw-settings-CN89xRVU.js} +4 -4
- package/dist/lib/{shadow-claw-settings-Bt1VAe-1.js.map → shadow-claw-settings-CN89xRVU.js.map} +1 -1
- package/dist/lib/{shadow-claw-storage-CFOjGf1d.js → shadow-claw-storage-VnhcObCe.js} +3 -3
- package/dist/lib/{shadow-claw-storage-CFOjGf1d.js.map → shadow-claw-storage-VnhcObCe.js.map} +1 -1
- package/dist/lib/{shadow-claw-task-server-BiKa2GOm.js → shadow-claw-task-server-jgEC2hHB.js} +2 -2
- package/dist/lib/{shadow-claw-task-server-BiKa2GOm.js.map → shadow-claw-task-server-jgEC2hHB.js.map} +1 -1
- package/dist/lib/{shadow-claw-tasks-DDHd8W4d.js → shadow-claw-tasks-i_evIufy.js} +6 -6
- package/dist/lib/{shadow-claw-tasks-DDHd8W4d.js.map → shadow-claw-tasks-i_evIufy.js.map} +1 -1
- package/dist/lib/{shadow-claw-terminal-kB6_tWKz.js → shadow-claw-terminal-CwScROlu.js} +2 -2
- package/dist/lib/{shadow-claw-terminal-kB6_tWKz.js.map → shadow-claw-terminal-CwScROlu.js.map} +1 -1
- package/dist/lib/{shadow-claw-tools-DxXIm0ku.js → shadow-claw-tools-DD3fyXP4.js} +5 -4
- package/dist/lib/{shadow-claw-tools-DxXIm0ku.js.map → shadow-claw-tools-DD3fyXP4.js.map} +1 -1
- package/dist/lib/{shadow-claw-webvm-Dc8oo7ao.js → shadow-claw-webvm-DbJq4I3-.js} +2 -2
- package/dist/lib/{shadow-claw-webvm-Dc8oo7ao.js.map → shadow-claw-webvm-DbJq4I3-.js.map} +1 -1
- package/dist/lib/{syncWebMcpRegistration-jyRGbC9w.js → syncWebMcpRegistration-DNLnQ-jz.js} +3 -2
- package/dist/lib/{syncWebMcpRegistration-jyRGbC9w.js.map → syncWebMcpRegistration-DNLnQ-jz.js.map} +1 -1
- package/dist/lib/tools-DwwB9RBa.js +546 -0
- package/dist/lib/tools-DwwB9RBa.js.map +1 -0
- package/dist/lib/{trusted-types-CkLDpLiZ.js → trusted-types-Dx0RZlrd.js} +19 -8
- package/dist/lib/trusted-types-Dx0RZlrd.js.map +1 -0
- package/dist/lib/utils/index.js +1 -1
- package/dist/lib/utils/utils.js +1 -1
- package/dist/public/.well-known/agent-skills/index.json +14 -0
- package/dist/public/AGENTS.md +5 -3
- package/dist/public/README.md +5 -3
- package/dist/public/agent.worker.js +1 -1
- package/dist/public/{configurePeerJs-COcwE0E7.js → configurePeerJs-BqgeBjP7.js} +1 -1
- package/dist/public/custom-element-security-FU04Cq05.js +1 -0
- package/dist/public/dist-B9m1QM9v.js +58 -0
- package/dist/public/docs/README.md +31 -31
- package/dist/public/docs/example/article/index.html +1 -1
- package/dist/public/docs/publishing/index.html +1 -1
- package/dist/public/docs/skill-creator/index.html +1 -1
- package/dist/public/docs/subsystems/a2ui.md +11 -1
- package/dist/public/docs/subsystems/cli.md +29 -0
- package/dist/public/docs/subsystems/control-plane.md +8 -2
- package/dist/public/docs/subsystems/custom-element-security.md +19 -9
- package/dist/public/docs/subsystems/mcp-server.md +39 -15
- package/dist/public/docs/subsystems/skills.md +30 -0
- package/dist/public/docs/subsystems/webmcp.md +9 -0
- package/dist/public/downloadGroupFile-D8KRJGGL.js +1 -0
- package/dist/public/e2e/README.md +7 -4
- package/dist/public/{e2e-bridge-CHARpbpW.js → e2e-bridge-Ceqr5kGc.js} +1 -1
- package/dist/public/effect-BJCrpFdp.js +1 -0
- package/dist/public/file-viewer-C-6Jc_tb.js +1 -0
- package/dist/public/index.html +1 -1
- package/dist/public/index.js +1 -1
- package/dist/public/initControlPlane-BN9cWyO0.js +1 -0
- package/dist/public/main/index.html +1 -1
- package/dist/public/main/memory/index.html +1 -1
- package/dist/public/{markdown-1I3O6Mmd.js → markdown-C3M4OW_A.js} +1 -1
- package/dist/public/{orchestrator-Cl95w2vb.js → orchestrator-CMbCTjBf.js} +7 -7
- package/dist/public/{orchestrator-D-xlXG92.js → orchestrator-DHjdLtqa.js} +663 -663
- package/dist/public/peerjs-DUCKH-m9.js +1 -0
- package/dist/public/service-worker.js +1 -1
- package/dist/public/{shadow-claw-CaoKmIIB.js → shadow-claw-EAt2ml5Y.js} +3 -3
- package/dist/public/{shadow-claw-accounts-CJvYC4li.js → shadow-claw-accounts-xUOLBsQZ.js} +1 -1
- package/dist/public/{shadow-claw-channels-3K62sU5f.js → shadow-claw-channels-XsfuWFF8.js} +4 -4
- package/dist/public/{shadow-claw-chat-Cu2keU2I.js → shadow-claw-chat-CbSaOZ4q.js} +7 -7
- package/dist/public/{shadow-claw-control-plane-D1OwlQI_.js → shadow-claw-control-plane-DHvN3Ukg.js} +2 -2
- package/dist/public/{shadow-claw-conversations-DDtg3BEZ.js → shadow-claw-conversations-BWs5VVfs.js} +2 -2
- package/dist/public/{shadow-claw-file-viewer-BR__1z9S.js → shadow-claw-file-viewer-BWsoW5QS.js} +5 -4
- package/dist/public/{shadow-claw-files-BJSyZ-Bl.js → shadow-claw-files-CG7MqWiV.js} +8 -8
- package/dist/public/{shadow-claw-git-MAjhXRLc.js → shadow-claw-git-DBRPZNav.js} +6 -6
- package/dist/public/{shadow-claw-integrations-82UoFuDR.js → shadow-claw-integrations-BBVnO0Fc.js} +8 -8
- package/dist/public/{shadow-claw-llm-R8j0lwPP.js → shadow-claw-llm-DMvLgKXo.js} +2 -2
- package/dist/public/{shadow-claw-mcp-remote-BzZoz4LX.js → shadow-claw-mcp-remote-Bkx0gsmF.js} +2 -2
- package/dist/public/{shadow-claw-networking-DLEd9cNm.js → shadow-claw-networking-Dd8Rw31D.js} +2 -2
- package/dist/public/{shadow-claw-notifications-1vwR7TbT.js → shadow-claw-notifications-Dbevj-lq.js} +2 -2
- package/dist/public/{shadow-claw-page-header-DMKbkv3s.js → shadow-claw-page-header-BccSHItx.js} +1 -1
- package/dist/public/{shadow-claw-pages-CjyeIV__.js → shadow-claw-pages-3_lQAv0t.js} +4 -3
- package/dist/public/{shadow-claw-settings-BfbT4dBU.js → shadow-claw-settings-t8TIlgrM.js} +5 -5
- package/dist/public/{shadow-claw-storage-C-mWQQML.js → shadow-claw-storage-CfEXoSIE.js} +2 -2
- package/dist/public/{shadow-claw-task-server-D3lHp0Nc.js → shadow-claw-task-server-DxQSsgRZ.js} +2 -2
- package/dist/public/{shadow-claw-tasks-DVVWEm-c.js → shadow-claw-tasks-DNpicQwz.js} +14 -14
- package/dist/public/{shadow-claw-terminal-BwuTRp-O.js → shadow-claw-terminal-DpY6zU_r.js} +1 -1
- package/dist/public/{shadow-claw-toast-ClCwgzFG.js → shadow-claw-toast-BkrQIP-3.js} +1 -1
- package/dist/public/{shadow-claw-tools-zFLk2nbV.js → shadow-claw-tools-WSwWohnk.js} +2 -2
- package/dist/public/{shadow-claw-webvm-qR9X7fg7.js → shadow-claw-webvm-CP6oFjg5.js} +2 -2
- package/dist/public/syncWebMcpRegistration-DOn9gLnD.js +1 -0
- package/dist/public/toast-BXgUfbyh.js +1 -0
- package/dist/public/tools-DvckJZG2.js +1 -0
- package/dist/server.js +188 -188
- package/package.json +3 -1
- package/src/components/shadow-claw-a2ui/shadow-claw-a2ui.stories.ts +1380 -93
- package/src/components/shadow-claw-a2ui/shadow-claw-a2ui.ts +11 -6
- package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.test.ts +8 -1
- package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.ts +13 -5
- package/src/components/shadow-claw-pages/utils/buildHtmlPageSrcdoc.ts +13 -5
- package/src/core/control-plane-client.ts +15 -0
- package/src/core/utils/initControlPlane.test.ts +187 -0
- package/src/core/utils/initControlPlane.ts +194 -20
- package/src/security/custom-element-security.test.ts +51 -0
- package/src/security/custom-element-security.ts +33 -15
- package/src/server/control-plane-types.ts +1 -0
- package/src/server/control-plane.test.ts +69 -0
- package/src/server/control-plane.ts +45 -3
- package/src/server/mcp/tools/built-in-tools.ts +80 -5
- package/src/server/mcp/tools/client-tool-relay.ts +183 -26
- package/src/server/mcp/tools/mcp-tools.test.ts +140 -0
- package/src/server/middleware/static-files.test.ts +142 -0
- package/src/server/middleware/static-files.ts +66 -8
- package/src/testing/jest-setup.ts +1 -0
- package/src/worker/utils/handleMessage.ts +4 -1
- package/dist/lib/initControlPlane-CsO4UR6_.js.map +0 -1
- package/dist/lib/readGroupFileBytes-Bve-e5e_.js.map +0 -1
- package/dist/lib/shadow-claw-file-viewer-BfDHHgpA.js.map +0 -1
- package/dist/lib/shadow-claw-pages-D54jF1Qq.js.map +0 -1
- package/dist/lib/trusted-types-CkLDpLiZ.js.map +0 -1
- package/dist/public/custom-element-security-NCqQ5lmC.js +0 -1
- package/dist/public/downloadGroupFile-G0BZQgQg.js +0 -1
- package/dist/public/effect-rHYr4nfu.js +0 -1
- package/dist/public/file-viewer-8PdCURDD.js +0 -1
- package/dist/public/initControlPlane-CcGXax0A.js +0 -1
- package/dist/public/peerjs-BZdxWQFv.js +0 -1
- package/dist/public/syncWebMcpRegistration-DD42YsYV.js +0 -1
- package/dist/public/toast-HAq8XWFj.js +0 -58
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-creator
|
|
3
|
+
description: Create, edit, review, and validate ShadowClaw declarative skills and their supporting resources.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
metadata:
|
|
6
|
+
allowed-tools: read_file write_file javascript create_directory
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# ShadowClaw Skill Creator
|
|
10
|
+
|
|
11
|
+
Use this skill when creating, modifying, reviewing, or validating a ShadowClaw agent skill or declarative tool pipeline.
|
|
12
|
+
|
|
13
|
+
## Workspace Layout Standards
|
|
14
|
+
|
|
15
|
+
- **Skills**: Create each skill in its dedicated directory under `.agents/skills/<group>/<skill-name>/SKILL.md` (default group: `main`).
|
|
16
|
+
- **Declarative Tools**: Define supporting declarative tools under `.agents/tools/<group>/<tool-name>.json` (default group: `main`).
|
|
17
|
+
- **Supporting Resources**: Co-locate skill-specific assets (reference documents, templates, helper scripts) inside the skill directory alongside `SKILL.md`.
|
|
18
|
+
|
|
19
|
+
## Workflow
|
|
20
|
+
|
|
21
|
+
1. **Establish Contract & Scope**
|
|
22
|
+
- For existing skills, read `SKILL.md` and related resources before editing.
|
|
23
|
+
- For new skills, define the trigger prompt, intended execution outcome, required tools, and output artifacts.
|
|
24
|
+
2. **Configure Frontmatter**
|
|
25
|
+
- Provide a clear, concise trigger description in `description` (1024 characters max).
|
|
26
|
+
- Set `user-invocable: true` if the skill should be triggerable via slash command (e.g. `/skill-name`).
|
|
27
|
+
- Use `disable-model-invocation: true` for skills intended strictly for slash-command execution.
|
|
28
|
+
- Place non-standard configuration (such as `allowed-tools`) within the standard `metadata` block to maintain Agent Skills specification compliance.
|
|
29
|
+
3. **Structure & Draft Content**
|
|
30
|
+
- Write instructions in `SKILL.md` using clear, modular procedures.
|
|
31
|
+
- Place deterministic operations in `javascript` tool calls; use `read_file` and `write_file` for workspace persistence.
|
|
32
|
+
- Create required target directories via `create_directory` prior to writing files.
|
|
33
|
+
4. **Declarative Pipelines (`execution.type: tools`)**
|
|
34
|
+
- Define sequential tool pipelines in frontmatter via `execution: { type: "tools", tools: [...] }`.
|
|
35
|
+
- Pass outputs between steps using `{ "$pipe": "prev" }` or step/tool identifiers.
|
|
36
|
+
- Optionally apply `suppressToast: true` or `suppressOutput: true` at the execution root or per step to suppress notifications and output blocks.
|
|
37
|
+
5. **Verify & Validate**
|
|
38
|
+
- Re-read the saved `SKILL.md` and verify valid YAML frontmatter syntax.
|
|
39
|
+
- Ensure the skill name uses 1–64 lowercase alphanumeric characters or hyphens and all referenced resource paths exist.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Declarative Execution Pipelines
|
|
2
|
+
|
|
3
|
+
Declarative execution pipelines allow skills to execute deterministic sequential tool chains directly on the worker thread without scheduling a Task or making model LLM calls.
|
|
4
|
+
|
|
5
|
+
## Configuration Syntax
|
|
6
|
+
|
|
7
|
+
Pipelines are declared in `SKILL.md` frontmatter under `metadata.execution`:
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
---
|
|
11
|
+
name: sample-pipeline
|
|
12
|
+
description: Run a deterministic tool chain.
|
|
13
|
+
user-invocable: true
|
|
14
|
+
metadata:
|
|
15
|
+
allowed-tools: javascript show_toast
|
|
16
|
+
execution:
|
|
17
|
+
type: tools
|
|
18
|
+
suppressToast: true
|
|
19
|
+
suppressOutput: true
|
|
20
|
+
tools:
|
|
21
|
+
- name: javascript
|
|
22
|
+
input:
|
|
23
|
+
code: "Math.floor(Math.random() * 100) + 1"
|
|
24
|
+
- name: show_toast
|
|
25
|
+
input:
|
|
26
|
+
title: "Random Number"
|
|
27
|
+
message:
|
|
28
|
+
$pipe: prev
|
|
29
|
+
---
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Data Piping (`$pipe`)
|
|
33
|
+
|
|
34
|
+
Inputs in tool step configurations can reference outputs from previous steps using the `$pipe` operator:
|
|
35
|
+
|
|
36
|
+
- `{ "$pipe": "prev" }` or `{ "$pipe": -1 }`: Resolves to the return output of the immediately preceding tool step.
|
|
37
|
+
- `{ "$pipe": 0 }`: Resolves to the return output of step index `0` (0-indexed).
|
|
38
|
+
- `{ "$pipe": "javascript" }`: Resolves to the return output of the last step that ran the `javascript` tool.
|
|
39
|
+
|
|
40
|
+
## Execution Suppression
|
|
41
|
+
|
|
42
|
+
- `suppressToast: true`: Suppresses step progress toasts ("Running skill tool...") during pipeline execution.
|
|
43
|
+
- `suppressOutput: true`: Suppresses raw tool result blocks from being rendered in the chat thread.
|
|
44
|
+
- Setting suppression options at the `execution` root cascades down to all steps unless explicitly overridden per tool step.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Declarative Tools
|
|
2
|
+
|
|
3
|
+
Declarative tools allow workspace authors to define reusable custom tools using JSON definitions placed under `.agents/tools/<group>/<tool-name>.json`.
|
|
4
|
+
|
|
5
|
+
## Directory Structure
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
.agents/tools/
|
|
9
|
+
└── main/
|
|
10
|
+
└── generate_random_number.json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Schema Format
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"name": "generate_random_number",
|
|
18
|
+
"description": "Generate a random integer within a specified range.",
|
|
19
|
+
"executor": "javascript",
|
|
20
|
+
"inputSchema": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"properties": {
|
|
23
|
+
"min": { "type": "number", "default": 1 },
|
|
24
|
+
"max": { "type": "number", "default": 1000000 }
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"code": "const min = Number(inputs.min ?? 1); const max = Number(inputs.max ?? 1000000); return Math.floor(Math.random() * (max - min + 1)) + min;"
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- **Automatic Discovery**: Automatically loaded from `.agents/tools/` across conversation workspaces.
|
|
34
|
+
- **WebMCP Integration**: Registered with the browser ModelContext API for both manual pinning and automated agent execution.
|
|
35
|
+
- **Expression Evaluation**: Code expressions automatically evaluate and return results without needing explicit wrapper boilerplate.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Frontmatter Specification
|
|
2
|
+
|
|
3
|
+
Agent skills in ShadowClaw are configured via YAML frontmatter at the top of `SKILL.md`. Frontmatter attributes adhere strictly to the standard Agent Skills specification.
|
|
4
|
+
|
|
5
|
+
## Specification Schema
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
---
|
|
9
|
+
name: skill-name
|
|
10
|
+
description: Clear, concise model-facing trigger description.
|
|
11
|
+
user-invocable: true
|
|
12
|
+
disable-model-invocation: false
|
|
13
|
+
argument-hint: "[arguments]"
|
|
14
|
+
metadata:
|
|
15
|
+
allowed-tools: read_file write_file javascript
|
|
16
|
+
compatibility: ShadowClaw
|
|
17
|
+
license: MIT
|
|
18
|
+
---
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Attribute Reference
|
|
22
|
+
|
|
23
|
+
| Attribute | Type | Required | Description |
|
|
24
|
+
| :------------------------- | :-------- | :------- | :-------------------------------------------------------------------------------------------------------- |
|
|
25
|
+
| `name` | `string` | **Yes** | Skill identifier (1–64 lowercase alphanumeric characters and single hyphens). |
|
|
26
|
+
| `description` | `string` | **Yes** | Model-facing description used for skill discovery and activation (max 1024 characters). |
|
|
27
|
+
| `user-invocable` | `boolean` | No | When `true` (default), allows users to invoke the skill directly via slash commands (e.g. `/skill-name`). |
|
|
28
|
+
| `disable-model-invocation` | `boolean` | No | When `true`, hides the skill from model discovery so it is only triggered via slash command. |
|
|
29
|
+
| `argument-hint` | `string` | No | Display placeholder in the UI search/autocomplete menu when typing slash commands. |
|
|
30
|
+
| `metadata` | `object` | No | Key-value dictionary for custom metadata, tool permissions (`allowed-tools`), and `execution` pipelines. |
|
|
31
|
+
| `compatibility` | `string` | No | Platform compatibility requirements or version strings. |
|
|
32
|
+
| `license` | `string` | No | Open-source software license string (e.g. `MIT`, `AGPL-3.0`). |
|
|
33
|
+
|
|
34
|
+
## Metadata Attributes (`metadata`)
|
|
35
|
+
|
|
36
|
+
Custom configuration properties and extension specifications (like declarative execution pipelines) that fall outside the standard Agent Skills frontmatter attributes should be placed inside `metadata`:
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
metadata:
|
|
40
|
+
allowed-tools: javascript show_toast generate_random_number
|
|
41
|
+
author: ShadowClaw Team
|
|
42
|
+
version: 1.0.0
|
|
43
|
+
execution:
|
|
44
|
+
type: tools
|
|
45
|
+
suppressToast: true
|
|
46
|
+
tools:
|
|
47
|
+
- name: javascript
|
|
48
|
+
input:
|
|
49
|
+
code: Math.floor(Math.random() * 100) + 1
|
|
50
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://schemas.agentskills.io/discovery/0.2.0/schema.json",
|
|
3
|
+
"name": "ShadowClaw",
|
|
4
|
+
"description": "ShadowClaw - Browser-native AI agent.",
|
|
5
|
+
"skills": [
|
|
6
|
+
{
|
|
7
|
+
"name": "skill-creator",
|
|
8
|
+
"type": "skill-md",
|
|
9
|
+
"description": "Create, edit, review, and validate ShadowClaw declarative skills and their supporting resources.",
|
|
10
|
+
"url": "../../.agents/skills/main/skill-creator/SKILL.md",
|
|
11
|
+
"digest": "sha256:e9876a79ab38c3a9acd0a990f2a26a578e1971abc2f3cd0eeda1988e6529f684"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ A fully-functional agent runtime built on browser-native technology — the orch
|
|
|
62
62
|
- **Model registry** — Dynamic metadata fetch (context window, modality support)
|
|
63
63
|
- **Attachment capabilities** — Native multimodal delivery with automatic text fallback
|
|
64
64
|
- **Remote MCP** — Discover and execute tools from external MCP servers
|
|
65
|
-
- **Stateless MCP server** — Expose ShadowClaw CLI commands and live browser tools to external agent hosts (Claude Desktop, Cursor, Goose) via STDIO (`npx shadow-claw mcp`) or Streamable HTTP (`POST /mcp`)
|
|
65
|
+
- **Stateless MCP server** — Expose ShadowClaw CLI commands and live browser tools to external agent hosts (Claude Desktop, Cursor, Goose) via STDIO (`npx shadow-claw mcp`) or Streamable HTTP (`POST /mcp`), featuring multi-client tool targeting (`shadowclaw_set_active_client`), per-tool client capability validation, client-side execution guards, and interactive `ask_user` relaying
|
|
66
66
|
- **A2UI interactive surfaces** — Render responsive UI components (Text, Button, TextField, Row/Column layouts) from agents via PeerJS WebRTC with two-way data binding
|
|
67
67
|
- **Multi-Agent Shared State** — Synchronize agent knowledge across participants using `STATE_SNAPSHOT` and `STATE_DELTA` events
|
|
68
68
|
- **Email integration** — IMAP/SMTP support with encrypted credentials
|
|
@@ -243,6 +243,7 @@ Pages complement the **main group MEMORY** (auto-created as `MEMORY.md` on first
|
|
|
243
243
|
## Agent Skills and Declarative Tools
|
|
244
244
|
|
|
245
245
|
- **Workspace Agent Skills** — Discovers `.agents/skills/**/SKILL.md` instruction packages, presents model-invocable skill descriptions in the system prompt, and loads instructions plus bundled resources through `activate_skill`. Default bundled skills include `skill-creator`.
|
|
246
|
+
- **Agent Skills Discovery Index** — Automatically indexes skills, tools, and scripts into `/.well-known/agent-skills/index.json` complying with Agent Skills Discovery RFC v0.2.0, computing SHA-256 digests and RFC 3986 relative URLs. Integrated into static builds (`bin/build/build.mjs`) and runnable via `npx shadow-claw skills:index [dir]` (alias `agent-skills`).
|
|
246
247
|
- **Slash Commands & Declarative Execution Pipelines** — User-invocable skills support `/skill-name` slash-command triggers. Skills with `execution: { type: "tools", tools: [...] }` execute tool pipelines directly on the worker thread via `executeToolChain` without scheduling Tasks or invoking LLM prompts. Supports `$pipe` output chaining and step-level or cascaded `suppressToast: true` and `suppressOutput: true` options.
|
|
247
248
|
- **Declarative Tools** — Content repositories can define executable tools as JSON under `.agents/tools/main/` using sandboxed Bash or JavaScript, or delegate to existing tools without changing ShadowClaw source (e.g. `generate_random_number` in the starter template repository).
|
|
248
249
|
- **Enhanced JS Tool Expression Evaluation** — The `javascript` tool automatically evaluates single expressions without explicit `return` statements by wrapping them in `return (<expression>);`.
|
|
@@ -252,7 +253,7 @@ Pages complement the **main group MEMORY** (auto-created as `MEMORY.md` on first
|
|
|
252
253
|
ShadowClaw packages its UI components as standard Web Components built on TC39 Signals and native Custom Elements:
|
|
253
254
|
|
|
254
255
|
- **Modular Package Exports** — Import pre-bundled components and utilities directly via `shadow-claw/components` (e.g. `ShadowClawToast`, `ShadowClawCard`, `ShadowClawDialog`, `ShadowClawEmptyState`, `ShadowClawPageHeader`) and `shadow-claw/utils` (e.g. `namespacedStorage`, `ulid`). TypeScript declaration files (`.d.ts`) are provided out of the box.
|
|
255
|
-
- **Storybook Workbench** — Interactive visual development environment powered by Storybook (`@storybook/web-components-vite`) with dark mode default, live controls, and isolated component testing (`npm run storybook`).
|
|
256
|
+
- **Storybook Workbench** — Interactive visual development environment powered by Storybook (`@storybook/web-components-vite`) with dark mode default, live controls, and isolated component testing (`npm run storybook`), including all 18 A2UI catalog components and UI primitives.
|
|
256
257
|
- **Reactive Element Lifecycle** — Custom elements extending `ShadowClawElement` observe attributes (`observedAttributes`) for declarative reactive DOM updates.
|
|
257
258
|
|
|
258
259
|
## WebVM (Optional Alpine Linux)
|
|
@@ -277,7 +278,7 @@ ShadowClaw uses **IndexedDB** for structured data (messages, config, tasks) and
|
|
|
277
278
|
- **30-second key expiry** for plaintext operations
|
|
278
279
|
- **No plaintext secrets on disk** — encrypted before storage
|
|
279
280
|
- **Trusted Types enforcement** — idempotent `"default"` policy (`src/security/default-trusted-types-policy.ts`) registered at boot via `theme-init.ts`; `getPolicy()` fallback prevents duplicate-creation errors on module reload
|
|
280
|
-
- **Custom element security guards** — `installCustomElementsRegistryGuard` and `installCustomElementDomGuard` prevent unauthorized custom element registration and dynamic DOM injection, strictly enforcing allowlists from `shadow-claw.config.json` (or `site-config.json`) or storage
|
|
281
|
+
- **Custom element security guards** — `installCustomElementsRegistryGuard` and `installCustomElementDomGuard` prevent unauthorized custom element registration and dynamic DOM injection, strictly enforcing allowlists from `shadow-claw.config.json` (or `site-config.json`) or storage. Script declarations support URLs and `{ src, hasInit }` descriptors (standardized on `src`), invoking `init()` exclusively when `hasInit: true` is configured.
|
|
281
282
|
- **Iframe sandbox & CSP hardening** — sandboxed preview iframes omit `allow-same-origin` by default to enforce opaque-origin (`null`) isolation without Chrome sandbox escape warnings, while injecting a transparent `postMessage` storage proxy bridge (`iframe-storage-bridge.js`) to provide namespaced `IndexedDB` and `localStorage` persistence for custom elements, trapping `ServiceWorker`/`caches` `SecurityError` rejections, polyfilling `showOpenFilePicker`/`showSaveFilePicker`, and relaying programmatic/link navigation and declarative `BroadcastChannel` messages via `IframeBroadcastProxy`
|
|
282
283
|
- **Iframe embed sanitization** — DOMPurify-based iframe allowlisting protects markdown and HTML previews, with Settings-backed host patterns and a safe default host list
|
|
283
284
|
- **SSRF proxy hardening** — `/proxy` blocks non-HTTP/S schemes and private/loopback IP ranges by default; bypassed via `--allow-private-proxy` flag or the authenticated service-worker JSON format
|
|
@@ -430,6 +431,7 @@ npx shadow-claw server --tmp # Run services with tempora
|
|
|
430
431
|
npx shadow-claw server --cache-dir <dir> # Run services with custom cache directory
|
|
431
432
|
npx shadow-claw webrtc listen # Start headless WebRTC DataChannel daemon
|
|
432
433
|
npx shadow-claw peer-id # Get or generate persistent CLI Peer ID
|
|
434
|
+
npx shadow-claw skills:index # Generate or update .well-known/agent-skills/index.json
|
|
433
435
|
```
|
|
434
436
|
|
|
435
437
|
When launching `dev`, `run`, `serve`, or `server` without an existing cache, ShadowClaw prompts interactively to select between the local directory (`.cache`), system temporary storage (`tmpdir()`), or a custom path (skip prompting via `--tmp`, `-y`, `--cache-dir <dir>`, or `SHADOWCLAW_CACHE_DIR`).
|
package/bin/build/build.mjs
CHANGED
|
@@ -18,11 +18,6 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
18
18
|
const __dirname = dirname(__filename);
|
|
19
19
|
const projectRoot = resolve(__dirname, "../..");
|
|
20
20
|
|
|
21
|
-
async function run(command, options = {}) {
|
|
22
|
-
console.log(`> ${command}`);
|
|
23
|
-
execSync(command, { stdio: "inherit", ...options });
|
|
24
|
-
}
|
|
25
|
-
|
|
26
21
|
async function pathExists(p) {
|
|
27
22
|
try {
|
|
28
23
|
await stat(p);
|
|
@@ -33,6 +28,28 @@ async function pathExists(p) {
|
|
|
33
28
|
}
|
|
34
29
|
|
|
35
30
|
export async function runBuild(options = {}) {
|
|
31
|
+
const isQuiet =
|
|
32
|
+
options.quiet ?? (process.env.NODE_ENV === "test" && !process.env.VERBOSE);
|
|
33
|
+
const defaultStdio =
|
|
34
|
+
options.stdio ??
|
|
35
|
+
(process.env.NODE_ENV === "test" && !process.env.VERBOSE
|
|
36
|
+
? "pipe"
|
|
37
|
+
: "inherit");
|
|
38
|
+
|
|
39
|
+
const log = (...args) => {
|
|
40
|
+
if (!isQuiet) {
|
|
41
|
+
console.log(...args);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
async function run(command, runOptions = {}) {
|
|
46
|
+
if (!isQuiet && !runOptions.quiet) {
|
|
47
|
+
console.log(`> ${command}`);
|
|
48
|
+
}
|
|
49
|
+
const stdio = runOptions.stdio ?? defaultStdio;
|
|
50
|
+
execSync(command, { stdio, ...runOptions });
|
|
51
|
+
}
|
|
52
|
+
|
|
36
53
|
const contentRoot = resolve(
|
|
37
54
|
options.contentRoot || env.SHADOWCLAW_CONTENT_ROOT || process.cwd(),
|
|
38
55
|
);
|
|
@@ -120,6 +137,39 @@ export async function runBuild(options = {}) {
|
|
|
120
137
|
});
|
|
121
138
|
} catch {}
|
|
122
139
|
|
|
140
|
+
try {
|
|
141
|
+
await cp(".agents/scripts", "dist/public/.agents/scripts", {
|
|
142
|
+
recursive: true,
|
|
143
|
+
});
|
|
144
|
+
} catch {}
|
|
145
|
+
|
|
146
|
+
// Generate / sync Agent Skills Discovery index (.well-known/agent-skills/index.json)
|
|
147
|
+
if (await pathExists(".agents/skills")) {
|
|
148
|
+
try {
|
|
149
|
+
const { generateSkillsIndex } =
|
|
150
|
+
await import("../commands/skills-index.mjs");
|
|
151
|
+
await generateSkillsIndex(projectRoot);
|
|
152
|
+
if (await pathExists(".well-known/agent-skills/index.json")) {
|
|
153
|
+
await cp(".well-known", "dist/public/.well-known", {
|
|
154
|
+
recursive: true,
|
|
155
|
+
force: true,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
} catch (err) {
|
|
159
|
+
console.warn(
|
|
160
|
+
"Notice: Failed to auto-generate agent-skills index:",
|
|
161
|
+
err,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
} else if (await pathExists(".well-known")) {
|
|
165
|
+
try {
|
|
166
|
+
await cp(".well-known", "dist/public/.well-known", {
|
|
167
|
+
recursive: true,
|
|
168
|
+
force: true,
|
|
169
|
+
});
|
|
170
|
+
} catch {}
|
|
171
|
+
}
|
|
172
|
+
|
|
123
173
|
await run("npm run -s rolldown");
|
|
124
174
|
|
|
125
175
|
if (prerenderMainMemory) {
|
|
@@ -141,14 +191,14 @@ export async function runBuild(options = {}) {
|
|
|
141
191
|
} catch {}
|
|
142
192
|
|
|
143
193
|
if (isProduction) {
|
|
144
|
-
|
|
194
|
+
log("Running production post-build steps...");
|
|
145
195
|
|
|
146
196
|
const pagesOrigin = options.pagesOrigin || env.PAGES_ORIGIN;
|
|
147
197
|
const basePath =
|
|
148
198
|
options.basePath || (env.PAGES_BASE_PATH ?? "/shadow-claw/");
|
|
149
199
|
|
|
150
|
-
|
|
151
|
-
|
|
200
|
+
log(` PAGES_ORIGIN : ${pagesOrigin || "(relative ./)"}`);
|
|
201
|
+
log(` PAGES_BASE_PATH: ${basePath}`);
|
|
152
202
|
|
|
153
203
|
if (pagesOrigin) {
|
|
154
204
|
try {
|
|
@@ -191,7 +241,7 @@ export async function runBuild(options = {}) {
|
|
|
191
241
|
await run("npm run -s build:service-worker");
|
|
192
242
|
await run("node bin/patch-service-worker-trusted-types.mjs");
|
|
193
243
|
|
|
194
|
-
|
|
244
|
+
log("Build completed successfully.");
|
|
195
245
|
return;
|
|
196
246
|
}
|
|
197
247
|
|
|
@@ -206,7 +256,7 @@ export async function runBuild(options = {}) {
|
|
|
206
256
|
const toolchainDist = join(toolchainRoot, "dist/public");
|
|
207
257
|
const toolchainBuilt = await pathExists(join(toolchainDist, "index.js"));
|
|
208
258
|
if (!toolchainBuilt) {
|
|
209
|
-
|
|
259
|
+
log("Building ShadowClaw core toolchain...");
|
|
210
260
|
await run("npm run -s build:clean", { cwd: toolchainRoot });
|
|
211
261
|
await run("npm run -s rolldown", { cwd: toolchainRoot });
|
|
212
262
|
}
|
|
@@ -289,20 +339,101 @@ export async function runBuild(options = {}) {
|
|
|
289
339
|
});
|
|
290
340
|
}
|
|
291
341
|
|
|
292
|
-
// 6. Copy .agents from contentRoot
|
|
342
|
+
// 6. Copy .agents from contentRoot (fallback to toolchainRoot)
|
|
293
343
|
const contentSkills = join(contentRoot, ".agents/skills");
|
|
294
344
|
if (await pathExists(contentSkills)) {
|
|
295
345
|
await cp(contentSkills, join(distPublicDir, ".agents/skills"), {
|
|
296
346
|
recursive: true,
|
|
297
347
|
force: true,
|
|
298
348
|
});
|
|
349
|
+
} else {
|
|
350
|
+
const toolchainSkills = join(toolchainRoot, ".agents/skills");
|
|
351
|
+
if (await pathExists(toolchainSkills)) {
|
|
352
|
+
await cp(toolchainSkills, join(distPublicDir, ".agents/skills"), {
|
|
353
|
+
recursive: true,
|
|
354
|
+
force: true,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
299
357
|
}
|
|
358
|
+
|
|
300
359
|
const contentTools = join(contentRoot, ".agents/tools");
|
|
301
360
|
if (await pathExists(contentTools)) {
|
|
302
361
|
await cp(contentTools, join(distPublicDir, ".agents/tools"), {
|
|
303
362
|
recursive: true,
|
|
304
363
|
force: true,
|
|
305
364
|
});
|
|
365
|
+
} else {
|
|
366
|
+
const toolchainTools = join(toolchainRoot, ".agents/tools");
|
|
367
|
+
if (await pathExists(toolchainTools)) {
|
|
368
|
+
await cp(toolchainTools, join(distPublicDir, ".agents/tools"), {
|
|
369
|
+
recursive: true,
|
|
370
|
+
force: true,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const contentScripts = join(contentRoot, ".agents/scripts");
|
|
376
|
+
if (await pathExists(contentScripts)) {
|
|
377
|
+
await cp(contentScripts, join(distPublicDir, ".agents/scripts"), {
|
|
378
|
+
recursive: true,
|
|
379
|
+
force: true,
|
|
380
|
+
});
|
|
381
|
+
} else {
|
|
382
|
+
const toolchainScripts = join(toolchainRoot, ".agents/scripts");
|
|
383
|
+
if (await pathExists(toolchainScripts)) {
|
|
384
|
+
await cp(toolchainScripts, join(distPublicDir, ".agents/scripts"), {
|
|
385
|
+
recursive: true,
|
|
386
|
+
force: true,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// 6b. Generate / sync Agent Skills Discovery index (.well-known/agent-skills/index.json)
|
|
392
|
+
if (await pathExists(contentSkills)) {
|
|
393
|
+
try {
|
|
394
|
+
const { generateSkillsIndex } =
|
|
395
|
+
await import("../commands/skills-index.mjs");
|
|
396
|
+
await generateSkillsIndex(contentRoot);
|
|
397
|
+
const rootWellKnownIndex = join(
|
|
398
|
+
contentRoot,
|
|
399
|
+
".well-known/agent-skills/index.json",
|
|
400
|
+
);
|
|
401
|
+
if (await pathExists(rootWellKnownIndex)) {
|
|
402
|
+
await cp(
|
|
403
|
+
join(contentRoot, ".well-known"),
|
|
404
|
+
join(distPublicDir, ".well-known"),
|
|
405
|
+
{
|
|
406
|
+
recursive: true,
|
|
407
|
+
force: true,
|
|
408
|
+
},
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
} catch (err) {
|
|
412
|
+
console.warn("Notice: Failed to auto-generate agent-skills index:", err);
|
|
413
|
+
const contentWellKnown = join(contentRoot, ".well-known");
|
|
414
|
+
if (await pathExists(contentWellKnown)) {
|
|
415
|
+
await cp(contentWellKnown, join(distPublicDir, ".well-known"), {
|
|
416
|
+
recursive: true,
|
|
417
|
+
force: true,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
} else {
|
|
422
|
+
const contentWellKnown = join(contentRoot, ".well-known");
|
|
423
|
+
if (await pathExists(contentWellKnown)) {
|
|
424
|
+
await cp(contentWellKnown, join(distPublicDir, ".well-known"), {
|
|
425
|
+
recursive: true,
|
|
426
|
+
force: true,
|
|
427
|
+
});
|
|
428
|
+
} else {
|
|
429
|
+
const toolchainWellKnown = join(toolchainRoot, ".well-known");
|
|
430
|
+
if (await pathExists(toolchainWellKnown)) {
|
|
431
|
+
await cp(toolchainWellKnown, join(distPublicDir, ".well-known"), {
|
|
432
|
+
recursive: true,
|
|
433
|
+
force: true,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
}
|
|
306
437
|
}
|
|
307
438
|
|
|
308
439
|
// 7. Prerender DSD Shell
|
|
@@ -348,11 +479,11 @@ export async function runBuild(options = {}) {
|
|
|
348
479
|
} catch {}
|
|
349
480
|
|
|
350
481
|
if (isProduction) {
|
|
351
|
-
|
|
482
|
+
log("Running production post-build steps...");
|
|
352
483
|
|
|
353
484
|
const pagesOrigin = options.pagesOrigin || env.PAGES_ORIGIN;
|
|
354
|
-
|
|
355
|
-
|
|
485
|
+
log(` PAGES_ORIGIN : ${pagesOrigin || "(relative ./)"}`);
|
|
486
|
+
log(` PAGES_BASE_PATH: ${basePath}`);
|
|
356
487
|
|
|
357
488
|
if (pagesOrigin) {
|
|
358
489
|
try {
|
|
@@ -425,7 +556,7 @@ export async function runBuild(options = {}) {
|
|
|
425
556
|
await run(`node "${patchSwScript}" "${swPath}"`);
|
|
426
557
|
}
|
|
427
558
|
|
|
428
|
-
|
|
559
|
+
log("Build completed successfully.");
|
|
429
560
|
}
|
|
430
561
|
|
|
431
562
|
const isMainModule =
|
package/bin/build/build.test.mjs
CHANGED
|
@@ -121,6 +121,22 @@ describe("build without and with pages", () => {
|
|
|
121
121
|
manifest.skills.filter((s) => s.displayPath.endsWith("SKILL.md")),
|
|
122
122
|
).toHaveLength(2);
|
|
123
123
|
expect(manifest.skillsPurgeId).toBe("skills-build-001");
|
|
124
|
+
|
|
125
|
+
const wellKnownIndexPath = path.join(
|
|
126
|
+
tempProjectRoot,
|
|
127
|
+
"dist/public/.well-known/agent-skills/index.json",
|
|
128
|
+
);
|
|
129
|
+
expect(fs.existsSync(wellKnownIndexPath)).toBe(true);
|
|
130
|
+
const wellKnownIndex = JSON.parse(
|
|
131
|
+
await readFile(wellKnownIndexPath, "utf8"),
|
|
132
|
+
);
|
|
133
|
+
expect(wellKnownIndex.$schema).toBe(
|
|
134
|
+
"https://schemas.agentskills.io/discovery/0.2.0/schema.json",
|
|
135
|
+
);
|
|
136
|
+
expect(wellKnownIndex.skills.map((s) => s.name)).toEqual(
|
|
137
|
+
expect.arrayContaining(["skill-creator", "example"]),
|
|
138
|
+
);
|
|
139
|
+
expect(wellKnownIndex.tools.map((t) => t.name)).toContain("echo");
|
|
124
140
|
});
|
|
125
141
|
|
|
126
142
|
it("builds with no pages directory and keeps default pages", async () => {
|
|
@@ -146,5 +162,46 @@ describe("build without and with pages", () => {
|
|
|
146
162
|
path.join(tempProjectRoot, "site-config.json"),
|
|
147
163
|
].find((p) => fs.existsSync(p));
|
|
148
164
|
expect(await readFile(configPath, "utf8")).toContain("ShadowClaw");
|
|
165
|
+
|
|
166
|
+
const wellKnownIndexPath = path.join(
|
|
167
|
+
tempProjectRoot,
|
|
168
|
+
"dist/public/.well-known/agent-skills/index.json",
|
|
169
|
+
);
|
|
170
|
+
expect(fs.existsSync(wellKnownIndexPath)).toBe(true);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("builds an external consumer content root and falls back to toolchain .agents and .well-known", async () => {
|
|
174
|
+
const tempConsumerRoot = await mkdtemp(
|
|
175
|
+
path.join(os.tmpdir(), "shadow-claw-consumer-"),
|
|
176
|
+
);
|
|
177
|
+
const logSpy = jest.spyOn(console, "log").mockImplementation(() => {});
|
|
178
|
+
try {
|
|
179
|
+
const { runBuild: runConsumerBuild } = await import("./build.mjs");
|
|
180
|
+
await runConsumerBuild({
|
|
181
|
+
contentRoot: tempConsumerRoot,
|
|
182
|
+
toolchainRoot: tempProjectRoot,
|
|
183
|
+
isProduction: false,
|
|
184
|
+
quiet: true,
|
|
185
|
+
stdio: "pipe",
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const consumerDistPublic = path.join(tempConsumerRoot, "dist/public");
|
|
189
|
+
expect(
|
|
190
|
+
fs.existsSync(
|
|
191
|
+
path.join(consumerDistPublic, ".well-known/agent-skills/index.json"),
|
|
192
|
+
),
|
|
193
|
+
).toBe(true);
|
|
194
|
+
expect(
|
|
195
|
+
fs.existsSync(
|
|
196
|
+
path.join(
|
|
197
|
+
consumerDistPublic,
|
|
198
|
+
".agents/skills/main/skill-creator/SKILL.md",
|
|
199
|
+
),
|
|
200
|
+
),
|
|
201
|
+
).toBe(true);
|
|
202
|
+
} finally {
|
|
203
|
+
logSpy.mockRestore();
|
|
204
|
+
await rm(tempConsumerRoot, { recursive: true, force: true });
|
|
205
|
+
}
|
|
149
206
|
});
|
|
150
207
|
});
|
package/bin/cli.mjs
CHANGED
|
@@ -15,6 +15,7 @@ import { runTasksCommand } from "./commands/tasks.mjs";
|
|
|
15
15
|
import { runPeerIdCommand } from "./commands/peer-id.mjs";
|
|
16
16
|
import { runWebRtcListenCommand } from "./commands/webrtc-listen.mjs";
|
|
17
17
|
import { runMcpCommand } from "./commands/mcp.mjs";
|
|
18
|
+
import { runSkillsIndexCommand } from "./commands/skills-index.mjs";
|
|
18
19
|
import { resolveCacheDir } from "./utils/resolve-cache-dir.mjs";
|
|
19
20
|
|
|
20
21
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -962,4 +963,29 @@ program
|
|
|
962
963
|
await runMcpCommand(options);
|
|
963
964
|
});
|
|
964
965
|
|
|
966
|
+
// ---------------------------------------------------------------------------
|
|
967
|
+
// AGENT SKILLS INDEX COMMAND
|
|
968
|
+
// ---------------------------------------------------------------------------
|
|
969
|
+
program
|
|
970
|
+
.command("skills:index [dir]")
|
|
971
|
+
.alias("agent-skills")
|
|
972
|
+
.description(
|
|
973
|
+
"Generate or update .well-known/agent-skills/index.json per the Agent Skills Discovery RFC",
|
|
974
|
+
)
|
|
975
|
+
.option(
|
|
976
|
+
"--out-dir <dir>",
|
|
977
|
+
"Output directory relative to content root (default: .well-known/agent-skills)",
|
|
978
|
+
)
|
|
979
|
+
.option("--out-file <file>", "Explicit destination path for index.json")
|
|
980
|
+
.option("--stdout", "Print generated index.json to stdout", false)
|
|
981
|
+
.option("--no-write", "Skip writing file to disk")
|
|
982
|
+
.action(async (dir, options) => {
|
|
983
|
+
try {
|
|
984
|
+
await runSkillsIndexCommand(dir, options);
|
|
985
|
+
} catch (err) {
|
|
986
|
+
console.error("Failed to generate skills index:", err);
|
|
987
|
+
process.exit(1);
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
|
|
965
991
|
program.parse(process.argv);
|