@hasna/hook-knowledge-context 0.1.0 → 0.1.2
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 +5 -2
- package/dist/hook.js +43 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,10 @@ The hook intentionally does not pass `--semantic`, does not call web search,
|
|
|
29
29
|
does not call ask/build/generate flows, and does not crawl raw stores directly.
|
|
30
30
|
When Knowledge returns a nonempty context pack, the hook redacts credential-like
|
|
31
31
|
text from that pack and emits Codewith-native
|
|
32
|
-
`hookSpecificOutput.additionalContext` with the same event name.
|
|
32
|
+
`hookSpecificOutput.additionalContext` with the same event name. Citation-only
|
|
33
|
+
packs are expanded into progressive context lines with a bounded preview and a
|
|
34
|
+
`knowledge get --id ... --json` read hint so agents can decide which full items
|
|
35
|
+
are worth opening.
|
|
33
36
|
|
|
34
37
|
All failures are fail-open: missing CLI, timeout, nonzero exit, malformed JSON,
|
|
35
38
|
bad stdin, or empty packs return `{"continue":true}` without context.
|
|
@@ -39,7 +42,7 @@ bad stdin, or empty packs return `{"continue":true}` without context.
|
|
|
39
42
|
```bash
|
|
40
43
|
export HOOKS_KNOWLEDGE_CONTEXT_DISABLE=1 # Kill switch
|
|
41
44
|
export HOOKS_KNOWLEDGE_COMMAND=knowledge # CLI command/path
|
|
42
|
-
export HOOKS_KNOWLEDGE_TIMEOUT_MS=
|
|
45
|
+
export HOOKS_KNOWLEDGE_TIMEOUT_MS=5000 # Per-call timeout
|
|
43
46
|
export HOOKS_KNOWLEDGE_MAX_ITEMS=6 # Context pack item budget
|
|
44
47
|
export HOOKS_KNOWLEDGE_MAX_TOKENS=1200 # Context pack token budget
|
|
45
48
|
export HOOKS_KNOWLEDGE_MAX_QUERY_CHARS=1200 # Redacted query bound
|
package/dist/hook.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// src/hook.ts
|
|
5
5
|
import { readFileSync } from "fs";
|
|
6
6
|
import { spawn } from "child_process";
|
|
7
|
-
var DEFAULT_TIMEOUT_MS =
|
|
7
|
+
var DEFAULT_TIMEOUT_MS = 5000;
|
|
8
8
|
var DEFAULT_MAX_ITEMS = 6;
|
|
9
9
|
var DEFAULT_MAX_TOKENS = 1200;
|
|
10
10
|
var DEFAULT_MAX_QUERY_CHARS = 1200;
|
|
@@ -148,6 +148,16 @@ function firstString(obj, keys) {
|
|
|
148
148
|
}
|
|
149
149
|
return null;
|
|
150
150
|
}
|
|
151
|
+
function firstSourceString(obj) {
|
|
152
|
+
const direct = firstString(obj, ["source_ref", "source_uri", "source", "uri", "ref", "url", "citation"]);
|
|
153
|
+
if (direct)
|
|
154
|
+
return direct;
|
|
155
|
+
const source = obj.source;
|
|
156
|
+
if (source && typeof source === "object") {
|
|
157
|
+
return firstString(source, ["uri", "ref", "url", "id"]);
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
151
161
|
function firstArray(obj, keys) {
|
|
152
162
|
for (const key of keys) {
|
|
153
163
|
const value = obj[key];
|
|
@@ -163,6 +173,13 @@ function truncate(text, max) {
|
|
|
163
173
|
return text.slice(0, max);
|
|
164
174
|
return `${text.slice(0, max - 3)}...`;
|
|
165
175
|
}
|
|
176
|
+
function compactText(text) {
|
|
177
|
+
return text.replace(/\s+/g, " ").trim();
|
|
178
|
+
}
|
|
179
|
+
function knowledgeItemId(source) {
|
|
180
|
+
const match = source?.match(/^knowledge:\/\/item\/([^/?#\s]+)$/);
|
|
181
|
+
return match?.[1] ?? null;
|
|
182
|
+
}
|
|
166
183
|
function formatPackItems(items) {
|
|
167
184
|
const lines = [];
|
|
168
185
|
for (const [index, item] of items.entries()) {
|
|
@@ -173,13 +190,33 @@ function formatPackItems(items) {
|
|
|
173
190
|
if (!item || typeof item !== "object")
|
|
174
191
|
continue;
|
|
175
192
|
const obj = item;
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
const
|
|
193
|
+
const citationId = firstString(obj, ["id", "citation_id", "citationId"]);
|
|
194
|
+
const source = firstSourceString(obj);
|
|
195
|
+
const itemId = knowledgeItemId(source);
|
|
196
|
+
const title = firstString(obj, ["title", "name"]) || (itemId ? `Knowledge item ${itemId}` : citationId || `item ${index + 1}`);
|
|
197
|
+
const body = firstString(obj, [
|
|
198
|
+
"summary",
|
|
199
|
+
"text",
|
|
200
|
+
"content",
|
|
201
|
+
"snippet",
|
|
202
|
+
"preview",
|
|
203
|
+
"quote_preview",
|
|
204
|
+
"quotePreview",
|
|
205
|
+
"excerpt",
|
|
206
|
+
"body",
|
|
207
|
+
"description"
|
|
208
|
+
]);
|
|
179
209
|
if (!body && !source)
|
|
180
210
|
continue;
|
|
181
|
-
const
|
|
182
|
-
|
|
211
|
+
const suffixParts = [
|
|
212
|
+
citationId && citationId !== title ? citationId : null,
|
|
213
|
+
source ? `source: ${truncate(source, 180)}` : null
|
|
214
|
+
].filter(Boolean);
|
|
215
|
+
const suffix = suffixParts.length > 0 ? ` (${suffixParts.join("; ")})` : "";
|
|
216
|
+
lines.push(`- ${truncate(title, 160)}${suffix}${body ? `: ${truncate(compactText(body), 520)}` : ""}`);
|
|
217
|
+
if (itemId) {
|
|
218
|
+
lines.push(` read: knowledge get --id ${itemId} --json`);
|
|
219
|
+
}
|
|
183
220
|
}
|
|
184
221
|
return lines.length > 0 ? lines.join(`
|
|
185
222
|
`) : null;
|
package/package.json
CHANGED