shadow-claw 1.28.0 → 1.29.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/.well-known/mcp/server-card.json +1 -1
- package/.well-known/mcp.json +1 -1
- package/README.md +96 -278
- package/bin/cli.mjs +4 -0
- package/bin/commands/mcp.mjs +409 -125
- package/bin/commands/mcp.test.mjs +151 -18
- package/bin/utils/control-client.mjs +338 -103
- package/bin/utils/control-client.test.mjs +14 -0
- package/dist/electron/main.cjs +179 -179
- package/dist/lib/components/index.js +21 -21
- 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-llm.js +1 -1
- package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
- package/dist/lib/components/settings/shadow-claw-notifications.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-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-llm.js +1 -1
- package/dist/lib/components/shadow-claw-networking.js +1 -1
- package/dist/lib/components/shadow-claw-notifications.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-D8Ph0-A9.js → configurePeerJs-DG4hliKp.js} +2 -2
- package/dist/lib/{configurePeerJs-D8Ph0-A9.js.map → configurePeerJs-DG4hliKp.js.map} +1 -1
- package/dist/lib/index.js +21 -21
- package/dist/lib/{initControlPlane-BIrWmpzc.js → initControlPlane-DnpAzphg.js} +8 -8
- package/dist/lib/{initControlPlane-BIrWmpzc.js.map → initControlPlane-DnpAzphg.js.map} +1 -1
- package/dist/lib/{markdown-DEUoM1c6.js → markdown-DgdSt2GD.js} +2 -2
- package/dist/lib/{markdown-DEUoM1c6.js.map → markdown-DgdSt2GD.js.map} +1 -1
- package/dist/lib/{orchestrator-CFCW-l1O.js → orchestrator-CjEau_RG.js} +5 -5
- package/dist/lib/{orchestrator-CFCW-l1O.js.map → orchestrator-CjEau_RG.js.map} +1 -1
- package/dist/lib/{orchestrator-BtVj9bBB.js → orchestrator-ClXbJ4Mb.js} +2 -2
- package/dist/lib/{orchestrator-BtVj9bBB.js.map → orchestrator-ClXbJ4Mb.js.map} +1 -1
- package/dist/lib/{peerjs-BoBkx9DJ.js → peerjs-BdfpltIe.js} +3 -3
- package/dist/lib/{peerjs-BoBkx9DJ.js.map → peerjs-BdfpltIe.js.map} +1 -1
- package/dist/lib/{push-client-D6hbzDNV.js → push-client-DjwKknNg.js} +9 -3
- package/dist/lib/push-client-DjwKknNg.js.map +1 -0
- package/dist/lib/{shadow-claw-Cuf2O5bZ.js → shadow-claw-DcPGKenn.js} +4 -4
- package/dist/lib/{shadow-claw-Cuf2O5bZ.js.map → shadow-claw-DcPGKenn.js.map} +1 -1
- package/dist/lib/{shadow-claw-channel-config-BDPKt6Bd.js → shadow-claw-channel-config-DEL-aZ7N.js} +3 -3
- package/dist/lib/{shadow-claw-channel-config-BDPKt6Bd.js.map → shadow-claw-channel-config-DEL-aZ7N.js.map} +1 -1
- package/dist/lib/{shadow-claw-channels-BsP5JABM.js → shadow-claw-channels-BgaJiPdE.js} +2 -2
- package/dist/lib/{shadow-claw-channels-BsP5JABM.js.map → shadow-claw-channels-BgaJiPdE.js.map} +1 -1
- package/dist/lib/{shadow-claw-chat-Cam2lX4k.js → shadow-claw-chat-mXPQZbwT.js} +4 -4
- package/dist/lib/{shadow-claw-chat-Cam2lX4k.js.map → shadow-claw-chat-mXPQZbwT.js.map} +1 -1
- package/dist/lib/{shadow-claw-control-plane-DB2qcCFs.js → shadow-claw-control-plane-DO6foOLV.js} +6 -6
- package/dist/lib/{shadow-claw-control-plane-DB2qcCFs.js.map → shadow-claw-control-plane-DO6foOLV.js.map} +1 -1
- package/dist/lib/{shadow-claw-conversations-C9Vf4XGx.js → shadow-claw-conversations-BLwHTwdW.js} +2 -2
- package/dist/lib/{shadow-claw-conversations-C9Vf4XGx.js.map → shadow-claw-conversations-BLwHTwdW.js.map} +1 -1
- package/dist/lib/{shadow-claw-file-viewer-B4HYiI0v.js → shadow-claw-file-viewer-BSbZvSl-.js} +3 -3
- package/dist/lib/{shadow-claw-file-viewer-B4HYiI0v.js.map → shadow-claw-file-viewer-BSbZvSl-.js.map} +1 -1
- package/dist/lib/{shadow-claw-files-DVROUESO.js → shadow-claw-files-BLVr9Pua.js} +2 -2
- package/dist/lib/{shadow-claw-files-DVROUESO.js.map → shadow-claw-files-BLVr9Pua.js.map} +1 -1
- package/dist/lib/{shadow-claw-git-BqrO7cHJ.js → shadow-claw-git-CHC1H86J.js} +3 -3
- package/dist/lib/{shadow-claw-git-BqrO7cHJ.js.map → shadow-claw-git-CHC1H86J.js.map} +1 -1
- package/dist/lib/{shadow-claw-llm-BexUQdYo.js → shadow-claw-llm-CKXfxd3D.js} +2 -2
- package/dist/lib/{shadow-claw-llm-BexUQdYo.js.map → shadow-claw-llm-CKXfxd3D.js.map} +1 -1
- package/dist/lib/{shadow-claw-networking-CfXRGpUD.js → shadow-claw-networking-dpYvfchh.js} +2 -2
- package/dist/lib/{shadow-claw-networking-CfXRGpUD.js.map → shadow-claw-networking-dpYvfchh.js.map} +1 -1
- package/dist/lib/{shadow-claw-notifications-C9KPMgx_.js → shadow-claw-notifications-_YeAVPga.js} +2 -2
- package/dist/lib/{shadow-claw-notifications-C9KPMgx_.js.map → shadow-claw-notifications-_YeAVPga.js.map} +1 -1
- package/dist/lib/{shadow-claw-pages-CGzGXmrI.js → shadow-claw-pages-DVzZriZ7.js} +3 -3
- package/dist/lib/{shadow-claw-pages-CGzGXmrI.js.map → shadow-claw-pages-DVzZriZ7.js.map} +1 -1
- package/dist/lib/{shadow-claw-peerjs-B0ZB7yhB.js → shadow-claw-peerjs-BvixjeBz.js} +3 -3
- package/dist/lib/{shadow-claw-peerjs-B0ZB7yhB.js.map → shadow-claw-peerjs-BvixjeBz.js.map} +1 -1
- package/dist/lib/{shadow-claw-settings-DBfMZdDS.js → shadow-claw-settings-DV9-gD4Q.js} +2 -2
- package/dist/lib/{shadow-claw-settings-DBfMZdDS.js.map → shadow-claw-settings-DV9-gD4Q.js.map} +1 -1
- package/dist/lib/{shadow-claw-storage-CM-w6mgG.js → shadow-claw-storage-Bv__kXG6.js} +2 -2
- package/dist/lib/{shadow-claw-storage-CM-w6mgG.js.map → shadow-claw-storage-Bv__kXG6.js.map} +1 -1
- package/dist/lib/{shadow-claw-task-server-DV4b1g2-.js → shadow-claw-task-server-DNOe8PWK.js} +2 -2
- package/dist/lib/{shadow-claw-task-server-DV4b1g2-.js.map → shadow-claw-task-server-DNOe8PWK.js.map} +1 -1
- package/dist/lib/{shadow-claw-tasks-K-foOHSE.js → shadow-claw-tasks-qmcDT4PU.js} +3 -3
- package/dist/lib/{shadow-claw-tasks-K-foOHSE.js.map → shadow-claw-tasks-qmcDT4PU.js.map} +1 -1
- package/dist/lib/{shadow-claw-terminal-CpAknKyA.js → shadow-claw-terminal-0QUWP8of.js} +2 -2
- package/dist/lib/{shadow-claw-terminal-CpAknKyA.js.map → shadow-claw-terminal-0QUWP8of.js.map} +1 -1
- package/dist/lib/{shadow-claw-tools-D98XZ0Ep.js → shadow-claw-tools-Bs_bmI6-.js} +3 -3
- package/dist/lib/{shadow-claw-tools-D98XZ0Ep.js.map → shadow-claw-tools-Bs_bmI6-.js.map} +1 -1
- package/dist/lib/{shadow-claw-webvm-DLOb8dMI.js → shadow-claw-webvm-DYaoL7QY.js} +2 -2
- package/dist/lib/{shadow-claw-webvm-DLOb8dMI.js.map → shadow-claw-webvm-DYaoL7QY.js.map} +1 -1
- package/dist/lib/{syncWebMcpRegistration-NspKefOI.js → syncWebMcpRegistration-BhbqI6R2.js} +2 -2
- package/dist/lib/{syncWebMcpRegistration-NspKefOI.js.map → syncWebMcpRegistration-BhbqI6R2.js.map} +1 -1
- package/dist/public/.well-known/mcp/server-card.json +1 -1
- package/dist/public/.well-known/mcp.json +1 -1
- package/dist/public/AGENTS.md +22 -3
- package/dist/public/README.md +96 -278
- package/dist/public/agent.worker.js +50 -50
- package/dist/public/{base-task-model-CYkpwnvU-DDfHUUIS.js → base-task-model-CYkpwnvU-DrXr4G1R.js} +1 -1
- package/dist/public/{configurePeerJs-BhBokQlC.js → configurePeerJs-B470pdeU.js} +1 -1
- package/dist/public/docs/README.md +31 -31
- package/dist/public/docs/architecture/context-management.md +7 -0
- package/dist/public/docs/architecture/storage.md +10 -1
- package/dist/public/docs/decisions/bundled-typescript-architecture.md +0 -1
- package/dist/public/docs/decisions/native-web-components-and-signals.md +0 -1
- package/dist/public/docs/example/article/index.html +1 -1
- package/dist/public/docs/guides/publishing-to-github-pages.md +334 -0
- package/dist/public/docs/guides/server-development-configuration.md +15 -0
- package/dist/public/docs/publishing/index.html +1 -1
- package/dist/public/docs/skill-creator/index.html +1 -1
- package/dist/public/docs/subsystems/cli.md +10 -2
- package/dist/public/docs/subsystems/control-plane.md +9 -8
- package/dist/public/docs/subsystems/crypto.md +9 -0
- package/dist/public/docs/subsystems/custom-element-security.md +2 -0
- package/dist/public/docs/subsystems/mcp-server.md +31 -16
- package/dist/public/docs/subsystems/notifications.md +8 -5
- package/dist/public/docs/subsystems/providers.md +9 -0
- package/dist/public/docs/subsystems/share-target.md +107 -0
- package/dist/public/docs/subsystems/webmcp.md +43 -0
- package/dist/public/e2e/README.md +4 -2
- package/dist/public/{e2e-bridge-DcBoeFvd.js → e2e-bridge-CSW0S5Yz.js} +1 -1
- package/dist/public/{file-viewer-CKtVC9Ix.js → file-viewer-Cs-riNvy.js} +1 -1
- package/dist/public/{firebase-OSDX3viP.js → firebase-cwAl_ABm.js} +1 -1
- package/dist/public/{git-CkhCJonj.js → git-GD09WATp.js} +25 -25
- package/dist/public/index.html +1 -1
- package/dist/public/index.js +1 -1
- package/dist/public/{initControlPlane-Bi8ouFEb.js → initControlPlane-BqCY0NQy.js} +1 -1
- package/dist/public/initControlPlane-C-IXaKYX.js +1 -0
- package/dist/public/{language-detector-BRKrlra0.js → language-detector-CIeEuQFk.js} +1 -1
- package/dist/public/llms.txt +4 -2
- package/dist/public/main/index.html +1 -1
- package/dist/public/main/memory/index.html +1 -1
- package/dist/public/{markdown-C-hCVJtc.js → markdown-Cw7vCtTg.js} +1 -1
- package/dist/public/{openai-Bpd71Oja.js → openai-BJIb2c5j.js} +3 -3
- package/dist/public/{orchestrator-8qNGfw8r.js → orchestrator-BWkHHO9Y.js} +1 -1
- package/dist/public/{orchestrator-BT3Ks5ip.js → orchestrator-DpkkeD6T.js} +1 -1
- package/dist/public/{peerjs-DfhwEiiq.js → peerjs-tf2EmWjB.js} +1 -1
- package/dist/public/{prompt-api-polyfill-Dl1kbJhR.js → prompt-api-polyfill-CXd75leW.js} +1 -1
- package/dist/public/{push-client-BVLrE9pK.js → push-client-CHjSbrWs.js} +1 -1
- package/dist/public/{rewriter-j6D9LDER.js → rewriter-BEHn9gll.js} +1 -1
- package/dist/public/service-worker.js +1 -1
- package/dist/public/{shadow-claw-DCjxNDCX.js → shadow-claw-BBPV_9X8.js} +2 -2
- package/dist/public/{shadow-claw-channels-CITDrqMl.js → shadow-claw-channels-BJvrKQjg.js} +1 -1
- package/dist/public/{shadow-claw-chat-BQrSgSKF.js → shadow-claw-chat-BG2EaRaw.js} +1 -1
- package/dist/public/{shadow-claw-control-plane-Cp001OY0.js → shadow-claw-control-plane-BBa7WbTg.js} +2 -2
- package/dist/public/{shadow-claw-conversations-EhX4RvIj.js → shadow-claw-conversations-CFaWFmkm.js} +1 -1
- package/dist/public/{shadow-claw-file-viewer-DiQXIjZD.js → shadow-claw-file-viewer-Z-GIKaE9.js} +1 -1
- package/dist/public/{shadow-claw-files-lkTnSJsn.js → shadow-claw-files-BBx4iMsk.js} +1 -1
- package/dist/public/{shadow-claw-git-BlcA_z8x.js → shadow-claw-git-vTOKatwd.js} +2 -2
- package/dist/public/{shadow-claw-llm-CW16X9Rg.js → shadow-claw-llm-Ce1Ax6-x.js} +1 -1
- package/dist/public/{shadow-claw-networking-ySsMBY_i.js → shadow-claw-networking-q4XIzdB5.js} +1 -1
- package/dist/public/{shadow-claw-notifications-CyV2zCQ8.js → shadow-claw-notifications-D2cz0gmm.js} +1 -1
- package/dist/public/{shadow-claw-pages-Cx7cF9ah.js → shadow-claw-pages-3335lmSC.js} +1 -1
- package/dist/public/{shadow-claw-settings-zm4PHHGi.js → shadow-claw-settings-4ptYuJwO.js} +2 -2
- package/dist/public/{shadow-claw-storage-dy9JAEGd.js → shadow-claw-storage-bIrPKFhF.js} +1 -1
- package/dist/public/{shadow-claw-task-server-Bleww48s.js → shadow-claw-task-server-5yqVBxy1.js} +1 -1
- package/dist/public/{shadow-claw-tasks-CTI5oaLN.js → shadow-claw-tasks-DcqYHPLZ.js} +1 -1
- package/dist/public/{shadow-claw-terminal-mZ3i4HaQ.js → shadow-claw-terminal-fARaDONr.js} +1 -1
- package/dist/public/{shadow-claw-tools-B_nuk8Zl.js → shadow-claw-tools-paEAhcJr.js} +1 -1
- package/dist/public/{shadow-claw-webvm-Vl_jH5YL.js → shadow-claw-webvm-CbzH_vyX.js} +1 -1
- package/dist/public/{summarizer-VJNr-7xG.js → summarizer-BT3AuFed.js} +1 -1
- package/dist/public/{syncWebMcpRegistration-n2vAMJ4w.js → syncWebMcpRegistration-CWSYaHex.js} +1 -1
- package/dist/public/{transformers-BhQMWQG5.js → transformers-1VTxqKjT.js} +1 -1
- package/dist/public/{translator-DEQXb7ZL.js → translator-B50RYlFt.js} +1 -1
- package/dist/public/{webllm-CHN5H-Sy.js → webllm-FmyJWWpt.js} +1 -1
- package/dist/public/{writer-CD9oN2pq.js → writer-Bhb4YYRE.js} +1 -1
- package/dist/server.js +205 -203
- package/package.json +1 -1
- package/src/components/settings/shadow-claw-llm/shadow-claw-llm.test.ts +2 -0
- package/src/core/orchestrator/utils/configurePeerJs.test.ts +2 -0
- package/src/server/client-registry.test.ts +9 -0
- package/src/server/client-registry.ts +14 -0
- package/src/server/mcp/mcp-integration.test.ts +68 -16
- package/src/server/mcp/tools/built-in-tools.ts +125 -34
- package/src/server/mcp/tools/client-tool-relay.ts +81 -44
- package/src/server/mcp/tools/mcp-tools.test.ts +103 -13
- package/src/server/mcp/types.ts +3 -0
- package/src/server/openapi/paths/push.ts +48 -0
- package/src/server/server.ts +30 -0
- package/src/subsystems/notifications/push-client.test.ts +17 -0
- package/src/subsystems/notifications/push-client.ts +22 -2
- package/src/subsystems/notifications/push-routes.test.ts +31 -0
- package/src/subsystems/notifications/push-routes.ts +10 -0
- package/src/subsystems/notifications/push-store.test.ts +49 -0
- package/src/subsystems/notifications/push-store.ts +45 -0
- package/src/worker/worker.test.ts +2 -0
- package/dist/lib/push-client-D6hbzDNV.js.map +0 -1
|
@@ -89,17 +89,50 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
89
89
|
expect(res).toBeDefined();
|
|
90
90
|
expect(res.result.resultType).toBe("complete");
|
|
91
91
|
const toolNames = res.result.tools.map((t) => t.name);
|
|
92
|
-
expect(toolNames).toContain("
|
|
93
|
-
expect(toolNames).toContain("
|
|
94
|
-
expect(toolNames).toContain("
|
|
95
|
-
expect(toolNames).toContain("
|
|
92
|
+
expect(toolNames).toContain("shadowclaw_server_list_clients");
|
|
93
|
+
expect(toolNames).toContain("shadowclaw_server_send_message");
|
|
94
|
+
expect(toolNames).toContain("shadowclaw_server_send_notification");
|
|
95
|
+
expect(toolNames).toContain("shadowclaw_server_status");
|
|
96
|
+
expect(toolNames).toContain("shadowclaw_client_read_file");
|
|
96
97
|
|
|
97
98
|
const notifTool = res.result.tools.find(
|
|
98
|
-
(t) => t.name === "
|
|
99
|
+
(t) => t.name === "shadowclaw_server_send_notification",
|
|
99
100
|
);
|
|
100
101
|
expect(notifTool.inputSchema.properties).toHaveProperty("clientId");
|
|
101
102
|
});
|
|
102
103
|
|
|
104
|
+
it("populates clientId enum and description for shadowclaw_server_send_notification when push clients are registered", async () => {
|
|
105
|
+
const mockClient = {
|
|
106
|
+
listClients: jest.fn().mockResolvedValue([]),
|
|
107
|
+
listPushClients: jest.fn().mockResolvedValue([
|
|
108
|
+
{ clientId: "client-pwa-1", deviceLabel: "Android Pixel" },
|
|
109
|
+
{ clientId: "client-pwa-2", deviceLabel: "iPad Safari" },
|
|
110
|
+
]),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const engine = createCliMcpEngine({
|
|
114
|
+
client: mockClient,
|
|
115
|
+
relayClientTools: false,
|
|
116
|
+
});
|
|
117
|
+
const res = await engine.handleMessage({
|
|
118
|
+
jsonrpc: "2.0",
|
|
119
|
+
id: 20,
|
|
120
|
+
method: "tools/list",
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(res).toBeDefined();
|
|
124
|
+
expect(res.result.resultType).toBe("complete");
|
|
125
|
+
const notifTool = res.result.tools.find(
|
|
126
|
+
(t) => t.name === "shadowclaw_server_send_notification",
|
|
127
|
+
);
|
|
128
|
+
expect(notifTool).toBeDefined();
|
|
129
|
+
const clientIdProp = notifTool.inputSchema.properties.clientId;
|
|
130
|
+
expect(clientIdProp).toBeDefined();
|
|
131
|
+
expect(clientIdProp.enum).toEqual(["client-pwa-1", "client-pwa-2"]);
|
|
132
|
+
expect(clientIdProp.description).toContain("client-pwa-1 (Android Pixel)");
|
|
133
|
+
expect(clientIdProp.description).toContain("client-pwa-2 (iPad Safari)");
|
|
134
|
+
});
|
|
135
|
+
|
|
103
136
|
it("processes tools/call for shadowclaw_send_notification directly via broadcastNotification", async () => {
|
|
104
137
|
const mockClient = {
|
|
105
138
|
listClients: jest.fn().mockResolvedValue([]),
|
|
@@ -251,7 +284,7 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
251
284
|
);
|
|
252
285
|
});
|
|
253
286
|
|
|
254
|
-
it("processes tools/call for
|
|
287
|
+
it("processes tools/call for shadowclaw_server_send_message and legacy alias", async () => {
|
|
255
288
|
const mockClient = {
|
|
256
289
|
listClients: jest
|
|
257
290
|
.fn()
|
|
@@ -268,7 +301,7 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
268
301
|
id: 3,
|
|
269
302
|
method: "tools/call",
|
|
270
303
|
params: {
|
|
271
|
-
name: "
|
|
304
|
+
name: "shadowclaw_server_send_message",
|
|
272
305
|
arguments: { text: "Test message" },
|
|
273
306
|
},
|
|
274
307
|
});
|
|
@@ -279,9 +312,55 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
279
312
|
text: "Test message",
|
|
280
313
|
groupId: undefined,
|
|
281
314
|
});
|
|
315
|
+
|
|
316
|
+
// Legacy alias
|
|
317
|
+
const resAlias = await engine.handleMessage({
|
|
318
|
+
jsonrpc: "2.0",
|
|
319
|
+
id: 4,
|
|
320
|
+
method: "tools/call",
|
|
321
|
+
params: {
|
|
322
|
+
name: "shadowclaw_send_message",
|
|
323
|
+
arguments: { text: "Legacy test message" },
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
expect(resAlias).toBeDefined();
|
|
327
|
+
expect(resAlias.result.resultType).toBe("complete");
|
|
328
|
+
expect(mockClient.sendCommand).toHaveBeenCalledWith("c1", "send-message", {
|
|
329
|
+
text: "Legacy test message",
|
|
330
|
+
groupId: undefined,
|
|
331
|
+
});
|
|
282
332
|
});
|
|
283
333
|
|
|
284
|
-
it("processes tools/call for
|
|
334
|
+
it("processes tools/call for shadowclaw_server_status", async () => {
|
|
335
|
+
const mockClient = {
|
|
336
|
+
listClients: jest
|
|
337
|
+
.fn()
|
|
338
|
+
.mockResolvedValue([{ clientId: "c1" }, { clientId: "c2" }]),
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const engine = createCliMcpEngine({
|
|
342
|
+
client: mockClient,
|
|
343
|
+
version: "1.28.1",
|
|
344
|
+
});
|
|
345
|
+
const res = await engine.handleMessage({
|
|
346
|
+
jsonrpc: "2.0",
|
|
347
|
+
id: 5,
|
|
348
|
+
method: "tools/call",
|
|
349
|
+
params: {
|
|
350
|
+
name: "shadowclaw_server_status",
|
|
351
|
+
arguments: {},
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
expect(res).toBeDefined();
|
|
356
|
+
expect(res.result.resultType).toBe("complete");
|
|
357
|
+
const statusData = JSON.parse(res.result.content[0].text);
|
|
358
|
+
expect(statusData.server).toBe("ShadowClaw");
|
|
359
|
+
expect(statusData.connectedClients).toBe(2);
|
|
360
|
+
expect(statusData.status).toBe("healthy");
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it("processes tools/call for relayed client tool (e.g. shadowclaw_client_list_files)", async () => {
|
|
285
364
|
const mockClient = {
|
|
286
365
|
listClients: jest
|
|
287
366
|
.fn()
|
|
@@ -307,7 +386,7 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
307
386
|
id: 4,
|
|
308
387
|
method: "tools/call",
|
|
309
388
|
params: {
|
|
310
|
-
name: "
|
|
389
|
+
name: "shadowclaw_client_list_files",
|
|
311
390
|
arguments: {},
|
|
312
391
|
},
|
|
313
392
|
});
|
|
@@ -321,6 +400,20 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
321
400
|
toolName: "list_files",
|
|
322
401
|
input: {},
|
|
323
402
|
});
|
|
403
|
+
|
|
404
|
+
// Also verify backward compatibility: calling with unprefixed name also proxies
|
|
405
|
+
const resUnprefixed = await engine.handleMessage({
|
|
406
|
+
jsonrpc: "2.0",
|
|
407
|
+
id: 41,
|
|
408
|
+
method: "tools/call",
|
|
409
|
+
params: {
|
|
410
|
+
name: "list_files",
|
|
411
|
+
arguments: {},
|
|
412
|
+
},
|
|
413
|
+
});
|
|
414
|
+
expect(resUnprefixed.result.content[0].text).toBe(
|
|
415
|
+
".agents/ MEMORY.md index.html -/",
|
|
416
|
+
);
|
|
324
417
|
});
|
|
325
418
|
|
|
326
419
|
it("handles tools/call relayed client tool failure with informative error content", async () => {
|
|
@@ -342,7 +435,7 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
342
435
|
id: 5,
|
|
343
436
|
method: "tools/call",
|
|
344
437
|
params: {
|
|
345
|
-
name: "
|
|
438
|
+
name: "shadowclaw_client_list_files",
|
|
346
439
|
arguments: { path: "restricted" },
|
|
347
440
|
},
|
|
348
441
|
});
|
|
@@ -413,7 +506,7 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
413
506
|
});
|
|
414
507
|
|
|
415
508
|
const listFilesTool = listRes.result.tools.find(
|
|
416
|
-
(t) => t.name === "
|
|
509
|
+
(t) => t.name === "shadowclaw_client_list_files",
|
|
417
510
|
);
|
|
418
511
|
expect(listFilesTool).toBeDefined();
|
|
419
512
|
expect(listFilesTool.description).toContain("[Default: Linux Desktop");
|
|
@@ -424,7 +517,9 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
424
517
|
]);
|
|
425
518
|
|
|
426
519
|
// ask_user should ONLY be available on client-alpha
|
|
427
|
-
const askUserTool = listRes.result.tools.find(
|
|
520
|
+
const askUserTool = listRes.result.tools.find(
|
|
521
|
+
(t) => t.name === "shadowclaw_client_ask_user",
|
|
522
|
+
);
|
|
428
523
|
expect(askUserTool).toBeDefined();
|
|
429
524
|
expect(askUserTool.description).toContain("[Client: Linux Desktop");
|
|
430
525
|
expect(askUserTool.inputSchema.properties.clientId.enum).toEqual([
|
|
@@ -437,7 +532,7 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
437
532
|
id: 11,
|
|
438
533
|
method: "tools/call",
|
|
439
534
|
params: {
|
|
440
|
-
name: "
|
|
535
|
+
name: "shadowclaw_client_list_files",
|
|
441
536
|
arguments: { clientId: "client-beta" },
|
|
442
537
|
},
|
|
443
538
|
});
|
|
@@ -473,7 +568,7 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
473
568
|
id: 13,
|
|
474
569
|
method: "tools/call",
|
|
475
570
|
params: {
|
|
476
|
-
name: "
|
|
571
|
+
name: "shadowclaw_client_list_files",
|
|
477
572
|
arguments: {},
|
|
478
573
|
},
|
|
479
574
|
});
|
|
@@ -488,14 +583,14 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
488
583
|
id: 14,
|
|
489
584
|
method: "tools/call",
|
|
490
585
|
params: {
|
|
491
|
-
name: "
|
|
586
|
+
name: "shadowclaw_client_ask_user",
|
|
492
587
|
arguments: { clientId: "client-beta", question: "Prompt client beta?" },
|
|
493
588
|
},
|
|
494
589
|
});
|
|
495
590
|
|
|
496
591
|
expect(unsupportedRes.result.isError).toBe(true);
|
|
497
592
|
expect(unsupportedRes.result.content[0].text).toContain(
|
|
498
|
-
"Tool '
|
|
593
|
+
"Tool 'shadowclaw_client_ask_user' is not enabled or available on client 'client-beta'",
|
|
499
594
|
);
|
|
500
595
|
expect(unsupportedRes.result.content[0].text).toContain(
|
|
501
596
|
"Available on: client-alpha",
|
|
@@ -508,7 +603,7 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
508
603
|
id: 15,
|
|
509
604
|
method: "tools/call",
|
|
510
605
|
params: {
|
|
511
|
-
name: "
|
|
606
|
+
name: "shadowclaw_client_ask_user",
|
|
512
607
|
arguments: { question: "Are you ready?" },
|
|
513
608
|
},
|
|
514
609
|
});
|
|
@@ -530,11 +625,49 @@ describe("CLI MCP Engine (createCliMcpEngine)", () => {
|
|
|
530
625
|
id: 16,
|
|
531
626
|
method: "tools/call",
|
|
532
627
|
params: {
|
|
533
|
-
name: "
|
|
628
|
+
name: "shadowclaw_client_ask_user",
|
|
534
629
|
arguments: { question: "Are you ready?" },
|
|
535
630
|
inputResponses: { response: "Yes, ready to go!" },
|
|
536
631
|
},
|
|
537
632
|
});
|
|
538
633
|
expect(fulfilledRes.result.content[0].text).toBe("Yes, ready to go!");
|
|
539
634
|
});
|
|
635
|
+
|
|
636
|
+
it("handles client.listClients error gracefully in shadowclaw_server_list_clients and legacy alias", async () => {
|
|
637
|
+
const mockClient = {
|
|
638
|
+
listClients: jest
|
|
639
|
+
.fn()
|
|
640
|
+
.mockRejectedValue(new Error("Unauthorized: Invalid control token")),
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
const engine = createCliMcpEngine({ client: mockClient });
|
|
644
|
+
const res = await engine.handleMessage({
|
|
645
|
+
jsonrpc: "2.0",
|
|
646
|
+
id: 99,
|
|
647
|
+
method: "tools/call",
|
|
648
|
+
params: {
|
|
649
|
+
name: "shadowclaw_server_list_clients",
|
|
650
|
+
arguments: {},
|
|
651
|
+
},
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
expect(res).toBeDefined();
|
|
655
|
+
expect(res.id).toBe(99);
|
|
656
|
+
expect(res.result.isError).toBe(true);
|
|
657
|
+
expect(res.result.content[0].text).toContain(
|
|
658
|
+
"Error listing clients: Unauthorized: Invalid control token",
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
// Legacy alias
|
|
662
|
+
const resAlias = await engine.handleMessage({
|
|
663
|
+
jsonrpc: "2.0",
|
|
664
|
+
id: 100,
|
|
665
|
+
method: "tools/call",
|
|
666
|
+
params: {
|
|
667
|
+
name: "shadowclaw_list_clients",
|
|
668
|
+
arguments: {},
|
|
669
|
+
},
|
|
670
|
+
});
|
|
671
|
+
expect(resAlias.result.isError).toBe(true);
|
|
672
|
+
});
|
|
540
673
|
});
|