@vellumai/assistant 0.5.14 → 0.5.16
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/ARCHITECTURE.md +2 -2
- package/docs/architecture/integrations.md +15 -14
- package/knip.json +3 -1
- package/openapi.yaml +11 -43
- package/package.json +1 -1
- package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -375
- package/src/__tests__/ces-rpc-credential-backend.test.ts +4 -1
- package/src/__tests__/checker.test.ts +59 -0
- package/src/__tests__/cli-command-risk-guard.test.ts +98 -10
- package/src/__tests__/cli-memory.test.ts +372 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -2
- package/src/__tests__/config-schema.test.ts +0 -2
- package/src/__tests__/config-watcher-feature-flags.test.ts +211 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +2 -6
- package/src/__tests__/conversation-usage.test.ts +1 -0
- package/src/__tests__/credential-security-e2e.test.ts +4 -1
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +7 -73
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -7
- package/src/__tests__/guardian-routing-invariants.test.ts +151 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -3
- package/src/__tests__/intent-routing.test.ts +6 -18
- package/src/__tests__/log-export-workspace.test.ts +2 -28
- package/src/__tests__/managed-skill-lifecycle.test.ts +7 -37
- package/src/__tests__/managed-store.test.ts +2 -10
- package/src/__tests__/messaging-send-tool.test.ts +6 -6
- package/src/__tests__/migration-cross-version-compatibility.test.ts +1 -29
- package/src/__tests__/migration-export-http.test.ts +3 -34
- package/src/__tests__/migration-import-commit-http.test.ts +1 -29
- package/src/__tests__/migration-import-preflight-http.test.ts +3 -34
- package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +2 -1
- package/src/__tests__/oauth-apps-routes.test.ts +120 -10
- package/src/__tests__/oauth-connect-orchestrator.test.ts +709 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +2 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +149 -0
- package/src/__tests__/oauth-providers-routes.test.ts +5 -2
- package/src/__tests__/oauth-store.test.ts +0 -5
- package/src/__tests__/outlook-messaging-provider.test.ts +576 -0
- package/src/__tests__/path-policy.test.ts +2 -17
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/platform-callback-registration.test.ts +3 -7
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
- package/src/__tests__/provider-error-scenarios.test.ts +0 -2
- package/src/__tests__/qdrant-manager.test.ts +68 -21
- package/src/__tests__/require-fresh-approval.test.ts +0 -1
- package/src/__tests__/sandbox-diagnostics.test.ts +20 -29
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +2 -10
- package/src/__tests__/secret-allowlist.test.ts +20 -35
- package/src/__tests__/shell-credential-ref.test.ts +0 -5
- package/src/__tests__/skill-load-feature-flag.test.ts +2 -43
- package/src/__tests__/skill-load-inline-command.test.ts +3 -65
- package/src/__tests__/skill-load-inline-includes.test.ts +3 -65
- package/src/__tests__/skill-load-tool.test.ts +3 -67
- package/src/__tests__/skill-memory.test.ts +362 -119
- package/src/__tests__/skills.test.ts +22 -49
- package/src/__tests__/slack-channel-config.test.ts +2 -21
- package/src/__tests__/starter-bundle.test.ts +2 -8
- package/src/__tests__/stt-hints.test.ts +7 -2
- package/src/__tests__/system-prompt.test.ts +25 -45
- package/src/__tests__/task-compiler.test.ts +0 -21
- package/src/__tests__/task-management-tools.test.ts +0 -21
- package/src/__tests__/task-memory-cleanup.test.ts +0 -21
- package/src/__tests__/task-runner.test.ts +0 -21
- package/src/__tests__/task-scheduler.test.ts +0 -21
- package/src/__tests__/terminal-tools.test.ts +1 -17
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +0 -79
- package/src/__tests__/tool-approval-handler.test.ts +1 -20
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +2 -11
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -25
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -20
- package/src/__tests__/tool-preview-lifecycle.test.ts +0 -20
- package/src/__tests__/trust-store.test.ts +9 -41
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -30
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -21
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -22
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -22
- package/src/__tests__/trusted-contact-verification.test.ts +0 -22
- package/src/__tests__/turn-boundary-resolution.test.ts +0 -28
- package/src/__tests__/twilio-provider.test.ts +0 -16
- package/src/__tests__/twilio-routes-twiml.test.ts +7 -12
- package/src/__tests__/twilio-routes.test.ts +0 -24
- package/src/__tests__/update-bulletin.test.ts +17 -89
- package/src/__tests__/usage-cache-backfill-migration.test.ts +0 -20
- package/src/__tests__/usage-routes.test.ts +0 -21
- package/src/__tests__/user-reference.test.ts +1 -5
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +4 -34
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -53
- package/src/__tests__/voice-invite-redemption.test.ts +0 -21
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -24
- package/src/__tests__/voice-session-bridge.test.ts +0 -21
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -23
- package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +2 -2
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -23
- package/src/__tests__/workspace-migration-down-functions.test.ts +0 -6
- package/src/acp/client-handler.ts +1 -2
- package/src/cli/__tests__/notifications.test.ts +0 -22
- package/src/cli/cli-memory.ts +176 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +15 -0
- package/src/cli/commands/oauth/providers.ts +49 -42
- package/src/cli/commands/platform/__tests__/connect.test.ts +2 -48
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +2 -48
- package/src/cli/commands/platform/__tests__/status.test.ts +0 -50
- package/src/config/bundled-skills/computer-use/TOOLS.json +7 -7
- package/src/config/bundled-skills/messaging/SKILL.md +17 -2
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/loader.ts +4 -0
- package/src/config/schemas/security.ts +0 -6
- package/src/config/schemas/services.ts +8 -0
- package/src/context/window-manager.ts +28 -9
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/daemon/config-watcher.ts +51 -0
- package/src/daemon/conversation-agent-loop.ts +3 -2
- package/src/daemon/conversation-process.ts +1 -0
- package/src/daemon/conversation-usage.ts +1 -0
- package/src/daemon/handlers/skills.ts +9 -1
- package/src/daemon/lifecycle.ts +13 -4
- package/src/daemon/message-types/conversations.ts +1 -0
- package/src/daemon/providers-setup.ts +2 -0
- package/src/daemon/server.ts +26 -22
- package/src/events/domain-events.ts +1 -2
- package/src/memory/db-init.ts +9 -0
- package/src/memory/job-handlers/batch-extraction.ts +16 -4
- package/src/memory/job-handlers/embedding.test.ts +3 -27
- package/src/memory/job-handlers/journal-carry-forward.test.ts +1 -29
- package/src/memory/llm-usage-store.ts +35 -2
- package/src/memory/migrations/201-oauth-providers-feature-flag.ts +11 -0
- package/src/memory/migrations/202-drop-callback-transport-column.ts +13 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/qdrant-manager.ts +26 -5
- package/src/memory/query-expansion.ts +1 -1
- package/src/memory/retriever.test.ts +22 -20
- package/src/memory/retriever.ts +10 -2
- package/src/memory/schema/oauth.ts +1 -1
- package/src/memory/search/mmr.ts +8 -5
- package/src/memory/slack-thread-store.ts +17 -0
- package/src/messaging/providers/outlook/adapter.ts +193 -0
- package/src/messaging/providers/outlook/client.ts +311 -0
- package/src/messaging/providers/outlook/types.ts +83 -0
- package/src/notifications/adapters/slack.ts +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +1 -1
- package/src/oauth/connect-orchestrator.ts +10 -3
- package/src/oauth/oauth-store.ts +10 -11
- package/src/oauth/provider-serializer.ts +3 -0
- package/src/oauth/provider-visibility.ts +16 -0
- package/src/oauth/seed-providers.ts +49 -17
- package/src/permissions/checker.ts +39 -7
- package/src/permissions/types.ts +2 -4
- package/src/prompts/journal-context.ts +9 -11
- package/src/prompts/system-prompt.ts +3 -64
- package/src/prompts/templates/UPDATES.md +6 -0
- package/src/runtime/auth/__tests__/credential-service.test.ts +1 -27
- package/src/runtime/auth/__tests__/token-service.test.ts +1 -25
- package/src/runtime/auth/route-policy.ts +0 -4
- package/src/runtime/guardian-reply-router.ts +6 -2
- package/src/runtime/routes/conversation-query-routes.ts +2 -58
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +43 -2
- package/src/runtime/routes/memory-item-routes.test.ts +0 -17
- package/src/runtime/routes/memory-item-routes.ts +103 -12
- package/src/runtime/routes/oauth-apps.ts +18 -1
- package/src/runtime/routes/oauth-providers.ts +13 -1
- package/src/runtime/routes/settings-routes.ts +1 -0
- package/src/runtime/routes/usage-routes.ts +19 -2
- package/src/runtime/routes/work-items-routes.test.ts +0 -21
- package/src/runtime/routes/workspace-routes.test.ts +3 -27
- package/src/security/secret-allowlist.ts +4 -4
- package/src/skills/skill-memory.ts +62 -23
- package/src/tools/memory/handlers.test.ts +1 -29
- package/src/tools/permission-checker.ts +0 -18
- package/src/tools/skills/skill-script-runner.ts +1 -1
- package/src/util/device-id.ts +3 -65
- package/src/workspace/git-service.ts +27 -6
|
@@ -1,26 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
1
|
+
import { rmSync } from "node:fs";
|
|
4
2
|
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
5
3
|
|
|
6
4
|
import { eq } from "drizzle-orm";
|
|
7
5
|
|
|
8
|
-
const testDir = mkdtempSync(join(tmpdir(), "skill-memory-"));
|
|
9
|
-
|
|
10
|
-
mock.module("../util/platform.js", () => ({
|
|
11
|
-
getDataDir: () => testDir,
|
|
12
|
-
isMacOS: () => process.platform === "darwin",
|
|
13
|
-
isLinux: () => process.platform === "linux",
|
|
14
|
-
isWindows: () => process.platform === "win32",
|
|
15
|
-
getPidPath: () => join(testDir, "test.pid"),
|
|
16
|
-
getDbPath: () => join(testDir, "test.db"),
|
|
17
|
-
getLogPath: () => join(testDir, "test.log"),
|
|
18
|
-
ensureDataDir: () => {},
|
|
19
|
-
getWorkspaceSkillsDir: () => join(testDir, "skills"),
|
|
20
|
-
getWorkspaceConfigPath: () => join(testDir, "config.json"),
|
|
21
|
-
readPlatformToken: () => undefined,
|
|
22
|
-
}));
|
|
23
|
-
|
|
24
6
|
mock.module("../util/logger.js", () => ({
|
|
25
7
|
getLogger: () =>
|
|
26
8
|
new Proxy({} as Record<string, unknown>, {
|
|
@@ -38,16 +20,15 @@ mock.module("../memory/qdrant-client.js", () => ({
|
|
|
38
20
|
initQdrantClient: () => {},
|
|
39
21
|
}));
|
|
40
22
|
|
|
41
|
-
// Controllable mock for
|
|
42
|
-
let
|
|
43
|
-
|
|
44
|
-
> = async () => [];
|
|
23
|
+
// Controllable mock for loadSkillCatalog used by seedCatalogSkillMemories
|
|
24
|
+
let mockLoadSkillCatalog: () => import("../config/skills.js").SkillSummary[] =
|
|
25
|
+
() => [];
|
|
45
26
|
|
|
46
|
-
mock.module("../skills
|
|
47
|
-
|
|
27
|
+
mock.module("../config/skills.js", () => ({
|
|
28
|
+
loadSkillCatalog: (..._args: unknown[]) => mockLoadSkillCatalog(),
|
|
48
29
|
}));
|
|
49
30
|
|
|
50
|
-
// Controllable mock for isAssistantFeatureFlagEnabled used by
|
|
31
|
+
// Controllable mock for isAssistantFeatureFlagEnabled used by resolveSkillStates
|
|
51
32
|
let mockIsFeatureFlagEnabled: (key: string) => boolean = () => true;
|
|
52
33
|
|
|
53
34
|
mock.module("../config/assistant-feature-flags.js", () => ({
|
|
@@ -78,25 +59,24 @@ mock.module("../config/loader.js", () => ({
|
|
|
78
59
|
invalidateConfigCache: () => {},
|
|
79
60
|
}));
|
|
80
61
|
|
|
62
|
+
import type { SkillSummary } from "../config/skills.js";
|
|
81
63
|
import { getDb, initializeDb, resetDb } from "../memory/db.js";
|
|
82
64
|
import { memoryItems, memoryJobs } from "../memory/schema.js";
|
|
83
|
-
import type { CatalogSkill } from "../skills/catalog-install.js";
|
|
84
65
|
import {
|
|
85
66
|
buildCapabilityStatement,
|
|
86
67
|
deleteSkillCapabilityMemory,
|
|
68
|
+
fromSkillSummary,
|
|
87
69
|
seedCatalogSkillMemories,
|
|
70
|
+
type SkillCapabilityInput,
|
|
88
71
|
upsertSkillCapabilityMemory,
|
|
89
72
|
} from "../skills/skill-memory.js";
|
|
73
|
+
import { ensureDataDir, getDbPath } from "../util/platform.js";
|
|
90
74
|
|
|
75
|
+
ensureDataDir();
|
|
91
76
|
initializeDb();
|
|
92
77
|
|
|
93
78
|
afterAll(() => {
|
|
94
79
|
resetDb();
|
|
95
|
-
try {
|
|
96
|
-
rmSync(testDir, { recursive: true });
|
|
97
|
-
} catch {
|
|
98
|
-
// best effort cleanup
|
|
99
|
-
}
|
|
100
80
|
});
|
|
101
81
|
|
|
102
82
|
function resetTables() {
|
|
@@ -107,11 +87,17 @@ function resetTables() {
|
|
|
107
87
|
db.run("DELETE FROM memory_jobs");
|
|
108
88
|
}
|
|
109
89
|
|
|
110
|
-
function
|
|
90
|
+
function makeSkillSummary(
|
|
91
|
+
overrides: Partial<SkillSummary> = {},
|
|
92
|
+
): SkillSummary {
|
|
111
93
|
return {
|
|
112
94
|
id: "test-skill",
|
|
113
|
-
name: "
|
|
95
|
+
name: "test-skill",
|
|
96
|
+
displayName: "Test Skill",
|
|
114
97
|
description: "A skill for testing",
|
|
98
|
+
directoryPath: "/skills/test-skill",
|
|
99
|
+
skillFilePath: "/skills/test-skill/SKILL.md",
|
|
100
|
+
source: "managed",
|
|
115
101
|
...overrides,
|
|
116
102
|
};
|
|
117
103
|
}
|
|
@@ -120,33 +106,63 @@ function makeSkill(overrides: Partial<CatalogSkill> = {}): CatalogSkill {
|
|
|
120
106
|
|
|
121
107
|
describe("buildCapabilityStatement", () => {
|
|
122
108
|
test("includes display name, id, and description", () => {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
109
|
+
const input: SkillCapabilityInput = {
|
|
110
|
+
id: "test-skill",
|
|
111
|
+
displayName: "My Skill",
|
|
112
|
+
description: "A skill for testing",
|
|
113
|
+
};
|
|
114
|
+
const result = buildCapabilityStatement(input);
|
|
127
115
|
expect(result).toContain('"My Skill"');
|
|
128
116
|
expect(result).toContain("(test-skill)");
|
|
129
117
|
expect(result).toContain("A skill for testing");
|
|
130
118
|
});
|
|
131
119
|
|
|
132
120
|
test("includes activation hints when present", () => {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
});
|
|
141
|
-
const result = buildCapabilityStatement(entry);
|
|
121
|
+
const input: SkillCapabilityInput = {
|
|
122
|
+
id: "test-skill",
|
|
123
|
+
displayName: "My Skill",
|
|
124
|
+
description: "A skill for testing",
|
|
125
|
+
activationHints: ["user asks to search", "needs web data"],
|
|
126
|
+
};
|
|
127
|
+
const result = buildCapabilityStatement(input);
|
|
142
128
|
expect(result).toContain("Use when:");
|
|
143
129
|
expect(result).toContain("user asks to search");
|
|
144
130
|
expect(result).toContain("needs web data");
|
|
145
131
|
});
|
|
146
132
|
|
|
147
|
-
test("
|
|
148
|
-
const
|
|
149
|
-
|
|
133
|
+
test("includes avoidWhen routing cues when present", () => {
|
|
134
|
+
const input: SkillCapabilityInput = {
|
|
135
|
+
id: "test-skill",
|
|
136
|
+
displayName: "My Skill",
|
|
137
|
+
description: "A skill for testing",
|
|
138
|
+
avoidWhen: ["user wants local files only", "offline mode"],
|
|
139
|
+
};
|
|
140
|
+
const result = buildCapabilityStatement(input);
|
|
141
|
+
expect(result).toContain("Avoid when:");
|
|
142
|
+
expect(result).toContain("user wants local files only");
|
|
143
|
+
expect(result).toContain("offline mode");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("includes both activationHints and avoidWhen when present", () => {
|
|
147
|
+
const input: SkillCapabilityInput = {
|
|
148
|
+
id: "test-skill",
|
|
149
|
+
displayName: "My Skill",
|
|
150
|
+
description: "A skill for testing",
|
|
151
|
+
activationHints: ["user asks to search"],
|
|
152
|
+
avoidWhen: ["offline mode"],
|
|
153
|
+
};
|
|
154
|
+
const result = buildCapabilityStatement(input);
|
|
155
|
+
expect(result).toContain("Use when: user asks to search.");
|
|
156
|
+
expect(result).toContain("Avoid when: offline mode.");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("works with just name as displayName", () => {
|
|
160
|
+
const input: SkillCapabilityInput = {
|
|
161
|
+
id: "test-skill",
|
|
162
|
+
displayName: "Test Skill",
|
|
163
|
+
description: "A skill for testing",
|
|
164
|
+
};
|
|
165
|
+
const result = buildCapabilityStatement(input);
|
|
150
166
|
expect(result).toContain('"Test Skill"');
|
|
151
167
|
expect(result).toContain("(test-skill)");
|
|
152
168
|
expect(result).toContain("A skill for testing");
|
|
@@ -154,20 +170,70 @@ describe("buildCapabilityStatement", () => {
|
|
|
154
170
|
|
|
155
171
|
test("truncates long statements to 500 chars", () => {
|
|
156
172
|
const longDesc = "x".repeat(600);
|
|
157
|
-
const
|
|
158
|
-
|
|
173
|
+
const input: SkillCapabilityInput = {
|
|
174
|
+
id: "test-skill",
|
|
175
|
+
displayName: "Test Skill",
|
|
176
|
+
description: longDesc,
|
|
177
|
+
};
|
|
178
|
+
const result = buildCapabilityStatement(input);
|
|
159
179
|
expect(result.length).toBe(500);
|
|
160
180
|
});
|
|
161
181
|
});
|
|
162
182
|
|
|
183
|
+
// ─── fromSkillSummary ────────────────────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
describe("fromSkillSummary", () => {
|
|
186
|
+
test("maps displayName from SkillSummary", () => {
|
|
187
|
+
const entry = makeSkillSummary({ displayName: "Pretty Name" });
|
|
188
|
+
const input = fromSkillSummary(entry);
|
|
189
|
+
expect(input.displayName).toBe("Pretty Name");
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("maps activationHints from SkillSummary", () => {
|
|
193
|
+
const hints = ["user asks to search", "needs web data"];
|
|
194
|
+
const entry = makeSkillSummary({ activationHints: hints });
|
|
195
|
+
const input = fromSkillSummary(entry);
|
|
196
|
+
expect(input.activationHints).toEqual(hints);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("leaves activationHints undefined when not present", () => {
|
|
200
|
+
const entry = makeSkillSummary({ activationHints: undefined });
|
|
201
|
+
const input = fromSkillSummary(entry);
|
|
202
|
+
expect(input.activationHints).toBeUndefined();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("maps avoidWhen from SkillSummary", () => {
|
|
206
|
+
const cues = ["offline mode", "user wants local files only"];
|
|
207
|
+
const entry = makeSkillSummary({ avoidWhen: cues });
|
|
208
|
+
const input = fromSkillSummary(entry);
|
|
209
|
+
expect(input.avoidWhen).toEqual(cues);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("leaves avoidWhen undefined when not present", () => {
|
|
213
|
+
const entry = makeSkillSummary({ avoidWhen: undefined });
|
|
214
|
+
const input = fromSkillSummary(entry);
|
|
215
|
+
expect(input.avoidWhen).toBeUndefined();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test("copies id and description directly", () => {
|
|
219
|
+
const entry = makeSkillSummary({
|
|
220
|
+
id: "my-id",
|
|
221
|
+
description: "Does amazing things",
|
|
222
|
+
});
|
|
223
|
+
const input = fromSkillSummary(entry);
|
|
224
|
+
expect(input.id).toBe("my-id");
|
|
225
|
+
expect(input.description).toBe("Does amazing things");
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
163
229
|
// ─── upsertSkillCapabilityMemory ─────────────────────────────────────────────
|
|
164
230
|
|
|
165
231
|
describe("upsertSkillCapabilityMemory", () => {
|
|
166
232
|
beforeEach(resetTables);
|
|
167
233
|
|
|
168
234
|
test("inserts with correct kind, subject, confidence, importance", () => {
|
|
169
|
-
const
|
|
170
|
-
upsertSkillCapabilityMemory("test-skill",
|
|
235
|
+
const input = fromSkillSummary(makeSkillSummary());
|
|
236
|
+
upsertSkillCapabilityMemory("test-skill", input);
|
|
171
237
|
|
|
172
238
|
const db = getDb();
|
|
173
239
|
const items = db.select().from(memoryItems).all();
|
|
@@ -186,8 +252,8 @@ describe("upsertSkillCapabilityMemory", () => {
|
|
|
186
252
|
});
|
|
187
253
|
|
|
188
254
|
test("is idempotent (same entry only touches lastSeenAt)", () => {
|
|
189
|
-
const
|
|
190
|
-
upsertSkillCapabilityMemory("test-skill",
|
|
255
|
+
const input = fromSkillSummary(makeSkillSummary());
|
|
256
|
+
upsertSkillCapabilityMemory("test-skill", input);
|
|
191
257
|
|
|
192
258
|
const db = getDb();
|
|
193
259
|
const before = db.select().from(memoryItems).all();
|
|
@@ -195,7 +261,7 @@ describe("upsertSkillCapabilityMemory", () => {
|
|
|
195
261
|
const originalLastSeen = before[0].lastSeenAt;
|
|
196
262
|
|
|
197
263
|
// Upsert again
|
|
198
|
-
upsertSkillCapabilityMemory("test-skill",
|
|
264
|
+
upsertSkillCapabilityMemory("test-skill", input);
|
|
199
265
|
|
|
200
266
|
const after = db.select().from(memoryItems).all();
|
|
201
267
|
expect(after).toHaveLength(1);
|
|
@@ -209,8 +275,10 @@ describe("upsertSkillCapabilityMemory", () => {
|
|
|
209
275
|
});
|
|
210
276
|
|
|
211
277
|
test("updates statement when description changes", () => {
|
|
212
|
-
const
|
|
213
|
-
|
|
278
|
+
const input = fromSkillSummary(
|
|
279
|
+
makeSkillSummary({ description: "Original description" }),
|
|
280
|
+
);
|
|
281
|
+
upsertSkillCapabilityMemory("test-skill", input);
|
|
214
282
|
|
|
215
283
|
const db = getDb();
|
|
216
284
|
const before = db.select().from(memoryItems).all();
|
|
@@ -218,8 +286,10 @@ describe("upsertSkillCapabilityMemory", () => {
|
|
|
218
286
|
expect(before[0].statement).toContain("Original description");
|
|
219
287
|
|
|
220
288
|
// Change description
|
|
221
|
-
const
|
|
222
|
-
|
|
289
|
+
const updatedInput = fromSkillSummary(
|
|
290
|
+
makeSkillSummary({ description: "Updated description" }),
|
|
291
|
+
);
|
|
292
|
+
upsertSkillCapabilityMemory("test-skill", updatedInput);
|
|
223
293
|
|
|
224
294
|
const after = db.select().from(memoryItems).all();
|
|
225
295
|
expect(after).toHaveLength(1);
|
|
@@ -232,8 +302,8 @@ describe("upsertSkillCapabilityMemory", () => {
|
|
|
232
302
|
});
|
|
233
303
|
|
|
234
304
|
test("reactivates soft-deleted items", () => {
|
|
235
|
-
const
|
|
236
|
-
upsertSkillCapabilityMemory("test-skill",
|
|
305
|
+
const input = fromSkillSummary(makeSkillSummary());
|
|
306
|
+
upsertSkillCapabilityMemory("test-skill", input);
|
|
237
307
|
|
|
238
308
|
const db = getDb();
|
|
239
309
|
// Soft-delete the item
|
|
@@ -249,7 +319,7 @@ describe("upsertSkillCapabilityMemory", () => {
|
|
|
249
319
|
db.run("DELETE FROM memory_jobs");
|
|
250
320
|
|
|
251
321
|
// Upsert again — should reactivate
|
|
252
|
-
upsertSkillCapabilityMemory("test-skill",
|
|
322
|
+
upsertSkillCapabilityMemory("test-skill", input);
|
|
253
323
|
|
|
254
324
|
const reactivated = db.select().from(memoryItems).all();
|
|
255
325
|
expect(reactivated).toHaveLength(1);
|
|
@@ -273,7 +343,10 @@ describe("upsertSkillCapabilityMemory", () => {
|
|
|
273
343
|
db.run("DROP TABLE IF EXISTS memory_items");
|
|
274
344
|
|
|
275
345
|
expect(() => {
|
|
276
|
-
upsertSkillCapabilityMemory(
|
|
346
|
+
upsertSkillCapabilityMemory(
|
|
347
|
+
"test-skill",
|
|
348
|
+
fromSkillSummary(makeSkillSummary()),
|
|
349
|
+
);
|
|
277
350
|
}).not.toThrow();
|
|
278
351
|
|
|
279
352
|
// Restore DB state for subsequent tests.
|
|
@@ -281,8 +354,9 @@ describe("upsertSkillCapabilityMemory", () => {
|
|
|
281
354
|
// resetting the connection leaves stale migration checkpoints that skip
|
|
282
355
|
// checkpoint-guarded ALTER TABLE migrations (e.g. source_type column).
|
|
283
356
|
resetDb();
|
|
357
|
+
const dbPath = getDbPath();
|
|
284
358
|
for (const ext of ["", "-wal", "-shm"]) {
|
|
285
|
-
rmSync(
|
|
359
|
+
rmSync(`${dbPath}${ext}`, { force: true });
|
|
286
360
|
}
|
|
287
361
|
initializeDb();
|
|
288
362
|
});
|
|
@@ -294,8 +368,8 @@ describe("deleteSkillCapabilityMemory", () => {
|
|
|
294
368
|
beforeEach(resetTables);
|
|
295
369
|
|
|
296
370
|
test("soft-deletes matching item", () => {
|
|
297
|
-
const
|
|
298
|
-
upsertSkillCapabilityMemory("test-skill",
|
|
371
|
+
const input = fromSkillSummary(makeSkillSummary());
|
|
372
|
+
upsertSkillCapabilityMemory("test-skill", input);
|
|
299
373
|
|
|
300
374
|
const db = getDb();
|
|
301
375
|
const before = db.select().from(memoryItems).all();
|
|
@@ -333,8 +407,9 @@ describe("deleteSkillCapabilityMemory", () => {
|
|
|
333
407
|
// Restore DB state for subsequent tests (see upsert "does not throw" test
|
|
334
408
|
// for rationale on why we delete the DB file).
|
|
335
409
|
resetDb();
|
|
410
|
+
const dbPath = getDbPath();
|
|
336
411
|
for (const ext of ["", "-wal", "-shm"]) {
|
|
337
|
-
rmSync(
|
|
412
|
+
rmSync(`${dbPath}${ext}`, { force: true });
|
|
338
413
|
}
|
|
339
414
|
initializeDb();
|
|
340
415
|
});
|
|
@@ -346,19 +421,31 @@ describe("seedCatalogSkillMemories", () => {
|
|
|
346
421
|
beforeEach(() => {
|
|
347
422
|
resetTables();
|
|
348
423
|
// Reset mocks to defaults
|
|
349
|
-
|
|
424
|
+
mockLoadSkillCatalog = () => [];
|
|
350
425
|
mockIsFeatureFlagEnabled = () => true;
|
|
351
426
|
});
|
|
352
427
|
|
|
353
|
-
test("upserts capability memories for all
|
|
354
|
-
const skills:
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
428
|
+
test("upserts capability memories for all enabled skills", () => {
|
|
429
|
+
const skills: SkillSummary[] = [
|
|
430
|
+
makeSkillSummary({
|
|
431
|
+
id: "skill-a",
|
|
432
|
+
displayName: "Skill A",
|
|
433
|
+
description: "Does A",
|
|
434
|
+
}),
|
|
435
|
+
makeSkillSummary({
|
|
436
|
+
id: "skill-b",
|
|
437
|
+
displayName: "Skill B",
|
|
438
|
+
description: "Does B",
|
|
439
|
+
}),
|
|
440
|
+
makeSkillSummary({
|
|
441
|
+
id: "skill-c",
|
|
442
|
+
displayName: "Skill C",
|
|
443
|
+
description: "Does C",
|
|
444
|
+
}),
|
|
358
445
|
];
|
|
359
|
-
|
|
446
|
+
mockLoadSkillCatalog = () => skills;
|
|
360
447
|
|
|
361
|
-
|
|
448
|
+
seedCatalogSkillMemories();
|
|
362
449
|
|
|
363
450
|
const db = getDb();
|
|
364
451
|
const items = db
|
|
@@ -381,15 +468,128 @@ describe("seedCatalogSkillMemories", () => {
|
|
|
381
468
|
}
|
|
382
469
|
});
|
|
383
470
|
|
|
384
|
-
test("
|
|
471
|
+
test("includes bundled skills in seeded memories", () => {
|
|
472
|
+
const skills: SkillSummary[] = [
|
|
473
|
+
makeSkillSummary({
|
|
474
|
+
id: "managed-skill",
|
|
475
|
+
displayName: "Managed",
|
|
476
|
+
description: "A managed skill",
|
|
477
|
+
source: "managed",
|
|
478
|
+
}),
|
|
479
|
+
makeSkillSummary({
|
|
480
|
+
id: "bundled-skill",
|
|
481
|
+
displayName: "Bundled",
|
|
482
|
+
description: "A bundled skill",
|
|
483
|
+
source: "bundled",
|
|
484
|
+
bundled: true,
|
|
485
|
+
}),
|
|
486
|
+
];
|
|
487
|
+
mockLoadSkillCatalog = () => skills;
|
|
488
|
+
|
|
489
|
+
seedCatalogSkillMemories();
|
|
490
|
+
|
|
491
|
+
const db = getDb();
|
|
492
|
+
const items = db
|
|
493
|
+
.select()
|
|
494
|
+
.from(memoryItems)
|
|
495
|
+
.where(eq(memoryItems.kind, "capability"))
|
|
496
|
+
.all();
|
|
497
|
+
expect(items).toHaveLength(2);
|
|
498
|
+
|
|
499
|
+
const subjects = items.map((i) => i.subject).sort();
|
|
500
|
+
expect(subjects).toEqual(["skill:bundled-skill", "skill:managed-skill"]);
|
|
501
|
+
|
|
502
|
+
for (const item of items) {
|
|
503
|
+
expect(item.status).toBe("active");
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
test("excludes bundled skills filtered by allowBundled config", () => {
|
|
508
|
+
const skills: SkillSummary[] = [
|
|
509
|
+
makeSkillSummary({
|
|
510
|
+
id: "allowed-bundled",
|
|
511
|
+
displayName: "Allowed Bundled",
|
|
512
|
+
description: "This bundled skill is allowed",
|
|
513
|
+
source: "bundled",
|
|
514
|
+
bundled: true,
|
|
515
|
+
}),
|
|
516
|
+
makeSkillSummary({
|
|
517
|
+
id: "blocked-bundled",
|
|
518
|
+
displayName: "Blocked Bundled",
|
|
519
|
+
description: "This bundled skill is not in allowBundled",
|
|
520
|
+
source: "bundled",
|
|
521
|
+
bundled: true,
|
|
522
|
+
}),
|
|
523
|
+
makeSkillSummary({
|
|
524
|
+
id: "managed-skill",
|
|
525
|
+
displayName: "Managed",
|
|
526
|
+
description: "A managed skill",
|
|
527
|
+
source: "managed",
|
|
528
|
+
}),
|
|
529
|
+
];
|
|
530
|
+
mockLoadSkillCatalog = () => skills;
|
|
531
|
+
|
|
532
|
+
// Override config to set allowBundled to only allow one bundled skill
|
|
533
|
+
const configWithAllowBundled = {
|
|
534
|
+
...TEST_CONFIG,
|
|
535
|
+
skills: {
|
|
536
|
+
...TEST_CONFIG.skills,
|
|
537
|
+
allowBundled: ["allowed-bundled"],
|
|
538
|
+
},
|
|
539
|
+
};
|
|
540
|
+
mock.module("../config/loader.js", () => ({
|
|
541
|
+
loadConfig: () => configWithAllowBundled,
|
|
542
|
+
getConfig: () => configWithAllowBundled,
|
|
543
|
+
loadRawConfig: () => ({}),
|
|
544
|
+
saveRawConfig: () => {},
|
|
545
|
+
invalidateConfigCache: () => {},
|
|
546
|
+
}));
|
|
547
|
+
|
|
548
|
+
seedCatalogSkillMemories();
|
|
549
|
+
|
|
550
|
+
const db = getDb();
|
|
551
|
+
const items = db
|
|
552
|
+
.select()
|
|
553
|
+
.from(memoryItems)
|
|
554
|
+
.where(eq(memoryItems.kind, "capability"))
|
|
555
|
+
.all();
|
|
556
|
+
|
|
557
|
+
// Only allowed-bundled and managed-skill should be seeded
|
|
558
|
+
expect(items).toHaveLength(2);
|
|
559
|
+
const subjects = items.map((i) => i.subject).sort();
|
|
560
|
+
expect(subjects).toEqual(["skill:allowed-bundled", "skill:managed-skill"]);
|
|
561
|
+
|
|
562
|
+
// Restore default config mock
|
|
563
|
+
mock.module("../config/loader.js", () => ({
|
|
564
|
+
loadConfig: () => TEST_CONFIG,
|
|
565
|
+
getConfig: () => TEST_CONFIG,
|
|
566
|
+
loadRawConfig: () => ({}),
|
|
567
|
+
saveRawConfig: () => {},
|
|
568
|
+
invalidateConfigCache: () => {},
|
|
569
|
+
}));
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
test("prunes stale capabilities for skills no longer enabled", () => {
|
|
385
573
|
// First seed with three skills
|
|
386
|
-
const initialSkills:
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
574
|
+
const initialSkills: SkillSummary[] = [
|
|
575
|
+
makeSkillSummary({
|
|
576
|
+
id: "skill-a",
|
|
577
|
+
displayName: "Skill A",
|
|
578
|
+
description: "Does A",
|
|
579
|
+
}),
|
|
580
|
+
makeSkillSummary({
|
|
581
|
+
id: "skill-b",
|
|
582
|
+
displayName: "Skill B",
|
|
583
|
+
description: "Does B",
|
|
584
|
+
}),
|
|
585
|
+
makeSkillSummary({
|
|
586
|
+
id: "skill-c",
|
|
587
|
+
displayName: "Skill C",
|
|
588
|
+
description: "Does C",
|
|
589
|
+
}),
|
|
390
590
|
];
|
|
391
|
-
|
|
392
|
-
|
|
591
|
+
mockLoadSkillCatalog = () => initialSkills;
|
|
592
|
+
seedCatalogSkillMemories();
|
|
393
593
|
|
|
394
594
|
const db = getDb();
|
|
395
595
|
const beforeItems = db
|
|
@@ -401,10 +601,14 @@ describe("seedCatalogSkillMemories", () => {
|
|
|
401
601
|
expect(beforeItems.every((i) => i.status === "active")).toBe(true);
|
|
402
602
|
|
|
403
603
|
// Now seed with only skill-a — skill-b and skill-c should be pruned
|
|
404
|
-
|
|
405
|
-
|
|
604
|
+
mockLoadSkillCatalog = () => [
|
|
605
|
+
makeSkillSummary({
|
|
606
|
+
id: "skill-a",
|
|
607
|
+
displayName: "Skill A",
|
|
608
|
+
description: "Does A",
|
|
609
|
+
}),
|
|
406
610
|
];
|
|
407
|
-
|
|
611
|
+
seedCatalogSkillMemories();
|
|
408
612
|
|
|
409
613
|
const afterItems = db
|
|
410
614
|
.select()
|
|
@@ -424,11 +628,11 @@ describe("seedCatalogSkillMemories", () => {
|
|
|
424
628
|
expect(deletedSubjects).toEqual(["skill:skill-b", "skill:skill-c"]);
|
|
425
629
|
});
|
|
426
630
|
|
|
427
|
-
test("handles empty catalog without errors",
|
|
631
|
+
test("handles empty catalog without errors", () => {
|
|
428
632
|
// Pre-populate a skill so we can verify it gets pruned
|
|
429
633
|
upsertSkillCapabilityMemory(
|
|
430
634
|
"existing-skill",
|
|
431
|
-
|
|
635
|
+
fromSkillSummary(makeSkillSummary({ id: "existing-skill" })),
|
|
432
636
|
);
|
|
433
637
|
|
|
434
638
|
const db = getDb();
|
|
@@ -437,8 +641,8 @@ describe("seedCatalogSkillMemories", () => {
|
|
|
437
641
|
expect(beforeItems[0].status).toBe("active");
|
|
438
642
|
|
|
439
643
|
// Seed with empty catalog
|
|
440
|
-
|
|
441
|
-
|
|
644
|
+
mockLoadSkillCatalog = () => [];
|
|
645
|
+
seedCatalogSkillMemories();
|
|
442
646
|
|
|
443
647
|
// The existing skill should be pruned (soft-deleted)
|
|
444
648
|
const afterItems = db.select().from(memoryItems).all();
|
|
@@ -446,35 +650,69 @@ describe("seedCatalogSkillMemories", () => {
|
|
|
446
650
|
expect(afterItems[0].status).toBe("deleted");
|
|
447
651
|
});
|
|
448
652
|
|
|
449
|
-
test("does not
|
|
450
|
-
|
|
451
|
-
|
|
653
|
+
test("does not prune non-skill capability memories", () => {
|
|
654
|
+
// Pre-insert a non-skill capability memory directly into the DB
|
|
655
|
+
const db = getDb();
|
|
656
|
+
const now = Date.now();
|
|
657
|
+
db.insert(memoryItems)
|
|
658
|
+
.values({
|
|
659
|
+
id: "cli-doctor-item",
|
|
660
|
+
kind: "capability",
|
|
661
|
+
subject: "cli:doctor",
|
|
662
|
+
statement: "The doctor command diagnoses issues.",
|
|
663
|
+
status: "active",
|
|
664
|
+
confidence: 1.0,
|
|
665
|
+
importance: 0.7,
|
|
666
|
+
fingerprint: "cli-doctor-fp",
|
|
667
|
+
sourceType: "extraction",
|
|
668
|
+
scopeId: "default",
|
|
669
|
+
firstSeenAt: now,
|
|
670
|
+
lastSeenAt: now,
|
|
671
|
+
})
|
|
672
|
+
.run();
|
|
673
|
+
|
|
674
|
+
// Seed with empty catalog — skill pruner runs but should skip cli:* items
|
|
675
|
+
mockLoadSkillCatalog = () => [];
|
|
676
|
+
seedCatalogSkillMemories();
|
|
677
|
+
|
|
678
|
+
const item = db
|
|
679
|
+
.select()
|
|
680
|
+
.from(memoryItems)
|
|
681
|
+
.where(eq(memoryItems.subject, "cli:doctor"))
|
|
682
|
+
.get();
|
|
683
|
+
expect(item).toBeDefined();
|
|
684
|
+
expect(item!.status).toBe("active");
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
test("does not throw when loadSkillCatalog throws", () => {
|
|
688
|
+
mockLoadSkillCatalog = () => {
|
|
689
|
+
throw new Error("Catalog load failure");
|
|
452
690
|
};
|
|
453
691
|
|
|
454
692
|
// Best-effort: should not propagate the error
|
|
455
|
-
|
|
693
|
+
expect(() => seedCatalogSkillMemories()).not.toThrow();
|
|
456
694
|
});
|
|
457
695
|
|
|
458
|
-
test("skips skills whose feature flag is disabled",
|
|
459
|
-
const skills:
|
|
460
|
-
|
|
696
|
+
test("skips skills whose feature flag is disabled", () => {
|
|
697
|
+
const skills: SkillSummary[] = [
|
|
698
|
+
makeSkillSummary({
|
|
461
699
|
id: "unflagged-skill",
|
|
462
|
-
|
|
700
|
+
displayName: "Unflagged",
|
|
463
701
|
description: "No flag",
|
|
464
702
|
}),
|
|
465
|
-
|
|
703
|
+
makeSkillSummary({
|
|
466
704
|
id: "flagged-skill",
|
|
467
|
-
|
|
705
|
+
displayName: "Flagged",
|
|
468
706
|
description: "Has flag",
|
|
469
|
-
|
|
707
|
+
featureFlag: "my_gated_feature",
|
|
470
708
|
}),
|
|
471
709
|
];
|
|
472
|
-
|
|
710
|
+
mockLoadSkillCatalog = () => skills;
|
|
473
711
|
|
|
474
712
|
// Disable the feature flag for the flagged skill
|
|
475
713
|
mockIsFeatureFlagEnabled = (key: string) => key !== "my_gated_feature";
|
|
476
714
|
|
|
477
|
-
|
|
715
|
+
seedCatalogSkillMemories();
|
|
478
716
|
|
|
479
717
|
const db = getDb();
|
|
480
718
|
const items = db
|
|
@@ -489,24 +727,24 @@ describe("seedCatalogSkillMemories", () => {
|
|
|
489
727
|
expect(items[0].status).toBe("active");
|
|
490
728
|
});
|
|
491
729
|
|
|
492
|
-
test("prunes pre-existing capability for a skill whose flag becomes disabled",
|
|
730
|
+
test("prunes pre-existing capability for a skill whose flag becomes disabled", () => {
|
|
493
731
|
// First seed with both skills, all flags enabled
|
|
494
|
-
const skills:
|
|
495
|
-
|
|
732
|
+
const skills: SkillSummary[] = [
|
|
733
|
+
makeSkillSummary({
|
|
496
734
|
id: "unflagged-skill",
|
|
497
|
-
|
|
735
|
+
displayName: "Unflagged",
|
|
498
736
|
description: "No flag",
|
|
499
737
|
}),
|
|
500
|
-
|
|
738
|
+
makeSkillSummary({
|
|
501
739
|
id: "flagged-skill",
|
|
502
|
-
|
|
740
|
+
displayName: "Flagged",
|
|
503
741
|
description: "Has flag",
|
|
504
|
-
|
|
742
|
+
featureFlag: "my_gated_feature",
|
|
505
743
|
}),
|
|
506
744
|
];
|
|
507
|
-
|
|
745
|
+
mockLoadSkillCatalog = () => skills;
|
|
508
746
|
mockIsFeatureFlagEnabled = () => true;
|
|
509
|
-
|
|
747
|
+
seedCatalogSkillMemories();
|
|
510
748
|
|
|
511
749
|
const db = getDb();
|
|
512
750
|
const beforeItems = db
|
|
@@ -519,7 +757,7 @@ describe("seedCatalogSkillMemories", () => {
|
|
|
519
757
|
|
|
520
758
|
// Now disable the flag — the flagged skill should be pruned
|
|
521
759
|
mockIsFeatureFlagEnabled = (key: string) => key !== "my_gated_feature";
|
|
522
|
-
|
|
760
|
+
seedCatalogSkillMemories();
|
|
523
761
|
|
|
524
762
|
const afterItems = db
|
|
525
763
|
.select()
|
|
@@ -538,9 +776,13 @@ describe("seedCatalogSkillMemories", () => {
|
|
|
538
776
|
expect(deleted[0].subject).toBe("skill:flagged-skill");
|
|
539
777
|
});
|
|
540
778
|
|
|
541
|
-
test("does not throw on DB error during pruning",
|
|
542
|
-
|
|
543
|
-
|
|
779
|
+
test("does not throw on DB error during pruning", () => {
|
|
780
|
+
mockLoadSkillCatalog = () => [
|
|
781
|
+
makeSkillSummary({
|
|
782
|
+
id: "skill-a",
|
|
783
|
+
displayName: "Skill A",
|
|
784
|
+
description: "Does A",
|
|
785
|
+
}),
|
|
544
786
|
];
|
|
545
787
|
|
|
546
788
|
// Drop memory_items to force a DB error during the prune phase
|
|
@@ -548,13 +790,14 @@ describe("seedCatalogSkillMemories", () => {
|
|
|
548
790
|
const db = getDb();
|
|
549
791
|
db.run("DROP TABLE IF EXISTS memory_items");
|
|
550
792
|
|
|
551
|
-
|
|
793
|
+
expect(() => seedCatalogSkillMemories()).not.toThrow();
|
|
552
794
|
|
|
553
795
|
// Restore DB state for subsequent tests (see upsert "does not throw" test
|
|
554
796
|
// for rationale on why we delete the DB file).
|
|
555
797
|
resetDb();
|
|
798
|
+
const dbPath = getDbPath();
|
|
556
799
|
for (const ext of ["", "-wal", "-shm"]) {
|
|
557
|
-
rmSync(
|
|
800
|
+
rmSync(`${dbPath}${ext}`, { force: true });
|
|
558
801
|
}
|
|
559
802
|
initializeDb();
|
|
560
803
|
});
|