@desplega.ai/agent-swarm 2.5.2 → 2.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{acp-adapter-csh0zz3b.js → acp-adapter-ek38cwsv.js} +5 -5
- package/dist/{actions-6xx079d1.js → actions-92mepq03.js} +19 -19
- package/dist/{amp-adapter-8n6f0hz8.js → amp-adapter-9gaxg015.js} +4 -4
- package/dist/{app-ft6r6v23.js → app-ctn8gsgx.js} +3 -3
- package/dist/{assistant-vt2cyfzd.js → assistant-zyr5kz47.js} +21 -21
- package/dist/{boot-reembed-tgrfy27t.js → boot-reembed-dwzfttdr.js} +1 -1
- package/dist/{boot-reembed-r3e808ky.js → boot-reembed-w75maga2.js} +1 -1
- package/dist/{boot-scrub-sweep-masdwxkm.js → boot-scrub-sweep-e9kq43kf.js} +3 -3
- package/dist/{boot-seeds-0n82qc7q.js → boot-seeds-x28v3fhb.js} +4 -4
- package/dist/{claude-adapter-s7j47k06.js → claude-adapter-f0afqnne.js} +5 -5
- package/dist/{claude-managed-adapter-gt6pa35d.js → claude-managed-adapter-x81a7r65.js} +3 -3
- package/dist/{claude-managed-setup-3hzrgrnk.js → claude-managed-setup-bqzwjd9x.js} +2 -2
- package/dist/{claude-sdk-session-0zrdzyx2.js → claude-sdk-session-7b7whkaq.js} +9307 -9254
- package/dist/{cli-a5ebc95n.js → cli-0shx9j93.js} +16 -13
- package/dist/{cli-4qkg9968.js → cli-19202kew.js} +4 -4
- package/dist/{cli-cyfgxnvb.js → cli-1r5ad7j5.js} +19 -17
- package/dist/{cli-jmcjbjkt.js → cli-25n3mv5d.js} +9 -7
- package/dist/cli-2655k16q.js +140 -0
- package/dist/{cli-wadzapwb.js → cli-277c31dw.js} +1 -1
- package/dist/{cli-n6kmqngw.js → cli-4b2z6n0m.js} +29 -7
- package/dist/{cli-7ccf7akh.js → cli-5bnsc0e1.js} +9 -7
- package/dist/{cli-qrjv7t18.js → cli-621ce7kw.js} +1 -1
- package/dist/{cli-xzge46sj.js → cli-64mh9mf3.js} +20 -6
- package/dist/{cli-b6tnjdvx.js → cli-6a1xg1p7.js} +6 -2
- package/dist/{cli-ydg6ep51.js → cli-6n8axjv1.js} +1 -1
- package/dist/{cli-e91vshb1.js → cli-7p4jxgtt.js} +5 -5
- package/dist/{cli-f3pfn4x3.js → cli-9j129brq.js} +9 -3
- package/dist/{cli-xw9q173h.js → cli-9s05422w.js} +1 -1
- package/dist/{cli-15xd0j7w.js → cli-abs8ndtr.js} +12 -12
- package/dist/{cli-h5d22pfs.js → cli-asq5ydm4.js} +219 -309
- package/dist/{cli-w9etnnxk.js → cli-bf8ma3f1.js} +120 -50
- package/dist/{cli-0vgy5wfw.js → cli-bvpgr9ny.js} +2 -2
- package/dist/{cli-3e9vs93g.js → cli-c61mbdds.js} +4 -4
- package/dist/{cli-e5bxnjps.js → cli-c952c7ac.js} +5 -5
- package/dist/{cli-p859hcc8.js → cli-dew6x255.js} +1 -1
- package/dist/{cli-tx00c0h6.js → cli-dqygeeh5.js} +17 -1
- package/dist/{cli-gpv60278.js → cli-e42vss7b.js} +2 -2
- package/dist/{cli-b63d08rs.js → cli-eftzyh9y.js} +1 -1
- package/dist/{cli-fgn7yg5r.js → cli-ethgy7ha.js} +1 -1
- package/dist/{cli-86zpfje5.js → cli-ff1tm9n9.js} +1 -1
- package/dist/{cli-cf63dnxj.js → cli-g9vd9ece.js} +37 -12
- package/dist/{cli-j3dwd4kz.js → cli-gbfxp48k.js} +770 -126
- package/dist/{cli-n2918sed.js → cli-gn5af0x5.js} +21 -21
- package/dist/{cli-d172svcw.js → cli-gwhjmh8g.js} +4 -4
- package/dist/{cli-stxdrqs2.js → cli-hh5we352.js} +24 -5
- package/dist/{cli-0ebey9hg.js → cli-j6rktc91.js} +1 -1
- package/dist/{cli-csh8fnbg.js → cli-jb30dzvk.js} +473 -58
- package/dist/{cli-vaxw3bg0.js → cli-jbnn4vxb.js} +3 -3
- package/dist/{cli-ha22h0eg.js → cli-k4tjsdx9.js} +45 -40
- package/dist/{cli-f55b6ky0.js → cli-m4ecdxvz.js} +40 -13
- package/dist/{cli-mntxtkhn.js → cli-mz9afxxf.js} +2 -1
- package/dist/{cli-ta8bd7th.js → cli-pzatvw94.js} +1 -1
- package/dist/{cli-3qv8naq8.js → cli-rr7zx19j.js} +1591 -353
- package/dist/{cli-b1tv22wr.js → cli-s682zgqz.js} +1 -1
- package/dist/{cli-bpbcpd8b.js → cli-sbwsxvtd.js} +1 -1
- package/dist/{cli-0xk505e8.js → cli-sxgtf5fw.js} +1 -1
- package/dist/{cli-6y43v79h.js → cli-tsma7p8v.js} +1 -1
- package/dist/{cli-edtm741g.js → cli-wghjkr0e.js} +5 -5
- package/dist/{cli-aaqnqpyw.js → cli-wx2nj19m.js} +30 -11
- package/dist/{cli-y3dzwyy3.js → cli-x0f2v69c.js} +180 -60
- package/dist/{cli-kcnwn85g.js → cli-xtrz6bzs.js} +7 -7
- package/dist/{cli-14v1sxxy.js → cli-xzfq4at3.js} +7 -7
- package/dist/cli.js +20 -20
- package/dist/{codex-adapter-brh2tcxr.js → codex-adapter-wch12q99.js} +3 -3
- package/dist/{codex-hook-e2he7aca.js → codex-hook-brpnycn5.js} +1 -1
- package/dist/{codex-session-runner-0dnj21qs.js → codex-session-runner-41pfcr95.js} +2 -2
- package/dist/{commands-1cnvseqx.js → commands-9849dkj6.js} +2 -2
- package/dist/{controller-kc7s9xhn.js → controller-ja0sd95p.js} +29 -3
- package/dist/{controllers-connect-jzx7t4bn.js → controllers-connect-xp05dj6x.js} +20 -20
- package/dist/{cursor-adapter-qpwp5sfg.js → cursor-adapter-623qxqew.js} +1 -2
- package/dist/{db-4vq88jkc.js → db-47vj40dy.js} +3 -3
- package/dist/{db-v5ytg5pw.js → db-w759qmx0.js} +2 -2
- package/dist/{dispatcher-trtcrqae.js → dispatcher-7b8e4z2j.js} +17 -17
- package/dist/{docker-nfy2gc8t.js → docker-s84hjs91.js} +2 -2
- package/dist/{dsh-adapter-f20xwn1z.js → dsh-adapter-2ezw3xea.js} +2 -3
- package/dist/{external-channel-n9bymc2n.js → external-channel-e2s028da.js} +2 -2
- package/dist/{grok-adapter-4kpmmnr6.js → grok-adapter-ys7gaqee.js} +6 -6
- package/dist/{handlers-ptsraqa8.js → handlers-wy1dr6ja.js} +20 -20
- package/dist/{heartbeat-60qtxtjf.js → heartbeat-w3mntghj.js} +20 -20
- package/dist/{hook-rbktcstg.js → hook-3jjywnpb.js} +9 -3
- package/dist/{hook-ngtvh729.js → hook-g7kvv6x9.js} +3 -2
- package/dist/{http-z8xy72gp.js → http-tkp7d4kb.js} +2984 -2483
- package/dist/{index-r70q0xjx.js → index-1ef1myq2.js} +17 -17
- package/dist/{index-a9nsavhx.js → index-3n8m9ea2.js} +1 -1
- package/dist/{index-cbxkmfc5.js → index-9pn1pfkf.js} +1 -1
- package/dist/{index-s193j5fh.js → index-nmm79qgr.js} +20 -20
- package/dist/{index-6srwvd5b.js → index-p4xfz37z.js} +1 -1
- package/dist/{index-06qkmcx6.js → index-q7m26kvs.js} +33 -23
- package/dist/{index-1cscynkb.js → index-xdaahthb.js} +17 -17
- package/dist/{keepalive-a9srcphj.js → keepalive-v4ta8wgg.js} +3 -3
- package/dist/{lead-3devneqy.js → lead-sawnyqxk.js} +35 -35
- package/dist/{maintenance-0er16h2y.js → maintenance-84n1ex21.js} +1 -1
- package/dist/{oauth-refresh-sweep-b65jcyw2.js → oauth-refresh-sweep-vjnnandw.js} +2 -2
- package/dist/{onboard-wqywz5py.js → onboard-sfmpe4np.js} +2 -2
- package/dist/{opencode-adapter-e56086m1.js → opencode-adapter-jmpst4q4.js} +4 -4
- package/dist/{otel-impl-vk32s884.js → otel-impl-v6cc0zve.js} +1 -1
- package/dist/{pi-mono-adapter-tzps8f38.js → pi-mono-adapter-fk8fkcf6.js} +33 -6
- package/dist/{pricing-refresh-t27anv4z.js → pricing-refresh-fsk1e1zc.js} +3 -3
- package/dist/{rbac-roles-452665y0.js → rbac-roles-prmkdnkw.js} +2 -2
- package/dist/{rbac-roles-bmcgsxjn.js → rbac-roles-zxmxqa39.js} +1 -1
- package/dist/{render-v2-0ttsk2j4.js → render-v2-pjwxvnkw.js} +3 -3
- package/dist/{resume-a26kvr41.js → resume-frdtgfa0.js} +9 -5
- package/dist/{session-access-dgh9nkwk.js → session-access-fpez4y5q.js} +4 -4
- package/dist/{setup-9vc9qahm.js → setup-mq6m3m8q.js} +1 -1
- package/dist/{work-objects-vn8nkxwn.js → work-objects-kfahhjsq.js} +20 -20
- package/dist/{worker-1x1h8vnm.js → worker-v5e5rxj3.js} +35 -35
- package/openapi.json +3078 -2424
- package/package.json +7 -7
- package/plugin/commands/create-pr.md +2 -2
- package/plugin/pi-skills/create-pr/SKILL.md +2 -2
- package/src/be/approval-config-question.ts +389 -0
- package/src/be/automation-preflight.ts +37 -3
- package/src/be/db/approvals.ts +48 -0
- package/src/be/db/session-tree.ts +73 -15
- package/src/be/db/skill-search.ts +87 -0
- package/src/be/db/tasks/read.ts +29 -2
- package/src/be/db/tasks/write.ts +15 -5
- package/src/be/db/workflow-idempotency.ts +183 -0
- package/src/be/db/workflow-runs.ts +366 -8
- package/src/be/db.ts +92 -22
- package/src/be/migrations/239_skills_fts.sql +40 -0
- package/src/be/migrations/240_workflow_run_parent_step_attempt.sql +37 -0
- package/src/be/migrations/241_skills_meta_fts.sql +39 -0
- package/src/be/migrations/242_workflow_idempotency_keys.sql +40 -0
- package/src/be/sealed-json.ts +1 -0
- package/src/be/seed-scripts/catalog/compound-insights.inline.ts +2 -2
- package/src/be/seed-scripts/catalog/compound-insights.ts +2 -2
- package/src/be/seed-skills/bundled-files.generated.json +1 -1
- package/src/be/sql-connections.ts +7 -1
- package/src/be/swarm-config-guard.ts +25 -0
- package/src/be/users.ts +9 -0
- package/src/commands/controller.ts +33 -0
- package/src/commands/runner.ts +6 -2
- package/src/extensions/apply-task-create.ts +57 -11
- package/src/extensions/catalog.generated.json +4 -4
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +25 -0
- package/src/extensions/dispatcher.ts +4 -0
- package/src/extensions/post-bridge.ts +8 -0
- package/src/hooks/context-bound-note.ts +196 -0
- package/src/hooks/hook.ts +12 -0
- package/src/http/approval-requests.ts +209 -38
- package/src/http/config.ts +70 -53
- package/src/http/idempotency-key.ts +117 -0
- package/src/http/sessions.ts +27 -2
- package/src/http/workflows.ts +129 -24
- package/src/integrations/chat-sdk/inbound.ts +5 -4
- package/src/prompts/context-bound-note.ts +48 -0
- package/src/prompts/session-templates.ts +25 -1
- package/src/providers/amp-adapter.ts +30 -8
- package/src/providers/claude-adapter.ts +29 -4
- package/src/providers/claude-managed-adapter.ts +26 -0
- package/src/providers/claude-sdk-session.ts +10 -0
- package/src/providers/claude-session-events.ts +13 -0
- package/src/providers/codex-adapter.ts +12 -0
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/opencode-adapter.ts +18 -0
- package/src/providers/pi-mono-adapter.ts +35 -0
- package/src/runtime-providers/docker.ts +6 -2
- package/src/scripts-runtime/types/swarm-extension.d.ts +35 -0
- package/src/tests/amp-adapter.test.ts +97 -0
- package/src/tests/approval-config-question.test.ts +702 -0
- package/src/tests/approval-requests.test.ts +10 -7
- package/src/tests/approval-sweeps.test.ts +12 -6
- package/src/tests/base-prompt.test.ts +1 -1
- package/src/tests/chat-sdk-inbound.test.ts +20 -0
- package/src/tests/claude-hook-output.test.ts +79 -1
- package/src/tests/claude-managed-adapter.test.ts +275 -0
- package/src/tests/codex-adapter.test.ts +163 -0
- package/src/tests/context-bound-note.test.ts +269 -0
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/entrypoint-gitlab-credential-helper.test.ts +273 -0
- package/src/tests/extensions-example-comms-adherence-gate.test.ts +321 -12
- package/src/tests/extensions-pre-task.test.ts +273 -0
- package/src/tests/fetch-resolved-env.test.ts +17 -0
- package/src/tests/fixtures/extensions/record-blocks/hooks.ts +10 -0
- package/src/tests/fixtures/extensions/record-blocks/manifest.json +7 -0
- package/src/tests/fixtures/fake-amp.ts +22 -8
- package/src/tests/fixtures/held-template-render.ts +42 -0
- package/src/tests/fixtures/workflow-idempotency-trigger.child.ts +73 -0
- package/src/tests/list-endpoint-slimming.test.ts +33 -0
- package/src/tests/migration-240-workflow-run-parent-step-attempt.test.ts +55 -0
- package/src/tests/openapi-route-headers.test.ts +2 -0
- package/src/tests/opencode-adapter.test.ts +134 -0
- package/src/tests/pi-mono-adapter.test.ts +105 -0
- package/src/tests/prompt-template-session.test.ts +4 -3
- package/src/tests/runner-push-delivery.test.ts +25 -0
- package/src/tests/runtime-controller-liveness.test.ts +133 -0
- package/src/tests/runtime-providers-docker.test.ts +2 -0
- package/src/tests/script-connections.test.ts +9 -0
- package/src/tests/script-run-config-scope.test.ts +91 -3
- package/src/tests/session-logs.test.ts +70 -0
- package/src/tests/sessions-tree.test.ts +205 -1
- package/src/tests/skill-search-long-content.test.ts +193 -0
- package/src/tests/skill-search.test.ts +173 -22
- package/src/tests/workflow-cascade-cancel.test.ts +1169 -0
- package/src/tests/workflow-foreach-supersede-retry.test.ts +488 -0
- package/src/tests/workflow-idempotency.test.ts +915 -0
- package/src/tests/workflow-sub-workflow.test.ts +538 -1
- package/src/tools/request-human-input.ts +27 -5
- package/src/tools/workflows/cancel-workflow-run.ts +1 -1
- package/src/types.ts +7 -0
- package/src/utils/context-window.ts +8 -6
- package/src/workflows/approval-cancel.ts +15 -13
- package/src/workflows/approval-notifications.ts +15 -4
- package/src/workflows/checkpoint.ts +72 -35
- package/src/workflows/engine.ts +262 -93
- package/src/workflows/executors/base.ts +6 -0
- package/src/workflows/executors/foreach.ts +2 -2
- package/src/workflows/executors/human-in-the-loop.ts +25 -1
- package/src/workflows/executors/sub-workflow.ts +45 -16
- package/src/workflows/foreach-driver.ts +10 -3
- package/src/workflows/foreach-join.ts +29 -6
- package/src/workflows/recovery.ts +68 -1
- package/src/workflows/resume.ts +228 -77
- package/src/workflows/retry-poller.ts +74 -7
- package/src/workflows/task-step-routing.ts +29 -7
- package/templates/ai-toolbox.manifest.json +8 -8
- package/templates/community/open-prompt-showreel/PLAYBOOK.md +5 -6
- package/templates/community/open-prompt-showreel/lead-prompt.md +1 -1
- package/templates/community/open-prompt-showreel/skills/open-prompt-showreel/SKILL.md +4 -4
- package/templates/extensions/comms-adherence-gate/README.md +38 -13
- package/templates/extensions/comms-adherence-gate/hooks.ts +272 -69
- package/templates/extensions/comms-adherence-gate/manifest.json +2 -2
- package/templates/skills/agent-browser/SKILL.md +4 -4
- package/templates/skills/agent-browser/content.md +4 -4
- package/templates/skills/code-quality/config.json +1 -1
- package/templates/skills/code-quality/content.md +2 -2
- package/templates/skills/delegate-work/content.md +29 -25
- package/templates/skills/delegate-work/files/scripts/codex-exec.sh +5 -5
- package/templates/skills/qa/content.md +2 -2
- package/templates/skills/researching/content.md +2 -0
- package/templates/skills/turso-interaction/content.md +1 -1
- package/templates/skills/work-on-task/SKILL.md +1 -1
- package/templates/skills/work-on-task/content.md +1 -1
- package/templates/skills/workflow-iterate/content.md +8 -1
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
1
2
|
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
3
|
import { unlink } from "node:fs/promises";
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
closeDb,
|
|
6
|
+
createSkill,
|
|
7
|
+
deleteSkill,
|
|
8
|
+
getDb,
|
|
9
|
+
initDb,
|
|
10
|
+
searchSkills,
|
|
11
|
+
updateSkill,
|
|
12
|
+
} from "../be/db";
|
|
4
13
|
|
|
5
14
|
const TEST_DB_PATH = `./test-skill-search-${process.pid}.sqlite`;
|
|
6
15
|
|
|
@@ -10,22 +19,69 @@ async function removeDbFiles(path: string): Promise<void> {
|
|
|
10
19
|
}
|
|
11
20
|
}
|
|
12
21
|
|
|
22
|
+
async function topNames(query: string, limit?: number): Promise<string[]> {
|
|
23
|
+
return (await searchSkills(query, limit)).map((skill) => skill.name);
|
|
24
|
+
}
|
|
25
|
+
|
|
13
26
|
describe("searchSkills", () => {
|
|
14
27
|
beforeAll(async () => {
|
|
15
28
|
await removeDbFiles(TEST_DB_PATH);
|
|
16
29
|
initDb(TEST_DB_PATH);
|
|
17
30
|
|
|
31
|
+
const fixture = [
|
|
32
|
+
{
|
|
33
|
+
name: "pr-review-fix-loop",
|
|
34
|
+
description: "Run review fix rounds on a pull request until CI is green.",
|
|
35
|
+
content: "Reply to each review thread, push the fix, wait for checks.",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "code-quality",
|
|
39
|
+
description: "Pre-push checklist for any code change.",
|
|
40
|
+
content: "Run lint, typecheck and tests, then read the diff as a reviewer would.",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "swarm-scripts",
|
|
44
|
+
description: "Author and run reusable TypeScript in the swarm.",
|
|
45
|
+
content: "script-upsert, script-run, credential bindings and secrets stay server-side.",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "agent-fs",
|
|
49
|
+
description: "Shared drive for documents between agents and people.",
|
|
50
|
+
content: "Upload markdown and create share links for outside readers.",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "scheduling",
|
|
54
|
+
description: "Create recurring jobs with cron expressions.",
|
|
55
|
+
content: "Pick a timezone, set the next run, pause or resume a schedule.",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "schedule-audit",
|
|
59
|
+
description: "Audit scheduling drift and missed schedules.",
|
|
60
|
+
content: "Compare each schedule's last run with its cron.",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "memory",
|
|
64
|
+
description: "Store, search and rate learnings from past sessions.",
|
|
65
|
+
content: "Use memory-store for a fix that will come back.",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "call-time-trap-placement",
|
|
69
|
+
description: "Decide where operational rules belong.",
|
|
70
|
+
content: "Use toolsMd and claudeMd to document the delivery surface.",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "content-search-example",
|
|
74
|
+
description: "A skill with a content-only term.",
|
|
75
|
+
content: "This body contains the needle-token.",
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
for (const skill of fixture) await createSkill({ ...skill, scope: "swarm" });
|
|
18
79
|
await createSkill({
|
|
19
|
-
name: "
|
|
20
|
-
description: "
|
|
21
|
-
content: "
|
|
22
|
-
scope: "swarm",
|
|
23
|
-
});
|
|
24
|
-
await createSkill({
|
|
25
|
-
name: "content-search-example",
|
|
26
|
-
description: "A skill with a content-only term.",
|
|
27
|
-
content: "This body contains the needle-token.",
|
|
80
|
+
name: "disabled-cron-helper",
|
|
81
|
+
description: "Recurring cron jobs, the old way.",
|
|
82
|
+
content: "cron cron cron schedule",
|
|
28
83
|
scope: "swarm",
|
|
84
|
+
isEnabled: false,
|
|
29
85
|
});
|
|
30
86
|
});
|
|
31
87
|
|
|
@@ -34,27 +90,122 @@ describe("searchSkills", () => {
|
|
|
34
90
|
await removeDbFiles(TEST_DB_PATH);
|
|
35
91
|
});
|
|
36
92
|
|
|
37
|
-
test("
|
|
38
|
-
|
|
93
|
+
test("ranks a name match first", async () => {
|
|
94
|
+
expect((await topNames("scheduling"))[0]).toBe("scheduling");
|
|
95
|
+
expect((await topNames("code quality"))[0]).toBe("code-quality");
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("ranks a description-only match first", async () => {
|
|
99
|
+
expect((await topNames("recurring cron jobs"))[0]).toBe("scheduling");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("ranks a content-only match first", async () => {
|
|
103
|
+
expect((await topNames("credential bindings"))[0]).toBe("swarm-scripts");
|
|
104
|
+
expect(await topNames("needle-token")).toEqual(["content-search-example"]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("ranks natural-language queries by relevance instead of requiring every word", async () => {
|
|
108
|
+
expect((await topNames("how do I review a pull request"))[0]).toBe("pr-review-fix-loop");
|
|
109
|
+
expect((await topNames("where to share a document with people"))[0]).toBe("agent-fs");
|
|
110
|
+
});
|
|
39
111
|
|
|
40
|
-
|
|
112
|
+
test("a query equal to a skill name ranks that skill first", async () => {
|
|
113
|
+
// On bm25 alone schedule-audit outscores scheduling for this query: its
|
|
114
|
+
// name and description both stem to "schedul". The exact-name boost wins.
|
|
115
|
+
expect((await topNames("Scheduling")).slice(0, 2)).toEqual(["scheduling", "schedule-audit"]);
|
|
116
|
+
expect((await topNames("MEMORY"))[0]).toBe("memory");
|
|
117
|
+
expect((await topNames("call-time-trap-placement"))[0]).toBe("call-time-trap-placement");
|
|
41
118
|
});
|
|
42
119
|
|
|
43
|
-
test("
|
|
44
|
-
const
|
|
120
|
+
test("quotes FTS5 syntax in user text instead of executing it", async () => {
|
|
121
|
+
for (const query of [
|
|
122
|
+
'"',
|
|
123
|
+
"*",
|
|
124
|
+
"NEAR",
|
|
125
|
+
"-",
|
|
126
|
+
'cron" OR "x',
|
|
127
|
+
"cron NEAR/2 jobs",
|
|
128
|
+
"-cron",
|
|
129
|
+
"name:cron",
|
|
130
|
+
"cron*",
|
|
131
|
+
]) {
|
|
132
|
+
await expect(searchSkills(query)).resolves.toBeArray();
|
|
133
|
+
}
|
|
134
|
+
expect((await topNames('timezone" OR "x'))[0]).toBe("scheduling");
|
|
135
|
+
expect((await topNames("-timezone"))[0]).toBe("scheduling");
|
|
136
|
+
// As a column filter, name:timezone would match nothing: "timezone" is
|
|
137
|
+
// only in the scheduling skill's content.
|
|
138
|
+
expect((await topNames("name:timezone"))[0]).toBe("scheduling");
|
|
139
|
+
});
|
|
45
140
|
|
|
46
|
-
|
|
141
|
+
test("excludes disabled skills", async () => {
|
|
142
|
+
expect(await topNames("cron")).not.toContain("disabled-cron-helper");
|
|
143
|
+
expect(await topNames("disabled-cron-helper")).not.toContain("disabled-cron-helper");
|
|
47
144
|
});
|
|
48
145
|
|
|
49
|
-
test("
|
|
50
|
-
|
|
146
|
+
test("respects the limit and the includeContent flag", async () => {
|
|
147
|
+
expect(await topNames("the", 2)).toHaveLength(2);
|
|
148
|
+
const slim = await searchSkills("scheduling", 5, false);
|
|
149
|
+
expect(slim[0]?.name).toBe("scheduling");
|
|
150
|
+
expect(slim[0]?.content).toBe("");
|
|
151
|
+
});
|
|
51
152
|
|
|
52
|
-
|
|
153
|
+
test("keeps the substring fallback for partial words", async () => {
|
|
154
|
+
expect(await topNames("needle-tok")).toEqual(["content-search-example"]);
|
|
53
155
|
});
|
|
54
156
|
|
|
55
|
-
test("keeps
|
|
56
|
-
const
|
|
157
|
+
test("keeps the index in sync on update and delete", async () => {
|
|
158
|
+
const skill = await createSkill({
|
|
159
|
+
name: "sync-probe",
|
|
160
|
+
description: "Starts with alphaword.",
|
|
161
|
+
content: "",
|
|
162
|
+
scope: "swarm",
|
|
163
|
+
});
|
|
164
|
+
expect(await topNames("alphaword")).toEqual(["sync-probe"]);
|
|
165
|
+
|
|
166
|
+
await updateSkill(skill.id, { description: "Now about betaword." });
|
|
167
|
+
expect(await topNames("betaword")).toEqual(["sync-probe"]);
|
|
168
|
+
expect(await topNames("alphaword")).toEqual([]);
|
|
169
|
+
|
|
170
|
+
await deleteSkill(skill.id);
|
|
171
|
+
expect(await topNames("betaword")).toEqual([]);
|
|
172
|
+
const ftsRows = getDb()
|
|
173
|
+
.query<{ n: number }, [string]>("SELECT count(*) AS n FROM skills_fts WHERE skill_id = ?")
|
|
174
|
+
.get(skill.id);
|
|
175
|
+
expect(ftsRows?.n).toBe(0);
|
|
176
|
+
});
|
|
57
177
|
|
|
58
|
-
|
|
178
|
+
test("migrated schema carries the sync triggers", () => {
|
|
179
|
+
const triggers = getDb()
|
|
180
|
+
.query<{ name: string }, []>(
|
|
181
|
+
"SELECT name FROM sqlite_master WHERE type = 'trigger' AND tbl_name = 'skills' AND name LIKE 'skills_fts_%' ORDER BY name",
|
|
182
|
+
)
|
|
183
|
+
.all()
|
|
184
|
+
.map((row) => row.name);
|
|
185
|
+
expect(triggers).toEqual(["skills_fts_delete", "skills_fts_insert", "skills_fts_update"]);
|
|
59
186
|
});
|
|
60
187
|
});
|
|
188
|
+
|
|
189
|
+
test("migration 239 backfills skills that existed before it ran", async () => {
|
|
190
|
+
const db = new Database(":memory:");
|
|
191
|
+
try {
|
|
192
|
+
db.exec(await Bun.file("src/be/migrations/019_skills.sql").text());
|
|
193
|
+
db.run(
|
|
194
|
+
"INSERT INTO skills (id, name, description, content, type, scope, createdAt, lastUpdatedAt) VALUES ('s1', 'legacy-skill', 'Old description', 'old body', 'remote', 'swarm', '2026-01-01', '2026-01-01')",
|
|
195
|
+
);
|
|
196
|
+
db.exec(await Bun.file("src/be/migrations/239_skills_fts.sql").text());
|
|
197
|
+
|
|
198
|
+
const rows = db
|
|
199
|
+
.query<{ skill_id: string }, [string]>(
|
|
200
|
+
"SELECT skill_id FROM skills_fts WHERE skills_fts MATCH ?",
|
|
201
|
+
)
|
|
202
|
+
.all('"body"');
|
|
203
|
+
expect(rows.map((row) => row.skill_id)).toEqual(["s1"]);
|
|
204
|
+
|
|
205
|
+
// Re-running the migration does not duplicate backfilled rows.
|
|
206
|
+
db.exec(await Bun.file("src/be/migrations/239_skills_fts.sql").text());
|
|
207
|
+
expect(db.query<{ n: number }, []>("SELECT count(*) AS n FROM skills_fts").get()?.n).toBe(1);
|
|
208
|
+
} finally {
|
|
209
|
+
db.close();
|
|
210
|
+
}
|
|
211
|
+
});
|