clast-ai 0.1.1 → 0.2.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/.claude-plugin/marketplace.json +14 -0
- package/.claude-plugin/plugin.json +11 -9
- package/README.md +449 -390
- package/bench/ab/onair-concept.json +22 -0
- package/bench/ab/onair-deadcode.json +7 -0
- package/bench/ab/onair-hard.json +32 -0
- package/bench/ab/onair-impact.json +17 -0
- package/bench/ab/onair-refactors.json +18 -0
- package/bench/ab/onair-survey.json +17 -0
- package/bench/ab/onair-tasks.json +20 -0
- package/bench/ab/onair.json +52 -0
- package/bench/ab/vscode-concept.json +22 -0
- package/bench/ab/vscode-hard.json +32 -0
- package/bench/ab/vscode-impact.json +17 -0
- package/bench/ab/vscode-refactors.json +18 -0
- package/bench/ab/vscode-tasks.json +20 -0
- package/bench/ab/vscode.json +52 -0
- package/bench/ab.mjs +213 -0
- package/bench/bench.mjs +98 -0
- package/bench/resolution.mjs +75 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +257 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/defaults.d.ts +12 -2
- package/dist/config/defaults.js +38 -31
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +26 -14
- package/dist/config/index.js.map +1 -1
- package/dist/db/index.d.ts +73 -13
- package/dist/db/index.js +481 -39
- package/dist/db/index.js.map +1 -1
- package/dist/engine.d.ts +15 -0
- package/dist/engine.js +28 -0
- package/dist/engine.js.map +1 -0
- package/dist/indexer/imports.d.ts +6 -0
- package/dist/indexer/imports.js +254 -0
- package/dist/indexer/imports.js.map +1 -0
- package/dist/indexer/index.d.ts +63 -0
- package/dist/indexer/index.js +360 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/process.d.ts +22 -0
- package/dist/indexer/process.js +42 -0
- package/dist/indexer/process.js.map +1 -0
- package/dist/indexer/scan.d.ts +43 -0
- package/dist/indexer/scan.js +223 -0
- package/dist/indexer/scan.js.map +1 -0
- package/dist/indexer/worker.d.ts +1 -0
- package/dist/indexer/worker.js +23 -0
- package/dist/indexer/worker.js.map +1 -0
- package/dist/llm/comment-generator.d.ts +17 -19
- package/dist/llm/comment-generator.js +46 -80
- package/dist/llm/comment-generator.js.map +1 -1
- package/dist/llm/index.d.ts +0 -1
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/prompts.d.ts +0 -1
- package/dist/llm/prompts.js +16 -16
- package/dist/parser/extractor.d.ts +21 -16
- package/dist/parser/extractor.js +700 -228
- package/dist/parser/extractor.js.map +1 -1
- package/dist/parser/index.d.ts +17 -21
- package/dist/parser/index.js +115 -171
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/langs/c.d.ts +3 -0
- package/dist/parser/langs/c.js +879 -0
- package/dist/parser/langs/c.js.map +1 -0
- package/dist/parser/langs/csharp.d.ts +2 -0
- package/dist/parser/langs/csharp.js +548 -0
- package/dist/parser/langs/csharp.js.map +1 -0
- package/dist/parser/langs/dart.d.ts +2 -0
- package/dist/parser/langs/dart.js +893 -0
- package/dist/parser/langs/dart.js.map +1 -0
- package/dist/parser/langs/go.d.ts +2 -0
- package/dist/parser/langs/go.js +455 -0
- package/dist/parser/langs/go.js.map +1 -0
- package/dist/parser/langs/java.d.ts +2 -0
- package/dist/parser/langs/java.js +390 -0
- package/dist/parser/langs/java.js.map +1 -0
- package/dist/parser/langs/php.d.ts +2 -0
- package/dist/parser/langs/php.js +486 -0
- package/dist/parser/langs/php.js.map +1 -0
- package/dist/parser/langs/python.d.ts +2 -0
- package/dist/parser/langs/python.js +216 -0
- package/dist/parser/langs/python.js.map +1 -0
- package/dist/parser/langs/ruby.d.ts +2 -0
- package/dist/parser/langs/ruby.js +602 -0
- package/dist/parser/langs/ruby.js.map +1 -0
- package/dist/parser/langs/rust.d.ts +2 -0
- package/dist/parser/langs/rust.js +931 -0
- package/dist/parser/langs/rust.js.map +1 -0
- package/dist/parser/langs/swift.d.ts +2 -0
- package/dist/parser/langs/swift.js +616 -0
- package/dist/parser/langs/swift.js.map +1 -0
- package/dist/parser/langs/typescript.d.ts +4 -0
- package/dist/parser/langs/typescript.js +535 -0
- package/dist/parser/langs/typescript.js.map +1 -0
- package/dist/parser/registry.d.ts +16 -0
- package/dist/parser/registry.js +87 -0
- package/dist/parser/registry.js.map +1 -0
- package/dist/parser/returns.d.ts +9 -0
- package/dist/parser/returns.js +152 -0
- package/dist/parser/returns.js.map +1 -0
- package/dist/parser/spec.d.ts +165 -0
- package/dist/parser/spec.js +188 -0
- package/dist/parser/spec.js.map +1 -0
- package/dist/query/arity.d.ts +27 -0
- package/dist/query/arity.js +187 -0
- package/dist/query/arity.js.map +1 -0
- package/dist/query/callgraph.d.ts +113 -0
- package/dist/query/callgraph.js +332 -0
- package/dist/query/callgraph.js.map +1 -0
- package/dist/query/format.d.ts +36 -0
- package/dist/query/format.js +136 -0
- package/dist/query/format.js.map +1 -0
- package/dist/query/hierarchy.d.ts +44 -0
- package/dist/query/hierarchy.js +441 -0
- package/dist/query/hierarchy.js.map +1 -0
- package/dist/query/resolve.d.ts +265 -0
- package/dist/query/resolve.js +1957 -0
- package/dist/query/resolve.js.map +1 -0
- package/dist/query/search.d.ts +35 -0
- package/dist/query/search.js +379 -0
- package/dist/query/search.js.map +1 -0
- package/dist/query/words.d.ts +30 -0
- package/dist/query/words.js +201 -0
- package/dist/query/words.js.map +1 -0
- package/dist/server/index.d.ts +1 -3
- package/dist/server/index.js +313 -73
- package/dist/server/index.js.map +1 -1
- package/dist/tools/context.d.ts +35 -0
- package/dist/tools/context.js +79 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/explore.d.ts +51 -0
- package/dist/tools/explore.js +779 -0
- package/dist/tools/explore.js.map +1 -0
- package/dist/tools/impact.d.ts +21 -0
- package/dist/tools/impact.js +743 -0
- package/dist/tools/impact.js.map +1 -0
- package/dist/tools/search.d.ts +59 -0
- package/dist/tools/search.js +843 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/stats.d.ts +26 -0
- package/dist/tools/stats.js +604 -0
- package/dist/tools/stats.js.map +1 -0
- package/dist/types.d.ts +95 -40
- package/dist/types.js +9 -1
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/dist/watcher/index.d.ts +18 -16
- package/dist/watcher/index.js +94 -77
- package/dist/watcher/index.js.map +1 -1
- package/package.json +21 -24
- package/plugin/server.mjs +50 -0
- package/skills/audit/SKILL.md +37 -0
- package/skills/deadcode/SKILL.md +33 -0
- package/skills/explore/SKILL.md +54 -0
- package/skills/impact/SKILL.md +24 -0
- package/skills/status/SKILL.md +11 -0
- package/src/cli.ts +256 -0
- package/src/config/defaults.ts +50 -32
- package/src/config/index.ts +23 -14
- package/src/db/index.ts +540 -43
- package/src/engine.ts +30 -0
- package/src/indexer/imports.ts +241 -0
- package/src/indexer/index.ts +369 -0
- package/src/indexer/process.ts +63 -0
- package/src/indexer/scan.ts +226 -0
- package/src/indexer/worker.ts +24 -0
- package/src/llm/comment-generator.ts +52 -103
- package/src/llm/index.ts +80 -80
- package/src/llm/prompts.ts +95 -95
- package/src/parser/extractor.ts +643 -256
- package/src/parser/index.ts +105 -205
- package/src/parser/langs/c.ts +860 -0
- package/src/parser/langs/csharp.ts +519 -0
- package/src/parser/langs/dart.ts +820 -0
- package/src/parser/langs/go.ts +437 -0
- package/src/parser/langs/java.ts +361 -0
- package/src/parser/langs/php.ts +450 -0
- package/src/parser/langs/python.ts +206 -0
- package/src/parser/langs/ruby.ts +554 -0
- package/src/parser/langs/rust.ts +904 -0
- package/src/parser/langs/swift.ts +590 -0
- package/src/parser/langs/typescript.ts +499 -0
- package/src/parser/registry.ts +88 -0
- package/src/parser/returns.ts +137 -0
- package/src/parser/spec.ts +309 -0
- package/src/query/arity.ts +173 -0
- package/src/query/callgraph.ts +473 -0
- package/src/query/format.ts +136 -0
- package/src/query/hierarchy.ts +447 -0
- package/src/query/resolve.ts +1972 -0
- package/src/query/search.ts +430 -0
- package/src/query/words.ts +183 -0
- package/src/server/index.ts +390 -79
- package/src/tools/context.ts +82 -0
- package/src/tools/explore.ts +860 -0
- package/src/tools/impact.ts +748 -0
- package/src/tools/search.ts +886 -0
- package/src/tools/stats.ts +633 -0
- package/src/types.ts +113 -45
- package/src/version.ts +2 -0
- package/src/watcher/index.ts +82 -88
- package/tsconfig.json +7 -4
- package/.mcp.json +0 -8
- package/commands/clast-status.md +0 -9
- package/dist/config/defaults.d.ts.map +0 -1
- package/dist/config/index.d.ts.map +0 -1
- package/dist/db/index.d.ts.map +0 -1
- package/dist/db/queries.d.ts +0 -44
- package/dist/db/queries.d.ts.map +0 -1
- package/dist/db/queries.js +0 -251
- package/dist/db/queries.js.map +0 -1
- package/dist/db/schema.d.ts +0 -3
- package/dist/db/schema.d.ts.map +0 -1
- package/dist/db/schema.js +0 -94
- package/dist/db/schema.js.map +0 -1
- package/dist/db/types.d.ts +0 -44
- package/dist/db/types.d.ts.map +0 -1
- package/dist/db/types.js +0 -2
- package/dist/db/types.js.map +0 -1
- package/dist/llm/comment-generator.d.ts.map +0 -1
- package/dist/llm/index.d.ts.map +0 -1
- package/dist/llm/prompts.d.ts.map +0 -1
- package/dist/parser/call-resolver.d.ts +0 -15
- package/dist/parser/call-resolver.d.ts.map +0 -1
- package/dist/parser/call-resolver.js +0 -16
- package/dist/parser/call-resolver.js.map +0 -1
- package/dist/parser/extractor.d.ts.map +0 -1
- package/dist/parser/index.d.ts.map +0 -1
- package/dist/parser/languages.d.ts +0 -11
- package/dist/parser/languages.d.ts.map +0 -1
- package/dist/parser/languages.js +0 -74
- package/dist/parser/languages.js.map +0 -1
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/register-tools.d.ts +0 -7
- package/dist/server/register-tools.d.ts.map +0 -1
- package/dist/server/register-tools.js +0 -17
- package/dist/server/register-tools.js.map +0 -1
- package/dist/server/tools/clast-call-graph.d.ts +0 -4
- package/dist/server/tools/clast-call-graph.d.ts.map +0 -1
- package/dist/server/tools/clast-call-graph.js +0 -70
- package/dist/server/tools/clast-call-graph.js.map +0 -1
- package/dist/server/tools/clast-comment.d.ts +0 -5
- package/dist/server/tools/clast-comment.d.ts.map +0 -1
- package/dist/server/tools/clast-comment.js +0 -64
- package/dist/server/tools/clast-comment.js.map +0 -1
- package/dist/server/tools/clast-file-summary.d.ts +0 -4
- package/dist/server/tools/clast-file-summary.d.ts.map +0 -1
- package/dist/server/tools/clast-file-summary.js +0 -42
- package/dist/server/tools/clast-file-summary.js.map +0 -1
- package/dist/server/tools/clast-get-context.d.ts +0 -4
- package/dist/server/tools/clast-get-context.d.ts.map +0 -1
- package/dist/server/tools/clast-get-context.js +0 -80
- package/dist/server/tools/clast-get-context.js.map +0 -1
- package/dist/server/tools/clast-reindex.d.ts +0 -5
- package/dist/server/tools/clast-reindex.d.ts.map +0 -1
- package/dist/server/tools/clast-reindex.js +0 -36
- package/dist/server/tools/clast-reindex.js.map +0 -1
- package/dist/server/tools/clast-search.d.ts +0 -4
- package/dist/server/tools/clast-search.d.ts.map +0 -1
- package/dist/server/tools/clast-search.js +0 -29
- package/dist/server/tools/clast-search.js.map +0 -1
- package/dist/server/tools/clast-status.d.ts +0 -5
- package/dist/server/tools/clast-status.d.ts.map +0 -1
- package/dist/server/tools/clast-status.js +0 -23
- package/dist/server/tools/clast-status.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/watcher/gitignore.d.ts +0 -9
- package/dist/watcher/gitignore.d.ts.map +0 -1
- package/dist/watcher/gitignore.js +0 -38
- package/dist/watcher/gitignore.js.map +0 -1
- package/dist/watcher/index.d.ts.map +0 -1
- package/skills/clast-explore/SKILL.md +0 -41
- package/src/db/queries.ts +0 -332
- package/src/db/schema.ts +0 -106
- package/src/db/types.ts +0 -47
- package/src/parser/call-resolver.ts +0 -17
- package/src/parser/languages.ts +0 -86
- package/src/server/register-tools.ts +0 -30
- package/src/server/tools/clast-call-graph.ts +0 -82
- package/src/server/tools/clast-comment.ts +0 -76
- package/src/server/tools/clast-file-summary.ts +0 -59
- package/src/server/tools/clast-get-context.ts +0 -97
- package/src/server/tools/clast-reindex.ts +0 -52
- package/src/server/tools/clast-search.ts +0 -38
- package/src/server/tools/clast-status.ts +0 -37
- package/src/watcher/gitignore.ts +0 -42
package/src/db/queries.ts
DELETED
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
import type { Database } from 'sql.js';
|
|
2
|
-
import type { FileRow, AstNodeRow, CallEdgeRow, CommentRow, StatusRow } from './types.js';
|
|
3
|
-
|
|
4
|
-
export class Queries {
|
|
5
|
-
private db: Database;
|
|
6
|
-
|
|
7
|
-
constructor(db: Database) {
|
|
8
|
-
this.db = db;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
private run(sql: string, params: unknown[] = []): void {
|
|
12
|
-
this.db.run(sql, params as (string | number | null | Uint8Array)[]);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
private get<T>(sql: string, params: unknown[] = []): T | undefined {
|
|
16
|
-
const result = this.db.exec(sql, params as (string | number | null | Uint8Array)[]);
|
|
17
|
-
if (result.length === 0 || result[0]!.values.length === 0) return undefined;
|
|
18
|
-
const columns = result[0]!.columns;
|
|
19
|
-
const values = result[0]!.values[0]!;
|
|
20
|
-
const obj: Record<string, unknown> = {};
|
|
21
|
-
for (let i = 0; i < columns.length; i++) {
|
|
22
|
-
obj[columns[i]!] = values[i];
|
|
23
|
-
}
|
|
24
|
-
return obj as T;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
private all<T>(sql: string, params: unknown[] = []): T[] {
|
|
28
|
-
const result = this.db.exec(sql, params as (string | number | null | Uint8Array)[]);
|
|
29
|
-
if (result.length === 0) return [];
|
|
30
|
-
const columns = result[0]!.columns;
|
|
31
|
-
return result[0]!.values.map(values => {
|
|
32
|
-
const obj: Record<string, unknown> = {};
|
|
33
|
-
for (let i = 0; i < columns.length; i++) {
|
|
34
|
-
obj[columns[i]!] = values[i];
|
|
35
|
-
}
|
|
36
|
-
return obj as T;
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private getLastInsertId(): number {
|
|
41
|
-
const result = this.db.exec('SELECT last_insert_rowid() as id');
|
|
42
|
-
if (result.length > 0 && result[0]!.values.length > 0) {
|
|
43
|
-
return Number(result[0]!.values[0]![0]);
|
|
44
|
-
}
|
|
45
|
-
return 0;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// --- File operations ---
|
|
49
|
-
|
|
50
|
-
upsertFile(filePath: string, hash: string, language: string, nodeCount: number): void {
|
|
51
|
-
this.run(
|
|
52
|
-
`INSERT OR REPLACE INTO files (file_path, hash, language, last_indexed, node_count)
|
|
53
|
-
VALUES (?, ?, ?, ?, ?)`,
|
|
54
|
-
[filePath, hash, language, Date.now(), nodeCount]
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
deleteFile(filePath: string): void {
|
|
59
|
-
// Manually cascade since sql.js foreign key cascade can be unreliable
|
|
60
|
-
this.run(`DELETE FROM comments WHERE node_id IN (SELECT id FROM ast_nodes WHERE file_path = ?)`, [filePath]);
|
|
61
|
-
this.run(`DELETE FROM call_edges WHERE caller_id IN (SELECT id FROM ast_nodes WHERE file_path = ?)`, [filePath]);
|
|
62
|
-
this.run(`DELETE FROM call_edges WHERE callee_id IN (SELECT id FROM ast_nodes WHERE file_path = ?)`, [filePath]);
|
|
63
|
-
this.run(`DELETE FROM ast_nodes WHERE file_path = ?`, [filePath]);
|
|
64
|
-
this.run(`DELETE FROM files WHERE file_path = ?`, [filePath]);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
getFileHash(filePath: string): string | null {
|
|
68
|
-
const row = this.get<{ hash: string }>(`SELECT hash FROM files WHERE file_path = ?`, [filePath]);
|
|
69
|
-
return row?.hash ?? null;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
getAllFiles(): FileRow[] {
|
|
73
|
-
return this.all<FileRow>(`SELECT * FROM files`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// --- Node operations ---
|
|
77
|
-
|
|
78
|
-
insertNode(node: Omit<AstNodeRow, 'id'>): number {
|
|
79
|
-
this.run(
|
|
80
|
-
`INSERT INTO ast_nodes (file_path, name, type, signature, start_line, end_line, start_col, end_col, parent_id, language, body_text)
|
|
81
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
82
|
-
[
|
|
83
|
-
node.file_path, node.name, node.type, node.signature,
|
|
84
|
-
node.start_line, node.end_line, node.start_col, node.end_col,
|
|
85
|
-
node.parent_id, node.language, node.body_text,
|
|
86
|
-
]
|
|
87
|
-
);
|
|
88
|
-
return this.getLastInsertId();
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
insertNodes(nodes: Omit<AstNodeRow, 'id'>[]): number[] {
|
|
92
|
-
const ids: number[] = [];
|
|
93
|
-
this.run('BEGIN TRANSACTION');
|
|
94
|
-
try {
|
|
95
|
-
for (const node of nodes) {
|
|
96
|
-
ids.push(this.insertNode(node));
|
|
97
|
-
}
|
|
98
|
-
this.run('COMMIT');
|
|
99
|
-
} catch (err) {
|
|
100
|
-
this.run('ROLLBACK');
|
|
101
|
-
throw err;
|
|
102
|
-
}
|
|
103
|
-
return ids;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
getNodeById(id: number): AstNodeRow | undefined {
|
|
107
|
-
return this.get<AstNodeRow>(`SELECT * FROM ast_nodes WHERE id = ?`, [id]);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
getNodeByName(name: string): AstNodeRow[] {
|
|
111
|
-
return this.all<AstNodeRow>(
|
|
112
|
-
`SELECT * FROM ast_nodes WHERE name = ? ORDER BY file_path, start_line`,
|
|
113
|
-
[name]
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
getNodesByFile(filePath: string): AstNodeRow[] {
|
|
118
|
-
return this.all<AstNodeRow>(
|
|
119
|
-
`SELECT * FROM ast_nodes WHERE file_path = ? ORDER BY start_line`,
|
|
120
|
-
[filePath]
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
searchNodes(query: string, type?: string, limit: number = 20): AstNodeRow[] {
|
|
125
|
-
const pattern = `%${query}%`;
|
|
126
|
-
if (type) {
|
|
127
|
-
return this.all<AstNodeRow>(
|
|
128
|
-
`SELECT * FROM ast_nodes WHERE name LIKE ? AND type = ? LIMIT ?`,
|
|
129
|
-
[pattern, type, limit]
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
return this.all<AstNodeRow>(
|
|
133
|
-
`SELECT * FROM ast_nodes WHERE name LIKE ? LIMIT ?`,
|
|
134
|
-
[pattern, limit]
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// --- Edge operations ---
|
|
139
|
-
|
|
140
|
-
insertEdge(edge: Omit<CallEdgeRow, 'id'>): number {
|
|
141
|
-
this.run(
|
|
142
|
-
`INSERT INTO call_edges (caller_id, callee_id, callee_name, file_path, line)
|
|
143
|
-
VALUES (?, ?, ?, ?, ?)`,
|
|
144
|
-
[edge.caller_id, edge.callee_id, edge.callee_name, edge.file_path, edge.line]
|
|
145
|
-
);
|
|
146
|
-
return this.getLastInsertId();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
insertEdges(edges: Omit<CallEdgeRow, 'id'>[]): void {
|
|
150
|
-
this.run('BEGIN TRANSACTION');
|
|
151
|
-
try {
|
|
152
|
-
for (const edge of edges) {
|
|
153
|
-
this.insertEdge(edge);
|
|
154
|
-
}
|
|
155
|
-
this.run('COMMIT');
|
|
156
|
-
} catch (err) {
|
|
157
|
-
this.run('ROLLBACK');
|
|
158
|
-
throw err;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
getCallersOf(nameOrId: string | number, depth: number = 2): AstNodeRow[] {
|
|
163
|
-
const whereClause = typeof nameOrId === 'number'
|
|
164
|
-
? 'callee_id = ?'
|
|
165
|
-
: 'callee_name = ?';
|
|
166
|
-
|
|
167
|
-
const sql = `
|
|
168
|
-
WITH RECURSIVE caller_chain(id, depth) AS (
|
|
169
|
-
SELECT caller_id, 1
|
|
170
|
-
FROM call_edges
|
|
171
|
-
WHERE ${whereClause}
|
|
172
|
-
UNION
|
|
173
|
-
SELECT ce.caller_id, cc.depth + 1
|
|
174
|
-
FROM call_edges ce
|
|
175
|
-
JOIN caller_chain cc ON ce.callee_id = cc.id
|
|
176
|
-
WHERE cc.depth < ?
|
|
177
|
-
)
|
|
178
|
-
SELECT DISTINCT an.* FROM ast_nodes an
|
|
179
|
-
JOIN caller_chain cc ON an.id = cc.id
|
|
180
|
-
ORDER BY an.file_path, an.start_line
|
|
181
|
-
`;
|
|
182
|
-
return this.all<AstNodeRow>(sql, [nameOrId, depth]);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
getCalleesOf(nameOrId: string | number, depth: number = 2): AstNodeRow[] {
|
|
186
|
-
const whereClause = typeof nameOrId === 'number'
|
|
187
|
-
? 'an.id = ?'
|
|
188
|
-
: 'an.name = ?';
|
|
189
|
-
|
|
190
|
-
const sql = `
|
|
191
|
-
WITH RECURSIVE callee_chain(id, name, depth) AS (
|
|
192
|
-
SELECT ce.callee_id, ce.callee_name, 1
|
|
193
|
-
FROM call_edges ce
|
|
194
|
-
JOIN ast_nodes an ON ce.caller_id = an.id
|
|
195
|
-
WHERE ${whereClause}
|
|
196
|
-
UNION
|
|
197
|
-
SELECT ce2.callee_id, ce2.callee_name, cc.depth + 1
|
|
198
|
-
FROM call_edges ce2
|
|
199
|
-
JOIN callee_chain cc ON ce2.caller_id = cc.id
|
|
200
|
-
WHERE cc.depth < ? AND cc.id IS NOT NULL
|
|
201
|
-
)
|
|
202
|
-
SELECT DISTINCT an.* FROM ast_nodes an
|
|
203
|
-
JOIN callee_chain cc ON an.id = cc.id
|
|
204
|
-
WHERE cc.id IS NOT NULL
|
|
205
|
-
ORDER BY an.file_path, an.start_line
|
|
206
|
-
`;
|
|
207
|
-
return this.all<AstNodeRow>(sql, [nameOrId, depth]);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
getCallEdgesForNode(nodeId: number): { outgoing: CallEdgeRow[]; incoming: CallEdgeRow[] } {
|
|
211
|
-
const outgoing = this.all<CallEdgeRow>(
|
|
212
|
-
`SELECT * FROM call_edges WHERE caller_id = ?`,
|
|
213
|
-
[nodeId]
|
|
214
|
-
);
|
|
215
|
-
const incoming = this.all<CallEdgeRow>(
|
|
216
|
-
`SELECT * FROM call_edges WHERE callee_id = ?`,
|
|
217
|
-
[nodeId]
|
|
218
|
-
);
|
|
219
|
-
return { outgoing, incoming };
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// --- Comment operations ---
|
|
223
|
-
|
|
224
|
-
insertComment(nodeId: number, text: string, source: 'original' | 'generated'): number {
|
|
225
|
-
this.run(
|
|
226
|
-
`INSERT INTO comments (node_id, text, source, generated_at)
|
|
227
|
-
VALUES (?, ?, ?, ?)`,
|
|
228
|
-
[nodeId, text, source, source === 'generated' ? Date.now() : null]
|
|
229
|
-
);
|
|
230
|
-
return this.getLastInsertId();
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
getCommentsForNode(nodeId: number): CommentRow[] {
|
|
234
|
-
return this.all<CommentRow>(`SELECT * FROM comments WHERE node_id = ?`, [nodeId]);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
deleteCommentsBySource(nodeId: number, source: 'original' | 'generated'): void {
|
|
238
|
-
this.run(`DELETE FROM comments WHERE node_id = ? AND source = ?`, [nodeId, source]);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// --- Context (combined) ---
|
|
242
|
-
|
|
243
|
-
getNodeWithContext(name: string): {
|
|
244
|
-
nodes: AstNodeRow[];
|
|
245
|
-
comments: CommentRow[];
|
|
246
|
-
callers: AstNodeRow[];
|
|
247
|
-
callees: AstNodeRow[];
|
|
248
|
-
} {
|
|
249
|
-
const nodes = this.getNodeByName(name);
|
|
250
|
-
if (nodes.length === 0) {
|
|
251
|
-
return { nodes: [], comments: [], callers: [], callees: [] };
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const allComments: CommentRow[] = [];
|
|
255
|
-
for (const node of nodes) {
|
|
256
|
-
allComments.push(...this.getCommentsForNode(node.id));
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const callers = this.getCallersOf(name, 1);
|
|
260
|
-
const callees = this.getCalleesOf(name, 1);
|
|
261
|
-
|
|
262
|
-
return { nodes, comments: allComments, callers, callees };
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// --- Status ---
|
|
266
|
-
|
|
267
|
-
getStatus(): StatusRow {
|
|
268
|
-
const result = this.get<StatusRow>(`
|
|
269
|
-
SELECT
|
|
270
|
-
(SELECT COUNT(*) FROM files) as files_indexed,
|
|
271
|
-
(SELECT COUNT(*) FROM ast_nodes) as total_nodes,
|
|
272
|
-
(SELECT COUNT(*) FROM call_edges) as total_edges,
|
|
273
|
-
(SELECT COUNT(*) FROM comments) as total_comments,
|
|
274
|
-
(SELECT MAX(last_indexed) FROM files) as last_indexed
|
|
275
|
-
`);
|
|
276
|
-
return result ?? {
|
|
277
|
-
files_indexed: 0,
|
|
278
|
-
total_nodes: 0,
|
|
279
|
-
total_edges: 0,
|
|
280
|
-
total_comments: 0,
|
|
281
|
-
last_indexed: null,
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// --- Bulk operations ---
|
|
286
|
-
|
|
287
|
-
deleteNodesForFile(filePath: string): void {
|
|
288
|
-
this.run(`DELETE FROM comments WHERE node_id IN (SELECT id FROM ast_nodes WHERE file_path = ?)`, [filePath]);
|
|
289
|
-
this.run(`DELETE FROM call_edges WHERE caller_id IN (SELECT id FROM ast_nodes WHERE file_path = ?)`, [filePath]);
|
|
290
|
-
this.run(`DELETE FROM ast_nodes WHERE file_path = ?`, [filePath]);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
resolveEdges(): number {
|
|
294
|
-
// Count unresolved before
|
|
295
|
-
const before = this.get<{ cnt: number }>(
|
|
296
|
-
`SELECT COUNT(*) as cnt FROM call_edges WHERE callee_id IS NULL`
|
|
297
|
-
);
|
|
298
|
-
const beforeCount = before?.cnt ?? 0;
|
|
299
|
-
|
|
300
|
-
this.run(`
|
|
301
|
-
UPDATE call_edges
|
|
302
|
-
SET callee_id = (
|
|
303
|
-
SELECT an.id FROM ast_nodes an
|
|
304
|
-
WHERE an.name = call_edges.callee_name
|
|
305
|
-
LIMIT 1
|
|
306
|
-
)
|
|
307
|
-
WHERE callee_id IS NULL
|
|
308
|
-
`);
|
|
309
|
-
|
|
310
|
-
const after = this.get<{ cnt: number }>(
|
|
311
|
-
`SELECT COUNT(*) as cnt FROM call_edges WHERE callee_id IS NULL`
|
|
312
|
-
);
|
|
313
|
-
const afterCount = after?.cnt ?? 0;
|
|
314
|
-
|
|
315
|
-
return beforeCount - afterCount;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
getNodesWithoutComments(limit: number = 100): AstNodeRow[] {
|
|
319
|
-
return this.all<AstNodeRow>(`
|
|
320
|
-
SELECT an.* FROM ast_nodes an
|
|
321
|
-
LEFT JOIN comments c ON an.id = c.node_id
|
|
322
|
-
WHERE c.id IS NULL
|
|
323
|
-
AND an.type IN ('function', 'method', 'class', 'interface', 'struct', 'trait')
|
|
324
|
-
LIMIT ?
|
|
325
|
-
`, [limit]);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/** Flush the in-memory database to a Uint8Array for saving to disk. */
|
|
329
|
-
export(): Uint8Array {
|
|
330
|
-
return this.db.export();
|
|
331
|
-
}
|
|
332
|
-
}
|
package/src/db/schema.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import type { Database } from 'sql.js';
|
|
2
|
-
|
|
3
|
-
const SCHEMA_VERSION = 1;
|
|
4
|
-
|
|
5
|
-
const CREATE_TABLES = `
|
|
6
|
-
CREATE TABLE IF NOT EXISTS _clast_meta (
|
|
7
|
-
key TEXT PRIMARY KEY,
|
|
8
|
-
value TEXT NOT NULL
|
|
9
|
-
);
|
|
10
|
-
|
|
11
|
-
CREATE TABLE IF NOT EXISTS files (
|
|
12
|
-
file_path TEXT PRIMARY KEY,
|
|
13
|
-
hash TEXT NOT NULL,
|
|
14
|
-
language TEXT NOT NULL,
|
|
15
|
-
last_indexed INTEGER NOT NULL,
|
|
16
|
-
node_count INTEGER NOT NULL DEFAULT 0
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
CREATE TABLE IF NOT EXISTS ast_nodes (
|
|
20
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
21
|
-
file_path TEXT NOT NULL,
|
|
22
|
-
name TEXT NOT NULL,
|
|
23
|
-
type TEXT NOT NULL,
|
|
24
|
-
signature TEXT NOT NULL DEFAULT '',
|
|
25
|
-
start_line INTEGER NOT NULL,
|
|
26
|
-
end_line INTEGER NOT NULL,
|
|
27
|
-
start_col INTEGER NOT NULL,
|
|
28
|
-
end_col INTEGER NOT NULL,
|
|
29
|
-
parent_id INTEGER,
|
|
30
|
-
language TEXT NOT NULL,
|
|
31
|
-
body_text TEXT NOT NULL DEFAULT '',
|
|
32
|
-
FOREIGN KEY (file_path) REFERENCES files(file_path) ON DELETE CASCADE,
|
|
33
|
-
FOREIGN KEY (parent_id) REFERENCES ast_nodes(id) ON DELETE CASCADE
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
CREATE INDEX IF NOT EXISTS idx_nodes_name ON ast_nodes(name);
|
|
37
|
-
CREATE INDEX IF NOT EXISTS idx_nodes_type ON ast_nodes(type);
|
|
38
|
-
CREATE INDEX IF NOT EXISTS idx_nodes_file ON ast_nodes(file_path);
|
|
39
|
-
CREATE INDEX IF NOT EXISTS idx_nodes_name_type ON ast_nodes(name, type);
|
|
40
|
-
|
|
41
|
-
CREATE TABLE IF NOT EXISTS call_edges (
|
|
42
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
43
|
-
caller_id INTEGER NOT NULL,
|
|
44
|
-
callee_id INTEGER,
|
|
45
|
-
callee_name TEXT NOT NULL,
|
|
46
|
-
file_path TEXT NOT NULL,
|
|
47
|
-
line INTEGER NOT NULL,
|
|
48
|
-
FOREIGN KEY (caller_id) REFERENCES ast_nodes(id) ON DELETE CASCADE,
|
|
49
|
-
FOREIGN KEY (callee_id) REFERENCES ast_nodes(id) ON DELETE SET NULL
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
CREATE INDEX IF NOT EXISTS idx_edges_caller ON call_edges(caller_id);
|
|
53
|
-
CREATE INDEX IF NOT EXISTS idx_edges_callee ON call_edges(callee_id);
|
|
54
|
-
CREATE INDEX IF NOT EXISTS idx_edges_callee_name ON call_edges(callee_name);
|
|
55
|
-
|
|
56
|
-
CREATE TABLE IF NOT EXISTS comments (
|
|
57
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
58
|
-
node_id INTEGER NOT NULL,
|
|
59
|
-
text TEXT NOT NULL,
|
|
60
|
-
source TEXT NOT NULL CHECK(source IN ('original', 'generated')),
|
|
61
|
-
generated_at INTEGER,
|
|
62
|
-
FOREIGN KEY (node_id) REFERENCES ast_nodes(id) ON DELETE CASCADE
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
CREATE INDEX IF NOT EXISTS idx_comments_node ON comments(node_id);
|
|
66
|
-
`;
|
|
67
|
-
|
|
68
|
-
export function initializeSchema(db: Database): void {
|
|
69
|
-
db.run('PRAGMA foreign_keys = ON');
|
|
70
|
-
|
|
71
|
-
const currentVersion = getSchemaVersion(db);
|
|
72
|
-
|
|
73
|
-
if (currentVersion < SCHEMA_VERSION) {
|
|
74
|
-
// sql.js doesn't support multi-statement exec with CREATE TABLE IF NOT EXISTS well,
|
|
75
|
-
// so we split and execute each statement
|
|
76
|
-
const statements = CREATE_TABLES.split(';')
|
|
77
|
-
.map(s => s.trim())
|
|
78
|
-
.filter(s => s.length > 0);
|
|
79
|
-
|
|
80
|
-
for (const stmt of statements) {
|
|
81
|
-
db.run(stmt);
|
|
82
|
-
}
|
|
83
|
-
setSchemaVersion(db, SCHEMA_VERSION);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function getSchemaVersion(db: Database): number {
|
|
88
|
-
try {
|
|
89
|
-
const result = db.exec(
|
|
90
|
-
`SELECT value FROM _clast_meta WHERE key = 'schema_version'`
|
|
91
|
-
);
|
|
92
|
-
if (result.length > 0 && result[0]!.values.length > 0) {
|
|
93
|
-
return parseInt(String(result[0]!.values[0]![0]), 10);
|
|
94
|
-
}
|
|
95
|
-
return 0;
|
|
96
|
-
} catch {
|
|
97
|
-
return 0;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function setSchemaVersion(db: Database, version: number): void {
|
|
102
|
-
db.run(
|
|
103
|
-
`INSERT OR REPLACE INTO _clast_meta (key, value) VALUES ('schema_version', ?)`,
|
|
104
|
-
[String(version)]
|
|
105
|
-
);
|
|
106
|
-
}
|
package/src/db/types.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export interface FileRow {
|
|
2
|
-
file_path: string;
|
|
3
|
-
hash: string;
|
|
4
|
-
language: string;
|
|
5
|
-
last_indexed: number;
|
|
6
|
-
node_count: number;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface AstNodeRow {
|
|
10
|
-
id: number;
|
|
11
|
-
file_path: string;
|
|
12
|
-
name: string;
|
|
13
|
-
type: string;
|
|
14
|
-
signature: string;
|
|
15
|
-
start_line: number;
|
|
16
|
-
end_line: number;
|
|
17
|
-
start_col: number;
|
|
18
|
-
end_col: number;
|
|
19
|
-
parent_id: number | null;
|
|
20
|
-
language: string;
|
|
21
|
-
body_text: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface CallEdgeRow {
|
|
25
|
-
id: number;
|
|
26
|
-
caller_id: number;
|
|
27
|
-
callee_id: number | null;
|
|
28
|
-
callee_name: string;
|
|
29
|
-
file_path: string;
|
|
30
|
-
line: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface CommentRow {
|
|
34
|
-
id: number;
|
|
35
|
-
node_id: number;
|
|
36
|
-
text: string;
|
|
37
|
-
source: 'original' | 'generated';
|
|
38
|
-
generated_at: number | null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface StatusRow {
|
|
42
|
-
files_indexed: number;
|
|
43
|
-
total_nodes: number;
|
|
44
|
-
total_edges: number;
|
|
45
|
-
total_comments: number;
|
|
46
|
-
last_indexed: number | null;
|
|
47
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { Queries } from '../db/queries.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Resolves unresolved call edges in the database.
|
|
5
|
-
*
|
|
6
|
-
* After all files are parsed and nodes inserted, call edges may have
|
|
7
|
-
* callee_id = null because the callee wasn't inserted yet. This resolver
|
|
8
|
-
* attempts to match callee_name to ast_nodes.name.
|
|
9
|
-
*
|
|
10
|
-
* Resolution strategy (best-effort):
|
|
11
|
-
* 1. Exact name match within the same file
|
|
12
|
-
* 2. Exact name match across all files
|
|
13
|
-
* 3. Leave unresolved if no match
|
|
14
|
-
*/
|
|
15
|
-
export function resolveCallEdges(queries: Queries): number {
|
|
16
|
-
return queries.resolveEdges();
|
|
17
|
-
}
|
package/src/parser/languages.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { join, dirname } from 'node:path';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { createRequire } from 'node:module';
|
|
5
|
-
|
|
6
|
-
interface LanguageEntry {
|
|
7
|
-
name: string;
|
|
8
|
-
extensions: string[];
|
|
9
|
-
wasmFile: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const LANGUAGES: LanguageEntry[] = [
|
|
13
|
-
{ name: 'typescript', extensions: ['.ts'], wasmFile: 'tree-sitter-typescript.wasm' },
|
|
14
|
-
{ name: 'tsx', extensions: ['.tsx'], wasmFile: 'tree-sitter-tsx.wasm' },
|
|
15
|
-
{ name: 'javascript', extensions: ['.js', '.jsx', '.mjs', '.cjs'], wasmFile: 'tree-sitter-javascript.wasm' },
|
|
16
|
-
{ name: 'python', extensions: ['.py', '.pyw'], wasmFile: 'tree-sitter-python.wasm' },
|
|
17
|
-
{ name: 'java', extensions: ['.java'], wasmFile: 'tree-sitter-java.wasm' },
|
|
18
|
-
{ name: 'csharp', extensions: ['.cs'], wasmFile: 'tree-sitter-c_sharp.wasm' },
|
|
19
|
-
{ name: 'go', extensions: ['.go'], wasmFile: 'tree-sitter-go.wasm' },
|
|
20
|
-
{ name: 'rust', extensions: ['.rs'], wasmFile: 'tree-sitter-rust.wasm' },
|
|
21
|
-
{ name: 'c', extensions: ['.c', '.h'], wasmFile: 'tree-sitter-c.wasm' },
|
|
22
|
-
{ name: 'cpp', extensions: ['.cpp', '.hpp', '.cc', '.hh', '.cxx', '.hxx'], wasmFile: 'tree-sitter-cpp.wasm' },
|
|
23
|
-
{ name: 'ruby', extensions: ['.rb'], wasmFile: 'tree-sitter-ruby.wasm' },
|
|
24
|
-
{ name: 'php', extensions: ['.php'], wasmFile: 'tree-sitter-php.wasm' },
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
// Extension → language entry mapping
|
|
28
|
-
const EXT_MAP = new Map<string, LanguageEntry>();
|
|
29
|
-
for (const lang of LANGUAGES) {
|
|
30
|
-
for (const ext of lang.extensions) {
|
|
31
|
-
EXT_MAP.set(ext, lang);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function getLanguageForExtension(ext: string): LanguageEntry | undefined {
|
|
36
|
-
return EXT_MAP.get(ext.toLowerCase());
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function getGrammarWasmPath(langName: string): string | null {
|
|
40
|
-
const entry = LANGUAGES.find(l => l.name === langName);
|
|
41
|
-
if (!entry) return null;
|
|
42
|
-
|
|
43
|
-
// Try to resolve from tree-sitter-wasms npm package first
|
|
44
|
-
const require = createRequire(import.meta.url);
|
|
45
|
-
try {
|
|
46
|
-
const wasmsDir = dirname(require.resolve('tree-sitter-wasms/package.json'));
|
|
47
|
-
const npmPath = join(wasmsDir, 'out', entry.wasmFile);
|
|
48
|
-
if (existsSync(npmPath)) return npmPath;
|
|
49
|
-
} catch {
|
|
50
|
-
// tree-sitter-wasms not installed, try fallbacks
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
54
|
-
|
|
55
|
-
// Check grammars/ directory relative to project
|
|
56
|
-
const candidates = [
|
|
57
|
-
// Custom grammars dir (env override)
|
|
58
|
-
process.env.CLAST_GRAMMARS_DIR ? join(process.env.CLAST_GRAMMARS_DIR, entry.wasmFile) : null,
|
|
59
|
-
// Plugin root
|
|
60
|
-
process.env.CLAUDE_PLUGIN_ROOT ? join(process.env.CLAUDE_PLUGIN_ROOT, 'grammars', entry.wasmFile) : null,
|
|
61
|
-
// Relative to dist/
|
|
62
|
-
join(__dirname, '..', '..', 'grammars', entry.wasmFile),
|
|
63
|
-
// CWD
|
|
64
|
-
join(process.cwd(), 'grammars', entry.wasmFile),
|
|
65
|
-
].filter(Boolean) as string[];
|
|
66
|
-
|
|
67
|
-
for (const candidate of candidates) {
|
|
68
|
-
if (existsSync(candidate)) return candidate;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function getSupportedExtensions(enabledLanguages?: string[]): string[] {
|
|
75
|
-
const result: string[] = [];
|
|
76
|
-
for (const lang of LANGUAGES) {
|
|
77
|
-
if (!enabledLanguages || enabledLanguages.includes(lang.name)) {
|
|
78
|
-
result.push(...lang.extensions);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return result;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function getAllLanguageNames(): string[] {
|
|
85
|
-
return LANGUAGES.map(l => l.name);
|
|
86
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import type { ClastDatabase } from '../db/index.js';
|
|
3
|
-
import type { ParserManager } from '../parser/index.js';
|
|
4
|
-
import type { FileWatcher } from '../watcher/index.js';
|
|
5
|
-
import type { CommentGenerator } from '../llm/comment-generator.js';
|
|
6
|
-
|
|
7
|
-
import { registerSearchTool } from './tools/clast-search.js';
|
|
8
|
-
import { registerCallGraphTool } from './tools/clast-call-graph.js';
|
|
9
|
-
import { registerFileSummaryTool } from './tools/clast-file-summary.js';
|
|
10
|
-
import { registerGetContextTool } from './tools/clast-get-context.js';
|
|
11
|
-
import { registerStatusTool } from './tools/clast-status.js';
|
|
12
|
-
import { registerReindexTool } from './tools/clast-reindex.js';
|
|
13
|
-
import { registerCommentTool } from './tools/clast-comment.js';
|
|
14
|
-
|
|
15
|
-
export function registerAllTools(
|
|
16
|
-
server: McpServer,
|
|
17
|
-
db: ClastDatabase,
|
|
18
|
-
parser: ParserManager,
|
|
19
|
-
watcher: FileWatcher,
|
|
20
|
-
commentGen: CommentGenerator,
|
|
21
|
-
projectRoot: string
|
|
22
|
-
): void {
|
|
23
|
-
registerSearchTool(server, db);
|
|
24
|
-
registerCallGraphTool(server, db);
|
|
25
|
-
registerFileSummaryTool(server, db);
|
|
26
|
-
registerGetContextTool(server, db);
|
|
27
|
-
registerStatusTool(server, db, watcher);
|
|
28
|
-
registerReindexTool(server, db, parser, projectRoot);
|
|
29
|
-
registerCommentTool(server, db, commentGen);
|
|
30
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
-
import type { ClastDatabase } from '../../db/index.js';
|
|
4
|
-
|
|
5
|
-
export function registerCallGraphTool(server: McpServer, db: ClastDatabase): void {
|
|
6
|
-
server.tool(
|
|
7
|
-
'clast_call_graph',
|
|
8
|
-
'Get the call graph for a function or method: what it calls (callees) and what calls it (callers). Use this BEFORE refactoring to understand impact — shows the full dependency chain with file paths and line numbers. Supports depth 1-5.',
|
|
9
|
-
{
|
|
10
|
-
name: z.string().describe('Function or method name to trace'),
|
|
11
|
-
depth: z.number().int().min(1).max(5).default(2).describe('How many levels deep to traverse'),
|
|
12
|
-
direction: z.enum(['callers', 'callees', 'both']).default('both').describe('Direction to traverse'),
|
|
13
|
-
},
|
|
14
|
-
async ({ name, depth, direction }) => {
|
|
15
|
-
const node = db.queries.getNodeByName(name);
|
|
16
|
-
if (node.length === 0) {
|
|
17
|
-
return {
|
|
18
|
-
content: [{
|
|
19
|
-
type: 'text' as const,
|
|
20
|
-
text: JSON.stringify({ error: `No symbol found with name "${name}"` }),
|
|
21
|
-
}],
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const result: Record<string, unknown> = {
|
|
26
|
-
symbol: {
|
|
27
|
-
name: node[0]!.name,
|
|
28
|
-
type: node[0]!.type,
|
|
29
|
-
filePath: node[0]!.file_path,
|
|
30
|
-
startLine: node[0]!.start_line,
|
|
31
|
-
endLine: node[0]!.end_line,
|
|
32
|
-
signature: node[0]!.signature,
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
if (direction === 'callers' || direction === 'both') {
|
|
37
|
-
const callers = db.queries.getCallersOf(name, depth);
|
|
38
|
-
result.callers = callers.map(n => ({
|
|
39
|
-
name: n.name,
|
|
40
|
-
type: n.type,
|
|
41
|
-
filePath: n.file_path,
|
|
42
|
-
startLine: n.start_line,
|
|
43
|
-
signature: n.signature,
|
|
44
|
-
}));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (direction === 'callees' || direction === 'both') {
|
|
48
|
-
const callees = db.queries.getCalleesOf(name, depth);
|
|
49
|
-
result.callees = callees.map(n => ({
|
|
50
|
-
name: n.name,
|
|
51
|
-
type: n.type,
|
|
52
|
-
filePath: n.file_path,
|
|
53
|
-
startLine: n.start_line,
|
|
54
|
-
signature: n.signature,
|
|
55
|
-
}));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Also include direct call edge details for the primary node
|
|
59
|
-
if (node[0]) {
|
|
60
|
-
const edges = db.queries.getCallEdgesForNode(node[0].id);
|
|
61
|
-
result.directCalls = {
|
|
62
|
-
outgoing: edges.outgoing.map(e => ({
|
|
63
|
-
calleeName: e.callee_name,
|
|
64
|
-
line: e.line,
|
|
65
|
-
resolved: e.callee_id !== null,
|
|
66
|
-
})),
|
|
67
|
-
incoming: edges.incoming.map(e => ({
|
|
68
|
-
callerId: e.caller_id,
|
|
69
|
-
line: e.line,
|
|
70
|
-
})),
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
content: [{
|
|
76
|
-
type: 'text' as const,
|
|
77
|
-
text: JSON.stringify(result, null, 2),
|
|
78
|
-
}],
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
);
|
|
82
|
-
}
|