shadow-claw 1.23.4 → 1.24.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/README.md +42 -5
- package/bin/cli.mjs +166 -0
- package/bin/cli.test.mjs +60 -0
- package/bin/commands/backup.mjs +70 -0
- package/bin/commands/clients.mjs +41 -0
- package/bin/commands/peer-id.mjs +76 -0
- package/bin/commands/peer-id.test.mjs +104 -0
- package/bin/commands/send.mjs +51 -0
- package/bin/commands/tasks.mjs +59 -0
- package/bin/commands/webrtc-listen.mjs +254 -0
- package/bin/prerender-dsd-shell/prerender-dsd-shell.test.mjs +46 -0
- package/bin/rolldown.config.test.mjs +401 -8
- package/bin/utils/control-client.mjs +243 -0
- package/bin/utils/control-client.test.mjs +83 -0
- package/bin/utils/ulid.mjs +45 -0
- package/bin/utils/webrtc-control-client.mjs +699 -0
- package/bin/utils/webrtc-control-client.test.mjs +318 -0
- package/dist/electron/main.cjs +1 -1
- package/dist/public/AGENTS.md +5 -3
- package/dist/public/README.md +42 -5
- package/dist/public/agent.worker.js +1 -1
- package/dist/public/backup-controller-C_s9in2t.js +1 -0
- package/dist/public/components/settings/shadow-claw-control-plane/shadow-claw-control-plane.css +1 -0
- package/dist/public/components/settings/shadow-claw-control-plane/shadow-claw-control-plane.html +1 -0
- package/dist/public/components/settings/shadow-claw-task-server/shadow-claw-task-server.css +1 -1
- package/dist/public/components/settings/shadow-claw-task-server/shadow-claw-task-server.html +1 -1
- package/dist/public/components/shadow-claw-settings/shadow-claw-settings.html +1 -1
- package/dist/public/config-CrHchneq.js +1 -0
- package/dist/public/{configurePeerJs-B4Ym9VMj.js → configurePeerJs-CxpZeDJJ.js} +1 -1
- package/dist/public/{connections-BEn6JYdu.js → connections-DvbgdkaB.js} +1 -1
- package/dist/public/{custom-element-security-DdYlUozq.js → custom-element-security-NCqQ5lmC.js} +1 -1
- package/dist/public/docs/README.md +3 -1
- package/dist/public/docs/architecture/overview.md +12 -12
- package/dist/public/docs/decisions/bundled-typescript-architecture.md +1 -1
- package/dist/public/docs/decisions/indexeddb-and-opfs-storage.md +2 -2
- package/dist/public/docs/decisions/native-web-components-and-signals.md +1 -1
- package/dist/public/docs/example/article/index.html +1 -1
- package/dist/public/docs/guides/configuring-messaging-channels.md +41 -6
- package/dist/public/docs/guides/server-development-configuration.md +24 -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/backup.md +56 -0
- package/dist/public/docs/subsystems/cli.md +124 -0
- package/dist/public/docs/subsystems/control-plane.md +158 -0
- package/dist/public/docs/subsystems/notifications.md +54 -2
- package/dist/public/docs/subsystems/reactive-ui.md +1 -0
- package/dist/public/downloadGroupFile-By0GR6eV.js +1 -0
- package/dist/public/e2e/README.md +5 -1
- package/dist/public/{e2e-bridge-BQ4KzUt5.js → e2e-bridge-IGWsRl4i.js} +1 -1
- package/dist/public/file-viewer-D0eflgt6.js +1 -0
- package/dist/public/getAllTasks-vpBlgGsc.js +1 -0
- package/dist/public/getGroupDir-P1h9wl6S.js +1 -0
- package/dist/public/{git-DEUvQTUA.js → git-7Vq_SJSp.js} +2 -2
- package/dist/public/{iframe-sanitizer-0NS4XLOd.js → iframe-sanitizer-y2Z1pPwY.js} +1 -1
- package/dist/public/index.html +1 -1
- package/dist/public/index.js +1 -1
- package/dist/public/{initChatSplitResize-llGkSJXg.js → initChatSplitResize-CzV2E7Ul.js} +1 -1
- package/dist/public/initControlPlane-C9jpnWev.js +1 -0
- package/dist/public/llms.txt +1 -1
- package/dist/public/main/index.html +1 -1
- package/dist/public/main/memory/index.html +1 -1
- package/dist/public/{markdown-CyYR4App.js → markdown-BnpKxSxl.js} +1 -1
- package/dist/public/{mcp-reconnect-CSx4aMwy.js → mcp-reconnect-9emsqGRe.js} +1 -1
- package/dist/public/{memoryStorage-Dwg8NhAZ.js → memoryStorage-C0KvLNUp.js} +1 -1
- package/dist/public/{orchestrator-DRfEudXk.js → orchestrator-3h9xxHUm.js} +676 -676
- package/dist/public/orchestrator-nJj59RqD.js +15 -0
- package/dist/public/{peerjs-CurBuKvk.js → peerjs-BP4laMXj.js} +1 -1
- package/dist/public/{push-client-Dii-vPEh.js → push-client-CrjEXK3U.js} +1 -1
- package/dist/public/service-worker/push-handler.js +1 -1
- package/dist/public/service-worker.js +1 -1
- package/dist/public/{shadow-claw-5IHaDDMJ.js → shadow-claw-CbwETBWf.js} +2 -2
- package/dist/public/{shadow-claw-accounts-CZvz4iQz.js → shadow-claw-accounts-B4sBTQEj.js} +1 -1
- package/dist/public/{shadow-claw-channels-BKXFyRS3.js → shadow-claw-channels-BDWG5Qa3.js} +1 -1
- package/dist/public/{shadow-claw-chat-CCLuhWdI.js → shadow-claw-chat-Crv0DTCY.js} +6 -6
- package/dist/public/shadow-claw-control-plane-CX1IGbh9.js +199 -0
- package/dist/public/{shadow-claw-conversations-DV-87UUh.js → shadow-claw-conversations-_9qAaRXk.js} +1 -1
- package/dist/public/shadow-claw-dialog-BrOwAOdk.js +1 -0
- package/dist/public/{shadow-claw-file-viewer-Dk2dbAUd.js → shadow-claw-file-viewer-Blf6yGVD.js} +1 -1
- package/dist/public/shadow-claw-files-CYySBDCl.js +840 -0
- package/dist/public/{shadow-claw-git-DRA7_qck.js → shadow-claw-git-v8S0JjuR.js} +2 -2
- package/dist/public/{shadow-claw-integrations-1Xu5snuV.js → shadow-claw-integrations-D7ufpwhX.js} +1 -1
- package/dist/public/{shadow-claw-llm-6Aci1BDP.js → shadow-claw-llm-GWgoVfhI.js} +2 -2
- package/dist/public/{shadow-claw-mcp-remote-BUjAeVXC.js → shadow-claw-mcp-remote-kY4LMFNN.js} +1 -1
- package/dist/public/{shadow-claw-networking-FQe4nCp3.js → shadow-claw-networking-qHbP95z9.js} +1 -1
- package/dist/public/{shadow-claw-notifications-DV2wibL3.js → shadow-claw-notifications-YyHOK2Fr.js} +1 -1
- package/dist/public/{shadow-claw-page-header-B63S4HTU.js → shadow-claw-page-header-DMKbkv3s.js} +1 -1
- package/dist/public/{shadow-claw-pages-DE3jWj5K.js → shadow-claw-pages-DFZHhzFZ.js} +1 -1
- package/dist/public/{shadow-claw-settings-S6DAKfYx.js → shadow-claw-settings-DhxrKIfA.js} +10 -3
- package/dist/public/{shadow-claw-storage-DaacA3_K.js → shadow-claw-storage-BFynbP0j.js} +2 -2
- package/dist/public/{shadow-claw-task-server-IjKX042p.js → shadow-claw-task-server-3BIeb5oZ.js} +25 -4
- package/dist/public/{shadow-claw-tasks-Cy0JYmGU.js → shadow-claw-tasks-Caxc9atL.js} +1 -1
- package/dist/public/{shadow-claw-terminal-znAt7HyP.js → shadow-claw-terminal-Beb5qF-U.js} +1 -1
- package/dist/public/{shadow-claw-tools-Cutv9Si5.js → shadow-claw-tools-BfJx3A9W.js} +1 -1
- package/dist/public/{shadow-claw-webvm-BH8mPDEu.js → shadow-claw-webvm-BCS8ykeP.js} +1 -1
- package/dist/public/{syncWebMcpRegistration-BqJxaMGR.js → syncWebMcpRegistration-B_M2fCjH.js} +1 -1
- package/dist/server.js +286 -189
- package/package.json +2 -1
- package/src/__mocks__/jszip.cjs +15 -5
- package/src/components/settings/shadow-claw-accounts/shadow-claw-accounts.test.ts +35 -0
- package/src/components/settings/shadow-claw-control-plane/shadow-claw-control-plane.css +117 -0
- package/src/components/settings/shadow-claw-control-plane/shadow-claw-control-plane.html +81 -0
- package/src/components/settings/shadow-claw-control-plane/shadow-claw-control-plane.test.ts +127 -0
- package/src/components/settings/shadow-claw-control-plane/shadow-claw-control-plane.ts +292 -0
- package/src/components/settings/shadow-claw-git/shadow-claw-git.test.ts +72 -0
- package/src/components/settings/shadow-claw-integrations/connection-test-auth.test.ts +20 -30
- package/src/components/settings/shadow-claw-integrations/shadow-claw-integrations.test.ts +116 -0
- package/src/components/settings/shadow-claw-llm/model-ranking.test.ts +143 -51
- package/src/components/settings/shadow-claw-llm/shadow-claw-llm.test.ts +307 -4
- package/src/components/settings/shadow-claw-llm/shadow-claw-llm.ts +8 -8
- package/src/components/settings/shadow-claw-mcp-remote/shadow-claw-mcp-remote.test.ts +31 -0
- package/src/components/settings/shadow-claw-peerjs/shadow-claw-peerjs.test.ts +186 -0
- package/src/components/settings/shadow-claw-storage/shadow-claw-storage.test.ts +76 -0
- package/src/components/settings/shadow-claw-task-server/shadow-claw-task-server.css +23 -2
- package/src/components/settings/shadow-claw-task-server/shadow-claw-task-server.html +1 -1
- package/src/components/settings/shadow-claw-task-server/shadow-claw-task-server.test.ts +19 -0
- package/src/components/settings/shadow-claw-task-server/shadow-claw-task-server.ts +2 -1
- package/src/components/shadow-claw/utils/initChatSplitResize.test.ts +180 -13
- package/src/components/shadow-claw/utils/setupEffects.test.ts +39 -0
- package/src/components/shadow-claw-a2ui/catalog/basic/shared.test.ts +117 -0
- package/src/components/shadow-claw-a2ui/shadow-claw-a2ui.test.ts +1159 -1
- package/src/components/shadow-claw-chat/shadow-claw-chat.test.ts +1523 -19
- package/src/components/shadow-claw-chat/utils/escapeHtml.test.ts +13 -0
- package/src/components/shadow-claw-chat/utils/getPeerChatDisplayStatus.test.ts +20 -0
- package/src/components/shadow-claw-conversations/shadow-claw-conversations.test.ts +494 -0
- package/src/components/shadow-claw-dialog/shadow-claw-dialog.ts +13 -2
- package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.test.ts +273 -0
- package/src/components/shadow-claw-files/shadow-claw-files.test.ts +408 -1
- package/src/components/shadow-claw-pdf-viewer/utils/installGetOrInsertComputedPolyfill.test.ts +65 -0
- package/src/components/shadow-claw-settings/shadow-claw-settings.html +7 -0
- package/src/components/shadow-claw-settings/shadow-claw-settings.test.ts +221 -0
- package/src/components/shadow-claw-settings/shadow-claw-settings.ts +2 -0
- package/src/components/shadow-claw-tasks/shadow-claw-tasks.test.ts +407 -0
- package/src/components/shadow-claw-terminal/utils/consumeEscapeSequence.test.ts +58 -0
- package/src/components/shadow-claw-tools/shadow-claw-tools.test.ts +80 -0
- package/src/config/config.ts +10 -0
- package/src/core/backup-controller.test.ts +101 -0
- package/src/core/backup-controller.ts +137 -0
- package/src/core/control-plane-client.test.ts +408 -0
- package/src/core/control-plane-client.ts +425 -0
- package/src/core/orchestrator/orchestrator.ts +4 -0
- package/src/core/orchestrator/utils/compactContext.test.ts +78 -0
- package/src/core/orchestrator/utils/operations/channel.test.ts +254 -9
- package/src/core/orchestrator/utils/operations/provider.test.ts +326 -34
- package/src/core/orchestrator/utils/operations/vm.test.ts +114 -2
- package/src/core/orchestrator/utils/syncProxyConfigToServiceWorker.test.ts +60 -0
- package/src/core/utils/initControlPlane.test.ts +276 -0
- package/src/core/utils/initControlPlane.ts +437 -0
- package/src/core/utils/initializeApp.ts +18 -0
- package/src/db/getSession.test.ts +13 -1
- package/src/server/app.test.ts +12 -0
- package/src/server/app.ts +18 -8
- package/src/server/client-registry.test.ts +250 -0
- package/src/server/client-registry.ts +477 -0
- package/src/server/config.ts +15 -0
- package/src/server/control-plane-types.ts +120 -0
- package/src/server/control-plane.test.ts +472 -0
- package/src/server/control-plane.ts +581 -0
- package/src/server/routes/backup.test.ts +263 -0
- package/src/server/routes/backup.ts +262 -0
- package/src/server/routes/integrations-email.test.ts +532 -0
- package/src/server/routes/llamafile.test.ts +172 -48
- package/src/server/routes/mesh-llm.test.ts +192 -0
- package/src/server/routes/ollama.test.ts +49 -0
- package/src/server/server-peer.test.ts +86 -0
- package/src/server/server-peer.ts +330 -0
- package/src/server/server.ts +35 -0
- package/src/server/services/llamafile-manager.test.ts +230 -6
- package/src/server/services/transformers-runtime.test.ts +186 -18
- package/src/server/webrtc.test.ts +21 -0
- package/src/server/webrtc.ts +72 -0
- package/src/service-worker/fetch-proxy.test.ts +64 -1
- package/src/service-worker/push-handler.ts +39 -0
- package/src/shell/vm.test.ts +744 -12
- package/src/storage/ensureMainGroupIndex.test.ts +153 -0
- package/src/storage/getGroupFile.test.ts +66 -0
- package/src/storage/memoryStorage.test.ts +82 -2
- package/src/storage/writeGroupFileBytes.test.ts +143 -0
- package/src/stores/chat-ui.test.ts +20 -0
- package/src/stores/orchestrator.test.ts +134 -0
- package/src/stores/toast.test.ts +50 -0
- package/src/stores/tools.test.ts +147 -10
- package/src/subsystems/channels/imessage.test.ts +59 -0
- package/src/subsystems/channels/peerjs.test.ts +500 -62
- package/src/subsystems/channels/peerjs.ts +71 -4
- package/src/subsystems/channels/telegram.test.ts +177 -0
- package/src/subsystems/email/catalog.test.ts +1 -0
- package/src/subsystems/email/connections.test.ts +39 -1
- package/src/subsystems/git/credentials.test.ts +160 -825
- package/src/subsystems/git/git.test.ts +463 -0
- package/src/subsystems/notifications/__mocks__/node-sqlite.cjs +12 -1
- package/src/subsystems/notifications/push-routes.test.ts +33 -0
- package/src/subsystems/notifications/push-routes.ts +23 -0
- package/src/subsystems/notifications/push-store.ts +1 -1
- package/src/subsystems/providers/builtin-ai-tasks.test.ts +74 -0
- package/src/subsystems/providers/litert-lm-provider.test.ts +212 -51
- package/src/subsystems/providers/model-registry.test.ts +115 -0
- package/src/subsystems/providers/providers.test.ts +94 -1
- package/src/subsystems/providers/transformers-js-provider.test.ts +279 -0
- package/src/subsystems/providers/utils/createModelCacheFetch.test.ts +2 -2
- package/src/subsystems/providers/utils/downloadModelToCache.test.ts +2 -2
- package/src/subsystems/providers/utils/loadModelStream.test.ts +2 -2
- package/src/subsystems/skills/activateSkill.test.ts +101 -0
- package/src/subsystems/skills/discoverSkills.test.ts +251 -0
- package/src/subsystems/tools/cron.test.ts +64 -0
- package/src/subsystems/tools/declarative.test.ts +255 -89
- package/src/testing/assets/v86.9pfs/libv86.mjs +63 -0
- package/src/testing/assets/v86.ext2/libv86.mjs +3 -0
- package/src/testing/assets_missing_v86/assets/v86.9pfs/libv86.mjs +1 -0
- package/src/testing/jest-setup.ts +328 -40
- package/src/testing/mock-v86.mjs +49 -0
- package/src/ui/a2ui/types.ts +4 -3
- package/src/ui/a2ui/utils/normaliseComponentsToMap.test.ts +102 -0
- package/src/ui/a2ui/utils/resolveChildIds.test.ts +63 -0
- package/src/ui/a2ui/utils/resolveDynamicNumber.test.ts +13 -1
- package/src/worker/tools/bash/utils/waitForVMReady.test.ts +40 -0
- package/src/worker/tools/email/email.test.ts +193 -8
- package/src/worker/tools/email/utils/asEmailAttachmentInputs.test.ts +47 -0
- package/src/worker/tools/git/git.test.ts +214 -3
- package/src/worker/tools/rooms/invite-to-room.test.ts +54 -0
- package/src/worker/tools/rooms/leave-room.test.ts +40 -0
- package/src/worker/tools/rooms/list-room-members.test.ts +75 -0
- package/src/worker/tools/tasks/tasks-utils.test.ts +22 -0
- package/src/worker/tools/ui/ask-user.test.ts +50 -0
- package/src/worker/tools/ui/clear-chat.test.ts +19 -0
- package/src/worker/tools/ui/get-current-time.test.ts +19 -0
- package/src/worker/tools/ui/javascript.test.ts +116 -0
- package/src/worker/tools/ui/list-components.test.ts +10 -0
- package/src/worker/tools/ui/list-tool-profiles.test.ts +42 -0
- package/src/worker/tools/ui/manage-tools.test.ts +34 -0
- package/src/worker/tools/ui/render-component.test.ts +346 -0
- package/src/worker/tools/ui/send-notification.test.ts +40 -0
- package/src/worker/tools/ui/utils/getAllowFullInternetAccess.test.ts +31 -0
- package/src/worker/tools/ui/utils/parseBooleanConfig.test.ts +25 -0
- package/src/worker/tools/workspace/attach-file.test.ts +84 -0
- package/src/worker/tools/workspace/copy-file.test.ts +69 -0
- package/src/worker/tools/workspace/create-directory.test.ts +40 -0
- package/src/worker/tools/workspace/delete-file.test.ts +73 -0
- package/src/worker/tools/workspace/diff-files.test.ts +94 -0
- package/src/worker/tools/workspace/list-files.test.ts +36 -0
- package/src/worker/tools/workspace/move-file.test.ts +66 -0
- package/src/worker/tools/workspace/open-file.test.ts +57 -0
- package/src/worker/tools/workspace/patch-file.test.ts +81 -0
- package/src/worker/tools/workspace/read-file.test.ts +116 -0
- package/src/worker/tools/workspace/send-file.test.ts +82 -0
- package/src/worker/tools/workspace/update-memory.test.ts +29 -0
- package/src/worker/tools/workspace/write-file.test.ts +28 -0
- package/src/worker/utils/rate-limit.test.ts +199 -0
- package/src/worker/utils/tool-state.test.ts +29 -0
- package/src/worker/utils/transformers-js-utils.test.ts +59 -0
- package/dist/public/config-BYAuxx3j.js +0 -1
- package/dist/public/downloadGroupFile-Drdvg1Ev.js +0 -1
- package/dist/public/file-viewer-CcZYw-PS.js +0 -1
- package/dist/public/orchestrator-o9Fj67BN.js +0 -15
- package/dist/public/shadow-claw-dialog-ByyHgxM9.js +0 -1
- package/dist/public/shadow-claw-files-BpfpJIuP.js +0 -840
|
@@ -382,4 +382,76 @@ describe("shadow-claw-git", () => {
|
|
|
382
382
|
|
|
383
383
|
document.body.removeChild(el);
|
|
384
384
|
});
|
|
385
|
+
|
|
386
|
+
it("handles setDefaultAccount and deleteAccount", async () => {
|
|
387
|
+
const el = new ShadowClawGit();
|
|
388
|
+
document.body.appendChild(el);
|
|
389
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
390
|
+
await el.render();
|
|
391
|
+
|
|
392
|
+
el.accounts = [
|
|
393
|
+
{
|
|
394
|
+
id: "acc-1",
|
|
395
|
+
label: "Account 1",
|
|
396
|
+
hostPattern: "github.com",
|
|
397
|
+
authMode: "token",
|
|
398
|
+
} as any,
|
|
399
|
+
{
|
|
400
|
+
id: "acc-2",
|
|
401
|
+
label: "Account 2",
|
|
402
|
+
hostPattern: "gitlab.com",
|
|
403
|
+
authMode: "token",
|
|
404
|
+
} as any,
|
|
405
|
+
];
|
|
406
|
+
el.defaultAccountId = "acc-1";
|
|
407
|
+
|
|
408
|
+
await el.setDefaultAccount("acc-2");
|
|
409
|
+
expect(el.defaultAccountId).toBe("acc-2");
|
|
410
|
+
|
|
411
|
+
await el.deleteAccount("acc-1");
|
|
412
|
+
expect(el.accounts.find((a) => a.id === "acc-1")).toBeUndefined();
|
|
413
|
+
expect(el.defaultAccountId).toBe("acc-2");
|
|
414
|
+
|
|
415
|
+
document.body.removeChild(el);
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it("handles saveGitSettings with custom proxy and author info", async () => {
|
|
419
|
+
const { setConfig } = await import("../../../db/setConfig.js");
|
|
420
|
+
const el = new ShadowClawGit();
|
|
421
|
+
document.body.appendChild(el);
|
|
422
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
423
|
+
await el.render();
|
|
424
|
+
el.db = {} as any;
|
|
425
|
+
|
|
426
|
+
const customRadio = el.shadowRoot?.querySelector(
|
|
427
|
+
'[data-setting="git-proxy-custom"]',
|
|
428
|
+
) as HTMLInputElement;
|
|
429
|
+
if (customRadio) customRadio.checked = true;
|
|
430
|
+
|
|
431
|
+
const authorNameInput = el.shadowRoot?.querySelector(
|
|
432
|
+
'[data-setting="git-author-name-input"]',
|
|
433
|
+
) as HTMLInputElement;
|
|
434
|
+
if (authorNameInput) authorNameInput.value = "Custom Author";
|
|
435
|
+
|
|
436
|
+
const authorEmailInput = el.shadowRoot?.querySelector(
|
|
437
|
+
'[data-setting="git-author-email-input"]',
|
|
438
|
+
) as HTMLInputElement;
|
|
439
|
+
if (authorEmailInput) authorEmailInput.value = "author@example.com";
|
|
440
|
+
|
|
441
|
+
await el.saveGitSettings();
|
|
442
|
+
|
|
443
|
+
expect(setConfig).toHaveBeenCalledWith(el.db, "git_cors_proxy", "custom");
|
|
444
|
+
expect(setConfig).toHaveBeenCalledWith(
|
|
445
|
+
el.db,
|
|
446
|
+
"git_author_name",
|
|
447
|
+
"Custom Author",
|
|
448
|
+
);
|
|
449
|
+
expect(setConfig).toHaveBeenCalledWith(
|
|
450
|
+
el.db,
|
|
451
|
+
"git_author_email",
|
|
452
|
+
"author@example.com",
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
document.body.removeChild(el);
|
|
456
|
+
});
|
|
385
457
|
});
|
|
@@ -1,55 +1,45 @@
|
|
|
1
|
-
import { describe, expect, it } from "@jest/globals";
|
|
2
|
-
|
|
3
1
|
import { resolveConnectionTestAuth } from "./connection-test-auth.js";
|
|
4
2
|
|
|
5
3
|
describe("resolveConnectionTestAuth", () => {
|
|
6
|
-
it("
|
|
4
|
+
it("resolves oauth authType with trimmed access token", () => {
|
|
7
5
|
const result = resolveConnectionTestAuth({
|
|
8
6
|
authMode: "oauth",
|
|
9
|
-
pendingOauthAccessToken: "
|
|
7
|
+
pendingOauthAccessToken: " my-access-token ",
|
|
8
|
+
passwordInput: "",
|
|
10
9
|
});
|
|
11
|
-
|
|
12
10
|
expect(result).toEqual({
|
|
13
11
|
authType: "oauth",
|
|
14
|
-
accessToken: "
|
|
12
|
+
accessToken: "my-access-token",
|
|
15
13
|
});
|
|
16
14
|
});
|
|
17
15
|
|
|
18
|
-
it("
|
|
19
|
-
const result = resolveConnectionTestAuth({
|
|
16
|
+
it("returns error when oauth access token is missing or empty", () => {
|
|
17
|
+
const result: any = resolveConnectionTestAuth({
|
|
20
18
|
authMode: "oauth",
|
|
21
|
-
pendingOauthAccessToken: "",
|
|
22
|
-
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
expect(result).toEqual({
|
|
26
|
-
error:
|
|
27
|
-
"OAuth access token is missing. Click Connect OAuth first (or save and reconnect).",
|
|
19
|
+
pendingOauthAccessToken: " ",
|
|
20
|
+
passwordInput: "",
|
|
28
21
|
});
|
|
22
|
+
expect(result.error).toContain("OAuth access token is missing");
|
|
29
23
|
});
|
|
30
24
|
|
|
31
|
-
it("
|
|
25
|
+
it("resolves basic_userpass authType with trimmed password", () => {
|
|
32
26
|
const result = resolveConnectionTestAuth({
|
|
33
|
-
authMode: "
|
|
34
|
-
|
|
27
|
+
authMode: "password",
|
|
28
|
+
pendingOauthAccessToken: "",
|
|
29
|
+
passwordInput: " secret-password ",
|
|
35
30
|
});
|
|
36
|
-
|
|
37
31
|
expect(result).toEqual({
|
|
38
32
|
authType: "basic_userpass",
|
|
39
|
-
password: "
|
|
33
|
+
password: "secret-password",
|
|
40
34
|
});
|
|
41
35
|
});
|
|
42
36
|
|
|
43
|
-
it("
|
|
44
|
-
const result = resolveConnectionTestAuth({
|
|
45
|
-
authMode: "
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
expect(result).toEqual({
|
|
51
|
-
error:
|
|
52
|
-
"Password/app password is missing. Enter it to test this connection.",
|
|
37
|
+
it("returns error when password is missing or empty", () => {
|
|
38
|
+
const result: any = resolveConnectionTestAuth({
|
|
39
|
+
authMode: "password",
|
|
40
|
+
pendingOauthAccessToken: "",
|
|
41
|
+
passwordInput: " ",
|
|
53
42
|
});
|
|
43
|
+
expect(result.error).toContain("Password/app password is missing");
|
|
54
44
|
});
|
|
55
45
|
});
|
|
@@ -384,4 +384,120 @@ describe("shadow-claw-integrations", () => {
|
|
|
384
384
|
|
|
385
385
|
document.body.removeChild(el);
|
|
386
386
|
});
|
|
387
|
+
|
|
388
|
+
it("handles testConnectionFromForm with success and error responses", async () => {
|
|
389
|
+
const el = new ShadowClawIntegrations();
|
|
390
|
+
document.body.appendChild(el);
|
|
391
|
+
await el.connectedCallback();
|
|
392
|
+
|
|
393
|
+
el.manifests = [
|
|
394
|
+
{
|
|
395
|
+
id: "imap",
|
|
396
|
+
name: "IMAP",
|
|
397
|
+
configurableFields: ["host", "port", "mailboxPath"],
|
|
398
|
+
description: "",
|
|
399
|
+
} as any,
|
|
400
|
+
];
|
|
401
|
+
(getEmailPluginManifest as jest.Mock).mockReturnValue(el.manifests[0]);
|
|
402
|
+
el.showForm(null);
|
|
403
|
+
|
|
404
|
+
const slot = el.shadowRoot?.querySelector(
|
|
405
|
+
'[data-region="connection-form"]',
|
|
406
|
+
) as HTMLElement;
|
|
407
|
+
|
|
408
|
+
const userInput = slot.querySelector("#int-username") as HTMLInputElement;
|
|
409
|
+
if (userInput) userInput.value = "user@test.com";
|
|
410
|
+
|
|
411
|
+
const hostInput = slot.querySelector("#cfg-host") as HTMLInputElement;
|
|
412
|
+
if (hostInput) hostInput.value = "imap.test.com";
|
|
413
|
+
|
|
414
|
+
const passInput = slot.querySelector("#int-password") as HTMLInputElement;
|
|
415
|
+
if (passInput) passInput.value = "secret-pass";
|
|
416
|
+
|
|
417
|
+
const { resolveConnectionTestAuth } =
|
|
418
|
+
await import("./connection-test-auth.js");
|
|
419
|
+
(resolveConnectionTestAuth as jest.Mock<any>).mockReturnValue({
|
|
420
|
+
authType: "basic_userpass",
|
|
421
|
+
password: "secret-pass",
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Mock fetch for /integrations/email/read success
|
|
425
|
+
(global.fetch as any) = (jest.fn() as any).mockResolvedValueOnce({
|
|
426
|
+
ok: true,
|
|
427
|
+
status: 200,
|
|
428
|
+
json: async () => ({ count: 5 }),
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
await el.testConnectionFromForm(slot);
|
|
432
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
433
|
+
"/integrations/email/read",
|
|
434
|
+
expect.objectContaining({ method: "POST" }),
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
// Mock fetch for failure
|
|
438
|
+
(global.fetch as any) = (jest.fn() as any).mockResolvedValueOnce({
|
|
439
|
+
ok: false,
|
|
440
|
+
status: 401,
|
|
441
|
+
statusText: "Unauthorized",
|
|
442
|
+
json: async () => ({ error: "Auth failed" }),
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
await el.testConnectionFromForm(slot);
|
|
446
|
+
|
|
447
|
+
// Toggle connection test
|
|
448
|
+
el.connections = [
|
|
449
|
+
{
|
|
450
|
+
id: "conn-1",
|
|
451
|
+
label: "My IMAP",
|
|
452
|
+
pluginId: "imap",
|
|
453
|
+
enabled: true,
|
|
454
|
+
config: {},
|
|
455
|
+
credentialRef: null,
|
|
456
|
+
createdAt: 0,
|
|
457
|
+
updatedAt: 0,
|
|
458
|
+
} as any,
|
|
459
|
+
];
|
|
460
|
+
const { upsertEmailConnection } =
|
|
461
|
+
await import("../../../subsystems/email/connections.js");
|
|
462
|
+
await el.toggleConnection("conn-1");
|
|
463
|
+
expect(upsertEmailConnection).toHaveBeenCalledWith(
|
|
464
|
+
el.db,
|
|
465
|
+
expect.objectContaining({
|
|
466
|
+
id: "conn-1",
|
|
467
|
+
enabled: false,
|
|
468
|
+
}),
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
// OAuth connect from form tests
|
|
472
|
+
const oauthSlot = document.createElement("div");
|
|
473
|
+
oauthSlot.innerHTML = `
|
|
474
|
+
<select id="int-oauth-provider"><option value="google">Google</option></select>
|
|
475
|
+
<input id="int-oauth-client-id" value="client-id-123" />
|
|
476
|
+
<input id="int-oauth-client-secret" value="secret-xyz" />
|
|
477
|
+
<input id="int-oauth-scope" value="https://mail.google.com/" />
|
|
478
|
+
<div data-region="oauth-status"></div>
|
|
479
|
+
<button data-action="connect-oauth"></button>
|
|
480
|
+
`;
|
|
481
|
+
el.shadowRoot?.appendChild(oauthSlot);
|
|
482
|
+
|
|
483
|
+
(global.fetch as any) = jest.fn<any>().mockResolvedValue({
|
|
484
|
+
ok: true,
|
|
485
|
+
status: 200,
|
|
486
|
+
json: async () => ({
|
|
487
|
+
authUrl: "https://accounts.google.com/o/oauth2/auth",
|
|
488
|
+
}),
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
const windowOpenSpy = jest
|
|
492
|
+
.spyOn(window, "open")
|
|
493
|
+
.mockImplementation(() => null);
|
|
494
|
+
await el.connectOAuthFromForm(oauthSlot);
|
|
495
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
496
|
+
"/oauth/authorize",
|
|
497
|
+
expect.objectContaining({ method: "POST" }),
|
|
498
|
+
);
|
|
499
|
+
windowOpenSpy.mockRestore();
|
|
500
|
+
|
|
501
|
+
document.body.removeChild(el);
|
|
502
|
+
});
|
|
387
503
|
});
|
|
@@ -4,61 +4,153 @@ import {
|
|
|
4
4
|
} from "./model-ranking.js";
|
|
5
5
|
|
|
6
6
|
describe("model-ranking", () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
isLikelyInstructionModelId("
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
true
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
describe("isLikelyInstructionModelId", () => {
|
|
8
|
+
it("identifies instruction/chat model names correctly", () => {
|
|
9
|
+
expect(isLikelyInstructionModelId("meta-llama/Llama-3-8B-Instruct")).toBe(
|
|
10
|
+
true,
|
|
11
|
+
);
|
|
12
|
+
expect(isLikelyInstructionModelId("google/gemma-2-2b-it")).toBe(true);
|
|
13
|
+
expect(isLikelyInstructionModelId("mistralai/Mistral-7B-Chat-v0.3")).toBe(
|
|
14
|
+
true,
|
|
15
|
+
);
|
|
16
|
+
expect(isLikelyInstructionModelId("org/model-assistant-v1")).toBe(true);
|
|
17
|
+
expect(isLikelyInstructionModelId("org/model-tool-v2")).toBe(true);
|
|
18
|
+
expect(
|
|
19
|
+
isLikelyInstructionModelId("onnx-community/Qwen2.5-0.5B-Instruct"),
|
|
20
|
+
).toBe(true);
|
|
21
|
+
expect(
|
|
22
|
+
isLikelyInstructionModelId("deepseek-ai/deepseek-r1-distill-qwen-1.5b"),
|
|
23
|
+
).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("returns false for non-instruction base model names", () => {
|
|
27
|
+
expect(isLikelyInstructionModelId("bert-base-uncased")).toBe(false);
|
|
28
|
+
expect(isLikelyInstructionModelId("gpt2")).toBe(false);
|
|
29
|
+
expect(isLikelyInstructionModelId("t5-small")).toBe(false);
|
|
30
|
+
});
|
|
17
31
|
});
|
|
18
32
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
id: "onnx-community/gemma-4-E4B-it-ONNX",
|
|
32
|
-
supportsTools: true,
|
|
33
|
-
contextLength: 131072,
|
|
34
|
-
};
|
|
33
|
+
describe("compareLocalModelCandidates", () => {
|
|
34
|
+
it("prioritizes models supporting tools over unsupported", () => {
|
|
35
|
+
const a = {
|
|
36
|
+
id: "model-a-instruct-onnx-0.5b",
|
|
37
|
+
supportsTools: true,
|
|
38
|
+
contextLength: 8192,
|
|
39
|
+
};
|
|
40
|
+
const b = {
|
|
41
|
+
id: "model-b-instruct-onnx-0.5b",
|
|
42
|
+
supportsTools: false,
|
|
43
|
+
contextLength: 8192,
|
|
44
|
+
};
|
|
35
45
|
|
|
36
|
-
|
|
37
|
-
compareLocalModelCandidates(
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
expect(compareLocalModelCandidates(a, b, "local")).toBeLessThan(0);
|
|
47
|
+
expect(compareLocalModelCandidates(b, a, "local")).toBeGreaterThan(0);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("ranks smaller quantized ONNX models higher for transformers_js_browser", () => {
|
|
51
|
+
const smallOnnx = {
|
|
52
|
+
id: "onnx-community/Qwen2.5-0.5B-Instruct-q4",
|
|
53
|
+
supportsTools: true,
|
|
54
|
+
contextLength: 32768,
|
|
55
|
+
};
|
|
56
|
+
const largeNonOnnx = {
|
|
57
|
+
id: "meta-llama/Llama-3-8B-Instruct",
|
|
58
|
+
supportsTools: true,
|
|
59
|
+
contextLength: 8192,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
expect(
|
|
63
|
+
compareLocalModelCandidates(
|
|
64
|
+
smallOnnx,
|
|
65
|
+
largeNonOnnx,
|
|
66
|
+
"transformers_js_browser",
|
|
67
|
+
),
|
|
68
|
+
).toBeLessThan(0);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("handles various model sizes (0.7b, 1.1b, 1.5b, 7b, unstated size)", () => {
|
|
72
|
+
const m07 = {
|
|
73
|
+
id: "model-0.7b-onnx",
|
|
74
|
+
supportsTools: true,
|
|
75
|
+
contextLength: 4096,
|
|
76
|
+
};
|
|
77
|
+
const m11 = {
|
|
78
|
+
id: "model-1.1b-onnx",
|
|
79
|
+
supportsTools: true,
|
|
80
|
+
contextLength: 4096,
|
|
81
|
+
};
|
|
82
|
+
const m15 = {
|
|
83
|
+
id: "model-1.5b-onnx",
|
|
84
|
+
supportsTools: true,
|
|
85
|
+
contextLength: 4096,
|
|
86
|
+
};
|
|
87
|
+
const m7b = {
|
|
88
|
+
id: "model-7b-onnx",
|
|
89
|
+
supportsTools: true,
|
|
90
|
+
contextLength: 4096,
|
|
91
|
+
};
|
|
92
|
+
const mNoSize = {
|
|
93
|
+
id: "model-onnx",
|
|
94
|
+
supportsTools: true,
|
|
95
|
+
contextLength: 4096,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
expect(compareLocalModelCandidates(m07, m11, "local")).toBeLessThan(0);
|
|
99
|
+
expect(compareLocalModelCandidates(m11, m15, "local")).toBeLessThan(0);
|
|
100
|
+
expect(compareLocalModelCandidates(m15, mNoSize, "local")).toBeLessThan(
|
|
101
|
+
0,
|
|
102
|
+
);
|
|
103
|
+
expect(compareLocalModelCandidates(mNoSize, m7b, "local")).toBeLessThan(
|
|
104
|
+
0,
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("handles Gemma style E2B/E4B IDs and tie-breaking by context length and id", () => {
|
|
109
|
+
const gemma = {
|
|
110
|
+
id: "google/gemma-e2b-it-onnx",
|
|
111
|
+
supportsTools: true,
|
|
112
|
+
contextLength: 8192,
|
|
113
|
+
};
|
|
114
|
+
const gemmaHighCtx = {
|
|
115
|
+
id: "google/gemma-e2b-it-onnx",
|
|
116
|
+
supportsTools: true,
|
|
117
|
+
contextLength: 16384,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Equal score -> higher context length wins (score negative)
|
|
121
|
+
expect(
|
|
122
|
+
compareLocalModelCandidates(gemmaHighCtx, gemma, "local"),
|
|
123
|
+
).toBeLessThan(0);
|
|
124
|
+
|
|
125
|
+
// Same context length -> alphabetical tie break
|
|
126
|
+
const m1 = {
|
|
127
|
+
id: "model-1-onnx-0.5b",
|
|
128
|
+
supportsTools: true,
|
|
129
|
+
contextLength: 4096,
|
|
130
|
+
};
|
|
131
|
+
const m2 = {
|
|
132
|
+
id: "model-2-onnx-0.5b",
|
|
133
|
+
supportsTools: true,
|
|
134
|
+
contextLength: 4096,
|
|
135
|
+
};
|
|
136
|
+
expect(compareLocalModelCandidates(m1, m2, "local")).toBeLessThan(0);
|
|
137
|
+
});
|
|
43
138
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
139
|
+
it("scores reasoning/thinking models appropriately", () => {
|
|
140
|
+
const normal = {
|
|
141
|
+
id: "qwen-0.5b-onnx-q4",
|
|
142
|
+
supportsTools: true,
|
|
143
|
+
contextLength: 8192,
|
|
144
|
+
};
|
|
145
|
+
const thinking = {
|
|
146
|
+
id: "qwen-0.5b-thinking-onnx-q4",
|
|
147
|
+
supportsTools: true,
|
|
148
|
+
contextLength: 8192,
|
|
149
|
+
};
|
|
55
150
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"transformers_js_browser",
|
|
61
|
-
),
|
|
62
|
-
).toBeLessThan(0);
|
|
151
|
+
expect(
|
|
152
|
+
compareLocalModelCandidates(normal, thinking, "local"),
|
|
153
|
+
).toBeLessThan(0);
|
|
154
|
+
});
|
|
63
155
|
});
|
|
64
156
|
});
|