@mrclrchtr/supi-tree-sitter 1.7.0 → 1.8.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/README.md +26 -15
- package/node_modules/@mrclrchtr/supi-core/package.json +13 -2
- package/node_modules/@mrclrchtr/supi-core/src/api.ts +26 -92
- package/node_modules/@mrclrchtr/supi-core/src/config.ts +11 -0
- package/node_modules/@mrclrchtr/supi-core/src/context.ts +16 -0
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +26 -92
- package/node_modules/@mrclrchtr/supi-core/src/path.ts +2 -0
- package/node_modules/@mrclrchtr/supi-core/src/project.ts +15 -0
- package/node_modules/@mrclrchtr/supi-core/src/session.ts +4 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +2 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings.ts +9 -0
- package/node_modules/@mrclrchtr/supi-core/src/substrate-types.ts +11 -0
- package/node_modules/@mrclrchtr/supi-core/src/types.ts +2 -0
- package/package.json +2 -2
- package/src/session/runtime.ts +1 -1
- package/src/session/service-registry.ts +1 -1
- package/src/tool/guidance.ts +29 -25
- package/src/tool/handlers.ts +196 -0
- package/src/tool/register-tools.ts +107 -0
- package/src/tool/tool-specs.ts +117 -0
- package/src/tree-sitter.ts +4 -300
- package/src/tool/action-specs.ts +0 -92
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// Per-action handler functions for the focused tree_sitter tool surface.
|
|
2
|
+
//
|
|
3
|
+
// Each handler receives only the parameters it needs (no action dispatch).
|
|
4
|
+
// Handlers are shared between the extension factory (tree-sitter.ts) and the
|
|
5
|
+
// tool registration layer (register-tools.ts).
|
|
6
|
+
|
|
7
|
+
import { detectGrammar, isJsTsGrammar } from "../language.ts";
|
|
8
|
+
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
9
|
+
import {
|
|
10
|
+
formatNonSuccess,
|
|
11
|
+
formatOutlineItemsCapped,
|
|
12
|
+
MAX_ITEMS,
|
|
13
|
+
truncate,
|
|
14
|
+
truncatedNotice,
|
|
15
|
+
truncateText,
|
|
16
|
+
} from "./formatting.ts";
|
|
17
|
+
import { collectOutline } from "./outline.ts";
|
|
18
|
+
import { extractExports, extractImports, lookupCalleesAt, lookupNodeAt } from "./structure.ts";
|
|
19
|
+
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Outline — JS/TS only
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
export async function handleOutline(runtime: TreeSitterRuntime, file: string): Promise<string> {
|
|
25
|
+
const parseResult = await runtime.parseFile(file);
|
|
26
|
+
if (parseResult.kind !== "success") return formatNonSuccess(parseResult);
|
|
27
|
+
if (!isJsTsGrammar(parseResult.data.grammarId)) {
|
|
28
|
+
return "Unsupported language: outline is only supported for JavaScript and TypeScript files";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const { tree, source } = parseResult.data;
|
|
32
|
+
let items: ReturnType<typeof collectOutline>;
|
|
33
|
+
try {
|
|
34
|
+
items = collectOutline(tree.rootNode, source);
|
|
35
|
+
} finally {
|
|
36
|
+
tree.delete();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (items.length === 0) return `No structural declarations found in ${file}`;
|
|
40
|
+
|
|
41
|
+
const lines = [`## Outline: ${file}`, ""];
|
|
42
|
+
const { omitted } = formatOutlineItemsCapped(items, lines, MAX_ITEMS);
|
|
43
|
+
if (omitted) lines.push("", truncatedNotice(omitted, "outline items"));
|
|
44
|
+
return lines.join("\n");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Imports — JS/TS only
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
export async function handleImports(runtime: TreeSitterRuntime, file: string): Promise<string> {
|
|
52
|
+
const grammarId = detectGrammar(file);
|
|
53
|
+
if (grammarId && !isJsTsGrammar(grammarId)) {
|
|
54
|
+
return "Unsupported language: imports is only supported for JavaScript and TypeScript files";
|
|
55
|
+
}
|
|
56
|
+
const result = await extractImports(runtime, file);
|
|
57
|
+
if (result.kind !== "success") return formatNonSuccess(result);
|
|
58
|
+
|
|
59
|
+
const { data: imports } = result;
|
|
60
|
+
if (imports.length === 0) return `No imports found in ${file}`;
|
|
61
|
+
|
|
62
|
+
const { included, truncated } = truncate(imports, MAX_ITEMS);
|
|
63
|
+
const lines = [`## Imports: ${file}`, ""];
|
|
64
|
+
for (const imp of included) {
|
|
65
|
+
const r = imp.range;
|
|
66
|
+
lines.push(`- "${imp.moduleSpecifier}" (L${r.startLine}:${r.startCharacter})`);
|
|
67
|
+
}
|
|
68
|
+
if (truncated) lines.push("", truncatedNotice(truncated, "imports"));
|
|
69
|
+
return lines.join("\n");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Exports — JS/TS only
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
export async function handleExports(runtime: TreeSitterRuntime, file: string): Promise<string> {
|
|
77
|
+
const grammarId = detectGrammar(file);
|
|
78
|
+
if (grammarId && !isJsTsGrammar(grammarId)) {
|
|
79
|
+
return "Unsupported language: exports is only supported for JavaScript and TypeScript files";
|
|
80
|
+
}
|
|
81
|
+
const result = await extractExports(runtime, file);
|
|
82
|
+
if (result.kind !== "success") return formatNonSuccess(result);
|
|
83
|
+
|
|
84
|
+
const { data: exports } = result;
|
|
85
|
+
if (exports.length === 0) return `No exports found in ${file}`;
|
|
86
|
+
|
|
87
|
+
const { included, truncated } = truncate(exports, MAX_ITEMS);
|
|
88
|
+
const lines = [`## Exports: ${file}`, ""];
|
|
89
|
+
for (const exp of included) {
|
|
90
|
+
const r = exp.range;
|
|
91
|
+
const from = exp.moduleSpecifier ? ` from "${exp.moduleSpecifier}"` : "";
|
|
92
|
+
lines.push(`- ${exp.kind}: ${exp.name}${from} (L${r.startLine}:${r.startCharacter})`);
|
|
93
|
+
}
|
|
94
|
+
if (truncated) lines.push("", truncatedNotice(truncated, "exports"));
|
|
95
|
+
return lines.join("\n");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Node at position — all supported grammars
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
export async function handleNodeAt(
|
|
103
|
+
runtime: TreeSitterRuntime,
|
|
104
|
+
file: string,
|
|
105
|
+
line: number,
|
|
106
|
+
character: number,
|
|
107
|
+
): Promise<string> {
|
|
108
|
+
const result = await lookupNodeAt(runtime, file, line, character);
|
|
109
|
+
if (result.kind !== "success") return formatNonSuccess(result);
|
|
110
|
+
|
|
111
|
+
const { data } = result;
|
|
112
|
+
const lines = [
|
|
113
|
+
`## Node at ${file}:${line}:${character}`,
|
|
114
|
+
"",
|
|
115
|
+
`**Type:** ${data.type}`,
|
|
116
|
+
`**Range:** L${data.range.startLine}:${data.range.startCharacter} — L${data.range.endLine}:${data.range.endCharacter}`,
|
|
117
|
+
`**Text:** ${truncateText(data.text, 200)}`,
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
if (data.ancestry.length > 0) {
|
|
121
|
+
lines.push("", "**Ancestry:**");
|
|
122
|
+
const { included, truncated } = truncate(data.ancestry, MAX_ITEMS);
|
|
123
|
+
for (const ancestor of included) {
|
|
124
|
+
lines.push(
|
|
125
|
+
`- ${ancestor.type} (L${ancestor.range.startLine}:${ancestor.range.startCharacter}-L${ancestor.range.endLine}:${ancestor.range.endCharacter})`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
if (truncated) lines.push("", truncatedNotice(truncated, "ancestry entries"));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return lines.join("\n");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Query — all supported grammars
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
|
|
138
|
+
export async function handleQuery(
|
|
139
|
+
runtime: TreeSitterRuntime,
|
|
140
|
+
file: string,
|
|
141
|
+
query: string,
|
|
142
|
+
): Promise<string> {
|
|
143
|
+
const result = await runtime.queryFile(file, query);
|
|
144
|
+
if (result.kind !== "success") return formatNonSuccess(result);
|
|
145
|
+
|
|
146
|
+
const { data: captures } = result;
|
|
147
|
+
if (captures.length === 0) return `No matches for query in ${file}`;
|
|
148
|
+
|
|
149
|
+
const { included, truncated } = truncate(captures, MAX_ITEMS);
|
|
150
|
+
const lines = [`## Query results: ${file}`, ""];
|
|
151
|
+
for (const capture of included) {
|
|
152
|
+
const r = capture.range;
|
|
153
|
+
lines.push(
|
|
154
|
+
`- ${capture.name}: ${capture.nodeType} (L${r.startLine}:${r.startCharacter}-L${r.endLine}:${r.endCharacter})`,
|
|
155
|
+
);
|
|
156
|
+
lines.push(` \`${truncateText(capture.text, 120)}\``);
|
|
157
|
+
}
|
|
158
|
+
if (truncated) lines.push("", truncatedNotice(truncated, "captures"));
|
|
159
|
+
return lines.join("\n");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// Callees — many supported grammars
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
export async function handleCallees(
|
|
167
|
+
runtime: TreeSitterRuntime,
|
|
168
|
+
file: string,
|
|
169
|
+
line: number,
|
|
170
|
+
character: number,
|
|
171
|
+
): Promise<string> {
|
|
172
|
+
const result = await lookupCalleesAt(runtime, file, line, character);
|
|
173
|
+
if (result.kind !== "success") return formatNonSuccess(result);
|
|
174
|
+
|
|
175
|
+
const { enclosingScope, callees } = result.data;
|
|
176
|
+
if (callees.length === 0) {
|
|
177
|
+
return `No outgoing calls found in \`${enclosingScope.name}\` at ${file}:${line}:${character}`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const lines: string[] = [];
|
|
181
|
+
lines.push(`## Callees: ${file}:${line}:${character}`);
|
|
182
|
+
lines.push("");
|
|
183
|
+
lines.push(
|
|
184
|
+
`**${callees.length} outgoing call${callees.length > 1 ? "s" : ""}** from \`${enclosingScope.name}\` at L${enclosingScope.range.startLine}-L${enclosingScope.range.endLine}`,
|
|
185
|
+
);
|
|
186
|
+
lines.push("");
|
|
187
|
+
|
|
188
|
+
for (const c of callees.slice(0, MAX_ITEMS)) {
|
|
189
|
+
lines.push(`- \`${c.name}\` (L${c.range.startLine})`);
|
|
190
|
+
}
|
|
191
|
+
if (callees.length > MAX_ITEMS) {
|
|
192
|
+
lines.push("", truncatedNotice(callees.length - MAX_ITEMS, "callees"));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return lines.join("\n");
|
|
196
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Focused tool registration for the tree_sitter extension.
|
|
2
|
+
//
|
|
3
|
+
// Derives tool metadata, schemas, and prompt surfaces from tool-specs.ts.
|
|
4
|
+
// Handler functions from ./handlers.ts do the actual work.
|
|
5
|
+
|
|
6
|
+
import type { AgentToolResult, ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import type { TreeSitterRuntime } from "../session/runtime.ts";
|
|
8
|
+
import {
|
|
9
|
+
handleCallees,
|
|
10
|
+
handleExports,
|
|
11
|
+
handleImports,
|
|
12
|
+
handleNodeAt,
|
|
13
|
+
handleOutline,
|
|
14
|
+
handleQuery,
|
|
15
|
+
} from "./handlers.ts";
|
|
16
|
+
import {
|
|
17
|
+
getTreeSitterToolSpec,
|
|
18
|
+
PARAM_SCHEMAS,
|
|
19
|
+
TREE_SITTER_TOOL_SPECS,
|
|
20
|
+
type TreeSitterToolName,
|
|
21
|
+
} from "./tool-specs.ts";
|
|
22
|
+
|
|
23
|
+
function notInitializedResult(): AgentToolResult<Record<string, unknown>> {
|
|
24
|
+
return {
|
|
25
|
+
content: [{ type: "text", text: "Tree-sitter not initialized. Start a new session first." }],
|
|
26
|
+
details: {},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function textResult(text: string): AgentToolResult<Record<string, unknown>> {
|
|
31
|
+
return { content: [{ type: "text", text }], details: {} };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Wraps a handler call into a pi-compatible execute function. */
|
|
35
|
+
function createExecute(
|
|
36
|
+
fn: (runtime: TreeSitterRuntime, params: Record<string, unknown>) => Promise<string> | string,
|
|
37
|
+
getRuntime: () => TreeSitterRuntime | undefined,
|
|
38
|
+
) {
|
|
39
|
+
// biome-ignore lint/complexity/useMaxParams: pi ToolDefinition.execute signature
|
|
40
|
+
return async (
|
|
41
|
+
_toolCallId: string,
|
|
42
|
+
params: Record<string, unknown>,
|
|
43
|
+
_signal: AbortSignal | undefined,
|
|
44
|
+
_onUpdate: unknown,
|
|
45
|
+
_ctx: { cwd: string },
|
|
46
|
+
): Promise<AgentToolResult<Record<string, unknown>>> => {
|
|
47
|
+
const runtime = getRuntime();
|
|
48
|
+
if (!runtime) return notInitializedResult();
|
|
49
|
+
|
|
50
|
+
// Guard against direct execute calls (tests, tool reuse) that bypass pi's schema validation
|
|
51
|
+
if (!params.file || typeof params.file !== "string") {
|
|
52
|
+
return textResult("Validation error: `file` is required.");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const text = await fn(runtime, params);
|
|
57
|
+
return textResult(text);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
return textResult(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── Handler dispatch map ───────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
type HandlerFn = (
|
|
67
|
+
runtime: TreeSitterRuntime,
|
|
68
|
+
params: Record<string, unknown>,
|
|
69
|
+
) => Promise<string> | string;
|
|
70
|
+
|
|
71
|
+
const HANDLER_MAP: Record<TreeSitterToolName, HandlerFn> = {
|
|
72
|
+
tree_sitter_outline: (runtime, params) => handleOutline(runtime, String(params.file)),
|
|
73
|
+
tree_sitter_imports: (runtime, params) => handleImports(runtime, String(params.file)),
|
|
74
|
+
tree_sitter_exports: (runtime, params) => handleExports(runtime, String(params.file)),
|
|
75
|
+
tree_sitter_node_at: (runtime, params) =>
|
|
76
|
+
handleNodeAt(runtime, String(params.file), Number(params.line), Number(params.character)),
|
|
77
|
+
tree_sitter_query: (runtime, params) =>
|
|
78
|
+
handleQuery(runtime, String(params.file), String(params.query)),
|
|
79
|
+
tree_sitter_callees: (runtime, params) =>
|
|
80
|
+
handleCallees(runtime, String(params.file), Number(params.line), Number(params.character)),
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// ── Registration ───────────────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Register 6 focused tree-sitter tools.
|
|
87
|
+
*
|
|
88
|
+
* @param pi — extension API
|
|
89
|
+
* @param getRuntime — thunk returning the current runtime (or undefined before session_start)
|
|
90
|
+
*/
|
|
91
|
+
export function registerFocusedTreeSitterTools(
|
|
92
|
+
pi: ExtensionAPI,
|
|
93
|
+
getRuntime: () => TreeSitterRuntime | undefined,
|
|
94
|
+
): void {
|
|
95
|
+
for (const spec of TREE_SITTER_TOOL_SPECS) {
|
|
96
|
+
const spec2 = getTreeSitterToolSpec(spec.name);
|
|
97
|
+
pi.registerTool({
|
|
98
|
+
name: spec2.name,
|
|
99
|
+
label: spec2.label,
|
|
100
|
+
description: spec2.description,
|
|
101
|
+
promptSnippet: spec2.promptSnippet,
|
|
102
|
+
promptGuidelines: spec2.promptGuidelines,
|
|
103
|
+
parameters: PARAM_SCHEMAS[spec2.paramSchemaKey],
|
|
104
|
+
execute: createExecute(HANDLER_MAP[spec2.name], getRuntime),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for the split `tree_sitter_*` tool surface.
|
|
3
|
+
*
|
|
4
|
+
* Tool registration, guidance, and parameter validation should derive
|
|
5
|
+
* from these specs so the public surface does not drift from the
|
|
6
|
+
* metadata that drives it.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Type } from "typebox";
|
|
10
|
+
|
|
11
|
+
// ── Shared parameter fragments ─────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
const FileParam = Type.String({ description: "File path" });
|
|
14
|
+
const LineParam = Type.Number({ description: "1-based line", minimum: 1 });
|
|
15
|
+
const CharacterParam = Type.Number({
|
|
16
|
+
description: "1-based UTF-16 column",
|
|
17
|
+
minimum: 1,
|
|
18
|
+
});
|
|
19
|
+
const QueryParam = Type.String({ description: "Tree-sitter query" });
|
|
20
|
+
|
|
21
|
+
export const PARAM_SCHEMAS = {
|
|
22
|
+
fileOnly: Type.Object({ file: FileParam }, { additionalProperties: false }),
|
|
23
|
+
fileLineChar: Type.Object(
|
|
24
|
+
{ file: FileParam, line: LineParam, character: CharacterParam },
|
|
25
|
+
{ additionalProperties: false },
|
|
26
|
+
),
|
|
27
|
+
fileQuery: Type.Object({ file: FileParam, query: QueryParam }, { additionalProperties: false }),
|
|
28
|
+
} as const;
|
|
29
|
+
|
|
30
|
+
export type ParamSchemaKey = keyof typeof PARAM_SCHEMAS;
|
|
31
|
+
|
|
32
|
+
// ── Tool names ─────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
export const TREE_SITTER_TOOL_NAMES = [
|
|
35
|
+
"tree_sitter_outline",
|
|
36
|
+
"tree_sitter_imports",
|
|
37
|
+
"tree_sitter_exports",
|
|
38
|
+
"tree_sitter_node_at",
|
|
39
|
+
"tree_sitter_query",
|
|
40
|
+
"tree_sitter_callees",
|
|
41
|
+
] as const;
|
|
42
|
+
|
|
43
|
+
export type TreeSitterToolName = (typeof TREE_SITTER_TOOL_NAMES)[number];
|
|
44
|
+
|
|
45
|
+
// ── Per-tool metadata ──────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
export interface TreeSitterToolSpec {
|
|
48
|
+
name: TreeSitterToolName;
|
|
49
|
+
label: string;
|
|
50
|
+
description: string;
|
|
51
|
+
promptSnippet: string;
|
|
52
|
+
promptGuidelines: string[];
|
|
53
|
+
paramSchemaKey: ParamSchemaKey;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const TREE_SITTER_TOOL_SPECS: readonly TreeSitterToolSpec[] = [
|
|
57
|
+
{
|
|
58
|
+
name: "tree_sitter_outline",
|
|
59
|
+
label: "Tree-sitter Outline",
|
|
60
|
+
description: "Shallow JS/TS outline of top-level declarations and supported members.",
|
|
61
|
+
promptSnippet: "tree_sitter_outline — quick JS/TS outline",
|
|
62
|
+
promptGuidelines: ["Use tree_sitter_outline(file) for a quick JS/TS outline."],
|
|
63
|
+
paramSchemaKey: "fileOnly",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "tree_sitter_imports",
|
|
67
|
+
label: "Tree-sitter Imports",
|
|
68
|
+
description: "List imports in a JS/TS file.",
|
|
69
|
+
promptSnippet: "tree_sitter_imports — JS/TS imports",
|
|
70
|
+
promptGuidelines: ["Use tree_sitter_imports(file) to inspect JS/TS dependencies."],
|
|
71
|
+
paramSchemaKey: "fileOnly",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "tree_sitter_exports",
|
|
75
|
+
label: "Tree-sitter Exports",
|
|
76
|
+
description: "List exports in a JS/TS file.",
|
|
77
|
+
promptSnippet: "tree_sitter_exports — JS/TS exports",
|
|
78
|
+
promptGuidelines: ["Use tree_sitter_exports(file) to inspect JS/TS exports."],
|
|
79
|
+
paramSchemaKey: "fileOnly",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "tree_sitter_node_at",
|
|
83
|
+
label: "Tree-sitter Node At",
|
|
84
|
+
description: "Show the syntax node and ancestry at a file position.",
|
|
85
|
+
promptSnippet: "tree_sitter_node_at — syntax node at a position",
|
|
86
|
+
promptGuidelines: ["Use tree_sitter_node_at(file,line,character) for the exact syntax node."],
|
|
87
|
+
paramSchemaKey: "fileLineChar",
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "tree_sitter_query",
|
|
91
|
+
label: "Tree-sitter Query",
|
|
92
|
+
description: "Run a custom Tree-sitter query against a file.",
|
|
93
|
+
promptSnippet: "tree_sitter_query — custom AST query",
|
|
94
|
+
promptGuidelines: ["Use tree_sitter_query(file,query) for custom AST matching."],
|
|
95
|
+
paramSchemaKey: "fileQuery",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "tree_sitter_callees",
|
|
99
|
+
label: "Tree-sitter Callees",
|
|
100
|
+
description: "List outgoing callees from the enclosing scope at a file position.",
|
|
101
|
+
promptSnippet: "tree_sitter_callees — outgoing callees",
|
|
102
|
+
promptGuidelines: ["Use tree_sitter_callees(file,line,character) for outgoing calls."],
|
|
103
|
+
paramSchemaKey: "fileLineChar",
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
// ── Lookup helpers ─────────────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
const TREE_SITTER_TOOL_SPEC_MAP = new Map<TreeSitterToolName, TreeSitterToolSpec>(
|
|
110
|
+
TREE_SITTER_TOOL_SPECS.map((spec) => [spec.name, spec]),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
export function getTreeSitterToolSpec(toolName: TreeSitterToolName): TreeSitterToolSpec {
|
|
114
|
+
const spec = TREE_SITTER_TOOL_SPEC_MAP.get(toolName);
|
|
115
|
+
if (!spec) throw new Error(`Unknown tree_sitter tool: ${toolName}`);
|
|
116
|
+
return spec;
|
|
117
|
+
}
|