@mrclrchtr/supi-code-intelligence 1.9.1 → 1.10.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 +15 -7
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/README.md +7 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
- package/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +4 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +13 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +45 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/src/workspace/context.ts +5 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/src/workspace/runtime.ts +14 -3
- package/node_modules/@mrclrchtr/supi-core/README.md +7 -1
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/README.md +7 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/README.md +7 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +4 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +13 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +45 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/workspace/context.ts +5 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/workspace/runtime.ts +14 -3
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/README.md +7 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/package.json +3 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-semantic-provider.ts +139 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +7 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/README.md +7 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +4 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +13 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +45 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/workspace/context.ts +5 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/workspace/runtime.ts +14 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md +7 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +3 -3
- package/package.json +5 -5
- package/src/intent/types.ts +34 -0
- package/src/planner/planner.ts +82 -0
- package/src/presentation/markdown/refactor.ts +27 -0
- package/src/refactor/apply-workspace-edit.ts +162 -0
- package/src/refactor/safety.ts +154 -0
- package/src/tool/execute-affected.ts +22 -0
- package/src/tool/execute-brief.ts +9 -2
- package/src/tool/execute-refactor.ts +101 -0
- package/src/tool/execute-relations.ts +21 -3
- package/src/tool/guidance.ts +18 -11
- package/src/tool/tool-specs.ts +25 -0
|
@@ -5,9 +5,18 @@ import type {
|
|
|
5
5
|
CodeLocation,
|
|
6
6
|
CodePosition,
|
|
7
7
|
CodeSymbol,
|
|
8
|
+
RefactorResult,
|
|
8
9
|
SemanticProvider,
|
|
9
10
|
} from "@mrclrchtr/supi-code-runtime/api";
|
|
10
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
DocumentSymbol,
|
|
13
|
+
Location,
|
|
14
|
+
LocationLink,
|
|
15
|
+
SymbolInformation,
|
|
16
|
+
TextDocumentEdit,
|
|
17
|
+
TextEdit,
|
|
18
|
+
WorkspaceEdit,
|
|
19
|
+
} from "../config/types.ts";
|
|
11
20
|
import type { SessionLspService } from "../session/service-registry.ts";
|
|
12
21
|
|
|
13
22
|
/**
|
|
@@ -50,9 +59,138 @@ export function createLspSemanticProvider(lsp: SessionLspService): SemanticProvi
|
|
|
50
59
|
if (!results) return null;
|
|
51
60
|
return results.map((sym) => toCodeSymbol(sym as SymbolInformation));
|
|
52
61
|
},
|
|
62
|
+
|
|
63
|
+
async rename(file: string, position: CodePosition, newName: string): Promise<RefactorResult> {
|
|
64
|
+
const edit = await lsp.rename(file, position, newName);
|
|
65
|
+
return convertLspWorkspaceEdit(edit);
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
async codeActions(file: string, position: CodePosition): Promise<RefactorResult[]> {
|
|
69
|
+
const actions = await lsp.codeActions(file, position);
|
|
70
|
+
if (!actions) return [];
|
|
71
|
+
|
|
72
|
+
const results: RefactorResult[] = [];
|
|
73
|
+
for (const action of actions) {
|
|
74
|
+
const edit = action.edit;
|
|
75
|
+
if (!edit) {
|
|
76
|
+
results.push({
|
|
77
|
+
kind: "unavailable",
|
|
78
|
+
reason: `Code action "${action.title}" has no edit`,
|
|
79
|
+
});
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const converted = convertLspWorkspaceEdit(edit);
|
|
83
|
+
if (converted.kind === "precise") {
|
|
84
|
+
results.push(converted);
|
|
85
|
+
} else {
|
|
86
|
+
results.push({
|
|
87
|
+
kind: "unavailable",
|
|
88
|
+
reason: `Code action "${action.title}" could not produce precise edits`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return results;
|
|
93
|
+
},
|
|
53
94
|
};
|
|
54
95
|
}
|
|
55
96
|
|
|
97
|
+
// ── LSP WorkspaceEdit converter ─────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Convert an LSP WorkspaceEdit to the shared RefactorResult type.
|
|
101
|
+
*
|
|
102
|
+
* LSP WorkspaceEdit can use:
|
|
103
|
+
* - `documentChanges` (preferred, with TextDocumentEdit)
|
|
104
|
+
* - `changes` (legacy, URI → TextEdit[] map)
|
|
105
|
+
*
|
|
106
|
+
* Returns `unavailable` when both are missing or both produce zero edits.
|
|
107
|
+
*/
|
|
108
|
+
function resolveFileFromUri(uri: string): string {
|
|
109
|
+
if (!uri.startsWith("file://")) return uri;
|
|
110
|
+
try {
|
|
111
|
+
return decodeURIComponent(uri.slice(7));
|
|
112
|
+
} catch {
|
|
113
|
+
return uri;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function collectDocumentChangeEdits(
|
|
118
|
+
docChanges: NonNullable<WorkspaceEdit["documentChanges"]>,
|
|
119
|
+
): Array<{
|
|
120
|
+
file: string;
|
|
121
|
+
range: { start: { line: number; character: number }; end: { line: number; character: number } };
|
|
122
|
+
newText: string;
|
|
123
|
+
}> {
|
|
124
|
+
const out: Array<{
|
|
125
|
+
file: string;
|
|
126
|
+
range: { start: { line: number; character: number }; end: { line: number; character: number } };
|
|
127
|
+
newText: string;
|
|
128
|
+
}> = [];
|
|
129
|
+
for (const change of docChanges) {
|
|
130
|
+
const tdEdit = change as TextDocumentEdit;
|
|
131
|
+
if (!tdEdit.textDocument || !tdEdit.edits) continue;
|
|
132
|
+
const file = resolveFileFromUri(tdEdit.textDocument.uri);
|
|
133
|
+
for (const singleEdit of tdEdit.edits) {
|
|
134
|
+
const te = singleEdit as TextEdit;
|
|
135
|
+
out.push({
|
|
136
|
+
file,
|
|
137
|
+
range: {
|
|
138
|
+
start: { line: te.range.start.line, character: te.range.start.character },
|
|
139
|
+
end: { line: te.range.end.line, character: te.range.end.character },
|
|
140
|
+
},
|
|
141
|
+
newText: te.newText,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function collectChangesEdits(changes: NonNullable<WorkspaceEdit["changes"]>): Array<{
|
|
149
|
+
file: string;
|
|
150
|
+
range: { start: { line: number; character: number }; end: { line: number; character: number } };
|
|
151
|
+
newText: string;
|
|
152
|
+
}> {
|
|
153
|
+
const out: Array<{
|
|
154
|
+
file: string;
|
|
155
|
+
range: { start: { line: number; character: number }; end: { line: number; character: number } };
|
|
156
|
+
newText: string;
|
|
157
|
+
}> = [];
|
|
158
|
+
for (const [uri, textEdits] of Object.entries(changes)) {
|
|
159
|
+
if (!textEdits || textEdits.length === 0) continue;
|
|
160
|
+
const file = resolveFileFromUri(uri);
|
|
161
|
+
for (const te of textEdits) {
|
|
162
|
+
out.push({
|
|
163
|
+
file,
|
|
164
|
+
range: {
|
|
165
|
+
start: { line: te.range.start.line, character: te.range.start.character },
|
|
166
|
+
end: { line: te.range.end.line, character: te.range.end.character },
|
|
167
|
+
},
|
|
168
|
+
newText: te.newText,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function convertLspWorkspaceEdit(edit: WorkspaceEdit | null): RefactorResult {
|
|
176
|
+
if (!edit) {
|
|
177
|
+
return { kind: "unavailable", reason: "LSP server returned no edit" };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
let fileEdits = edit.documentChanges?.length
|
|
181
|
+
? collectDocumentChangeEdits(edit.documentChanges)
|
|
182
|
+
: [];
|
|
183
|
+
if (fileEdits.length === 0 && edit.changes) {
|
|
184
|
+
fileEdits = collectChangesEdits(edit.changes);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (fileEdits.length === 0) {
|
|
188
|
+
return { kind: "unavailable", reason: "Workspace edit contains no file edits" };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return { kind: "precise", edits: { edits: fileEdits } };
|
|
192
|
+
}
|
|
193
|
+
|
|
56
194
|
// ── Type conversion helpers ───────────────────────────────────────────
|
|
57
195
|
|
|
58
196
|
function toCodeLocation(item: Location | LocationLink): CodeLocation | null {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://github.com/mrclrchtr/supi/tree/main/packages/supi-tree-sitter">
|
|
3
|
+
<picture>
|
|
4
|
+
<img src="https://raw.githubusercontent.com/mrclrchtr/supi/main/packages/supi-tree-sitter/assets/logo.png" alt="SuPi" width="50%">
|
|
5
|
+
</picture>
|
|
6
|
+
</a>
|
|
7
|
+
</div>
|
|
2
8
|
|
|
3
9
|
# @mrclrchtr/supi-tree-sitter
|
|
4
10
|
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://github.com/mrclrchtr/supi/tree/main/packages/supi-core">
|
|
3
|
+
<picture>
|
|
4
|
+
<img src="https://raw.githubusercontent.com/mrclrchtr/supi/main/packages/supi-core/assets/logo.png" alt="SuPi" width="50%">
|
|
5
|
+
</picture>
|
|
6
|
+
</a>
|
|
7
|
+
</div>
|
|
2
8
|
|
|
3
9
|
# @mrclrchtr/supi-core
|
|
4
10
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-code-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "SuPi code-runtime — shared workspace context, capability contracts, and canonical types for the code-understanding stack",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"!__tests__"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@mrclrchtr/supi-core": "1.
|
|
22
|
+
"@mrclrchtr/supi-core": "1.10.0"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"@earendil-works/pi-coding-agent": "*"
|
|
@@ -21,11 +21,15 @@ export type {
|
|
|
21
21
|
CodeResult,
|
|
22
22
|
CodeSymbol,
|
|
23
23
|
ConfidenceMode,
|
|
24
|
+
DisambiguationCandidate,
|
|
24
25
|
ExportData,
|
|
26
|
+
FileEdit,
|
|
25
27
|
ImportData,
|
|
26
28
|
NodeAtData,
|
|
27
29
|
OutlineData,
|
|
30
|
+
RefactorResult,
|
|
28
31
|
SourceRange,
|
|
32
|
+
WorkspaceEdit,
|
|
29
33
|
} from "./types.ts";
|
|
30
34
|
export type { WorkspaceContext } from "./workspace/context.ts";
|
|
31
35
|
// Workspace context
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
ImportData,
|
|
15
15
|
NodeAtData,
|
|
16
16
|
OutlineData,
|
|
17
|
+
RefactorResult,
|
|
17
18
|
} from "../types.ts";
|
|
18
19
|
|
|
19
20
|
// ── Availability state ─────────────────────────────────────────────────
|
|
@@ -47,6 +48,18 @@ export interface SemanticProvider {
|
|
|
47
48
|
implementation(filePath: string, position: CodePosition): Promise<CodeLocation[] | null>;
|
|
48
49
|
documentSymbols(filePath: string): Promise<CodeSymbol[] | null>;
|
|
49
50
|
workspaceSymbols(query: string): Promise<CodeSymbol[] | null>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Optional rename capability. When present, the provider supports
|
|
54
|
+
* precise semantic rename operations.
|
|
55
|
+
*/
|
|
56
|
+
rename?(file: string, position: CodePosition, newName: string): Promise<RefactorResult>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Optional code actions capability. When present, the provider
|
|
60
|
+
* supports code-action-based refactors.
|
|
61
|
+
*/
|
|
62
|
+
codeActions?(file: string, position: CodePosition): Promise<RefactorResult[]>;
|
|
50
63
|
}
|
|
51
64
|
|
|
52
65
|
/**
|
|
@@ -104,6 +104,51 @@ export interface NodeAtData {
|
|
|
104
104
|
}>;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
// ── Refactor types ───────────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* A single file edit within a workspace edit.
|
|
111
|
+
*/
|
|
112
|
+
export interface FileEdit {
|
|
113
|
+
/** Absolute file path */
|
|
114
|
+
file: string;
|
|
115
|
+
/** The source range to replace */
|
|
116
|
+
range: SourceRange;
|
|
117
|
+
/** The new text to insert */
|
|
118
|
+
newText: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* A precise workspace edit — one or more file edits to apply atomically.
|
|
123
|
+
*/
|
|
124
|
+
export interface WorkspaceEdit {
|
|
125
|
+
edits: FileEdit[];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* A disambiguation candidate when a refactor target is ambiguous.
|
|
130
|
+
*/
|
|
131
|
+
export interface DisambiguationCandidate {
|
|
132
|
+
description: string;
|
|
133
|
+
file?: string;
|
|
134
|
+
line?: number;
|
|
135
|
+
character?: number;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Result of a refactor operation.
|
|
140
|
+
*
|
|
141
|
+
* - `precise`: exact edits available for safe direct apply
|
|
142
|
+
* - `ambiguous`: multiple candidates, caller must disambiguate
|
|
143
|
+
* - `unavailable`: refactoring not possible
|
|
144
|
+
*/
|
|
145
|
+
export type RefactorResult =
|
|
146
|
+
| { kind: "precise"; edits: WorkspaceEdit }
|
|
147
|
+
| { kind: "ambiguous"; candidates: DisambiguationCandidate[] }
|
|
148
|
+
| { kind: "unavailable"; reason: string };
|
|
149
|
+
|
|
150
|
+
// ── Structural data shapes (value types, range-flattened) ──────────────
|
|
151
|
+
|
|
107
152
|
export interface CalleesData {
|
|
108
153
|
enclosingScope: { name: string; startLine: number; endLine: number };
|
|
109
154
|
callees: Array<{ name: string; startLine: number }>;
|
|
@@ -19,7 +19,11 @@ export interface WorkspaceContext {
|
|
|
19
19
|
/** The working directory this context is scoped to. */
|
|
20
20
|
cwd: string;
|
|
21
21
|
/** Semantic analysis capability state and provider. */
|
|
22
|
-
semantic: {
|
|
22
|
+
semantic: {
|
|
23
|
+
state: CapabilityState;
|
|
24
|
+
provider: SemanticProvider | null;
|
|
25
|
+
refactorAvailable: boolean;
|
|
26
|
+
};
|
|
23
27
|
/** Structural analysis capability state and provider. */
|
|
24
28
|
structural: { state: CapabilityState; provider: StructuralProvider | null };
|
|
25
29
|
}
|
|
@@ -20,7 +20,12 @@ import type { CapabilityState, SemanticProvider, StructuralProvider } from "../c
|
|
|
20
20
|
* provider instance (null when not ready).
|
|
21
21
|
*/
|
|
22
22
|
export interface WorkspaceCapabilities {
|
|
23
|
-
semantic: {
|
|
23
|
+
semantic: {
|
|
24
|
+
state: CapabilityState;
|
|
25
|
+
provider: SemanticProvider | null;
|
|
26
|
+
/** Whether the semantic provider supports precise refactoring operations */
|
|
27
|
+
refactorAvailable: boolean;
|
|
28
|
+
};
|
|
24
29
|
structural: { state: CapabilityState; provider: StructuralProvider | null };
|
|
25
30
|
}
|
|
26
31
|
|
|
@@ -33,6 +38,7 @@ function createDefaultCapabilities(): WorkspaceCapabilities {
|
|
|
33
38
|
semantic: {
|
|
34
39
|
state: { kind: "unavailable", reason: DEFAULT_UNAVAILABLE_REASON },
|
|
35
40
|
provider: null,
|
|
41
|
+
refactorAvailable: false,
|
|
36
42
|
},
|
|
37
43
|
structural: {
|
|
38
44
|
state: { kind: "unavailable", reason: DEFAULT_UNAVAILABLE_REASON },
|
|
@@ -41,6 +47,10 @@ function createDefaultCapabilities(): WorkspaceCapabilities {
|
|
|
41
47
|
};
|
|
42
48
|
}
|
|
43
49
|
|
|
50
|
+
function hasRefactorCapability(provider: SemanticProvider | null): boolean {
|
|
51
|
+
return !!(provider && (provider.rename !== undefined || provider.codeActions !== undefined));
|
|
52
|
+
}
|
|
53
|
+
|
|
44
54
|
// ── Runtime ────────────────────────────────────────────────────────────
|
|
45
55
|
|
|
46
56
|
/**
|
|
@@ -73,12 +83,13 @@ export class WorkspaceRuntime {
|
|
|
73
83
|
* without affecting the structural provider.
|
|
74
84
|
*/
|
|
75
85
|
registerSemantic(cwd: string, provider: SemanticProvider): void {
|
|
86
|
+
const refactorAvailable = hasRefactorCapability(provider);
|
|
76
87
|
const existing = this.#workspaces.get(cwd);
|
|
77
88
|
if (existing) {
|
|
78
|
-
existing.semantic = { state: { kind: "ready" }, provider };
|
|
89
|
+
existing.semantic = { state: { kind: "ready" }, provider, refactorAvailable };
|
|
79
90
|
} else {
|
|
80
91
|
this.#workspaces.set(cwd, {
|
|
81
|
-
semantic: { state: { kind: "ready" }, provider },
|
|
92
|
+
semantic: { state: { kind: "ready" }, provider, refactorAvailable },
|
|
82
93
|
structural: createDefaultCapabilities().structural,
|
|
83
94
|
});
|
|
84
95
|
}
|
package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://github.com/mrclrchtr/supi/tree/main/packages/supi-core">
|
|
3
|
+
<picture>
|
|
4
|
+
<img src="https://raw.githubusercontent.com/mrclrchtr/supi/main/packages/supi-core/assets/logo.png" alt="SuPi" width="50%">
|
|
5
|
+
</picture>
|
|
6
|
+
</a>
|
|
7
|
+
</div>
|
|
2
8
|
|
|
3
9
|
# @mrclrchtr/supi-core
|
|
4
10
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-tree-sitter",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "SuPi Tree-sitter extension — structural AST analysis for pi",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"web-tree-sitter": "^0.26.8",
|
|
27
|
-
"@mrclrchtr/supi-
|
|
28
|
-
"@mrclrchtr/supi-
|
|
27
|
+
"@mrclrchtr/supi-core": "1.10.0",
|
|
28
|
+
"@mrclrchtr/supi-code-runtime": "1.10.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"@earendil-works/pi-ai": "*",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-code-intelligence",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "SuPi Code Intelligence extension — architecture briefs, caller/callee analysis, impact assessment, and pattern search for pi",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"src/**/*.ts"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@mrclrchtr/supi-
|
|
23
|
-
"@mrclrchtr/supi-core": "1.
|
|
24
|
-
"@mrclrchtr/supi-
|
|
25
|
-
"@mrclrchtr/supi-
|
|
22
|
+
"@mrclrchtr/supi-code-runtime": "1.10.0",
|
|
23
|
+
"@mrclrchtr/supi-core": "1.10.0",
|
|
24
|
+
"@mrclrchtr/supi-tree-sitter": "1.10.0",
|
|
25
|
+
"@mrclrchtr/supi-lsp": "1.10.0"
|
|
26
26
|
},
|
|
27
27
|
"bundledDependencies": [
|
|
28
28
|
"@mrclrchtr/supi-code-runtime",
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalized intent and routing types for the code-intelligence planner.
|
|
3
|
+
*/
|
|
4
|
+
import type { CodeIntelligenceToolName, CodeRelationsKind } from "../tool/tool-specs.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A route describes how the planner recommends handling a tool intent.
|
|
8
|
+
*/
|
|
9
|
+
export interface PlannerRoute {
|
|
10
|
+
/** Whether a semantic (LSP-backed) provider is available */
|
|
11
|
+
semanticAvailable: boolean;
|
|
12
|
+
/** Whether a structural (tree-sitter-backed) provider is available */
|
|
13
|
+
structuralAvailable: boolean;
|
|
14
|
+
/** Whether precise refactoring is available */
|
|
15
|
+
refactorAvailable: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* The preferred execution strategy for this intent.
|
|
18
|
+
* - `semantic`: use LSP first
|
|
19
|
+
* - `structural`: use tree-sitter first
|
|
20
|
+
* - `search`: use explicit text/heuristic search
|
|
21
|
+
* - `unavailable`: no capability can satisfy this intent
|
|
22
|
+
*/
|
|
23
|
+
preferred: "semantic" | "structural" | "search" | "unavailable";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A resolved intents for a tool execution request.
|
|
28
|
+
* Provides the normalized target and routing info together.
|
|
29
|
+
*/
|
|
30
|
+
export interface ResolvedIntent {
|
|
31
|
+
tool: CodeIntelligenceToolName;
|
|
32
|
+
relationsKind?: CodeRelationsKind;
|
|
33
|
+
route: PlannerRoute;
|
|
34
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Central planner for code-intelligence tool routing.
|
|
3
|
+
*
|
|
4
|
+
* Reads capability state from the shared workspace broker and returns
|
|
5
|
+
* routing decisions for each tool intent. Keeps the execution strategy
|
|
6
|
+
* explicit and centralized instead of scattering capability checks
|
|
7
|
+
* across per-tool execute files.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { getDefaultWorkspaceRuntime } from "@mrclrchtr/supi-code-runtime/api";
|
|
11
|
+
import type { PlannerRoute } from "../intent/types.ts";
|
|
12
|
+
import type { CodeIntelligenceToolName, CodeRelationsKind } from "../tool/tool-specs.ts";
|
|
13
|
+
|
|
14
|
+
interface RouteAvailability {
|
|
15
|
+
semanticAvailable: boolean;
|
|
16
|
+
structuralAvailable: boolean;
|
|
17
|
+
refactorAvailable: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function readAvailability(cwd: string): RouteAvailability {
|
|
21
|
+
const runtime = getDefaultWorkspaceRuntime();
|
|
22
|
+
const workspace = runtime.getWorkspace(cwd);
|
|
23
|
+
return {
|
|
24
|
+
semanticAvailable:
|
|
25
|
+
workspace.semantic.state.kind === "ready" && workspace.semantic.provider !== null,
|
|
26
|
+
structuralAvailable:
|
|
27
|
+
workspace.structural.state.kind === "ready" && workspace.structural.provider !== null,
|
|
28
|
+
refactorAvailable: workspace.semantic.refactorAvailable,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function withPreferred(
|
|
33
|
+
availability: RouteAvailability,
|
|
34
|
+
preferred: PlannerRoute["preferred"],
|
|
35
|
+
): PlannerRoute {
|
|
36
|
+
return { ...availability, preferred };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function semanticOnly(availability: RouteAvailability): PlannerRoute["preferred"] {
|
|
40
|
+
return availability.semanticAvailable ? "semantic" : "unavailable";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function structuralOnly(availability: RouteAvailability): PlannerRoute["preferred"] {
|
|
44
|
+
return availability.structuralAvailable ? "structural" : "unavailable";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function briefPreferred(availability: RouteAvailability): PlannerRoute["preferred"] {
|
|
48
|
+
if (availability.semanticAvailable) return "semantic";
|
|
49
|
+
if (availability.structuralAvailable) return "structural";
|
|
50
|
+
return "unavailable";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get the routing decision for a tool intent in a workspace.
|
|
55
|
+
*/
|
|
56
|
+
export function routeFor(
|
|
57
|
+
cwd: string,
|
|
58
|
+
tool: CodeIntelligenceToolName,
|
|
59
|
+
relationsKind?: CodeRelationsKind,
|
|
60
|
+
): PlannerRoute {
|
|
61
|
+
const availability = readAvailability(cwd);
|
|
62
|
+
|
|
63
|
+
if (tool === "code_pattern") {
|
|
64
|
+
return withPreferred(availability, "search");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (tool === "code_relations") {
|
|
68
|
+
const preferred =
|
|
69
|
+
relationsKind === "callees" ? structuralOnly(availability) : semanticOnly(availability);
|
|
70
|
+
return withPreferred(availability, preferred);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (tool === "code_affected") {
|
|
74
|
+
return withPreferred(availability, semanticOnly(availability));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (tool === "code_refactor") {
|
|
78
|
+
return withPreferred(availability, availability.refactorAvailable ? "semantic" : "unavailable");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return withPreferred(availability, briefPreferred(availability));
|
|
82
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown renderer for refactor results.
|
|
3
|
+
*/
|
|
4
|
+
import type { ApplyResult } from "../../refactor/apply-workspace-edit.ts";
|
|
5
|
+
|
|
6
|
+
export interface RefactorRenderInput {
|
|
7
|
+
result: ApplyResult;
|
|
8
|
+
operation: string;
|
|
9
|
+
targetDescription: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Render a refactor result as human-readable markdown.
|
|
14
|
+
*/
|
|
15
|
+
export function renderRefactorResult(input: RefactorRenderInput): string {
|
|
16
|
+
const { result, operation, targetDescription } = input;
|
|
17
|
+
|
|
18
|
+
if (result.kind === "error") {
|
|
19
|
+
return `**Refactor failed:** ${result.reason}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return [
|
|
23
|
+
`**Refactor applied:** ${operation} on ${targetDescription}`,
|
|
24
|
+
`- Files changed: ${result.filesChanged}`,
|
|
25
|
+
`- Total edits: ${result.totalEdits}`,
|
|
26
|
+
].join("\n");
|
|
27
|
+
}
|