@tai-io/codesearch 2026.313.1614

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.
Files changed (78) hide show
  1. package/dist/build-info.d.ts +3 -0
  2. package/dist/build-info.js +4 -0
  3. package/dist/config.d.ts +62 -0
  4. package/dist/config.js +52 -0
  5. package/dist/core/cleanup.d.ts +8 -0
  6. package/dist/core/cleanup.js +41 -0
  7. package/dist/core/doc-indexer.d.ts +13 -0
  8. package/dist/core/doc-indexer.js +76 -0
  9. package/dist/core/doc-searcher.d.ts +13 -0
  10. package/dist/core/doc-searcher.js +65 -0
  11. package/dist/core/file-category.d.ts +7 -0
  12. package/dist/core/file-category.js +75 -0
  13. package/dist/core/indexer.d.ts +18 -0
  14. package/dist/core/indexer.js +177 -0
  15. package/dist/core/preview.d.ts +13 -0
  16. package/dist/core/preview.js +58 -0
  17. package/dist/core/repo-map.d.ts +33 -0
  18. package/dist/core/repo-map.js +144 -0
  19. package/dist/core/searcher.d.ts +12 -0
  20. package/dist/core/searcher.js +97 -0
  21. package/dist/core/sync.d.ts +15 -0
  22. package/dist/core/sync.js +212 -0
  23. package/dist/core/targeted-indexer.d.ts +19 -0
  24. package/dist/core/targeted-indexer.js +127 -0
  25. package/dist/embedding/factory.d.ts +4 -0
  26. package/dist/embedding/factory.js +24 -0
  27. package/dist/embedding/openai.d.ts +33 -0
  28. package/dist/embedding/openai.js +234 -0
  29. package/dist/embedding/truncate.d.ts +6 -0
  30. package/dist/embedding/truncate.js +14 -0
  31. package/dist/embedding/types.d.ts +18 -0
  32. package/dist/embedding/types.js +2 -0
  33. package/dist/errors.d.ts +17 -0
  34. package/dist/errors.js +21 -0
  35. package/dist/format.d.ts +18 -0
  36. package/dist/format.js +151 -0
  37. package/dist/hooks/cli-router.d.ts +7 -0
  38. package/dist/hooks/cli-router.js +47 -0
  39. package/dist/hooks/hook-output.d.ts +56 -0
  40. package/dist/hooks/hook-output.js +21 -0
  41. package/dist/hooks/post-tool-use.d.ts +13 -0
  42. package/dist/hooks/post-tool-use.js +123 -0
  43. package/dist/hooks/stop-hook.d.ts +11 -0
  44. package/dist/hooks/stop-hook.js +137 -0
  45. package/dist/hooks/targeted-runner.d.ts +11 -0
  46. package/dist/hooks/targeted-runner.js +58 -0
  47. package/dist/index.d.ts +3 -0
  48. package/dist/index.js +138 -0
  49. package/dist/paths.d.ts +11 -0
  50. package/dist/paths.js +54 -0
  51. package/dist/setup-message.d.ts +4 -0
  52. package/dist/setup-message.js +48 -0
  53. package/dist/splitter/ast.d.ts +13 -0
  54. package/dist/splitter/ast.js +231 -0
  55. package/dist/splitter/line.d.ts +10 -0
  56. package/dist/splitter/line.js +103 -0
  57. package/dist/splitter/symbol-extract.d.ts +16 -0
  58. package/dist/splitter/symbol-extract.js +61 -0
  59. package/dist/splitter/types.d.ts +16 -0
  60. package/dist/splitter/types.js +2 -0
  61. package/dist/state/doc-metadata.d.ts +18 -0
  62. package/dist/state/doc-metadata.js +59 -0
  63. package/dist/state/registry.d.ts +7 -0
  64. package/dist/state/registry.js +46 -0
  65. package/dist/state/snapshot.d.ts +26 -0
  66. package/dist/state/snapshot.js +100 -0
  67. package/dist/tool-schemas.d.ts +215 -0
  68. package/dist/tool-schemas.js +269 -0
  69. package/dist/tools.d.ts +58 -0
  70. package/dist/tools.js +245 -0
  71. package/dist/vectordb/rrf.d.ts +32 -0
  72. package/dist/vectordb/rrf.js +88 -0
  73. package/dist/vectordb/sqlite.d.ts +34 -0
  74. package/dist/vectordb/sqlite.js +624 -0
  75. package/dist/vectordb/types.d.ts +63 -0
  76. package/dist/vectordb/types.js +2 -0
  77. package/messages.yaml +69 -0
  78. package/package.json +79 -0
package/dist/paths.js ADDED
@@ -0,0 +1,54 @@
1
+ import path from 'node:path';
2
+ import os from 'node:os';
3
+ import { getConfig } from './config.js';
4
+ export function normalizePath(inputPath) {
5
+ let resolved = inputPath;
6
+ if (resolved.startsWith('~')) {
7
+ resolved = path.join(os.homedir(), resolved.slice(1));
8
+ }
9
+ resolved = path.resolve(resolved);
10
+ resolved = resolved.replace(/\\/g, '/');
11
+ if (resolved.length > 1 && resolved.endsWith('/')) {
12
+ resolved = resolved.slice(0, -1);
13
+ }
14
+ return resolved;
15
+ }
16
+ export function getDataDir() {
17
+ return normalizePath(getConfig().eideticDataDir);
18
+ }
19
+ export function getSnapshotDir() {
20
+ return `${getDataDir()}/snapshots`;
21
+ }
22
+ export function getCacheDir() {
23
+ return `${getDataDir()}/cache`;
24
+ }
25
+ export function getRegistryPath() {
26
+ return `${getDataDir()}/registry.json`;
27
+ }
28
+ export function pathToCollectionName(absolutePath) {
29
+ const normalized = normalizePath(absolutePath);
30
+ const safe = normalized
31
+ .toLowerCase()
32
+ .replace(/[^a-z0-9]/g, '_')
33
+ .replace(/_+/g, '_')
34
+ .replace(/^_|_$/g, '');
35
+ return `eidetic_${safe}`;
36
+ }
37
+ export function getCodesearchDbPath() {
38
+ return `${getDataDir()}/codesearch.db`;
39
+ }
40
+ export function getSnapshotDbPath() {
41
+ return `${getDataDir()}/snapshots.db`;
42
+ }
43
+ export function getDocMetadataPath() {
44
+ return `${getDataDir()}/doc-metadata.json`;
45
+ }
46
+ export function docCollectionName(library) {
47
+ const safe = library
48
+ .toLowerCase()
49
+ .replace(/[^a-z0-9]/g, '_')
50
+ .replace(/_+/g, '_')
51
+ .replace(/^_|_$/g, '');
52
+ return `doc_${safe}`;
53
+ }
54
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1,4 @@
1
+ export type SetupContext = 'missing' | 'invalid' | 'unknown';
2
+ export declare function getSetupErrorMessage(errorDetail: string, context?: SetupContext): string;
3
+ export declare function getWelcomeMessage(): string;
4
+ //# sourceMappingURL=setup-message.d.ts.map
@@ -0,0 +1,48 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+ import { parse as parseYaml } from 'yaml';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+ const yamlPath = join(__dirname, '..', 'messages.yaml');
8
+ let _cached = null;
9
+ function loadMessages() {
10
+ if (_cached)
11
+ return _cached;
12
+ _cached = parseYaml(readFileSync(yamlPath, 'utf-8'));
13
+ return _cached;
14
+ }
15
+ function detectContext() {
16
+ const hasKey = !!process.env.OPENAI_API_KEY;
17
+ const isOllama = process.env.EMBEDDING_PROVIDER === 'ollama';
18
+ if (!hasKey && !isOllama)
19
+ return 'missing';
20
+ return 'invalid';
21
+ }
22
+ function getConfigInstructions() {
23
+ const msgs = loadMessages();
24
+ const isWindows = process.platform === 'win32';
25
+ const primary = isWindows
26
+ ? msgs.setup.config_instructions_windows
27
+ : msgs.setup.config_instructions_unix;
28
+ return primary + '\n' + msgs.setup.config_alternatives;
29
+ }
30
+ export function getSetupErrorMessage(errorDetail, context) {
31
+ const ctx = context ?? detectContext();
32
+ const msgs = loadMessages();
33
+ const block = msgs.setup[ctx];
34
+ const header = block.header.replace('{error}', errorDetail);
35
+ const diagnosis = block.diagnosis.trim() ? `**Diagnosis:** ${block.diagnosis.trim()}\n\n` : '';
36
+ return (`${header}\n\n` +
37
+ diagnosis +
38
+ '## How to fix\n\n' +
39
+ `1. ${block.step1}\n` +
40
+ '2. **Set or update your config:**\n\n' +
41
+ getConfigInstructions() +
42
+ `3. ${msgs.setup.footer}`);
43
+ }
44
+ export function getWelcomeMessage() {
45
+ const msgs = loadMessages();
46
+ return msgs.welcome.ascii_art.trimEnd() + '\n\n' + msgs.welcome.first_run.trimEnd();
47
+ }
48
+ //# sourceMappingURL=setup-message.js.map
@@ -0,0 +1,13 @@
1
+ import type { Splitter, CodeChunk } from './types.js';
2
+ export declare class AstSplitter implements Splitter {
3
+ private parser;
4
+ private currentLang;
5
+ private static langCache;
6
+ private static resolveLanguage;
7
+ split(code: string, language: string, filePath: string): CodeChunk[];
8
+ static isSupported(language: string): boolean;
9
+ private extractChunks;
10
+ private refineChunks;
11
+ private splitLargeChunk;
12
+ }
13
+ //# sourceMappingURL=ast.d.ts.map
@@ -0,0 +1,231 @@
1
+ import { createRequire } from 'node:module';
2
+ import { MAX_CHUNK_CHARS } from './types.js';
3
+ import { extractSymbolInfo, isContainerType } from './symbol-extract.js';
4
+ // tree-sitter and language parsers are native CommonJS modules
5
+ const require = createRequire(import.meta.url);
6
+ const Parser = require('tree-sitter');
7
+ // Lazy-load language parsers to avoid startup cost for unused languages
8
+ const languageParsers = {
9
+ javascript: () => require('tree-sitter-javascript'),
10
+ js: () => require('tree-sitter-javascript'),
11
+ typescript: () => require('tree-sitter-typescript').typescript,
12
+ ts: () => require('tree-sitter-typescript').typescript,
13
+ tsx: () => require('tree-sitter-typescript').tsx,
14
+ python: () => require('tree-sitter-python'),
15
+ py: () => require('tree-sitter-python'),
16
+ go: () => require('tree-sitter-go'),
17
+ java: () => require('tree-sitter-java'),
18
+ rust: () => require('tree-sitter-rust'),
19
+ rs: () => require('tree-sitter-rust'),
20
+ cpp: () => require('tree-sitter-cpp'),
21
+ 'c++': () => require('tree-sitter-cpp'),
22
+ c: () => require('tree-sitter-cpp'),
23
+ csharp: () => require('tree-sitter-c-sharp'),
24
+ cs: () => require('tree-sitter-c-sharp'),
25
+ };
26
+ // AST node types that represent logical code units per language
27
+ const SPLITTABLE_TYPES = {
28
+ javascript: ['function_declaration', 'arrow_function', 'class_declaration', 'method_definition'],
29
+ typescript: [
30
+ 'function_declaration',
31
+ 'arrow_function',
32
+ 'class_declaration',
33
+ 'method_definition',
34
+ 'interface_declaration',
35
+ 'type_alias_declaration',
36
+ ],
37
+ tsx: [
38
+ 'function_declaration',
39
+ 'arrow_function',
40
+ 'class_declaration',
41
+ 'method_definition',
42
+ 'interface_declaration',
43
+ 'type_alias_declaration',
44
+ ],
45
+ python: [
46
+ 'function_definition',
47
+ 'class_definition',
48
+ 'decorated_definition',
49
+ 'async_function_definition',
50
+ ],
51
+ java: [
52
+ 'method_declaration',
53
+ 'class_declaration',
54
+ 'interface_declaration',
55
+ 'constructor_declaration',
56
+ ],
57
+ cpp: ['function_definition', 'class_specifier', 'namespace_definition', 'declaration'],
58
+ go: [
59
+ 'function_declaration',
60
+ 'method_declaration',
61
+ 'type_declaration',
62
+ 'var_declaration',
63
+ 'const_declaration',
64
+ ],
65
+ rust: ['function_item', 'impl_item', 'struct_item', 'enum_item', 'trait_item', 'mod_item'],
66
+ csharp: [
67
+ 'method_declaration',
68
+ 'class_declaration',
69
+ 'interface_declaration',
70
+ 'struct_declaration',
71
+ 'enum_declaration',
72
+ ],
73
+ };
74
+ const LANG_CANONICAL = {
75
+ js: 'javascript',
76
+ ts: 'typescript',
77
+ py: 'python',
78
+ rs: 'rust',
79
+ 'c++': 'cpp',
80
+ c: 'cpp',
81
+ cs: 'csharp',
82
+ };
83
+ export class AstSplitter {
84
+ parser = new Parser();
85
+ currentLang = '';
86
+ // Shared across all AstSplitter instances — one cache per process
87
+ static langCache = new Map();
88
+ static resolveLanguage(lang) {
89
+ const canonical = LANG_CANONICAL[lang] ?? lang;
90
+ const cached = AstSplitter.langCache.get(canonical);
91
+ if (cached)
92
+ return cached;
93
+ const factory = languageParsers[canonical] ?? languageParsers[lang];
94
+ if (!factory)
95
+ return null;
96
+ try {
97
+ const mod = factory();
98
+ AstSplitter.langCache.set(canonical, mod);
99
+ return mod;
100
+ }
101
+ catch (err) {
102
+ console.warn(`Failed to load tree-sitter parser for "${lang}":`, err);
103
+ return null;
104
+ }
105
+ }
106
+ split(code, language, filePath) {
107
+ const lang = language.toLowerCase();
108
+ const canonical = LANG_CANONICAL[lang] ?? lang;
109
+ const langModule = AstSplitter.resolveLanguage(lang);
110
+ if (!langModule) {
111
+ return [];
112
+ }
113
+ try {
114
+ if (canonical !== this.currentLang) {
115
+ this.parser.setLanguage(langModule);
116
+ this.currentLang = canonical;
117
+ }
118
+ const tree = this.parser.parse(code);
119
+ if (!tree.rootNode)
120
+ return [];
121
+ const nodeTypes = SPLITTABLE_TYPES[canonical] ?? [];
122
+ const rawChunks = this.extractChunks(tree.rootNode, code, nodeTypes, language, filePath);
123
+ if (rawChunks.length === 0)
124
+ return [];
125
+ return this.refineChunks(rawChunks);
126
+ }
127
+ catch (err) {
128
+ console.warn(`AST parse failed for "${filePath}" (${language}):`, err);
129
+ return [];
130
+ }
131
+ }
132
+ static isSupported(language) {
133
+ return language.toLowerCase() in languageParsers;
134
+ }
135
+ extractChunks(node, code, splittableTypes, language, filePath) {
136
+ const chunks = [];
137
+ const traverse = (current, parentName) => {
138
+ if (splittableTypes.includes(current.type)) {
139
+ const text = code.slice(current.startIndex, current.endIndex);
140
+ if (text.trim().length > 0) {
141
+ const symbolInfo = extractSymbolInfo(current, code, parentName);
142
+ const chunk = {
143
+ content: text,
144
+ startLine: current.startPosition.row + 1,
145
+ endLine: current.endPosition.row + 1,
146
+ language,
147
+ filePath,
148
+ };
149
+ if (symbolInfo) {
150
+ chunk.symbolName = symbolInfo.name;
151
+ chunk.symbolKind = symbolInfo.kind;
152
+ chunk.symbolSignature = symbolInfo.signature;
153
+ if (parentName)
154
+ chunk.parentSymbol = parentName;
155
+ }
156
+ chunks.push(chunk);
157
+ // If this is a container, pass its name as parentName to children
158
+ if (isContainerType(current.type) && symbolInfo?.name) {
159
+ for (const child of current.children) {
160
+ traverse(child, symbolInfo.name);
161
+ }
162
+ return;
163
+ }
164
+ }
165
+ }
166
+ for (const child of current.children) {
167
+ traverse(child, parentName);
168
+ }
169
+ };
170
+ traverse(node);
171
+ return chunks;
172
+ }
173
+ refineChunks(chunks) {
174
+ const result = [];
175
+ for (const chunk of chunks) {
176
+ if (chunk.content.length <= MAX_CHUNK_CHARS) {
177
+ result.push(chunk);
178
+ }
179
+ else {
180
+ result.push(...this.splitLargeChunk(chunk));
181
+ }
182
+ }
183
+ return result;
184
+ }
185
+ splitLargeChunk(chunk) {
186
+ const lines = chunk.content.split('\n');
187
+ const subChunks = [];
188
+ let current = '';
189
+ let startLine = chunk.startLine;
190
+ let lineCount = 0;
191
+ for (let i = 0; i < lines.length; i++) {
192
+ const line = lines[i];
193
+ const addition = i < lines.length - 1 ? line + '\n' : line;
194
+ if (current.length + addition.length > MAX_CHUNK_CHARS && current.length > 0) {
195
+ subChunks.push({
196
+ content: current,
197
+ startLine,
198
+ endLine: startLine + lineCount - 1,
199
+ language: chunk.language,
200
+ filePath: chunk.filePath,
201
+ symbolName: chunk.symbolName,
202
+ symbolKind: chunk.symbolKind,
203
+ symbolSignature: chunk.symbolSignature,
204
+ parentSymbol: chunk.parentSymbol,
205
+ });
206
+ current = addition;
207
+ startLine = chunk.startLine + i;
208
+ lineCount = 1;
209
+ }
210
+ else {
211
+ current += addition;
212
+ lineCount++;
213
+ }
214
+ }
215
+ if (current.trim().length > 0) {
216
+ subChunks.push({
217
+ content: current,
218
+ startLine,
219
+ endLine: startLine + lineCount - 1,
220
+ language: chunk.language,
221
+ filePath: chunk.filePath,
222
+ symbolName: chunk.symbolName,
223
+ symbolKind: chunk.symbolKind,
224
+ symbolSignature: chunk.symbolSignature,
225
+ parentSymbol: chunk.parentSymbol,
226
+ });
227
+ }
228
+ return subChunks;
229
+ }
230
+ }
231
+ //# sourceMappingURL=ast.js.map
@@ -0,0 +1,10 @@
1
+ import type { Splitter, CodeChunk } from './types.js';
2
+ export declare class LineSplitter implements Splitter {
3
+ private chunkLines;
4
+ private overlapLines;
5
+ constructor(chunkLines?: number, overlapLines?: number);
6
+ split(code: string, language: string, filePath: string): CodeChunk[];
7
+ private refineChunks;
8
+ private splitLargeChunk;
9
+ }
10
+ //# sourceMappingURL=line.d.ts.map
@@ -0,0 +1,103 @@
1
+ import { MAX_CHUNK_CHARS } from './types.js';
2
+ const DEFAULT_CHUNK_LINES = 60;
3
+ const OVERLAP_LINES = 5;
4
+ export class LineSplitter {
5
+ chunkLines;
6
+ overlapLines;
7
+ constructor(chunkLines = DEFAULT_CHUNK_LINES, overlapLines = OVERLAP_LINES) {
8
+ this.chunkLines = chunkLines;
9
+ this.overlapLines = Math.min(overlapLines, chunkLines - 1);
10
+ }
11
+ split(code, language, filePath) {
12
+ const lines = code.split('\n');
13
+ if (lines.length === 0)
14
+ return [];
15
+ const raw = [];
16
+ let start = 0;
17
+ while (start < lines.length) {
18
+ const end = Math.min(start + this.chunkLines, lines.length);
19
+ const content = lines.slice(start, end).join('\n');
20
+ if (content.trim().length > 0) {
21
+ raw.push({
22
+ content,
23
+ startLine: start + 1,
24
+ endLine: end,
25
+ language,
26
+ filePath,
27
+ });
28
+ }
29
+ start = Math.max(start + 1, end - this.overlapLines);
30
+ }
31
+ return this.refineChunks(raw);
32
+ }
33
+ refineChunks(chunks) {
34
+ const result = [];
35
+ for (const chunk of chunks) {
36
+ if (chunk.content.length <= MAX_CHUNK_CHARS) {
37
+ result.push(chunk);
38
+ }
39
+ else {
40
+ result.push(...this.splitLargeChunk(chunk));
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+ splitLargeChunk(chunk) {
46
+ const lines = chunk.content.split('\n');
47
+ const subChunks = [];
48
+ let current = '';
49
+ let startLine = chunk.startLine;
50
+ let lineCount = 0;
51
+ const flush = () => {
52
+ if (current.trim().length > 0) {
53
+ subChunks.push({
54
+ content: current,
55
+ startLine,
56
+ endLine: startLine + lineCount - 1,
57
+ language: chunk.language,
58
+ filePath: chunk.filePath,
59
+ });
60
+ }
61
+ };
62
+ for (let i = 0; i < lines.length; i++) {
63
+ const line = lines[i];
64
+ const addition = i < lines.length - 1 ? line + '\n' : line;
65
+ if (current.length + addition.length > MAX_CHUNK_CHARS && current.length > 0) {
66
+ flush();
67
+ current = '';
68
+ startLine = chunk.startLine + i;
69
+ lineCount = 0;
70
+ }
71
+ if (addition.length > MAX_CHUNK_CHARS) {
72
+ if (current.length > 0) {
73
+ flush();
74
+ current = '';
75
+ startLine = chunk.startLine + i;
76
+ lineCount = 0;
77
+ }
78
+ const lineNum = chunk.startLine + i;
79
+ for (let offset = 0; offset < addition.length; offset += MAX_CHUNK_CHARS) {
80
+ const slice = addition.slice(offset, offset + MAX_CHUNK_CHARS);
81
+ if (slice.trim().length > 0) {
82
+ subChunks.push({
83
+ content: slice,
84
+ startLine: lineNum,
85
+ endLine: lineNum,
86
+ language: chunk.language,
87
+ filePath: chunk.filePath,
88
+ });
89
+ }
90
+ }
91
+ startLine = chunk.startLine + i + 1;
92
+ lineCount = 0;
93
+ }
94
+ else {
95
+ current += addition;
96
+ lineCount++;
97
+ }
98
+ }
99
+ flush();
100
+ return subChunks;
101
+ }
102
+ }
103
+ //# sourceMappingURL=line.js.map
@@ -0,0 +1,16 @@
1
+ export interface SymbolInfo {
2
+ name: string;
3
+ kind: string;
4
+ signature: string;
5
+ }
6
+ interface AstNode {
7
+ type: string;
8
+ startIndex: number;
9
+ endIndex: number;
10
+ children: AstNode[];
11
+ text?: string;
12
+ }
13
+ export declare function extractSymbolInfo(node: AstNode, code: string, parentName?: string): SymbolInfo | undefined;
14
+ export declare function isContainerType(nodeType: string): boolean;
15
+ export {};
16
+ //# sourceMappingURL=symbol-extract.d.ts.map
@@ -0,0 +1,61 @@
1
+ const CONTAINER_TYPES = new Set(['class_declaration', 'class_definition', 'interface_declaration']);
2
+ const KIND_MAP = {
3
+ function_declaration: 'function',
4
+ arrow_function: 'function',
5
+ async_function_definition: 'function',
6
+ function_definition: 'function',
7
+ class_declaration: 'class',
8
+ class_definition: 'class',
9
+ interface_declaration: 'interface',
10
+ method_definition: 'method',
11
+ method_declaration: 'method',
12
+ type_alias_declaration: 'type',
13
+ enum_declaration: 'enum',
14
+ // Java
15
+ constructor_declaration: 'constructor',
16
+ // Rust
17
+ function_item: 'function',
18
+ impl_item: 'impl',
19
+ struct_item: 'struct',
20
+ enum_item: 'enum',
21
+ trait_item: 'trait',
22
+ // C#
23
+ struct_declaration: 'struct',
24
+ };
25
+ function getIdentifier(node, code) {
26
+ const identChild = node.children.find((c) => c.type === 'identifier' || c.type === 'type_identifier' || c.type === 'name');
27
+ if (identChild)
28
+ return code.slice(identChild.startIndex, identChild.endIndex);
29
+ return undefined;
30
+ }
31
+ function extractSignature(node, code) {
32
+ const text = code.slice(node.startIndex, node.endIndex);
33
+ // Take first line up to opening brace or end of line
34
+ const firstLine = text.split('\n')[0];
35
+ const upToBrace = firstLine.split('{')[0].trimEnd();
36
+ const sig = upToBrace || firstLine;
37
+ return sig.length > 200 ? sig.slice(0, 200) + '…' : sig;
38
+ }
39
+ export function extractSymbolInfo(node, code, parentName) {
40
+ const nodeType = node.type;
41
+ // Handle export_statement: recurse into declaration child
42
+ if (nodeType === 'export_statement') {
43
+ const declChild = node.children.find((c) => c.type !== 'export' && c.type !== 'default' && c.type !== ';' && c.type !== 'identifier');
44
+ if (declChild)
45
+ return extractSymbolInfo(declChild, code, parentName);
46
+ return undefined;
47
+ }
48
+ const kind = KIND_MAP[nodeType];
49
+ if (!kind)
50
+ return undefined;
51
+ const name = getIdentifier(node, code);
52
+ if (!name)
53
+ return undefined;
54
+ const signature = extractSignature(node, code);
55
+ void parentName; // consumed by caller to set chunk.parentSymbol
56
+ return { name, kind, signature };
57
+ }
58
+ export function isContainerType(nodeType) {
59
+ return CONTAINER_TYPES.has(nodeType);
60
+ }
61
+ //# sourceMappingURL=symbol-extract.js.map
@@ -0,0 +1,16 @@
1
+ export declare const MAX_CHUNK_CHARS = 2500;
2
+ export interface CodeChunk {
3
+ content: string;
4
+ startLine: number;
5
+ endLine: number;
6
+ language: string;
7
+ filePath: string;
8
+ symbolName?: string;
9
+ symbolKind?: string;
10
+ symbolSignature?: string;
11
+ parentSymbol?: string;
12
+ }
13
+ export interface Splitter {
14
+ split(code: string, language: string, filePath: string): CodeChunk[];
15
+ }
16
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export const MAX_CHUNK_CHARS = 2500;
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,18 @@
1
+ export interface DocEntry {
2
+ library: string;
3
+ topic: string;
4
+ source: string;
5
+ collectionName: string;
6
+ indexedAt: string;
7
+ ttlDays: number;
8
+ totalChunks: number;
9
+ }
10
+ export type DocMetadata = Record<string, DocEntry>;
11
+ export declare function loadDocMetadata(): DocMetadata;
12
+ export declare function saveDocMetadata(metadata: DocMetadata): void;
13
+ export declare function upsertDocEntry(entry: DocEntry): void;
14
+ export declare function removeDocEntry(library: string, topic: string): boolean;
15
+ export declare function findDocEntries(library: string): DocEntry[];
16
+ export declare function isStale(entry: DocEntry): boolean;
17
+ export declare function listDocLibraries(): string[];
18
+ //# sourceMappingURL=doc-metadata.d.ts.map
@@ -0,0 +1,59 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { getDocMetadataPath } from '../paths.js';
4
+ function metadataKey(library, topic) {
5
+ return `${library.toLowerCase()}::${topic.toLowerCase()}`;
6
+ }
7
+ export function loadDocMetadata() {
8
+ const metadataPath = getDocMetadataPath();
9
+ try {
10
+ const data = fs.readFileSync(metadataPath, 'utf-8');
11
+ return JSON.parse(data);
12
+ }
13
+ catch {
14
+ return {};
15
+ }
16
+ }
17
+ export function saveDocMetadata(metadata) {
18
+ const metadataPath = getDocMetadataPath();
19
+ const dir = path.dirname(metadataPath);
20
+ fs.mkdirSync(dir, { recursive: true });
21
+ fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2) + '\n', 'utf-8');
22
+ }
23
+ export function upsertDocEntry(entry) {
24
+ const metadata = loadDocMetadata();
25
+ const key = metadataKey(entry.library, entry.topic);
26
+ metadata[key] = entry;
27
+ saveDocMetadata(metadata);
28
+ }
29
+ export function removeDocEntry(library, topic) {
30
+ const metadata = loadDocMetadata();
31
+ const key = metadataKey(library, topic);
32
+ if (!(key in metadata))
33
+ return false;
34
+ Reflect.deleteProperty(metadata, key);
35
+ saveDocMetadata(metadata);
36
+ return true;
37
+ }
38
+ export function findDocEntries(library) {
39
+ const metadata = loadDocMetadata();
40
+ const prefix = `${library.toLowerCase()}::`;
41
+ return Object.entries(metadata)
42
+ .filter(([key]) => key.startsWith(prefix))
43
+ .map(([, entry]) => entry);
44
+ }
45
+ export function isStale(entry) {
46
+ const indexedAt = new Date(entry.indexedAt).getTime();
47
+ const now = Date.now();
48
+ const ttlMs = entry.ttlDays * 24 * 60 * 60 * 1000;
49
+ return now - indexedAt > ttlMs;
50
+ }
51
+ export function listDocLibraries() {
52
+ const metadata = loadDocMetadata();
53
+ const libs = new Set();
54
+ for (const entry of Object.values(metadata)) {
55
+ libs.add(entry.library);
56
+ }
57
+ return [...libs].sort();
58
+ }
59
+ //# sourceMappingURL=doc-metadata.js.map
@@ -0,0 +1,7 @@
1
+ type Registry = Record<string, string>;
2
+ export declare function registerProject(absolutePath: string): void;
3
+ export declare function resolveProject(project: string): string | undefined;
4
+ export declare function listProjects(): Registry;
5
+ export declare function findProjectByPath(dir: string): string | undefined;
6
+ export {};
7
+ //# sourceMappingURL=registry.d.ts.map