llm-kb 0.2.0 → 0.4.1
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 +322 -60
- package/bin/anthropic-5TIU2EED.js +5515 -0
- package/bin/azure-openai-responses-ZVUVMK3G.js +190 -0
- package/bin/chunk-2WV6TQRI.js +4792 -0
- package/bin/chunk-3YMNGUZZ.js +262 -0
- package/bin/chunk-5PYKQQLA.js +14295 -0
- package/bin/chunk-65KFH7OI.js +31 -0
- package/bin/chunk-DHOXVEIR.js +7261 -0
- package/bin/chunk-EAQYK3U2.js +41 -0
- package/bin/chunk-IFS3OKBN.js +428 -0
- package/bin/chunk-LDHOKBJA.js +86 -0
- package/bin/chunk-SLYBG6ZQ.js +32681 -0
- package/bin/chunk-UEODFF7H.js +17 -0
- package/bin/chunk-XCXTZJGO.js +174 -0
- package/bin/chunk-XFV534WU.js +7056 -0
- package/bin/cli.js +5496 -163
- package/bin/dist-3YH7P2QF.js +1244 -0
- package/bin/google-JFC43EFJ.js +371 -0
- package/bin/google-gemini-cli-K4XNMYDI.js +712 -0
- package/bin/google-vertex-Y42F254G.js +414 -0
- package/bin/indexer-KSYRIVVN.js +10 -0
- package/bin/mistral-ZU2JS5XZ.js +38406 -0
- package/bin/multipart-parser-CO464TZY.js +371 -0
- package/bin/openai-codex-responses-NW2LELBH.js +712 -0
- package/bin/openai-completions-TW3VKTHO.js +662 -0
- package/bin/openai-responses-VGL522MK.js +198 -0
- package/bin/src-Y22OHE3S.js +1408 -0
- package/package.json +16 -6
- package/PHASE2_SPEC.md +0 -274
- package/SPEC.md +0 -275
- package/bin/chunk-MYQ36JJB.js +0 -118
- package/bin/indexer-LSYSZXZX.js +0 -6
- package/plan.md +0 -55
- package/src/cli.ts +0 -132
- package/src/indexer.ts +0 -148
- package/src/pdf.ts +0 -119
- package/src/query.ts +0 -132
- package/src/resolve-kb.ts +0 -19
- package/src/scan.ts +0 -59
- package/src/watcher.ts +0 -84
- package/tsconfig.json +0 -14
package/src/query.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createAgentSession,
|
|
3
|
-
createBashTool,
|
|
4
|
-
createReadTool,
|
|
5
|
-
createWriteTool,
|
|
6
|
-
DefaultResourceLoader,
|
|
7
|
-
SessionManager,
|
|
8
|
-
SettingsManager,
|
|
9
|
-
} from "@mariozechner/pi-coding-agent";
|
|
10
|
-
import { readdir, mkdir } from "node:fs/promises";
|
|
11
|
-
import { join, dirname } from "node:path";
|
|
12
|
-
import { fileURLToPath } from "node:url";
|
|
13
|
-
|
|
14
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
-
|
|
16
|
-
function getNodeModulesPath(): string {
|
|
17
|
-
let dir = __dirname;
|
|
18
|
-
for (let i = 0; i < 5; i++) {
|
|
19
|
-
const candidate = join(dir, "node_modules");
|
|
20
|
-
try { return candidate; } catch { dir = dirname(dir); }
|
|
21
|
-
}
|
|
22
|
-
return join(process.cwd(), "node_modules");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function buildQueryAgents(sourceFiles: string[], save: boolean): string {
|
|
26
|
-
const sourceList = sourceFiles.map((f) => ` - ${f}`).join("\n");
|
|
27
|
-
|
|
28
|
-
let content = `# llm-kb Knowledge Base — Query Mode
|
|
29
|
-
|
|
30
|
-
## How to answer questions
|
|
31
|
-
|
|
32
|
-
1. FIRST read .llm-kb/wiki/index.md to understand all available sources
|
|
33
|
-
2. Based on the question, select the most relevant source files (usually 2-5)
|
|
34
|
-
3. Read those source files in full from .llm-kb/wiki/sources/
|
|
35
|
-
4. Answer with inline citations: (filename, page number)
|
|
36
|
-
5. If the answer requires cross-referencing multiple files, read additional ones
|
|
37
|
-
6. If you can't find the answer, say so — don't hallucinate
|
|
38
|
-
|
|
39
|
-
## Available parsed sources
|
|
40
|
-
${sourceList}
|
|
41
|
-
|
|
42
|
-
## Non-PDF files
|
|
43
|
-
If the user's folder has Excel, Word, or PowerPoint files, these libraries are available:
|
|
44
|
-
- **exceljs** — for .xlsx/.xls files
|
|
45
|
-
- **mammoth** — for .docx files
|
|
46
|
-
- **officeparser** — for .pptx files
|
|
47
|
-
Write a quick Node.js script via bash to read them.
|
|
48
|
-
|
|
49
|
-
## Rules
|
|
50
|
-
- Always cite sources with filename and page number
|
|
51
|
-
- Read the FULL source file, not just the beginning
|
|
52
|
-
- Prefer primary sources over previous analyses
|
|
53
|
-
`;
|
|
54
|
-
|
|
55
|
-
if (save) {
|
|
56
|
-
content += `
|
|
57
|
-
## Research Mode
|
|
58
|
-
Save your analysis to .llm-kb/wiki/outputs/ with a descriptive filename (e.g., comparison-analysis.md).
|
|
59
|
-
Include the question at the top and all citations.
|
|
60
|
-
`;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return content;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export async function query(
|
|
67
|
-
folder: string,
|
|
68
|
-
question: string,
|
|
69
|
-
options: { save?: boolean }
|
|
70
|
-
): Promise<void> {
|
|
71
|
-
const sourcesDir = join(folder, ".llm-kb", "wiki", "sources");
|
|
72
|
-
|
|
73
|
-
const files = await readdir(sourcesDir);
|
|
74
|
-
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
75
|
-
|
|
76
|
-
if (mdFiles.length === 0) {
|
|
77
|
-
throw new Error("No sources found. Run 'llm-kb run' first to parse documents.");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (options.save) {
|
|
81
|
-
await mkdir(join(folder, ".llm-kb", "wiki", "outputs"), { recursive: true });
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
process.env.NODE_PATH = getNodeModulesPath();
|
|
85
|
-
|
|
86
|
-
const agentsContent = buildQueryAgents(mdFiles, !!options.save);
|
|
87
|
-
|
|
88
|
-
const loader = new DefaultResourceLoader({
|
|
89
|
-
cwd: folder,
|
|
90
|
-
agentsFilesOverride: (current) => ({
|
|
91
|
-
agentsFiles: [
|
|
92
|
-
...current.agentsFiles,
|
|
93
|
-
{ path: ".llm-kb/AGENTS.md", content: agentsContent },
|
|
94
|
-
],
|
|
95
|
-
}),
|
|
96
|
-
});
|
|
97
|
-
await loader.reload();
|
|
98
|
-
|
|
99
|
-
const tools = [createReadTool(folder)];
|
|
100
|
-
if (options.save) {
|
|
101
|
-
tools.push(createBashTool(folder), createWriteTool(folder));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const { session } = await createAgentSession({
|
|
105
|
-
cwd: folder,
|
|
106
|
-
resourceLoader: loader,
|
|
107
|
-
tools,
|
|
108
|
-
sessionManager: SessionManager.inMemory(),
|
|
109
|
-
settingsManager: SettingsManager.inMemory({
|
|
110
|
-
compaction: { enabled: false },
|
|
111
|
-
}),
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
session.subscribe((event) => {
|
|
115
|
-
if (
|
|
116
|
-
event.type === "message_update" &&
|
|
117
|
-
event.assistantMessageEvent.type === "text_delta"
|
|
118
|
-
) {
|
|
119
|
-
process.stdout.write(event.assistantMessageEvent.delta);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
await session.prompt(question);
|
|
124
|
-
console.log();
|
|
125
|
-
session.dispose();
|
|
126
|
-
|
|
127
|
-
// Re-index after save so the compounding loop works
|
|
128
|
-
if (options.save) {
|
|
129
|
-
const { buildIndex } = await import("./indexer.js");
|
|
130
|
-
await buildIndex(folder, sourcesDir);
|
|
131
|
-
}
|
|
132
|
-
}
|
package/src/resolve-kb.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { resolve, join, dirname } from "node:path";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Walk up from startDir looking for a .llm-kb/ directory.
|
|
6
|
-
* Returns the folder containing .llm-kb/, or null if not found.
|
|
7
|
-
*/
|
|
8
|
-
export function resolveKnowledgeBase(startDir: string): string | null {
|
|
9
|
-
let dir = resolve(startDir);
|
|
10
|
-
|
|
11
|
-
while (true) {
|
|
12
|
-
if (existsSync(join(dir, ".llm-kb"))) {
|
|
13
|
-
return dir;
|
|
14
|
-
}
|
|
15
|
-
const parent = dirname(dir);
|
|
16
|
-
if (parent === dir) return null;
|
|
17
|
-
dir = parent;
|
|
18
|
-
}
|
|
19
|
-
}
|
package/src/scan.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { readdir } from "node:fs/promises";
|
|
2
|
-
import { resolve, extname, relative } from "node:path";
|
|
3
|
-
|
|
4
|
-
export interface ScannedFile {
|
|
5
|
-
name: string;
|
|
6
|
-
path: string;
|
|
7
|
-
ext: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const SUPPORTED_EXTENSIONS = new Set([
|
|
11
|
-
".pdf",
|
|
12
|
-
".xlsx",
|
|
13
|
-
".xls",
|
|
14
|
-
".docx",
|
|
15
|
-
".pptx",
|
|
16
|
-
".jpg",
|
|
17
|
-
".jpeg",
|
|
18
|
-
".png",
|
|
19
|
-
".txt",
|
|
20
|
-
".md",
|
|
21
|
-
".csv",
|
|
22
|
-
]);
|
|
23
|
-
|
|
24
|
-
export async function scan(folder: string): Promise<ScannedFile[]> {
|
|
25
|
-
const root = resolve(folder);
|
|
26
|
-
const entries = await readdir(root, { recursive: true, withFileTypes: true });
|
|
27
|
-
|
|
28
|
-
const files: ScannedFile[] = [];
|
|
29
|
-
|
|
30
|
-
for (const entry of entries) {
|
|
31
|
-
if (!entry.isFile()) continue;
|
|
32
|
-
|
|
33
|
-
const fullPath = resolve(entry.parentPath, entry.name);
|
|
34
|
-
const rel = relative(root, fullPath);
|
|
35
|
-
|
|
36
|
-
// Skip .llm-kb internal folder
|
|
37
|
-
if (rel.startsWith(".llm-kb")) continue;
|
|
38
|
-
|
|
39
|
-
const ext = extname(entry.name).toLowerCase();
|
|
40
|
-
if (!SUPPORTED_EXTENSIONS.has(ext)) continue;
|
|
41
|
-
|
|
42
|
-
files.push({ name: entry.name, path: rel, ext });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return files;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function summarize(files: ScannedFile[]): string {
|
|
49
|
-
const counts = new Map<string, number>();
|
|
50
|
-
for (const f of files) {
|
|
51
|
-
counts.set(f.ext, (counts.get(f.ext) || 0) + 1);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const parts = Array.from(counts.entries())
|
|
55
|
-
.sort((a, b) => b[1] - a[1])
|
|
56
|
-
.map(([ext, count]) => `${count} ${ext.toUpperCase().slice(1)}`);
|
|
57
|
-
|
|
58
|
-
return parts.join(", ");
|
|
59
|
-
}
|
package/src/watcher.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { watch } from "chokidar";
|
|
2
|
-
import { extname, join, basename } from "node:path";
|
|
3
|
-
import { parsePDF } from "./pdf.js";
|
|
4
|
-
import { buildIndex } from "./indexer.js";
|
|
5
|
-
import chalk from "chalk";
|
|
6
|
-
|
|
7
|
-
interface WatcherOptions {
|
|
8
|
-
folder: string;
|
|
9
|
-
sourcesDir: string;
|
|
10
|
-
debounceMs?: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function startWatcher({ folder, sourcesDir, debounceMs = 2000 }: WatcherOptions) {
|
|
14
|
-
let pendingFiles: string[] = [];
|
|
15
|
-
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
16
|
-
|
|
17
|
-
async function processBatch() {
|
|
18
|
-
const files = [...pendingFiles];
|
|
19
|
-
pendingFiles = [];
|
|
20
|
-
|
|
21
|
-
if (files.length === 0) return;
|
|
22
|
-
|
|
23
|
-
console.log();
|
|
24
|
-
for (const filePath of files) {
|
|
25
|
-
const name = basename(filePath);
|
|
26
|
-
process.stdout.write(` Parsing ${name}...`);
|
|
27
|
-
try {
|
|
28
|
-
const result = await parsePDF(filePath, sourcesDir);
|
|
29
|
-
if (result.skipped) {
|
|
30
|
-
console.log(chalk.dim(` skipped (up to date)`));
|
|
31
|
-
} else {
|
|
32
|
-
console.log(chalk.green(` ✓ ${result.totalPages} pages`));
|
|
33
|
-
}
|
|
34
|
-
} catch (err: any) {
|
|
35
|
-
console.log(chalk.red(` ✗ ${err.message}`));
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Re-index
|
|
40
|
-
process.stdout.write(` Re-indexing...`);
|
|
41
|
-
try {
|
|
42
|
-
await buildIndex(folder, sourcesDir);
|
|
43
|
-
console.log(chalk.green(` ✓ index.md updated`));
|
|
44
|
-
} catch (err: any) {
|
|
45
|
-
console.log(chalk.red(` ✗ ${err.message}`));
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function queueFile(filePath: string) {
|
|
50
|
-
if (!pendingFiles.includes(filePath)) {
|
|
51
|
-
pendingFiles.push(filePath);
|
|
52
|
-
}
|
|
53
|
-
if (debounceTimer) clearTimeout(debounceTimer);
|
|
54
|
-
debounceTimer = setTimeout(processBatch, debounceMs);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const watcher = watch(folder, {
|
|
58
|
-
ignoreInitial: true,
|
|
59
|
-
ignored: [
|
|
60
|
-
"**/node_modules/**",
|
|
61
|
-
"**/.llm-kb/**",
|
|
62
|
-
"**/.git/**",
|
|
63
|
-
],
|
|
64
|
-
depth: 10,
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
watcher.on("add", (filePath) => {
|
|
68
|
-
const ext = extname(filePath).toLowerCase();
|
|
69
|
-
if (ext === ".pdf") {
|
|
70
|
-
console.log(chalk.dim(`\n New file: ${basename(filePath)}`));
|
|
71
|
-
queueFile(filePath);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
watcher.on("change", (filePath) => {
|
|
76
|
-
const ext = extname(filePath).toLowerCase();
|
|
77
|
-
if (ext === ".pdf") {
|
|
78
|
-
console.log(chalk.dim(`\n Changed: ${basename(filePath)}`));
|
|
79
|
-
queueFile(filePath);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
return watcher;
|
|
84
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ES2022",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"strict": true,
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"outDir": "dist",
|
|
9
|
-
"rootDir": "src",
|
|
10
|
-
"declaration": true,
|
|
11
|
-
"sourceMap": true
|
|
12
|
-
},
|
|
13
|
-
"include": ["src"]
|
|
14
|
-
}
|