codetree-claude 1.0.0
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/.codetreerc.default.json +41 -0
- package/README.md +171 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +185 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +131 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +111 -0
- package/dist/config.js.map +1 -0
- package/dist/hook/hook-client.d.ts +6 -0
- package/dist/hook/hook-client.d.ts.map +1 -0
- package/dist/hook/hook-client.js +48 -0
- package/dist/hook/hook-client.js.map +1 -0
- package/dist/hook/pre-tool-use.bundled.js +162 -0
- package/dist/hook/pre-tool-use.d.ts +14 -0
- package/dist/hook/pre-tool-use.d.ts.map +1 -0
- package/dist/hook/pre-tool-use.js +140 -0
- package/dist/hook/pre-tool-use.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer/extractor-registry.d.ts +10 -0
- package/dist/indexer/extractor-registry.d.ts.map +1 -0
- package/dist/indexer/extractor-registry.js +39 -0
- package/dist/indexer/extractor-registry.js.map +1 -0
- package/dist/indexer/extractors/generic.d.ts +11 -0
- package/dist/indexer/extractors/generic.d.ts.map +1 -0
- package/dist/indexer/extractors/generic.js +12 -0
- package/dist/indexer/extractors/generic.js.map +1 -0
- package/dist/indexer/extractors/go.d.ts +10 -0
- package/dist/indexer/extractors/go.d.ts.map +1 -0
- package/dist/indexer/extractors/go.js +119 -0
- package/dist/indexer/extractors/go.js.map +1 -0
- package/dist/indexer/extractors/java.d.ts +10 -0
- package/dist/indexer/extractors/java.d.ts.map +1 -0
- package/dist/indexer/extractors/java.js +89 -0
- package/dist/indexer/extractors/java.js.map +1 -0
- package/dist/indexer/extractors/javascript.d.ts +11 -0
- package/dist/indexer/extractors/javascript.d.ts.map +1 -0
- package/dist/indexer/extractors/javascript.js +190 -0
- package/dist/indexer/extractors/javascript.js.map +1 -0
- package/dist/indexer/extractors/python.d.ts +11 -0
- package/dist/indexer/extractors/python.d.ts.map +1 -0
- package/dist/indexer/extractors/python.js +115 -0
- package/dist/indexer/extractors/python.js.map +1 -0
- package/dist/indexer/extractors/types.d.ts +26 -0
- package/dist/indexer/extractors/types.d.ts.map +1 -0
- package/dist/indexer/extractors/types.js +36 -0
- package/dist/indexer/extractors/types.js.map +1 -0
- package/dist/indexer/hasher.d.ts +11 -0
- package/dist/indexer/hasher.d.ts.map +1 -0
- package/dist/indexer/hasher.js +41 -0
- package/dist/indexer/hasher.js.map +1 -0
- package/dist/indexer/ignore.d.ts +15 -0
- package/dist/indexer/ignore.d.ts.map +1 -0
- package/dist/indexer/ignore.js +63 -0
- package/dist/indexer/ignore.js.map +1 -0
- package/dist/indexer/indexer.d.ts +64 -0
- package/dist/indexer/indexer.d.ts.map +1 -0
- package/dist/indexer/indexer.js +295 -0
- package/dist/indexer/indexer.js.map +1 -0
- package/dist/indexer/watcher.d.ts +16 -0
- package/dist/indexer/watcher.d.ts.map +1 -0
- package/dist/indexer/watcher.js +79 -0
- package/dist/indexer/watcher.js.map +1 -0
- package/dist/server/ipc.d.ts +38 -0
- package/dist/server/ipc.d.ts.map +1 -0
- package/dist/server/ipc.js +212 -0
- package/dist/server/ipc.js.map +1 -0
- package/dist/server/mcp-server.d.ts +2 -0
- package/dist/server/mcp-server.d.ts.map +1 -0
- package/dist/server/mcp-server.js +133 -0
- package/dist/server/mcp-server.js.map +1 -0
- package/dist/server/tools/codetree-find-refs.d.ts +46 -0
- package/dist/server/tools/codetree-find-refs.d.ts.map +1 -0
- package/dist/server/tools/codetree-find-refs.js +83 -0
- package/dist/server/tools/codetree-find-refs.js.map +1 -0
- package/dist/server/tools/codetree-read.d.ts +46 -0
- package/dist/server/tools/codetree-read.d.ts.map +1 -0
- package/dist/server/tools/codetree-read.js +82 -0
- package/dist/server/tools/codetree-read.js.map +1 -0
- package/dist/server/tools/codetree-search.d.ts +59 -0
- package/dist/server/tools/codetree-search.d.ts.map +1 -0
- package/dist/server/tools/codetree-search.js +92 -0
- package/dist/server/tools/codetree-search.js.map +1 -0
- package/dist/server/tools/codetree-structure.d.ts +55 -0
- package/dist/server/tools/codetree-structure.d.ts.map +1 -0
- package/dist/server/tools/codetree-structure.js +137 -0
- package/dist/server/tools/codetree-structure.js.map +1 -0
- package/dist/server/tools/codetree-summary.d.ts +36 -0
- package/dist/server/tools/codetree-summary.d.ts.map +1 -0
- package/dist/server/tools/codetree-summary.js +94 -0
- package/dist/server/tools/codetree-summary.js.map +1 -0
- package/dist/setup/install.d.ts +26 -0
- package/dist/setup/install.d.ts.map +1 -0
- package/dist/setup/install.js +127 -0
- package/dist/setup/install.js.map +1 -0
- package/dist/storage/cache.d.ts +29 -0
- package/dist/storage/cache.d.ts.map +1 -0
- package/dist/storage/cache.js +54 -0
- package/dist/storage/cache.js.map +1 -0
- package/dist/storage/database.d.ts +52 -0
- package/dist/storage/database.d.ts.map +1 -0
- package/dist/storage/database.js +346 -0
- package/dist/storage/database.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import ignoreModule from "ignore";
|
|
2
|
+
const ignore = ignoreModule.default || ignoreModule;
|
|
3
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
4
|
+
import { join, extname } from "node:path";
|
|
5
|
+
import { isBinaryExtension } from "../config.js";
|
|
6
|
+
export class IgnoreFilter {
|
|
7
|
+
ig;
|
|
8
|
+
config;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
this.ig = ignore();
|
|
12
|
+
// Add configured ignore patterns
|
|
13
|
+
this.ig.add(config.ignore);
|
|
14
|
+
// Add .codetree directory itself
|
|
15
|
+
this.ig.add(".codetree");
|
|
16
|
+
// Load .gitignore if present
|
|
17
|
+
const gitignorePath = join(config.projectRoot, ".gitignore");
|
|
18
|
+
if (existsSync(gitignorePath)) {
|
|
19
|
+
try {
|
|
20
|
+
const content = readFileSync(gitignorePath, "utf-8");
|
|
21
|
+
this.ig.add(content);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Ignore read errors
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Load .codetreeignore if present
|
|
28
|
+
const codetreeIgnorePath = join(config.projectRoot, ".codetreeignore");
|
|
29
|
+
if (existsSync(codetreeIgnorePath)) {
|
|
30
|
+
try {
|
|
31
|
+
const content = readFileSync(codetreeIgnorePath, "utf-8");
|
|
32
|
+
this.ig.add(content);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Ignore read errors
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Check if a relative path should be ignored.
|
|
41
|
+
*/
|
|
42
|
+
isIgnored(relativePath) {
|
|
43
|
+
// Normalize to forward slashes
|
|
44
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
45
|
+
// Check ignore patterns
|
|
46
|
+
if (this.ig.ignores(normalized))
|
|
47
|
+
return true;
|
|
48
|
+
// Check binary extensions
|
|
49
|
+
if (this.config.ignoreBinary) {
|
|
50
|
+
const ext = extname(normalized);
|
|
51
|
+
if (ext && isBinaryExtension(ext))
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Filter a list of relative paths, returning only non-ignored ones.
|
|
58
|
+
*/
|
|
59
|
+
filter(paths) {
|
|
60
|
+
return paths.filter((p) => !this.isIgnored(p));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=ignore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ignore.js","sourceRoot":"","sources":["../../src/indexer/ignore.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,IAAI,YAAY,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAuB,MAAM,cAAc,CAAC;AAEtE,MAAM,OAAO,YAAY;IACf,EAAE,CAAS;IACX,MAAM,CAAiB;IAE/B,YAAY,MAAsB;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC;QAEnB,iCAAiC;QACjC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE3B,iCAAiC;QACjC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAEzB,6BAA6B;QAC7B,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAC7D,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;gBACrD,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,qBAAqB;YACvB,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,MAAM,kBAAkB,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;QACvE,IAAI,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;gBAC1D,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,qBAAqB;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,YAAoB;QAC5B,+BAA+B;QAC/B,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAEpD,wBAAwB;QACxB,IAAI,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;YAAE,OAAO,IAAI,CAAC;QAE7C,0BAA0B;QAC1B,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;YAChC,IAAI,GAAG,IAAI,iBAAiB,CAAC,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;QACjD,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAe;QACpB,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;CACF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type CodeTreeConfig } from "../config.js";
|
|
2
|
+
import { Database } from "../storage/database.js";
|
|
3
|
+
import { ContentCache } from "../storage/cache.js";
|
|
4
|
+
export interface IndexStats {
|
|
5
|
+
totalFiles: number;
|
|
6
|
+
indexedFiles: number;
|
|
7
|
+
symbolCount: number;
|
|
8
|
+
indexTimeMs: number;
|
|
9
|
+
cacheHitRate: number;
|
|
10
|
+
}
|
|
11
|
+
export interface IndexerEvents {
|
|
12
|
+
onProgress?: (indexed: number, total: number) => void;
|
|
13
|
+
onError?: (path: string, error: Error) => void;
|
|
14
|
+
onComplete?: (stats: IndexStats) => void;
|
|
15
|
+
}
|
|
16
|
+
export declare class Indexer {
|
|
17
|
+
private db;
|
|
18
|
+
private cache;
|
|
19
|
+
private ignoreFilter;
|
|
20
|
+
private extractors;
|
|
21
|
+
private config;
|
|
22
|
+
private indexing;
|
|
23
|
+
private ready;
|
|
24
|
+
constructor(config: CodeTreeConfig, db: Database, cache: ContentCache);
|
|
25
|
+
init(): Promise<void>;
|
|
26
|
+
isReady(): boolean;
|
|
27
|
+
isIndexing(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Full scan of the project directory. Incremental: skips files that haven't changed.
|
|
30
|
+
*/
|
|
31
|
+
fullScan(events?: IndexerEvents): Promise<IndexStats>;
|
|
32
|
+
/**
|
|
33
|
+
* Index a single file. Returns null if file hasn't changed since last index.
|
|
34
|
+
*/
|
|
35
|
+
indexFile(absPath: string): {
|
|
36
|
+
symbolCount: number;
|
|
37
|
+
} | null;
|
|
38
|
+
/**
|
|
39
|
+
* Remove a file from the index (when it's deleted from disk).
|
|
40
|
+
*/
|
|
41
|
+
removeFile(absPath: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Read a file from cache. Returns null on cache miss.
|
|
44
|
+
*/
|
|
45
|
+
readCached(relPath: string): string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Check if a file is in the cache and still valid.
|
|
48
|
+
*/
|
|
49
|
+
isCacheValid(absPath: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Get project structure as a tree.
|
|
52
|
+
*/
|
|
53
|
+
getProjectTree(): Record<string, {
|
|
54
|
+
language: string | null;
|
|
55
|
+
size: number;
|
|
56
|
+
lineCount: number;
|
|
57
|
+
symbolCount: number;
|
|
58
|
+
}>;
|
|
59
|
+
getStats(): IndexStats;
|
|
60
|
+
private collectFiles;
|
|
61
|
+
private walkDir;
|
|
62
|
+
private pruneDeletedFiles;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=indexer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../../src/indexer/indexer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,QAAQ,EAA6D,MAAM,wBAAwB,CAAC;AAC7G,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;AAMpE,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC/C,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAC1C;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY;IAQ/D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,OAAO,IAAI,OAAO;IAIlB,UAAU,IAAI,OAAO;IAIrB;;OAEG;IACG,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC;IA2C3D;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IA0G1D;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAMjC;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA+B1C;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAatC;;OAEG;IACH,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAiBnH,QAAQ,IAAI,UAAU;IAatB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,OAAO;IAsBf,OAAO,CAAC,iBAAiB;CAa1B"}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { readFileSync, statSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { deflateSync, inflateSync } from "node:zlib";
|
|
4
|
+
import { normalizePath } from "../config.js";
|
|
5
|
+
import { hashContent, ensureHasherReady, quickHash } from "./hasher.js";
|
|
6
|
+
import { IgnoreFilter } from "./ignore.js";
|
|
7
|
+
import { ExtractorRegistry } from "./extractor-registry.js";
|
|
8
|
+
import { detectLanguage } from "./extractors/types.js";
|
|
9
|
+
export class Indexer {
|
|
10
|
+
db;
|
|
11
|
+
cache;
|
|
12
|
+
ignoreFilter;
|
|
13
|
+
extractors;
|
|
14
|
+
config;
|
|
15
|
+
indexing = false;
|
|
16
|
+
ready = false;
|
|
17
|
+
constructor(config, db, cache) {
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.db = db;
|
|
20
|
+
this.cache = cache;
|
|
21
|
+
this.ignoreFilter = new IgnoreFilter(config);
|
|
22
|
+
this.extractors = new ExtractorRegistry();
|
|
23
|
+
}
|
|
24
|
+
async init() {
|
|
25
|
+
await ensureHasherReady();
|
|
26
|
+
this.ready = true;
|
|
27
|
+
}
|
|
28
|
+
isReady() {
|
|
29
|
+
return this.ready && !this.indexing;
|
|
30
|
+
}
|
|
31
|
+
isIndexing() {
|
|
32
|
+
return this.indexing;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Full scan of the project directory. Incremental: skips files that haven't changed.
|
|
36
|
+
*/
|
|
37
|
+
async fullScan(events) {
|
|
38
|
+
if (!this.ready)
|
|
39
|
+
throw new Error("Indexer not initialized");
|
|
40
|
+
this.indexing = true;
|
|
41
|
+
const startTime = Date.now();
|
|
42
|
+
const filePaths = this.collectFiles(this.config.projectRoot);
|
|
43
|
+
let indexed = 0;
|
|
44
|
+
let symbolCount = 0;
|
|
45
|
+
for (const absPath of filePaths) {
|
|
46
|
+
try {
|
|
47
|
+
const result = this.indexFile(absPath);
|
|
48
|
+
if (result) {
|
|
49
|
+
symbolCount += result.symbolCount;
|
|
50
|
+
}
|
|
51
|
+
indexed++;
|
|
52
|
+
events?.onProgress?.(indexed, filePaths.length);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
events?.onError?.(absPath, err);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Remove files from index that no longer exist on disk
|
|
59
|
+
this.pruneDeletedFiles(filePaths);
|
|
60
|
+
// Evict old content cache entries
|
|
61
|
+
this.db.evictContentCache(this.config.cache.contentCacheMaxMB);
|
|
62
|
+
this.db.persistToDisk();
|
|
63
|
+
this.indexing = false;
|
|
64
|
+
const stats = {
|
|
65
|
+
totalFiles: filePaths.length,
|
|
66
|
+
indexedFiles: indexed,
|
|
67
|
+
symbolCount,
|
|
68
|
+
indexTimeMs: Date.now() - startTime,
|
|
69
|
+
cacheHitRate: this.cache.getStats().hitRate,
|
|
70
|
+
};
|
|
71
|
+
events?.onComplete?.(stats);
|
|
72
|
+
return stats;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Index a single file. Returns null if file hasn't changed since last index.
|
|
76
|
+
*/
|
|
77
|
+
indexFile(absPath) {
|
|
78
|
+
const relPath = normalizePath(relative(this.config.projectRoot, absPath));
|
|
79
|
+
let stat;
|
|
80
|
+
try {
|
|
81
|
+
stat = statSync(absPath);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// File doesn't exist or can't be read — remove from index
|
|
85
|
+
this.db.deleteFile(relPath);
|
|
86
|
+
this.cache.delete(relPath);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
// Skip files over size limit
|
|
90
|
+
if (stat.size > this.config.maxFileSize)
|
|
91
|
+
return null;
|
|
92
|
+
if (stat.size === 0)
|
|
93
|
+
return null;
|
|
94
|
+
// Quick check: has the file changed since last index?
|
|
95
|
+
const existing = this.db.getFile(relPath);
|
|
96
|
+
if (existing) {
|
|
97
|
+
const quick = quickHash(stat.size, Math.floor(stat.mtimeMs));
|
|
98
|
+
const existingQuick = quickHash(existing.size, existing.mtime_ms);
|
|
99
|
+
if (quick === existingQuick) {
|
|
100
|
+
// File hasn't changed — skip
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Read and index the file
|
|
105
|
+
let content;
|
|
106
|
+
try {
|
|
107
|
+
content = readFileSync(absPath, "utf-8");
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const hash = hashContent(content);
|
|
113
|
+
// Double check: if hash matches, file content is truly the same
|
|
114
|
+
if (existing && existing.hash === hash) {
|
|
115
|
+
// Update mtime but skip re-extraction
|
|
116
|
+
this.db.upsertFile({
|
|
117
|
+
...existing,
|
|
118
|
+
mtime_ms: Math.floor(stat.mtimeMs),
|
|
119
|
+
indexed_at: Date.now(),
|
|
120
|
+
});
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const lineCount = content.split("\n").length;
|
|
124
|
+
const language = detectLanguage(absPath);
|
|
125
|
+
// Store file record
|
|
126
|
+
const fileRecord = {
|
|
127
|
+
path: relPath,
|
|
128
|
+
hash,
|
|
129
|
+
size: stat.size,
|
|
130
|
+
mtime_ms: Math.floor(stat.mtimeMs),
|
|
131
|
+
language,
|
|
132
|
+
line_count: lineCount,
|
|
133
|
+
indexed_at: Date.now(),
|
|
134
|
+
};
|
|
135
|
+
this.db.upsertFile(fileRecord);
|
|
136
|
+
// Extract symbols and dependencies
|
|
137
|
+
let symbolCount = 0;
|
|
138
|
+
if (this.config.symbols.enabled) {
|
|
139
|
+
const extraction = this.extractors.extract(content, absPath);
|
|
140
|
+
const symbolRecords = extraction.symbols.map((s) => ({
|
|
141
|
+
file_path: relPath,
|
|
142
|
+
name: s.name,
|
|
143
|
+
kind: s.kind,
|
|
144
|
+
line_start: s.lineStart,
|
|
145
|
+
line_end: s.lineEnd,
|
|
146
|
+
signature: s.signature,
|
|
147
|
+
exported: s.exported,
|
|
148
|
+
}));
|
|
149
|
+
this.db.upsertSymbols(relPath, symbolRecords);
|
|
150
|
+
symbolCount = symbolRecords.length;
|
|
151
|
+
const depRecords = extraction.dependencies.map((d) => ({
|
|
152
|
+
source_path: relPath,
|
|
153
|
+
target_spec: d.specifier,
|
|
154
|
+
target_resolved: null, // Could resolve in a second pass
|
|
155
|
+
}));
|
|
156
|
+
this.db.upsertDependencies(relPath, depRecords);
|
|
157
|
+
}
|
|
158
|
+
// Cache content (compressed in SQLite, raw in LRU)
|
|
159
|
+
try {
|
|
160
|
+
const compressed = deflateSync(Buffer.from(content, "utf-8"));
|
|
161
|
+
this.db.cacheContent(relPath, compressed);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Compression failed, skip caching in DB
|
|
165
|
+
}
|
|
166
|
+
this.cache.set(relPath, {
|
|
167
|
+
content,
|
|
168
|
+
hash,
|
|
169
|
+
mtimeMs: stat.mtimeMs,
|
|
170
|
+
size: stat.size,
|
|
171
|
+
});
|
|
172
|
+
return { symbolCount };
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Remove a file from the index (when it's deleted from disk).
|
|
176
|
+
*/
|
|
177
|
+
removeFile(absPath) {
|
|
178
|
+
const relPath = normalizePath(relative(this.config.projectRoot, absPath));
|
|
179
|
+
this.db.deleteFile(relPath);
|
|
180
|
+
this.cache.delete(relPath);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Read a file from cache. Returns null on cache miss.
|
|
184
|
+
*/
|
|
185
|
+
readCached(relPath) {
|
|
186
|
+
const normalized = normalizePath(relPath);
|
|
187
|
+
// Try in-memory LRU first
|
|
188
|
+
const cached = this.cache.get(normalized);
|
|
189
|
+
if (cached)
|
|
190
|
+
return cached.content;
|
|
191
|
+
// Try SQLite content cache
|
|
192
|
+
const dbContent = this.db.getCachedContent(normalized);
|
|
193
|
+
if (dbContent) {
|
|
194
|
+
try {
|
|
195
|
+
const content = inflateSync(dbContent).toString("utf-8");
|
|
196
|
+
// Promote to LRU
|
|
197
|
+
const fileRecord = this.db.getFile(normalized);
|
|
198
|
+
if (fileRecord) {
|
|
199
|
+
this.cache.set(normalized, {
|
|
200
|
+
content,
|
|
201
|
+
hash: fileRecord.hash,
|
|
202
|
+
mtimeMs: fileRecord.mtime_ms,
|
|
203
|
+
size: fileRecord.size,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return content;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Check if a file is in the cache and still valid.
|
|
216
|
+
*/
|
|
217
|
+
isCacheValid(absPath) {
|
|
218
|
+
const relPath = normalizePath(relative(this.config.projectRoot, absPath));
|
|
219
|
+
const record = this.db.getFile(relPath);
|
|
220
|
+
if (!record)
|
|
221
|
+
return false;
|
|
222
|
+
try {
|
|
223
|
+
const stat = statSync(absPath);
|
|
224
|
+
return record.size === stat.size && record.mtime_ms === Math.floor(stat.mtimeMs);
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Get project structure as a tree.
|
|
232
|
+
*/
|
|
233
|
+
getProjectTree() {
|
|
234
|
+
const files = this.db.getAllFiles();
|
|
235
|
+
const tree = {};
|
|
236
|
+
for (const file of files) {
|
|
237
|
+
const symbols = this.db.getSymbolsForFile(file.path);
|
|
238
|
+
tree[file.path] = {
|
|
239
|
+
language: file.language,
|
|
240
|
+
size: file.size,
|
|
241
|
+
lineCount: file.line_count,
|
|
242
|
+
symbolCount: symbols.length,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
return tree;
|
|
246
|
+
}
|
|
247
|
+
getStats() {
|
|
248
|
+
const cacheStats = this.cache.getStats();
|
|
249
|
+
return {
|
|
250
|
+
totalFiles: this.db.getFileCount(),
|
|
251
|
+
indexedFiles: this.db.getFileCount(),
|
|
252
|
+
symbolCount: 0, // Would need a separate query
|
|
253
|
+
indexTimeMs: 0,
|
|
254
|
+
cacheHitRate: cacheStats.hitRate,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
// ─── Private ─────────────────────────────────────────────────
|
|
258
|
+
collectFiles(dir) {
|
|
259
|
+
const files = [];
|
|
260
|
+
this.walkDir(dir, files);
|
|
261
|
+
return files;
|
|
262
|
+
}
|
|
263
|
+
walkDir(dir, files) {
|
|
264
|
+
let entries;
|
|
265
|
+
try {
|
|
266
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
for (const entry of entries) {
|
|
272
|
+
const fullPath = join(dir, entry.name);
|
|
273
|
+
const relPath = normalizePath(relative(this.config.projectRoot, fullPath));
|
|
274
|
+
if (this.ignoreFilter.isIgnored(relPath))
|
|
275
|
+
continue;
|
|
276
|
+
if (entry.isDirectory()) {
|
|
277
|
+
this.walkDir(fullPath, files);
|
|
278
|
+
}
|
|
279
|
+
else if (entry.isFile()) {
|
|
280
|
+
files.push(fullPath);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
pruneDeletedFiles(currentFiles) {
|
|
285
|
+
const currentSet = new Set(currentFiles.map((f) => normalizePath(relative(this.config.projectRoot, f))));
|
|
286
|
+
const indexedFiles = this.db.getAllFiles();
|
|
287
|
+
for (const file of indexedFiles) {
|
|
288
|
+
if (!currentSet.has(file.path)) {
|
|
289
|
+
this.db.deleteFile(file.path);
|
|
290
|
+
this.cache.delete(file.path);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=indexer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer.js","sourceRoot":"","sources":["../../src/indexer/indexer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type CodeTreeConfig } from "../config.js";
|
|
2
|
+
import type { Indexer } from "./indexer.js";
|
|
3
|
+
export declare class FileWatcher {
|
|
4
|
+
private watcher;
|
|
5
|
+
private config;
|
|
6
|
+
private indexer;
|
|
7
|
+
private debounceTimers;
|
|
8
|
+
private running;
|
|
9
|
+
constructor(config: CodeTreeConfig, indexer: Indexer);
|
|
10
|
+
start(): void;
|
|
11
|
+
stop(): void;
|
|
12
|
+
isRunning(): boolean;
|
|
13
|
+
private handleChange;
|
|
14
|
+
private handleDelete;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/indexer/watcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,cAAc,CAAyD;IAC/E,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO;IAKpD,KAAK,IAAI,IAAI;IA4Bb,IAAI,IAAI,IAAI;IAYZ,SAAS,IAAI,OAAO;IAIpB,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,YAAY;CAQrB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import chokidar from "chokidar";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { normalizePath } from "../config.js";
|
|
4
|
+
export class FileWatcher {
|
|
5
|
+
watcher = null;
|
|
6
|
+
config;
|
|
7
|
+
indexer;
|
|
8
|
+
debounceTimers = new Map();
|
|
9
|
+
running = false;
|
|
10
|
+
constructor(config, indexer) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.indexer = indexer;
|
|
13
|
+
}
|
|
14
|
+
start() {
|
|
15
|
+
if (this.running)
|
|
16
|
+
return;
|
|
17
|
+
const ignored = [
|
|
18
|
+
...this.config.ignore.map((p) => `**/${p}/**`),
|
|
19
|
+
"**/.codetree/**",
|
|
20
|
+
"**/node_modules/**",
|
|
21
|
+
"**/.git/**",
|
|
22
|
+
];
|
|
23
|
+
this.watcher = chokidar.watch(this.config.projectRoot, {
|
|
24
|
+
ignored,
|
|
25
|
+
persistent: true,
|
|
26
|
+
ignoreInitial: true,
|
|
27
|
+
usePolling: this.config.watch.usePolling,
|
|
28
|
+
awaitWriteFinish: {
|
|
29
|
+
stabilityThreshold: 200,
|
|
30
|
+
pollInterval: 100,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
this.watcher.on("change", (path) => this.handleChange(path));
|
|
34
|
+
this.watcher.on("add", (path) => this.handleChange(path));
|
|
35
|
+
this.watcher.on("unlink", (path) => this.handleDelete(path));
|
|
36
|
+
this.running = true;
|
|
37
|
+
}
|
|
38
|
+
stop() {
|
|
39
|
+
if (this.watcher) {
|
|
40
|
+
this.watcher.close();
|
|
41
|
+
this.watcher = null;
|
|
42
|
+
}
|
|
43
|
+
for (const timer of this.debounceTimers.values()) {
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
}
|
|
46
|
+
this.debounceTimers.clear();
|
|
47
|
+
this.running = false;
|
|
48
|
+
}
|
|
49
|
+
isRunning() {
|
|
50
|
+
return this.running;
|
|
51
|
+
}
|
|
52
|
+
handleChange(path) {
|
|
53
|
+
const absPath = resolve(path);
|
|
54
|
+
const key = normalizePath(absPath);
|
|
55
|
+
// Debounce rapid changes to the same file
|
|
56
|
+
const existing = this.debounceTimers.get(key);
|
|
57
|
+
if (existing)
|
|
58
|
+
clearTimeout(existing);
|
|
59
|
+
this.debounceTimers.set(key, setTimeout(() => {
|
|
60
|
+
this.debounceTimers.delete(key);
|
|
61
|
+
try {
|
|
62
|
+
this.indexer.indexFile(absPath);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
console.error(`[codetree] Failed to reindex ${key}:`, err);
|
|
66
|
+
}
|
|
67
|
+
}, this.config.watch.debounceMs));
|
|
68
|
+
}
|
|
69
|
+
handleDelete(path) {
|
|
70
|
+
const absPath = resolve(path);
|
|
71
|
+
try {
|
|
72
|
+
this.indexer.removeFile(absPath);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
console.error(`[codetree] Failed to remove ${normalizePath(absPath)} from index:`, err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/indexer/watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Indexer } from "../indexer/indexer.js";
|
|
2
|
+
import type { Database } from "../storage/database.js";
|
|
3
|
+
import { type CodeTreeConfig } from "../config.js";
|
|
4
|
+
/**
|
|
5
|
+
* Lightweight HTTP server for hook->MCP server IPC.
|
|
6
|
+
* The PreToolUse hook queries this to check cache status before deciding to allow/deny.
|
|
7
|
+
*/
|
|
8
|
+
export declare class IpcServer {
|
|
9
|
+
private server;
|
|
10
|
+
private port;
|
|
11
|
+
private config;
|
|
12
|
+
private indexer;
|
|
13
|
+
private db;
|
|
14
|
+
private stats;
|
|
15
|
+
constructor(config: CodeTreeConfig, indexer: Indexer, db: Database);
|
|
16
|
+
start(): Promise<number>;
|
|
17
|
+
getPort(): number;
|
|
18
|
+
stop(): void;
|
|
19
|
+
private writePortFile;
|
|
20
|
+
private handleRequest;
|
|
21
|
+
/**
|
|
22
|
+
* Check if a file Read can be served from cache.
|
|
23
|
+
* Returns { cached: true, tool: "codetree_read", path: "..." } or { cached: false }
|
|
24
|
+
*/
|
|
25
|
+
private handleCheck;
|
|
26
|
+
/**
|
|
27
|
+
* Check if a Grep search can be answered from the index.
|
|
28
|
+
*/
|
|
29
|
+
private handleCheckSearch;
|
|
30
|
+
/**
|
|
31
|
+
* Check if a Glob can be answered from the file tree.
|
|
32
|
+
*/
|
|
33
|
+
private handleCheckGlob;
|
|
34
|
+
private handleStatus;
|
|
35
|
+
private handleStats;
|
|
36
|
+
private persistStats;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=ipc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipc.d.ts","sourceRoot":"","sources":["../../src/server/ipc.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAGlE;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,EAAE,CAAW;IAGrB,OAAO,CAAC,KAAK,CAKX;gBAEU,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ;IAM5D,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAkB9B,OAAO,IAAI,MAAM;IAIjB,IAAI,IAAI,IAAI;IAQZ,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,aAAa;IA2BrB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAgCnB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;OAEG;IACH,OAAO,CAAC,eAAe;IA0BvB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,YAAY;CAWrB"}
|