claude-all-hands 1.0.2 → 1.0.4
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/.claude/agents/curator.md +1 -5
- package/.claude/agents/documentation-taxonomist.md +255 -0
- package/.claude/agents/documentation-writer.md +366 -0
- package/.claude/agents/surveyor.md +1 -1
- package/.claude/commands/continue.md +12 -10
- package/.claude/commands/create-skill.md +2 -2
- package/.claude/commands/create-specialist.md +3 -3
- package/.claude/commands/debug.md +5 -5
- package/.claude/commands/docs-adjust.md +214 -0
- package/.claude/commands/docs-audit.md +172 -0
- package/.claude/commands/docs-init.md +210 -0
- package/.claude/commands/plan.md +6 -6
- package/.claude/commands/whats-next.md +2 -2
- package/.claude/envoy/README.md +5 -5
- package/.claude/envoy/package-lock.json +216 -10
- package/.claude/envoy/package.json +9 -0
- package/.claude/envoy/src/commands/docs.ts +881 -0
- package/.claude/envoy/src/commands/knowledge.ts +33 -42
- package/.claude/envoy/src/lib/ast-queries.ts +261 -0
- package/.claude/envoy/src/lib/knowledge.ts +176 -124
- package/.claude/envoy/src/lib/tree-sitter-utils.ts +301 -0
- package/.claude/envoy/src/types/tree-sitter.d.ts +76 -0
- package/.claude/hooks/scripts/enforce_research_fetch.py +1 -1
- package/.claude/protocols/bug-discovery.yaml +1 -1
- package/.claude/protocols/discovery.yaml +1 -1
- package/.claude/settings.json +4 -3
- package/.claude/skills/discovery-mode/SKILL.md +7 -7
- package/.claude/skills/documentation-taxonomy/SKILL.md +287 -0
- package/.claude/skills/implementation-mode/SKILL.md +7 -7
- package/.claude/skills/knowledge-discovery/SKILL.md +178 -0
- package/bin/cli.js +41 -1
- package/package.json +1 -1
- package/.claude/agents/documentor.md +0 -147
- package/.claude/commands/audit-docs.md +0 -94
- package/.claude/commands/create-docs.md +0 -100
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
* Uses @visheratin/web-ai-node for embeddings and usearch for HNSW indexing.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { Index, MetricKind, ScalarKind, type Matches } from "usearch";
|
|
6
|
+
import { createHash } from "crypto";
|
|
7
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
9
8
|
import matter from "gray-matter";
|
|
9
|
+
import { createRequire } from "module";
|
|
10
|
+
import { basename, extname, join, relative } from "path";
|
|
11
|
+
import { Index, MetricKind, ScalarKind } from "usearch";
|
|
12
|
+
|
|
13
|
+
// Create require function for ESM compatibility (needed for fetch caching)
|
|
14
|
+
const require = createRequire(import.meta.url);
|
|
10
15
|
|
|
11
16
|
// Types
|
|
12
17
|
interface DocumentMeta {
|
|
@@ -53,32 +58,13 @@ interface IndexConfig {
|
|
|
53
58
|
hasFrontmatter: boolean;
|
|
54
59
|
}
|
|
55
60
|
|
|
56
|
-
//
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
hasFrontmatter: true,
|
|
64
|
-
},
|
|
65
|
-
curator: {
|
|
66
|
-
name: "curator",
|
|
67
|
-
paths: [
|
|
68
|
-
".claude/agents/",
|
|
69
|
-
".claude/hooks/",
|
|
70
|
-
".claude/skills/",
|
|
71
|
-
".claude/commands/",
|
|
72
|
-
".claude/output-styles/",
|
|
73
|
-
".claude/envoy/README.md",
|
|
74
|
-
".claude/settings.json",
|
|
75
|
-
".claude/envoy/src/",
|
|
76
|
-
".claude/envoy/package.json",
|
|
77
|
-
],
|
|
78
|
-
extensions: [".md", ".yaml", ".yml", ".ts", ".json"],
|
|
79
|
-
description: ".claude/ files for curator agent",
|
|
80
|
-
hasFrontmatter: false,
|
|
81
|
-
},
|
|
61
|
+
// Docs index configuration (only supported index)
|
|
62
|
+
const DOCS_CONFIG: IndexConfig = {
|
|
63
|
+
name: "docs",
|
|
64
|
+
paths: ["docs/"],
|
|
65
|
+
extensions: [".md"],
|
|
66
|
+
description: "Project documentation",
|
|
67
|
+
hasFrontmatter: true,
|
|
82
68
|
};
|
|
83
69
|
|
|
84
70
|
// File reference patterns for auto-populating relevant_files
|
|
@@ -90,14 +76,14 @@ const FILE_REF_PATTERNS = [
|
|
|
90
76
|
|
|
91
77
|
// Environment config with defaults
|
|
92
78
|
const SEARCH_SIMILARITY_THRESHOLD = parseFloat(
|
|
93
|
-
process.env.SEARCH_SIMILARITY_THRESHOLD ?? "0.
|
|
79
|
+
process.env.SEARCH_SIMILARITY_THRESHOLD ?? "0.65"
|
|
94
80
|
);
|
|
95
81
|
const SEARCH_CONTEXT_TOKEN_LIMIT = parseInt(
|
|
96
82
|
process.env.SEARCH_CONTEXT_TOKEN_LIMIT ?? "5000",
|
|
97
83
|
10
|
|
98
84
|
);
|
|
99
85
|
const SEARCH_FULL_CONTEXT_SIMILARITY_THRESHOLD = parseFloat(
|
|
100
|
-
process.env.SEARCH_FULL_CONTEXT_SIMILARITY_THRESHOLD ?? "0.
|
|
86
|
+
process.env.SEARCH_FULL_CONTEXT_SIMILARITY_THRESHOLD ?? "0.82"
|
|
101
87
|
);
|
|
102
88
|
|
|
103
89
|
export class KnowledgeService {
|
|
@@ -120,14 +106,101 @@ export class KnowledgeService {
|
|
|
120
106
|
}
|
|
121
107
|
|
|
122
108
|
/**
|
|
123
|
-
*
|
|
109
|
+
* Get model cache directory
|
|
110
|
+
*/
|
|
111
|
+
private getModelCacheDir(): string {
|
|
112
|
+
return join(this.knowledgeDir, "models");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Install caching wrapper for node-fetch (must call before importing web-ai-node)
|
|
117
|
+
*/
|
|
118
|
+
private installFetchCache(): void {
|
|
119
|
+
const cacheDir = this.getModelCacheDir();
|
|
120
|
+
if (!existsSync(cacheDir)) {
|
|
121
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
125
|
+
const nodeFetchModule = require("node-fetch");
|
|
126
|
+
const originalFetch = nodeFetchModule.default || nodeFetchModule;
|
|
127
|
+
|
|
128
|
+
// Skip if already patched
|
|
129
|
+
if ((originalFetch as { __cached?: boolean }).__cached) return;
|
|
130
|
+
|
|
131
|
+
const self = this;
|
|
132
|
+
const cachedFetch = async function (url: string, init?: RequestInit) {
|
|
133
|
+
// Only cache model files
|
|
134
|
+
if (!url.includes("web-ai-models.org") && !url.includes(".onnx")) {
|
|
135
|
+
return originalFetch(url, init);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const urlHash = createHash("md5").update(url).digest("hex").slice(0, 8);
|
|
139
|
+
const fileName = `${urlHash}-${basename(url)}`;
|
|
140
|
+
const cachePath = join(self.getModelCacheDir(), fileName);
|
|
141
|
+
|
|
142
|
+
if (existsSync(cachePath)) {
|
|
143
|
+
console.error(`[knowledge] Using cached model: ${fileName}`);
|
|
144
|
+
const data = readFileSync(cachePath);
|
|
145
|
+
// Return a mock response with arrayBuffer method
|
|
146
|
+
return {
|
|
147
|
+
ok: true,
|
|
148
|
+
status: 200,
|
|
149
|
+
arrayBuffer: async () => data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.error(`[knowledge] Downloading model: ${basename(url)}`);
|
|
154
|
+
const response = await originalFetch(url, init);
|
|
155
|
+
if (!response.ok) {
|
|
156
|
+
return response;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
160
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
161
|
+
writeFileSync(cachePath, buffer);
|
|
162
|
+
console.error(`[knowledge] Cached model: ${fileName} (${(buffer.length / 1024 / 1024).toFixed(1)}MB)`);
|
|
163
|
+
|
|
164
|
+
// Return a mock response since we consumed the original
|
|
165
|
+
return {
|
|
166
|
+
ok: true,
|
|
167
|
+
status: 200,
|
|
168
|
+
arrayBuffer: async () => arrayBuffer,
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
(cachedFetch as { __cached?: boolean }).__cached = true;
|
|
173
|
+
|
|
174
|
+
// Patch the module's default export
|
|
175
|
+
if (nodeFetchModule.default) {
|
|
176
|
+
nodeFetchModule.default = cachedFetch;
|
|
177
|
+
}
|
|
178
|
+
// Also patch require.cache
|
|
179
|
+
const cacheKey = require.resolve("node-fetch");
|
|
180
|
+
if (require.cache[cacheKey]) {
|
|
181
|
+
require.cache[cacheKey]!.exports = cachedFetch;
|
|
182
|
+
require.cache[cacheKey]!.exports.default = cachedFetch;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Lazy-load embedding model with local caching
|
|
124
188
|
*/
|
|
125
189
|
async getModel(): Promise<unknown> {
|
|
126
190
|
if (this.model) return this.model;
|
|
127
191
|
|
|
192
|
+
this.ensureDir();
|
|
193
|
+
console.error("[knowledge] Loading embedding model...");
|
|
194
|
+
const startTime = Date.now();
|
|
195
|
+
|
|
196
|
+
// Install caching before importing the library
|
|
197
|
+
this.installFetchCache();
|
|
198
|
+
|
|
128
199
|
const { TextModel } = await import("@visheratin/web-ai-node/text");
|
|
129
200
|
const modelResult = await TextModel.create("gtr-t5-quant");
|
|
130
201
|
this.model = modelResult.model;
|
|
202
|
+
|
|
203
|
+
console.error(`[knowledge] Model loaded in ${((Date.now() - startTime) / 1000).toFixed(1)}s`);
|
|
131
204
|
return this.model;
|
|
132
205
|
}
|
|
133
206
|
|
|
@@ -153,10 +226,10 @@ export class KnowledgeService {
|
|
|
153
226
|
/**
|
|
154
227
|
* Get index file paths
|
|
155
228
|
*/
|
|
156
|
-
private getIndexPaths(
|
|
229
|
+
private getIndexPaths(): { index: string; meta: string } {
|
|
157
230
|
return {
|
|
158
|
-
index: join(this.knowledgeDir,
|
|
159
|
-
meta: join(this.knowledgeDir,
|
|
231
|
+
index: join(this.knowledgeDir, "docs.usearch"),
|
|
232
|
+
meta: join(this.knowledgeDir, "docs.meta.json"),
|
|
160
233
|
};
|
|
161
234
|
}
|
|
162
235
|
|
|
@@ -188,10 +261,8 @@ export class KnowledgeService {
|
|
|
188
261
|
/**
|
|
189
262
|
* Load index + metadata from disk
|
|
190
263
|
*/
|
|
191
|
-
async loadIndex(
|
|
192
|
-
|
|
193
|
-
): Promise<{ index: Index; meta: IndexMetadata }> {
|
|
194
|
-
const paths = this.getIndexPaths(indexName);
|
|
264
|
+
async loadIndex(): Promise<{ index: Index; meta: IndexMetadata }> {
|
|
265
|
+
const paths = this.getIndexPaths();
|
|
195
266
|
|
|
196
267
|
if (!existsSync(paths.index) || !existsSync(paths.meta)) {
|
|
197
268
|
return {
|
|
@@ -210,13 +281,9 @@ export class KnowledgeService {
|
|
|
210
281
|
/**
|
|
211
282
|
* Save index + metadata to disk
|
|
212
283
|
*/
|
|
213
|
-
async saveIndex(
|
|
214
|
-
indexName: string,
|
|
215
|
-
index: Index,
|
|
216
|
-
meta: IndexMetadata
|
|
217
|
-
): Promise<void> {
|
|
284
|
+
async saveIndex(index: Index, meta: IndexMetadata): Promise<void> {
|
|
218
285
|
this.ensureDir();
|
|
219
|
-
const paths = this.getIndexPaths(
|
|
286
|
+
const paths = this.getIndexPaths();
|
|
220
287
|
|
|
221
288
|
meta.lastUpdated = new Date().toISOString();
|
|
222
289
|
index.save(paths.index);
|
|
@@ -356,10 +423,11 @@ export class KnowledgeService {
|
|
|
356
423
|
}
|
|
357
424
|
|
|
358
425
|
/**
|
|
359
|
-
* Search with similarity computation
|
|
426
|
+
* Search docs index with similarity computation
|
|
427
|
+
* @param metadataOnly - If true, only return file paths and descriptions (no full_resource_context)
|
|
360
428
|
*/
|
|
361
|
-
async search(
|
|
362
|
-
const { index, meta } = await this.loadIndex(
|
|
429
|
+
async search(query: string, k: number = 50, metadataOnly: boolean = false): Promise<SearchResult[]> {
|
|
430
|
+
const { index, meta } = await this.loadIndex();
|
|
363
431
|
|
|
364
432
|
if (Object.keys(meta.documents).length === 0) {
|
|
365
433
|
return [];
|
|
@@ -403,8 +471,8 @@ export class KnowledgeService {
|
|
|
403
471
|
relevant_files: docMeta.relevant_files,
|
|
404
472
|
};
|
|
405
473
|
|
|
406
|
-
// Include full context for high-similarity results
|
|
407
|
-
if (similarity >= SEARCH_FULL_CONTEXT_SIMILARITY_THRESHOLD) {
|
|
474
|
+
// Include full context for high-similarity results (unless metadata-only mode)
|
|
475
|
+
if (!metadataOnly && similarity >= SEARCH_FULL_CONTEXT_SIMILARITY_THRESHOLD) {
|
|
408
476
|
const fullPath = join(this.projectRoot, path);
|
|
409
477
|
if (existsSync(fullPath)) {
|
|
410
478
|
result.full_resource_context = readFileSync(fullPath, "utf-8");
|
|
@@ -418,86 +486,76 @@ export class KnowledgeService {
|
|
|
418
486
|
}
|
|
419
487
|
|
|
420
488
|
/**
|
|
421
|
-
* Full reindex
|
|
489
|
+
* Full reindex of docs
|
|
422
490
|
*/
|
|
423
|
-
async reindexAll(
|
|
491
|
+
async reindexAll(): Promise<ReindexResult> {
|
|
424
492
|
this.ensureDir();
|
|
425
|
-
const
|
|
493
|
+
const startTime = Date.now();
|
|
494
|
+
console.error("[knowledge] Reindexing docs...");
|
|
426
495
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
const config = INDEX_CONFIGS[name];
|
|
431
|
-
if (!config) {
|
|
432
|
-
throw new Error(`Unknown index: ${name}`);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
// Create fresh index
|
|
436
|
-
const index = this.createIndex();
|
|
437
|
-
const meta = this.createEmptyMetadata();
|
|
438
|
-
|
|
439
|
-
// Discover and index files
|
|
440
|
-
const files = this.discoverFiles(config);
|
|
441
|
-
let totalTokens = 0;
|
|
496
|
+
// Create fresh index
|
|
497
|
+
const index = this.createIndex();
|
|
498
|
+
const meta = this.createEmptyMetadata();
|
|
442
499
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
500
|
+
// Discover and index files
|
|
501
|
+
const files = this.discoverFiles(DOCS_CONFIG);
|
|
502
|
+
console.error(`[knowledge] Found ${files.length} files`);
|
|
503
|
+
let totalTokens = 0;
|
|
446
504
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
505
|
+
for (let i = 0; i < files.length; i++) {
|
|
506
|
+
const filePath = files[i];
|
|
507
|
+
const fullPath = join(this.projectRoot, filePath);
|
|
508
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
509
|
+
|
|
510
|
+
// Parse front-matter
|
|
511
|
+
let frontMatter: Record<string, unknown> = {};
|
|
512
|
+
if (filePath.endsWith(".md")) {
|
|
513
|
+
try {
|
|
514
|
+
const parsed = matter(content);
|
|
515
|
+
frontMatter = parsed.data;
|
|
516
|
+
} catch {
|
|
517
|
+
// Skip files with invalid front-matter
|
|
456
518
|
}
|
|
457
|
-
|
|
458
|
-
await this.indexDocument(index, meta, filePath, content, frontMatter);
|
|
459
|
-
totalTokens += meta.documents[filePath].token_count;
|
|
460
519
|
}
|
|
461
520
|
|
|
462
|
-
|
|
463
|
-
await this.
|
|
464
|
-
|
|
465
|
-
results[name] = {
|
|
466
|
-
files_indexed: files.length,
|
|
467
|
-
total_tokens: totalTokens,
|
|
468
|
-
};
|
|
521
|
+
console.error(`[knowledge] Embedding ${i + 1}/${files.length}: ${filePath}`);
|
|
522
|
+
await this.indexDocument(index, meta, filePath, content, frontMatter);
|
|
523
|
+
totalTokens += meta.documents[filePath].token_count;
|
|
469
524
|
}
|
|
470
525
|
|
|
471
|
-
|
|
526
|
+
// Save
|
|
527
|
+
await this.saveIndex(index, meta);
|
|
528
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
529
|
+
console.error(`[knowledge] Reindex complete: ${files.length} files, ${totalTokens} tokens in ${duration}s`);
|
|
530
|
+
|
|
531
|
+
return {
|
|
532
|
+
files_indexed: files.length,
|
|
533
|
+
total_tokens: totalTokens,
|
|
534
|
+
};
|
|
472
535
|
}
|
|
473
536
|
|
|
474
537
|
/**
|
|
475
538
|
* Incremental reindex from changed files
|
|
476
539
|
*/
|
|
477
|
-
async reindexFromChanges(
|
|
478
|
-
indexName: string,
|
|
479
|
-
changes: FileChange[]
|
|
480
|
-
): Promise<{
|
|
540
|
+
async reindexFromChanges(changes: FileChange[]): Promise<{
|
|
481
541
|
success: boolean;
|
|
482
542
|
message: string;
|
|
483
543
|
missing_references?: { doc_path: string; missing_files: string[] }[];
|
|
484
544
|
files: { path: string; action: string }[];
|
|
485
545
|
}> {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
throw new Error(`Unknown index: ${indexName}`);
|
|
489
|
-
}
|
|
546
|
+
console.error(`[knowledge] Incremental reindex: ${changes.length} change(s)`);
|
|
547
|
+
const startTime = Date.now();
|
|
490
548
|
|
|
491
|
-
const { index, meta } = await this.loadIndex(
|
|
549
|
+
const { index, meta } = await this.loadIndex();
|
|
492
550
|
const processedFiles: { path: string; action: string }[] = [];
|
|
493
551
|
const missingReferences: { doc_path: string; missing_files: string[] }[] = [];
|
|
494
552
|
|
|
495
553
|
for (const change of changes) {
|
|
496
554
|
const { path, added, deleted, modified } = change;
|
|
497
555
|
|
|
498
|
-
// Check if file matches
|
|
499
|
-
const matchesConfig =
|
|
500
|
-
|
|
556
|
+
// Check if file matches docs config
|
|
557
|
+
const matchesConfig = DOCS_CONFIG.paths.some((p: string) => path.startsWith(p)) &&
|
|
558
|
+
DOCS_CONFIG.extensions.includes(extname(path));
|
|
501
559
|
|
|
502
560
|
if (!matchesConfig) continue;
|
|
503
561
|
|
|
@@ -511,6 +569,7 @@ export class KnowledgeService {
|
|
|
511
569
|
delete meta.path_to_id[path];
|
|
512
570
|
delete meta.documents[path];
|
|
513
571
|
processedFiles.push({ path, action: "deleted" });
|
|
572
|
+
console.error(`[knowledge] Deleted: ${path}`);
|
|
514
573
|
}
|
|
515
574
|
} else if (added || modified) {
|
|
516
575
|
const fullPath = join(this.projectRoot, path);
|
|
@@ -519,8 +578,8 @@ export class KnowledgeService {
|
|
|
519
578
|
const content = readFileSync(fullPath, "utf-8");
|
|
520
579
|
let frontMatter: Record<string, unknown> = {};
|
|
521
580
|
|
|
522
|
-
//
|
|
523
|
-
if (
|
|
581
|
+
// Process front-matter and file references
|
|
582
|
+
if (path.endsWith(".md")) {
|
|
524
583
|
try {
|
|
525
584
|
const parsed = matter(content);
|
|
526
585
|
frontMatter = parsed.data;
|
|
@@ -546,13 +605,17 @@ export class KnowledgeService {
|
|
|
546
605
|
}
|
|
547
606
|
|
|
548
607
|
// Index document
|
|
608
|
+
const action = added ? "added" : "modified";
|
|
609
|
+
console.error(`[knowledge] Embedding (${action}): ${path}`);
|
|
549
610
|
await this.indexDocument(index, meta, path, content, frontMatter);
|
|
550
|
-
processedFiles.push({ path, action
|
|
611
|
+
processedFiles.push({ path, action });
|
|
551
612
|
}
|
|
552
613
|
}
|
|
553
614
|
|
|
554
615
|
// Save updated index
|
|
555
|
-
await this.saveIndex(
|
|
616
|
+
await this.saveIndex(index, meta);
|
|
617
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
618
|
+
console.error(`[knowledge] Incremental reindex complete: ${processedFiles.length} file(s) in ${duration}s`);
|
|
556
619
|
|
|
557
620
|
if (missingReferences.length > 0) {
|
|
558
621
|
return {
|
|
@@ -571,24 +634,13 @@ export class KnowledgeService {
|
|
|
571
634
|
}
|
|
572
635
|
|
|
573
636
|
/**
|
|
574
|
-
* Check if
|
|
637
|
+
* Check if docs index exists
|
|
575
638
|
*/
|
|
576
|
-
async
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
for (const name of Object.keys(INDEX_CONFIGS)) {
|
|
581
|
-
const paths = this.getIndexPaths(name);
|
|
582
|
-
if (existsSync(paths.index) && existsSync(paths.meta)) {
|
|
583
|
-
valid.push(name);
|
|
584
|
-
} else {
|
|
585
|
-
missing.push(name);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
return { valid, missing };
|
|
639
|
+
async checkIndex(): Promise<{ exists: boolean }> {
|
|
640
|
+
const paths = this.getIndexPaths();
|
|
641
|
+
return { exists: existsSync(paths.index) && existsSync(paths.meta) };
|
|
590
642
|
}
|
|
591
643
|
}
|
|
592
644
|
|
|
593
|
-
export {
|
|
594
|
-
|
|
645
|
+
export type { DocumentMeta, FileChange, IndexMetadata, ReindexResult, SearchResult };
|
|
646
|
+
|