@hasna/hooks 0.8.0 → 0.9.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/bin/index.js +315 -67
- package/bin/serve.js +12 -0
- package/dist/index.js +52 -4
- package/dist/lib/installer.d.ts +40 -1
- package/dist/lib/registration.d.ts +75 -0
- package/dist/lib/registry.d.ts +14 -0
- package/hooks/hook-agent-rules-version-check/README.md +1 -1
- package/hooks/hook-trash-guard/README.md +132 -0
- package/hooks/hook-trash-guard/package.json +12 -0
- package/hooks/hook-trash-guard/src/hook.ts +1114 -0
- package/package.json +4 -2
- package/hooks/codewith-native-common.test.ts +0 -1935
- package/hooks/hook-affected-tests/tsconfig.json +0 -25
- package/hooks/hook-agent-rules-version-check/src/hook.test.ts +0 -104
- package/hooks/hook-agent-rules-version-check/tsconfig.json +0 -25
- package/hooks/hook-announce-start/tsconfig.json +0 -25
- package/hooks/hook-announce-stop/tsconfig.json +0 -25
- package/hooks/hook-autoformat/tsconfig.json +0 -25
- package/hooks/hook-branchprotect/tsconfig.json +0 -25
- package/hooks/hook-checkbugs/tsconfig.json +0 -15
- package/hooks/hook-checkdocs/tsconfig.json +0 -15
- package/hooks/hook-checkfiles/tsconfig.json +0 -15
- package/hooks/hook-checklint/tsconfig.json +0 -15
- package/hooks/hook-checkpoint/tsconfig.json +0 -25
- package/hooks/hook-checksecurity/tsconfig.json +0 -15
- package/hooks/hook-checktasks/tsconfig.json +0 -20
- package/hooks/hook-checktests/tsconfig.json +0 -15
- package/hooks/hook-conflict-detect/tsconfig.json +0 -25
- package/hooks/hook-contextrefresh/tsconfig.json +0 -25
- package/hooks/hook-desktopnotify/tsconfig.json +0 -25
- package/hooks/hook-dm-inject/tsconfig.json +0 -25
- package/hooks/hook-envsetup/tsconfig.json +0 -25
- package/hooks/hook-failure-to-task/tsconfig.json +0 -25
- package/hooks/hook-filelock/tsconfig.json +0 -25
- package/hooks/hook-fleet-blockers-gate/src/hook.test.ts +0 -302
- package/hooks/hook-fleet-blockers-gate/tsconfig.json +0 -25
- package/hooks/hook-fleet-catchup/src/hook.test.ts +0 -156
- package/hooks/hook-fleet-catchup/tsconfig.json +0 -25
- package/hooks/hook-gitguard/tsconfig.json +0 -25
- package/hooks/hook-knowledge-context/src/hook.test.ts +0 -379
- package/hooks/hook-packageage/tsconfig.json +0 -25
- package/hooks/hook-permissionguard/tsconfig.json +0 -25
- package/hooks/hook-phonenotify/tsconfig.json +0 -25
- package/hooks/hook-precompact/tsconfig.json +0 -25
- package/hooks/hook-protectfiles/tsconfig.json +0 -25
- package/hooks/hook-scanoutput/src/hook.test.ts +0 -217
- package/hooks/hook-spiral-detector/src/hook.test.ts +0 -72
- package/hooks/hook-stylescheck/tsconfig.json +0 -25
- package/hooks/hook-typecheck-gate/tsconfig.json +0 -25
- package/hooks/hook-workspace-repos-guard/src/hook.test.ts +0 -466
- package/hooks/hook-workspace-repos-guard/tsconfig.json +0 -21
- package/hooks/mention-context/src/hook.test.ts +0 -68
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import {
|
|
3
|
-
buildHookOutput,
|
|
4
|
-
buildKnowledgeArgs,
|
|
5
|
-
buildQuery,
|
|
6
|
-
extractContextText,
|
|
7
|
-
getConfig,
|
|
8
|
-
promptSignalScore,
|
|
9
|
-
redactSecrets,
|
|
10
|
-
sanitizeQuery,
|
|
11
|
-
type KnowledgeContextConfig,
|
|
12
|
-
type KnowledgeExecutor,
|
|
13
|
-
} from "./hook";
|
|
14
|
-
|
|
15
|
-
const baseConfig: KnowledgeContextConfig = {
|
|
16
|
-
command: "knowledge",
|
|
17
|
-
timeoutMs: 5000,
|
|
18
|
-
maxItems: 3,
|
|
19
|
-
candidateItems: 12,
|
|
20
|
-
maxTokens: 1200,
|
|
21
|
-
minPromptChars: 6,
|
|
22
|
-
minSignalScore: 3,
|
|
23
|
-
maxQueryChars: 1200,
|
|
24
|
-
maxOutputChars: 8000,
|
|
25
|
-
requireHighSignal: true,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
describe("hook-knowledge-context", () => {
|
|
29
|
-
test("defaults Knowledge CLI timeout to 5000ms and keeps env override", () => {
|
|
30
|
-
expect(getConfig({}).timeoutMs).toBe(5000);
|
|
31
|
-
expect(getConfig({}).maxItems).toBe(3);
|
|
32
|
-
expect(getConfig({}).candidateItems).toBe(12);
|
|
33
|
-
expect(getConfig({}).minPromptChars).toBe(6);
|
|
34
|
-
expect(getConfig({}).minSignalScore).toBe(3);
|
|
35
|
-
expect(getConfig({}).requireHighSignal).toBe(true);
|
|
36
|
-
expect(getConfig({ HOOKS_KNOWLEDGE_TIMEOUT_MS: "2345" }).timeoutMs).toBe(2345);
|
|
37
|
-
expect(getConfig({ HOOKS_KNOWLEDGE_REQUIRE_HIGH_SIGNAL: "0" }).requireHighSignal).toBe(false);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test("applies bounded env overrides and rejects unsafe command override", () => {
|
|
41
|
-
const config = getConfig({
|
|
42
|
-
HOOKS_KNOWLEDGE_COMMAND: "/tmp/knowledge",
|
|
43
|
-
HOOKS_KNOWLEDGE_MAX_ITEMS: "9",
|
|
44
|
-
HOOKS_KNOWLEDGE_CANDIDATE_ITEMS: "15",
|
|
45
|
-
HOOKS_KNOWLEDGE_MAX_TOKENS: "2345",
|
|
46
|
-
HOOKS_KNOWLEDGE_MIN_PROMPT_CHARS: "12",
|
|
47
|
-
HOOKS_KNOWLEDGE_MIN_SIGNAL_SCORE: "4",
|
|
48
|
-
HOOKS_KNOWLEDGE_MAX_QUERY_CHARS: "200",
|
|
49
|
-
HOOKS_KNOWLEDGE_MAX_OUTPUT_CHARS: "9999",
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
expect(config.command).toBe("/tmp/knowledge");
|
|
53
|
-
expect(config.maxItems).toBe(9);
|
|
54
|
-
expect(config.candidateItems).toBe(15);
|
|
55
|
-
expect(config.maxTokens).toBe(2345);
|
|
56
|
-
expect(config.minPromptChars).toBe(12);
|
|
57
|
-
expect(config.minSignalScore).toBe(4);
|
|
58
|
-
expect(config.maxQueryChars).toBe(200);
|
|
59
|
-
expect(config.maxOutputChars).toBe(9999);
|
|
60
|
-
expect(buildKnowledgeArgs("q", config)).toContain("15");
|
|
61
|
-
expect(getConfig({ HOOKS_KNOWLEDGE_COMMAND: "bad command" }).command).toBe("knowledge");
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test("builds deterministic knowledge context pack args without semantic, web, or generation flags", () => {
|
|
65
|
-
const args = buildKnowledgeArgs("repo hook context", baseConfig);
|
|
66
|
-
|
|
67
|
-
expect(args).toEqual([
|
|
68
|
-
"context",
|
|
69
|
-
"pack",
|
|
70
|
-
"repo hook context",
|
|
71
|
-
"--from",
|
|
72
|
-
"search",
|
|
73
|
-
"--max-items",
|
|
74
|
-
"12",
|
|
75
|
-
"--max-tokens",
|
|
76
|
-
"1200",
|
|
77
|
-
"--json",
|
|
78
|
-
]);
|
|
79
|
-
expect(args).not.toContain("--semantic");
|
|
80
|
-
expect(args).not.toContain("--generate");
|
|
81
|
-
expect(args).not.toContain("web");
|
|
82
|
-
expect(args).not.toContain("ask");
|
|
83
|
-
expect(args).not.toContain("build");
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test("emits Codewith additionalContext for SessionStart", async () => {
|
|
87
|
-
const executor: KnowledgeExecutor = async () => ({
|
|
88
|
-
ok: true,
|
|
89
|
-
stdout: JSON.stringify({ context: "Use hooks.json for Codewith lifecycle hooks." }),
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const output = await buildHookOutput(
|
|
93
|
-
{
|
|
94
|
-
hook_event_name: "SessionStart",
|
|
95
|
-
cwd: "/repo",
|
|
96
|
-
source: "startup",
|
|
97
|
-
model: "gpt-test",
|
|
98
|
-
},
|
|
99
|
-
executor
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
expect(output.continue).toBe(true);
|
|
103
|
-
expect(output.hookSpecificOutput?.hookEventName).toBe("SessionStart");
|
|
104
|
-
expect(output.hookSpecificOutput?.additionalContext).toContain("Knowledge matches");
|
|
105
|
-
expect(output.hookSpecificOutput?.additionalContext).toContain("Use hooks.json");
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test("emits event-matched additionalContext for UserPromptSubmit and redacts query secrets", async () => {
|
|
109
|
-
let capturedQuery = "";
|
|
110
|
-
const executor: KnowledgeExecutor = async (query) => {
|
|
111
|
-
capturedQuery = query;
|
|
112
|
-
return {
|
|
113
|
-
ok: true,
|
|
114
|
-
stdout: JSON.stringify({
|
|
115
|
-
items: [{ title: "Decision", text: "Prefer deterministic context packs. secret=demo" }],
|
|
116
|
-
}),
|
|
117
|
-
};
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const output = await buildHookOutput(
|
|
121
|
-
{
|
|
122
|
-
hook_event_name: "UserPromptSubmit",
|
|
123
|
-
cwd: "/repo",
|
|
124
|
-
prompt: "implement the knowledge hook context output with token=demo",
|
|
125
|
-
},
|
|
126
|
-
executor
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
expect(output.hookSpecificOutput?.hookEventName).toBe("UserPromptSubmit");
|
|
130
|
-
expect(output.hookSpecificOutput?.additionalContext).toContain("Prefer deterministic context packs");
|
|
131
|
-
expect(output.hookSpecificOutput?.additionalContext).toContain("secret=<redacted>");
|
|
132
|
-
expect(output.hookSpecificOutput?.additionalContext).not.toContain("secret=demo");
|
|
133
|
-
expect(capturedQuery).toContain("token=<redacted>");
|
|
134
|
-
expect(capturedQuery).not.toContain("token=demo");
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test("emits event-matched additionalContext for SubagentStart", async () => {
|
|
138
|
-
const executor: KnowledgeExecutor = async () => ({
|
|
139
|
-
ok: true,
|
|
140
|
-
stdout: JSON.stringify({ data: { markdown: "Subagents inherit parent scope and should stay bounded." } }),
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
const output = await buildHookOutput(
|
|
144
|
-
{
|
|
145
|
-
hook_event_name: "SubagentStart",
|
|
146
|
-
cwd: "/repo",
|
|
147
|
-
agent_type: "verifier",
|
|
148
|
-
turn_id: "turn-1",
|
|
149
|
-
},
|
|
150
|
-
executor
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
expect(output.hookSpecificOutput?.hookEventName).toBe("SubagentStart");
|
|
154
|
-
expect(output.hookSpecificOutput?.additionalContext).toContain("Subagents inherit parent scope");
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
test("fails open without context on executor error, timeout, or invalid JSON", async () => {
|
|
158
|
-
const failed = await buildHookOutput({ hook_event_name: "SessionStart", cwd: "/repo" }, async () => ({ ok: false }));
|
|
159
|
-
const timedOut = await buildHookOutput(
|
|
160
|
-
{ hook_event_name: "SessionStart", cwd: "/repo" },
|
|
161
|
-
async () => ({ ok: false, timedOut: true })
|
|
162
|
-
);
|
|
163
|
-
const invalidJson = await buildHookOutput(
|
|
164
|
-
{ hook_event_name: "SessionStart", cwd: "/repo" },
|
|
165
|
-
async () => ({ ok: true, stdout: "not json" })
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
expect(failed).toEqual({ continue: true });
|
|
169
|
-
expect(timedOut).toEqual({ continue: true });
|
|
170
|
-
expect(invalidJson).toEqual({ continue: true });
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test("fails open for disabled or unsupported events", async () => {
|
|
174
|
-
const executor: KnowledgeExecutor = async () => {
|
|
175
|
-
throw new Error("executor should not run");
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
expect(
|
|
179
|
-
await buildHookOutput({ hook_event_name: "PostToolUse", cwd: "/repo" }, executor)
|
|
180
|
-
).toEqual({ continue: true });
|
|
181
|
-
expect(
|
|
182
|
-
await buildHookOutput({ hook_event_name: "SessionStart", cwd: "/repo" }, executor, {
|
|
183
|
-
HOOKS_KNOWLEDGE_CONTEXT_DISABLE: "1",
|
|
184
|
-
})
|
|
185
|
-
).toEqual({ continue: true });
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
test("fails open for low-signal UserPromptSubmit prompts before calling Knowledge", async () => {
|
|
189
|
-
let executorCalls = 0;
|
|
190
|
-
const executor: KnowledgeExecutor = async () => {
|
|
191
|
-
executorCalls += 1;
|
|
192
|
-
throw new Error("executor should not run for low-signal prompts");
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
for (const prompt of ["", "ok", "thanks", "?", "continue", "tell me again"]) {
|
|
196
|
-
expect(
|
|
197
|
-
await buildHookOutput({ hook_event_name: "UserPromptSubmit", cwd: "/repo", prompt }, executor)
|
|
198
|
-
).toEqual({ continue: true });
|
|
199
|
-
}
|
|
200
|
-
expect(executorCalls).toBe(0);
|
|
201
|
-
for (const prompt of [
|
|
202
|
-
"fix authz",
|
|
203
|
-
"release",
|
|
204
|
-
"publish npm",
|
|
205
|
-
"check src/hook.ts",
|
|
206
|
-
"@hasna/hooks",
|
|
207
|
-
"merge PR 12",
|
|
208
|
-
"review staged diff",
|
|
209
|
-
"rerun tests",
|
|
210
|
-
]) {
|
|
211
|
-
expect(promptSignalScore(prompt, "/home/hasna/workspace/hasna/opensource/hooks")).toBeGreaterThanOrEqual(3);
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
test("can opt out of high-signal gating for UserPromptSubmit", async () => {
|
|
216
|
-
const output = await buildHookOutput(
|
|
217
|
-
{ hook_event_name: "UserPromptSubmit", cwd: "/repo", prompt: "ok" },
|
|
218
|
-
async () => ({
|
|
219
|
-
ok: true,
|
|
220
|
-
stdout: JSON.stringify({ context: "Forced low-signal context." }),
|
|
221
|
-
}),
|
|
222
|
-
{ HOOKS_KNOWLEDGE_REQUIRE_HIGH_SIGNAL: "0" }
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
expect(output.hookSpecificOutput?.additionalContext).toContain("Forced low-signal context");
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
test("sanitizes and bounds queries", () => {
|
|
229
|
-
expect(redactSecrets("password=hunter2 token=demo")).toBe(
|
|
230
|
-
"password=<redacted> token=<redacted>"
|
|
231
|
-
);
|
|
232
|
-
expect(sanitizeQuery("a\nb\tc", 100)).toBe("a b c");
|
|
233
|
-
expect(sanitizeQuery("word ".repeat(200), 20).length).toBeLessThanOrEqual(20);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
test("builds event-specific queries and extracts common context pack shapes", () => {
|
|
237
|
-
const config = getConfig({});
|
|
238
|
-
|
|
239
|
-
expect(buildQuery({ hook_event_name: "SessionStart", cwd: "/repo", source: "resume" }, config)).toContain(
|
|
240
|
-
"session start"
|
|
241
|
-
);
|
|
242
|
-
expect(buildQuery({ hook_event_name: "SubagentStart", cwd: "/repo", agent_type: "reviewer" }, config)).toContain(
|
|
243
|
-
"subagent start"
|
|
244
|
-
);
|
|
245
|
-
expect(extractContextText({ pack: { context: "direct context" } })).toBe("direct context");
|
|
246
|
-
expect(extractContextText([{ title: "One", text: "Body", uri: "knowledge://item/one" }])).toContain("Body");
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
test("formats citation-only packs as item_id/cite bullets with one read hint", () => {
|
|
250
|
-
const text = extractContextText({
|
|
251
|
-
citations: [
|
|
252
|
-
{
|
|
253
|
-
id: "cite_1",
|
|
254
|
-
source_ref: "knowledge://item/k_one",
|
|
255
|
-
quote_preview: "First preview that tells the agent why this Knowledge item might matter.",
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
id: "cite_2",
|
|
259
|
-
source_ref: "knowledge://item/k_two",
|
|
260
|
-
quote_preview: "Second preview that tells the agent why this Knowledge item might matter.",
|
|
261
|
-
},
|
|
262
|
-
],
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
expect(text).toContain("If a match looks relevant, read it with: knowledge get --id <item_id> --json");
|
|
266
|
-
expect(text?.match(/knowledge get --id/g) ?? []).toHaveLength(1);
|
|
267
|
-
expect(text).toContain("- item_id=k_one cite=cite_1: First preview");
|
|
268
|
-
expect(text).toContain("- item_id=k_two cite=cite_2: Second preview");
|
|
269
|
-
expect(text).not.toContain("open: knowledge get --id k_one --json");
|
|
270
|
-
expect(text).not.toContain("(cite_1)");
|
|
271
|
-
expect(text).not.toContain("source: knowledge://item/k_one");
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
test("extracts item_id from legacy Knowledge source paths", () => {
|
|
275
|
-
const text = extractContextText({
|
|
276
|
-
citations: [
|
|
277
|
-
{
|
|
278
|
-
id: "cite_abc",
|
|
279
|
-
source_ref: "open-files://source/legacy-json/path/k_mqyrz7gt_olq82e",
|
|
280
|
-
quote_preview: "Legacy file source preview.",
|
|
281
|
-
},
|
|
282
|
-
],
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
expect(text).toContain("item_id=k_mqyrz7gt_olq82e");
|
|
286
|
-
expect(text).toContain("cite=cite_abc");
|
|
287
|
-
expect(text).not.toContain("source=open-files://source/legacy-json/path/k_mqyrz7gt_olq82e");
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
test("keeps source fallback for non-Knowledge citations without item ids", () => {
|
|
291
|
-
const text = extractContextText({
|
|
292
|
-
citations: [
|
|
293
|
-
{
|
|
294
|
-
id: "cite_url",
|
|
295
|
-
source_ref: "https://example.test/doc",
|
|
296
|
-
quote_preview: "External preview.",
|
|
297
|
-
},
|
|
298
|
-
],
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
expect(text).toContain("- cite=cite_url source=https://example.test/doc: External preview.");
|
|
302
|
-
expect(text).not.toContain("item_id=");
|
|
303
|
-
expect(text).not.toContain("knowledge get --id");
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
test("cleans legacy empty-title bullet artifacts in item text", () => {
|
|
307
|
-
expect(extractContextText(["- : legacy empty title preview"])).toBe("- legacy empty title preview");
|
|
308
|
-
expect(extractContextText("- : legacy direct context")).toBe("- legacy direct context");
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
test("filters historical reference-only archive items from injected context", () => {
|
|
312
|
-
const text = extractContextText(
|
|
313
|
-
{
|
|
314
|
-
citations: [
|
|
315
|
-
{
|
|
316
|
-
id: "cite_archived",
|
|
317
|
-
source_ref: "knowledge://item/k_archived",
|
|
318
|
-
quote_preview:
|
|
319
|
-
"Archived on 2026-06-25 before removing brain orchestration startup files from spark01. Historical/reference only; not an active startup instruction.",
|
|
320
|
-
},
|
|
321
|
-
{
|
|
322
|
-
id: "cite_active",
|
|
323
|
-
source_ref: "knowledge://item/k_active",
|
|
324
|
-
quote_preview: "Current npm publish convention: use scoped granular tokens through the secrets CLI.",
|
|
325
|
-
},
|
|
326
|
-
],
|
|
327
|
-
},
|
|
328
|
-
{ maxItems: 3 }
|
|
329
|
-
);
|
|
330
|
-
|
|
331
|
-
expect(text).toContain("item_id=k_active cite=cite_active");
|
|
332
|
-
expect(text).toContain("Current npm publish convention");
|
|
333
|
-
expect(text).not.toContain("k_archived");
|
|
334
|
-
expect(text).not.toContain("Archived on 2026-06-25");
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
test("fails open when all citation candidates are non-autoloadable archive items", () => {
|
|
338
|
-
expect(
|
|
339
|
-
extractContextText(
|
|
340
|
-
{
|
|
341
|
-
citations: [
|
|
342
|
-
{
|
|
343
|
-
id: "cite_archived",
|
|
344
|
-
source_ref: "knowledge://item/k_archived",
|
|
345
|
-
quote_preview:
|
|
346
|
-
"Archived on 2026-06-25 from local Claude startup context. These instructions are historical/reference only and should not be auto-loaded for normal agents.",
|
|
347
|
-
},
|
|
348
|
-
],
|
|
349
|
-
},
|
|
350
|
-
{ maxItems: 3 }
|
|
351
|
-
)
|
|
352
|
-
).toBeNull();
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
test("caps emitted items after filtering extra search candidates", () => {
|
|
356
|
-
const text = extractContextText(
|
|
357
|
-
{
|
|
358
|
-
citations: [
|
|
359
|
-
{
|
|
360
|
-
id: "cite_archived",
|
|
361
|
-
source_ref: "knowledge://item/k_archived",
|
|
362
|
-
quote_preview:
|
|
363
|
-
"Archived on 2026-06-25 before removing brain orchestration startup files. Historical/reference only; not an active startup instruction.",
|
|
364
|
-
},
|
|
365
|
-
{ id: "cite_one", source_ref: "knowledge://item/k_one", quote_preview: "First active item." },
|
|
366
|
-
{ id: "cite_two", source_ref: "knowledge://item/k_two", quote_preview: "Second active item." },
|
|
367
|
-
{ id: "cite_three", source_ref: "knowledge://item/k_three", quote_preview: "Third active item." },
|
|
368
|
-
],
|
|
369
|
-
},
|
|
370
|
-
{ maxItems: 2 }
|
|
371
|
-
);
|
|
372
|
-
|
|
373
|
-
expect(text?.match(/^- item_id=/gm) ?? []).toHaveLength(2);
|
|
374
|
-
expect(text).toContain("item_id=k_one");
|
|
375
|
-
expect(text).toContain("item_id=k_two");
|
|
376
|
-
expect(text).not.toContain("item_id=k_three");
|
|
377
|
-
expect(text).not.toContain("item_id=k_archived");
|
|
378
|
-
});
|
|
379
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": ["ESNext"],
|
|
6
|
-
"moduleResolution": "bundler",
|
|
7
|
-
"allowImportingTsExtensions": true,
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"isolatedModules": true,
|
|
14
|
-
"noEmit": true,
|
|
15
|
-
"noUnusedLocals": true,
|
|
16
|
-
"noUnusedParameters": true,
|
|
17
|
-
"declaration": true,
|
|
18
|
-
"declarationMap": true,
|
|
19
|
-
"outDir": "./dist",
|
|
20
|
-
"rootDir": "./src",
|
|
21
|
-
"types": ["bun-types"]
|
|
22
|
-
},
|
|
23
|
-
"include": ["src/**/*"],
|
|
24
|
-
"exclude": ["node_modules", "dist"]
|
|
25
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": ["ESNext"],
|
|
6
|
-
"moduleResolution": "bundler",
|
|
7
|
-
"allowImportingTsExtensions": true,
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"isolatedModules": true,
|
|
14
|
-
"noEmit": true,
|
|
15
|
-
"noUnusedLocals": true,
|
|
16
|
-
"noUnusedParameters": true,
|
|
17
|
-
"declaration": true,
|
|
18
|
-
"declarationMap": true,
|
|
19
|
-
"outDir": "./dist",
|
|
20
|
-
"rootDir": "./src",
|
|
21
|
-
"types": ["bun-types"]
|
|
22
|
-
},
|
|
23
|
-
"include": ["src/**/*"],
|
|
24
|
-
"exclude": ["node_modules", "dist"]
|
|
25
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": ["ESNext"],
|
|
6
|
-
"moduleResolution": "bundler",
|
|
7
|
-
"allowImportingTsExtensions": true,
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"isolatedModules": true,
|
|
14
|
-
"noEmit": true,
|
|
15
|
-
"noUnusedLocals": true,
|
|
16
|
-
"noUnusedParameters": true,
|
|
17
|
-
"declaration": true,
|
|
18
|
-
"declarationMap": true,
|
|
19
|
-
"outDir": "./dist",
|
|
20
|
-
"rootDir": "./src",
|
|
21
|
-
"types": ["bun-types"]
|
|
22
|
-
},
|
|
23
|
-
"include": ["src/**/*"],
|
|
24
|
-
"exclude": ["node_modules", "dist"]
|
|
25
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": ["ESNext"],
|
|
6
|
-
"moduleResolution": "bundler",
|
|
7
|
-
"allowImportingTsExtensions": true,
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"isolatedModules": true,
|
|
14
|
-
"noEmit": true,
|
|
15
|
-
"noUnusedLocals": true,
|
|
16
|
-
"noUnusedParameters": true,
|
|
17
|
-
"declaration": true,
|
|
18
|
-
"declarationMap": true,
|
|
19
|
-
"outDir": "./dist",
|
|
20
|
-
"rootDir": "./src",
|
|
21
|
-
"types": ["bun-types"]
|
|
22
|
-
},
|
|
23
|
-
"include": ["src/**/*"],
|
|
24
|
-
"exclude": ["node_modules", "dist"]
|
|
25
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": ["ESNext"],
|
|
6
|
-
"moduleResolution": "bundler",
|
|
7
|
-
"allowImportingTsExtensions": true,
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"isolatedModules": true,
|
|
14
|
-
"noEmit": true,
|
|
15
|
-
"noUnusedLocals": true,
|
|
16
|
-
"noUnusedParameters": true,
|
|
17
|
-
"declaration": true,
|
|
18
|
-
"declarationMap": true,
|
|
19
|
-
"outDir": "./dist",
|
|
20
|
-
"rootDir": "./src",
|
|
21
|
-
"types": ["bun-types"]
|
|
22
|
-
},
|
|
23
|
-
"include": ["src/**/*"],
|
|
24
|
-
"exclude": ["node_modules", "dist"]
|
|
25
|
-
}
|