@vpxa/kb 0.1.1 → 0.1.3
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 +3 -3
- package/package.json +1 -1
- package/packages/analyzers/dist/blast-radius-analyzer.js +13 -114
- package/packages/analyzers/dist/dependency-analyzer.js +11 -425
- package/packages/analyzers/dist/diagram-generator.js +4 -86
- package/packages/analyzers/dist/entry-point-analyzer.js +5 -239
- package/packages/analyzers/dist/index.js +1 -23
- package/packages/analyzers/dist/knowledge-producer.js +24 -113
- package/packages/analyzers/dist/pattern-analyzer.js +5 -359
- package/packages/analyzers/dist/regex-call-graph.js +1 -428
- package/packages/analyzers/dist/structure-analyzer.js +4 -258
- package/packages/analyzers/dist/symbol-analyzer.js +13 -442
- package/packages/analyzers/dist/ts-call-graph.js +1 -160
- package/packages/analyzers/dist/types.js +0 -1
- package/packages/chunker/dist/call-graph-extractor.js +1 -90
- package/packages/chunker/dist/chunker-factory.js +1 -36
- package/packages/chunker/dist/chunker.interface.js +0 -1
- package/packages/chunker/dist/code-chunker.js +14 -134
- package/packages/chunker/dist/generic-chunker.js +5 -72
- package/packages/chunker/dist/index.js +1 -21
- package/packages/chunker/dist/markdown-chunker.js +7 -119
- package/packages/chunker/dist/treesitter-chunker.js +8 -234
- package/packages/cli/dist/commands/analyze.js +3 -112
- package/packages/cli/dist/commands/context-cmds.js +1 -155
- package/packages/cli/dist/commands/environment.js +2 -204
- package/packages/cli/dist/commands/execution.js +1 -137
- package/packages/cli/dist/commands/graph.js +7 -81
- package/packages/cli/dist/commands/init.js +9 -87
- package/packages/cli/dist/commands/knowledge.js +1 -139
- package/packages/cli/dist/commands/search.js +8 -267
- package/packages/cli/dist/commands/system.js +4 -241
- package/packages/cli/dist/commands/workspace.js +2 -388
- package/packages/cli/dist/context.js +1 -14
- package/packages/cli/dist/helpers.js +3 -458
- package/packages/cli/dist/index.d.ts +1 -1
- package/packages/cli/dist/index.js +3 -69
- package/packages/cli/dist/kb-init.js +1 -82
- package/packages/cli/dist/types.js +0 -1
- package/packages/core/dist/constants.js +1 -43
- package/packages/core/dist/content-detector.js +1 -79
- package/packages/core/dist/errors.js +1 -40
- package/packages/core/dist/index.js +1 -9
- package/packages/core/dist/logger.js +1 -34
- package/packages/core/dist/types.js +0 -1
- package/packages/embeddings/dist/embedder.interface.js +0 -1
- package/packages/embeddings/dist/index.js +1 -5
- package/packages/embeddings/dist/onnx-embedder.js +1 -82
- package/packages/indexer/dist/file-hasher.js +1 -13
- package/packages/indexer/dist/filesystem-crawler.js +1 -125
- package/packages/indexer/dist/graph-extractor.js +1 -111
- package/packages/indexer/dist/incremental-indexer.js +1 -278
- package/packages/indexer/dist/index.js +1 -14
- package/packages/server/dist/api.js +1 -9
- package/packages/server/dist/config.js +1 -75
- package/packages/server/dist/curated-manager.js +9 -356
- package/packages/server/dist/index.js +1 -134
- package/packages/server/dist/replay-interceptor.js +1 -38
- package/packages/server/dist/resources/resources.js +2 -40
- package/packages/server/dist/server.js +1 -247
- package/packages/server/dist/tools/analyze.tools.js +1 -288
- package/packages/server/dist/tools/forge.tools.js +11 -499
- package/packages/server/dist/tools/forget.tool.js +3 -39
- package/packages/server/dist/tools/graph.tool.js +5 -110
- package/packages/server/dist/tools/list.tool.js +5 -53
- package/packages/server/dist/tools/lookup.tool.js +8 -51
- package/packages/server/dist/tools/onboard.tool.js +2 -112
- package/packages/server/dist/tools/produce.tool.js +4 -74
- package/packages/server/dist/tools/read.tool.js +4 -47
- package/packages/server/dist/tools/reindex.tool.js +2 -70
- package/packages/server/dist/tools/remember.tool.js +3 -42
- package/packages/server/dist/tools/replay.tool.js +6 -88
- package/packages/server/dist/tools/search.tool.js +17 -327
- package/packages/server/dist/tools/status.tool.js +3 -68
- package/packages/server/dist/tools/toolkit.tools.js +20 -1673
- package/packages/server/dist/tools/update.tool.js +3 -39
- package/packages/server/dist/tools/utility.tools.js +19 -456
- package/packages/store/dist/graph-store.interface.js +0 -1
- package/packages/store/dist/index.js +1 -9
- package/packages/store/dist/lance-store.js +1 -258
- package/packages/store/dist/sqlite-graph-store.js +8 -309
- package/packages/store/dist/store-factory.js +1 -14
- package/packages/store/dist/store.interface.js +0 -1
- package/packages/tools/dist/batch.js +1 -45
- package/packages/tools/dist/changelog.js +2 -112
- package/packages/tools/dist/check.js +2 -59
- package/packages/tools/dist/checkpoint.js +2 -43
- package/packages/tools/dist/codemod.js +2 -69
- package/packages/tools/dist/compact.js +3 -60
- package/packages/tools/dist/data-transform.js +1 -124
- package/packages/tools/dist/dead-symbols.js +2 -71
- package/packages/tools/dist/delegate.js +3 -128
- package/packages/tools/dist/diff-parse.js +3 -153
- package/packages/tools/dist/digest.js +7 -242
- package/packages/tools/dist/encode.js +1 -46
- package/packages/tools/dist/env-info.js +1 -58
- package/packages/tools/dist/eval.js +3 -79
- package/packages/tools/dist/evidence-map.js +3 -203
- package/packages/tools/dist/file-summary.js +2 -106
- package/packages/tools/dist/file-walk.js +1 -75
- package/packages/tools/dist/find-examples.js +3 -48
- package/packages/tools/dist/find.js +1 -120
- package/packages/tools/dist/forge-classify.js +2 -319
- package/packages/tools/dist/forge-ground.js +1 -184
- package/packages/tools/dist/git-context.js +3 -46
- package/packages/tools/dist/graph-query.js +1 -194
- package/packages/tools/dist/health.js +1 -118
- package/packages/tools/dist/http-request.js +1 -58
- package/packages/tools/dist/index.js +1 -273
- package/packages/tools/dist/lane.js +7 -227
- package/packages/tools/dist/measure.js +2 -119
- package/packages/tools/dist/onboard.js +42 -1136
- package/packages/tools/dist/parse-output.js +2 -158
- package/packages/tools/dist/process-manager.js +1 -69
- package/packages/tools/dist/queue.js +2 -126
- package/packages/tools/dist/regex-test.js +1 -39
- package/packages/tools/dist/rename.js +2 -70
- package/packages/tools/dist/replay.js +6 -108
- package/packages/tools/dist/schema-validate.js +1 -141
- package/packages/tools/dist/scope-map.js +1 -72
- package/packages/tools/dist/snippet.js +1 -80
- package/packages/tools/dist/stash.js +2 -60
- package/packages/tools/dist/stratum-card.js +5 -238
- package/packages/tools/dist/symbol.js +3 -87
- package/packages/tools/dist/test-run.js +2 -55
- package/packages/tools/dist/text-utils.js +2 -31
- package/packages/tools/dist/time-utils.js +1 -135
- package/packages/tools/dist/trace.js +2 -114
- package/packages/tools/dist/truncation.js +10 -41
- package/packages/tools/dist/watch.js +1 -61
- package/packages/tools/dist/web-fetch.js +9 -244
- package/packages/tools/dist/web-search.js +1 -46
- package/packages/tools/dist/workset.js +2 -77
- package/packages/tui/dist/App.js +260 -52468
- package/packages/tui/dist/index.js +286 -54551
- package/packages/tui/dist/panels/CuratedPanel.js +211 -34291
- package/packages/tui/dist/panels/LogPanel.js +259 -51703
- package/packages/tui/dist/panels/SearchPanel.js +212 -34824
- package/packages/tui/dist/panels/StatusPanel.js +211 -34304
|
@@ -1,249 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { paragraphTruncate } from "./truncation.js";
|
|
3
|
-
const DEFAULT_MAX_LENGTH = 15e3;
|
|
4
|
-
const DEFAULT_TIMEOUT = 15e3;
|
|
5
|
-
const STRIP_ELEMENTS = [
|
|
6
|
-
"script",
|
|
7
|
-
"style",
|
|
8
|
-
"noscript",
|
|
9
|
-
"iframe",
|
|
10
|
-
"svg",
|
|
11
|
-
"nav",
|
|
12
|
-
"footer",
|
|
13
|
-
"header",
|
|
14
|
-
"aside",
|
|
15
|
-
"form",
|
|
16
|
-
"button",
|
|
17
|
-
"input",
|
|
18
|
-
"select",
|
|
19
|
-
"textarea",
|
|
20
|
-
'[role="navigation"]',
|
|
21
|
-
'[role="banner"]',
|
|
22
|
-
'[role="contentinfo"]',
|
|
23
|
-
'[aria-hidden="true"]',
|
|
24
|
-
".sidebar",
|
|
25
|
-
".nav",
|
|
26
|
-
".menu",
|
|
27
|
-
".footer",
|
|
28
|
-
".header",
|
|
29
|
-
".ad",
|
|
30
|
-
".advertisement",
|
|
31
|
-
".cookie-banner",
|
|
32
|
-
".popup",
|
|
33
|
-
".modal"
|
|
34
|
-
];
|
|
35
|
-
const MAIN_CONTENT_SELECTORS = [
|
|
36
|
-
"article",
|
|
37
|
-
'[role="main"]',
|
|
38
|
-
"main",
|
|
39
|
-
".post-content",
|
|
40
|
-
".article-content",
|
|
41
|
-
".entry-content",
|
|
42
|
-
".content",
|
|
43
|
-
"#content",
|
|
44
|
-
".prose",
|
|
45
|
-
".markdown-body",
|
|
46
|
-
".documentation",
|
|
47
|
-
".doc-content"
|
|
48
|
-
];
|
|
49
|
-
async function webFetch(options) {
|
|
50
|
-
const {
|
|
51
|
-
url,
|
|
52
|
-
mode = "markdown",
|
|
53
|
-
selector,
|
|
54
|
-
maxLength = DEFAULT_MAX_LENGTH,
|
|
55
|
-
includeMetadata = true,
|
|
56
|
-
includeLinks = false,
|
|
57
|
-
includeImages = false,
|
|
58
|
-
timeout = DEFAULT_TIMEOUT
|
|
59
|
-
} = options;
|
|
60
|
-
const parsed = new URL(url);
|
|
61
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
62
|
-
throw new Error(`Unsupported protocol: ${parsed.protocol} \u2014 only http/https allowed`);
|
|
63
|
-
}
|
|
64
|
-
const controller = new AbortController();
|
|
65
|
-
const timer = setTimeout(() => controller.abort(), timeout);
|
|
66
|
-
let response;
|
|
67
|
-
try {
|
|
68
|
-
response = await fetch(url, {
|
|
69
|
-
signal: controller.signal,
|
|
70
|
-
headers: {
|
|
71
|
-
"User-Agent": "kb-web-fetch/1.0 (LLM context tool)",
|
|
72
|
-
Accept: "text/html,application/xhtml+xml,text/plain"
|
|
73
|
-
},
|
|
74
|
-
redirect: "follow"
|
|
75
|
-
});
|
|
76
|
-
} finally {
|
|
77
|
-
clearTimeout(timer);
|
|
78
|
-
}
|
|
79
|
-
if (!response.ok) {
|
|
80
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
81
|
-
}
|
|
82
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
83
|
-
const isHtml = /text\/html|application\/xhtml\+xml/i.test(contentType);
|
|
84
|
-
const responseText = await response.text();
|
|
85
|
-
const finalUrl = response.url;
|
|
86
|
-
if (!isHtml) {
|
|
87
|
-
let content2 = responseText;
|
|
88
|
-
const title2 = finalUrl.split("/").pop() ?? "";
|
|
89
|
-
if (includeMetadata) {
|
|
90
|
-
const meta = buildMetadataHeader(title2, "", finalUrl);
|
|
91
|
-
content2 = meta + content2;
|
|
92
|
-
}
|
|
93
|
-
const originalLength2 = content2.length;
|
|
94
|
-
const truncated2 = originalLength2 > maxLength;
|
|
95
|
-
if (truncated2) {
|
|
96
|
-
content2 = smartTruncate(content2, maxLength);
|
|
97
|
-
}
|
|
98
|
-
return { content: content2, title: title2, description: "", url: finalUrl, originalLength: originalLength2, truncated: truncated2 };
|
|
99
|
-
}
|
|
100
|
-
const { parseHTML } = await import("linkedom");
|
|
101
|
-
const { document } = parseHTML(responseText);
|
|
102
|
-
const title = document.querySelector("title")?.textContent?.trim() ?? document.querySelector('meta[property="og:title"]')?.getAttribute("content")?.trim() ?? "";
|
|
103
|
-
const description = document.querySelector('meta[name="description"]')?.getAttribute("content")?.trim() ?? document.querySelector('meta[property="og:description"]')?.getAttribute("content")?.trim() ?? "";
|
|
104
|
-
for (const sel of STRIP_ELEMENTS) {
|
|
105
|
-
for (const el of document.querySelectorAll(sel)) {
|
|
106
|
-
el.remove();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (!includeImages) {
|
|
110
|
-
for (const img of document.querySelectorAll("img")) {
|
|
111
|
-
img.remove();
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
let contentEl = null;
|
|
115
|
-
if (selector) {
|
|
116
|
-
contentEl = document.querySelector(selector);
|
|
117
|
-
if (!contentEl) {
|
|
118
|
-
throw new Error(`Selector "${selector}" matched no elements on the page`);
|
|
119
|
-
}
|
|
120
|
-
} else {
|
|
121
|
-
for (const s of MAIN_CONTENT_SELECTORS) {
|
|
122
|
-
contentEl = document.querySelector(s);
|
|
123
|
-
if (contentEl) break;
|
|
124
|
-
}
|
|
125
|
-
if (!contentEl) {
|
|
126
|
-
contentEl = document.querySelector("body");
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
if (!contentEl) {
|
|
130
|
-
return {
|
|
131
|
-
content: "(empty page \u2014 no content found)",
|
|
132
|
-
title,
|
|
133
|
-
description,
|
|
134
|
-
url: finalUrl,
|
|
135
|
-
originalLength: 0,
|
|
136
|
-
truncated: false
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
const contentHtml = contentEl.innerHTML;
|
|
140
|
-
const links = [];
|
|
141
|
-
if (includeLinks || mode === "links") {
|
|
142
|
-
for (const a of contentEl.querySelectorAll("a[href]")) {
|
|
143
|
-
const text = a.textContent?.trim();
|
|
144
|
-
const href = a.getAttribute("href");
|
|
145
|
-
if (text && href && !href.startsWith("#") && !href.startsWith("javascript:")) {
|
|
146
|
-
links.push({ text, href: resolveUrl(href, finalUrl) });
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
let content;
|
|
151
|
-
switch (mode) {
|
|
152
|
-
case "raw":
|
|
153
|
-
content = contentHtml;
|
|
154
|
-
break;
|
|
155
|
-
case "links":
|
|
156
|
-
content = formatLinks(links);
|
|
157
|
-
break;
|
|
158
|
-
case "outline":
|
|
159
|
-
content = extractOutline(contentEl);
|
|
160
|
-
break;
|
|
161
|
-
default:
|
|
162
|
-
content = htmlToMarkdown(contentHtml, includeImages);
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
if (includeMetadata && mode !== "links") {
|
|
166
|
-
const meta = buildMetadataHeader(title, description, finalUrl);
|
|
167
|
-
content = meta + content;
|
|
168
|
-
}
|
|
169
|
-
if (includeLinks && mode !== "links" && links.length > 0) {
|
|
170
|
-
content += `
|
|
1
|
+
import N from"turndown";import{paragraphTruncate as W}from"./truncation.js";const _=15e3,C=15e3,H=["script","style","noscript","iframe","svg","nav","footer","header","aside","form","button","input","select","textarea",'[role="navigation"]','[role="banner"]','[role="contentinfo"]','[aria-hidden="true"]',".sidebar",".nav",".menu",".footer",".header",".ad",".advertisement",".cookie-banner",".popup",".modal"],I=["article",'[role="main"]',"main",".post-content",".article-content",".entry-content",".content","#content",".prose",".markdown-body",".documentation",".doc-content"];async function X(r){const{url:o,mode:e="markdown",selector:t,maxLength:c=_,includeMetadata:d=!0,includeLinks:p=!1,includeImages:y=!1,timeout:v=C}=r,g=new URL(o);if(g.protocol!=="http:"&&g.protocol!=="https:")throw new Error(`Unsupported protocol: ${g.protocol} \u2014 only http/https allowed`);const k=new AbortController,$=setTimeout(()=>k.abort(),v);let l;try{l=await fetch(o,{signal:k.signal,headers:{"User-Agent":"kb-web-fetch/1.0 (LLM context tool)",Accept:"text/html,application/xhtml+xml,text/plain"},redirect:"follow"})}finally{clearTimeout($)}if(!l.ok)throw new Error(`HTTP ${l.status}: ${l.statusText}`);const R=l.headers.get("content-type")??"",U=/text\/html|application\/xhtml\+xml/i.test(R),L=await l.text(),u=l.url;if(!U){let n=L;const m=u.split("/").pop()??"";d&&(n=M(m,"",u)+n);const f=n.length,E=f>c;return E&&(n=q(n,c)),{content:n,title:m,description:"",url:u,originalLength:f,truncated:E}}const{parseHTML:F}=await import("linkedom"),{document:a}=F(L),b=a.querySelector("title")?.textContent?.trim()??a.querySelector('meta[property="og:title"]')?.getAttribute("content")?.trim()??"",x=a.querySelector('meta[name="description"]')?.getAttribute("content")?.trim()??a.querySelector('meta[property="og:description"]')?.getAttribute("content")?.trim()??"";for(const n of H)for(const m of a.querySelectorAll(n))m.remove();if(!y)for(const n of a.querySelectorAll("img"))n.remove();let s=null;if(t){if(s=a.querySelector(t),!s)throw new Error(`Selector "${t}" matched no elements on the page`)}else{for(const n of I)if(s=a.querySelector(n),s)break;s||(s=a.querySelector("body"))}if(!s)return{content:"(empty page \u2014 no content found)",title:b,description:x,url:u,originalLength:0,truncated:!1};const w=s.innerHTML,h=[];if(p||e==="links")for(const n of s.querySelectorAll("a[href]")){const m=n.textContent?.trim(),f=n.getAttribute("href");m&&f&&!f.startsWith("#")&&!f.startsWith("javascript:")&&h.push({text:m,href:P(f,u)})}let i;switch(e){case"raw":i=w;break;case"links":i=A(h);break;case"outline":i=j(s);break;default:i=O(w,y);break}d&&e!=="links"&&(i=M(b,x,u)+i),p&&e!=="links"&&h.length>0&&(i+=`
|
|
171
2
|
|
|
172
3
|
---
|
|
173
4
|
|
|
174
5
|
## Links
|
|
175
6
|
|
|
176
|
-
${
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
function htmlToMarkdown(html, includeImages) {
|
|
186
|
-
const td = new TurndownService({
|
|
187
|
-
headingStyle: "atx",
|
|
188
|
-
codeBlockStyle: "fenced",
|
|
189
|
-
bulletListMarker: "-"
|
|
190
|
-
});
|
|
191
|
-
td.addRule("emptyLinks", {
|
|
192
|
-
filter: (node) => node.nodeName === "A" && !node.textContent?.trim(),
|
|
193
|
-
replacement: () => ""
|
|
194
|
-
});
|
|
195
|
-
if (!includeImages) {
|
|
196
|
-
td.addRule("removeImages", {
|
|
197
|
-
filter: "img",
|
|
198
|
-
replacement: () => ""
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
let md = td.turndown(html);
|
|
202
|
-
md = md.replace(/\n{3,}/g, "\n\n").trim();
|
|
203
|
-
return md;
|
|
204
|
-
}
|
|
205
|
-
function extractOutline(element) {
|
|
206
|
-
const headings = element.querySelectorAll("h1, h2, h3, h4, h5, h6");
|
|
207
|
-
const lines = [];
|
|
208
|
-
for (const h of headings) {
|
|
209
|
-
const level = Number.parseInt(h.tagName.slice(1), 10);
|
|
210
|
-
const indent = " ".repeat(level - 1);
|
|
211
|
-
const text = h.textContent?.trim() ?? "";
|
|
212
|
-
if (text) {
|
|
213
|
-
lines.push(`${indent}- ${text}`);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return lines.length > 0 ? lines.join("\n") : "(no headings found)";
|
|
217
|
-
}
|
|
218
|
-
function formatLinks(links) {
|
|
219
|
-
if (links.length === 0) return "(no links found)";
|
|
220
|
-
const seen = /* @__PURE__ */ new Set();
|
|
221
|
-
const unique = [];
|
|
222
|
-
for (const link of links) {
|
|
223
|
-
if (!seen.has(link.href)) {
|
|
224
|
-
seen.add(link.href);
|
|
225
|
-
unique.push(link);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return unique.map((l) => `- [${l.text}](${l.href})`).join("\n");
|
|
229
|
-
}
|
|
230
|
-
function buildMetadataHeader(title, description, url) {
|
|
231
|
-
const parts = ["---"];
|
|
232
|
-
if (title) parts.push(`**${title}**`);
|
|
233
|
-
parts.push(`URL: ${url}`);
|
|
234
|
-
if (description) parts.push(`> ${description}`);
|
|
235
|
-
parts.push("---\n\n");
|
|
236
|
-
return parts.join("\n");
|
|
237
|
-
}
|
|
238
|
-
function resolveUrl(href, base) {
|
|
239
|
-
try {
|
|
240
|
-
return new URL(href, base).href;
|
|
241
|
-
} catch {
|
|
242
|
-
return href;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
const smartTruncate = paragraphTruncate;
|
|
246
|
-
export {
|
|
247
|
-
webFetch
|
|
248
|
-
};
|
|
249
|
-
//# sourceMappingURL=web-fetch.js.map
|
|
7
|
+
${A(h)}`);const T=i.length,S=T>c;return S&&(i=q(i,c)),{content:i,title:b,description:x,url:u,originalLength:T,truncated:S}}function O(r,o){const e=new N({headingStyle:"atx",codeBlockStyle:"fenced",bulletListMarker:"-"});e.addRule("emptyLinks",{filter:c=>c.nodeName==="A"&&!c.textContent?.trim(),replacement:()=>""}),o||e.addRule("removeImages",{filter:"img",replacement:()=>""});let t=e.turndown(r);return t=t.replace(/\n{3,}/g,`
|
|
8
|
+
|
|
9
|
+
`).trim(),t}function j(r){const o=r.querySelectorAll("h1, h2, h3, h4, h5, h6"),e=[];for(const t of o){const c=Number.parseInt(t.tagName.slice(1),10),d=" ".repeat(c-1),p=t.textContent?.trim()??"";p&&e.push(`${d}- ${p}`)}return e.length>0?e.join(`
|
|
10
|
+
`):"(no headings found)"}function A(r){if(r.length===0)return"(no links found)";const o=new Set,e=[];for(const t of r)o.has(t.href)||(o.add(t.href),e.push(t));return e.map(t=>`- [${t.text}](${t.href})`).join(`
|
|
11
|
+
`)}function M(r,o,e){const t=["---"];return r&&t.push(`**${r}**`),t.push(`URL: ${e}`),o&&t.push(`> ${o}`),t.push(`---
|
|
12
|
+
|
|
13
|
+
`),t.join(`
|
|
14
|
+
`)}function P(r,o){try{return new URL(r,o).href}catch{return r}}const q=W;export{X as webFetch};
|
|
@@ -1,46 +1 @@
|
|
|
1
|
-
const
|
|
2
|
-
async function webSearch(options) {
|
|
3
|
-
const { query, limit = DEFAULT_LIMIT, site } = options;
|
|
4
|
-
if (!query.trim()) throw new Error("Search query cannot be empty");
|
|
5
|
-
const searchQuery = site ? `${query} site:${site}` : query;
|
|
6
|
-
const response = await fetch("https://html.duckduckgo.com/html/", {
|
|
7
|
-
method: "POST",
|
|
8
|
-
headers: {
|
|
9
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
10
|
-
"User-Agent": "kb-web-search/1.0 (LLM developer tool)"
|
|
11
|
-
},
|
|
12
|
-
body: `q=${encodeURIComponent(searchQuery)}`
|
|
13
|
-
});
|
|
14
|
-
if (!response.ok) {
|
|
15
|
-
throw new Error(`Search failed: HTTP ${response.status}`);
|
|
16
|
-
}
|
|
17
|
-
const html = await response.text();
|
|
18
|
-
return parseSearchResults(html, searchQuery, limit);
|
|
19
|
-
}
|
|
20
|
-
function parseSearchResults(html, query, limit) {
|
|
21
|
-
const results = [];
|
|
22
|
-
const blockRegex = /<a[^>]+class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/gi;
|
|
23
|
-
let match = blockRegex.exec(html);
|
|
24
|
-
while (match !== null && results.length < limit) {
|
|
25
|
-
let url = match[1];
|
|
26
|
-
const title = stripHtml(match[2]).trim();
|
|
27
|
-
const snippet = stripHtml(match[3]).trim();
|
|
28
|
-
if (url.includes("uddg=")) {
|
|
29
|
-
const decoded = url.match(/uddg=([^&]+)/)?.[1];
|
|
30
|
-
if (decoded) url = decodeURIComponent(decoded);
|
|
31
|
-
}
|
|
32
|
-
if (title && url?.startsWith("http")) {
|
|
33
|
-
results.push({ title, url, snippet });
|
|
34
|
-
}
|
|
35
|
-
match = blockRegex.exec(html);
|
|
36
|
-
}
|
|
37
|
-
return { results, query };
|
|
38
|
-
}
|
|
39
|
-
function stripHtml(html) {
|
|
40
|
-
return html.replace(/<[^>]+>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'");
|
|
41
|
-
}
|
|
42
|
-
export {
|
|
43
|
-
parseSearchResults,
|
|
44
|
-
webSearch
|
|
45
|
-
};
|
|
46
|
-
//# sourceMappingURL=web-search.js.map
|
|
1
|
+
const h=5;async function g(r){const{query:n,limit:i=5,site:s}=r;if(!n.trim())throw new Error("Search query cannot be empty");const c=s?`${n} site:${s}`:n,e=await fetch("https://html.duckduckgo.com/html/",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded","User-Agent":"kb-web-search/1.0 (LLM developer tool)"},body:`q=${encodeURIComponent(c)}`});if(!e.ok)throw new Error(`Search failed: HTTP ${e.status}`);const t=await e.text();return p(t,c,i)}function p(r,n,i){const s=[],c=/<a[^>]+class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/gi;let e=c.exec(r);for(;e!==null&&s.length<i;){let t=e[1];const o=l(e[2]).trim(),u=l(e[3]).trim();if(t.includes("uddg=")){const a=t.match(/uddg=([^&]+)/)?.[1];a&&(t=decodeURIComponent(a))}o&&t?.startsWith("http")&&s.push({title:o,url:t,snippet:u}),e=c.exec(r)}return{results:s,query:n}}function l(r){return r.replace(/<[^>]+>/g,"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'")}export{p as parseSearchResults,g as webSearch};
|
|
@@ -1,77 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
const STATE_DIR = ".kb-state";
|
|
4
|
-
const WORKSETS_FILE = "worksets.json";
|
|
5
|
-
function getStorePath(cwd) {
|
|
6
|
-
const root = cwd ?? process.cwd();
|
|
7
|
-
return resolve(root, STATE_DIR, WORKSETS_FILE);
|
|
8
|
-
}
|
|
9
|
-
function loadStore(cwd) {
|
|
10
|
-
const path = getStorePath(cwd);
|
|
11
|
-
if (!existsSync(path)) return { worksets: {} };
|
|
12
|
-
const raw = readFileSync(path, "utf-8");
|
|
13
|
-
return JSON.parse(raw);
|
|
14
|
-
}
|
|
15
|
-
function saveStore(store, cwd) {
|
|
16
|
-
const path = getStorePath(cwd);
|
|
17
|
-
const dir = dirname(path);
|
|
18
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
19
|
-
writeFileSync(path, `${JSON.stringify(store, null, 2)}
|
|
20
|
-
`, "utf-8");
|
|
21
|
-
}
|
|
22
|
-
function saveWorkset(name, files, options) {
|
|
23
|
-
const store = loadStore(options?.cwd);
|
|
24
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25
|
-
const existing = store.worksets[name];
|
|
26
|
-
const workset = {
|
|
27
|
-
name,
|
|
28
|
-
files,
|
|
29
|
-
created: existing?.created ?? now,
|
|
30
|
-
updated: now,
|
|
31
|
-
description: options?.description ?? existing?.description
|
|
32
|
-
};
|
|
33
|
-
store.worksets[name] = workset;
|
|
34
|
-
saveStore(store, options?.cwd);
|
|
35
|
-
return workset;
|
|
36
|
-
}
|
|
37
|
-
function getWorkset(name, cwd) {
|
|
38
|
-
const store = loadStore(cwd);
|
|
39
|
-
return store.worksets[name] ?? null;
|
|
40
|
-
}
|
|
41
|
-
function listWorksets(cwd) {
|
|
42
|
-
const store = loadStore(cwd);
|
|
43
|
-
return Object.values(store.worksets).sort(
|
|
44
|
-
(a, b) => new Date(b.updated).getTime() - new Date(a.updated).getTime()
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
function deleteWorkset(name, cwd) {
|
|
48
|
-
const store = loadStore(cwd);
|
|
49
|
-
if (!store.worksets[name]) return false;
|
|
50
|
-
delete store.worksets[name];
|
|
51
|
-
saveStore(store, cwd);
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
function addToWorkset(name, files, cwd) {
|
|
55
|
-
const store = loadStore(cwd);
|
|
56
|
-
const existing = store.worksets[name];
|
|
57
|
-
const currentFiles = existing?.files ?? [];
|
|
58
|
-
const merged = [.../* @__PURE__ */ new Set([...currentFiles, ...files])];
|
|
59
|
-
return saveWorkset(name, merged, { cwd });
|
|
60
|
-
}
|
|
61
|
-
function removeFromWorkset(name, files, cwd) {
|
|
62
|
-
const store = loadStore(cwd);
|
|
63
|
-
const existing = store.worksets[name];
|
|
64
|
-
if (!existing) return null;
|
|
65
|
-
const toRemove = new Set(files);
|
|
66
|
-
const filtered = existing.files.filter((f) => !toRemove.has(f));
|
|
67
|
-
return saveWorkset(name, filtered, { cwd });
|
|
68
|
-
}
|
|
69
|
-
export {
|
|
70
|
-
addToWorkset,
|
|
71
|
-
deleteWorkset,
|
|
72
|
-
getWorkset,
|
|
73
|
-
listWorksets,
|
|
74
|
-
removeFromWorkset,
|
|
75
|
-
saveWorkset
|
|
76
|
-
};
|
|
77
|
-
//# sourceMappingURL=workset.js.map
|
|
1
|
+
import{existsSync as g,mkdirSync as l,readFileSync as a,writeFileSync as p}from"node:fs";import{dirname as w,resolve as S}from"node:path";const W=".kb-state",x="worksets.json";function u(t){const r=t??process.cwd();return S(r,W,x)}function c(t){const r=u(t);if(!g(r))return{worksets:{}};const e=a(r,"utf-8");return JSON.parse(e)}function k(t,r){const e=u(r),s=w(e);g(s)||l(s,{recursive:!0}),p(e,`${JSON.stringify(t,null,2)}
|
|
2
|
+
`,"utf-8")}function d(t,r,e){const s=c(e?.cwd),o=new Date().toISOString(),n=s.worksets[t],i={name:t,files:r,created:n?.created??o,updated:o,description:e?.description??n?.description};return s.worksets[t]=i,k(s,e?.cwd),i}function T(t,r){return c(r).worksets[t]??null}function y(t){const r=c(t);return Object.values(r.worksets).sort((e,s)=>new Date(s.updated).getTime()-new Date(e.updated).getTime())}function F(t,r){const e=c(r);return e.worksets[t]?(delete e.worksets[t],k(e,r),!0):!1}function O(t,r,e){const n=c(e).worksets[t]?.files??[],i=[...new Set([...n,...r])];return d(t,i,{cwd:e})}function h(t,r,e){const o=c(e).worksets[t];if(!o)return null;const n=new Set(r),i=o.files.filter(f=>!n.has(f));return d(t,i,{cwd:e})}export{O as addToWorkset,F as deleteWorkset,T as getWorkset,y as listWorksets,h as removeFromWorkset,d as saveWorkset};
|