@mrclrchtr/supi-code-intelligence 6.3.0 → 7.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/README.md +164 -82
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +8 -1
- package/node_modules/@mrclrchtr/supi-core/README.md +8 -0
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +10 -3
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +2 -0
- package/node_modules/@mrclrchtr/supi-core/src/llm.ts +141 -16
- package/node_modules/@mrclrchtr/supi-lsp/README.md +35 -13
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +8 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/README.md +8 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +10 -3
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/index.ts +2 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/llm.ts +141 -16
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/index.js +3 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/legacy.js +3 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/package.json +3 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +16 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-cache.ts +43 -35
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-capabilities.ts +83 -17
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-collection.ts +108 -92
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-evidence.ts +44 -82
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-host.ts +3 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-publication.ts +9 -68
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-pull.ts +45 -58
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-refresh.ts +230 -331
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-request.ts +201 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-timing.ts +129 -70
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-typescript.ts +395 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-waiters.ts +8 -12
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostics.ts +685 -183
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-state.ts +2 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-sync.ts +60 -60
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-request-enrollment.ts +75 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-semantic-input-barrier.ts +443 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-semantic-input-errors.ts +30 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-semantic-input-file.ts +15 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +290 -37
- package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +72 -16
- package/node_modules/@mrclrchtr/supi-lsp/src/config/capabilities.ts +1 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/config/tsconfig-scope.ts +30 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/evidence.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/workspace-sentinels.ts +4 -32
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/workspace-sources.ts +108 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-diagnostics.ts +10 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-process-crash-report.ts +50 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +11 -7
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +770 -56
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostic-surface.ts +3 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostics.ts +37 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registry.ts +48 -12
- package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +50 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +8 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md +8 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +10 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/index.ts +2 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/llm.ts +141 -16
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +3 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/provider/tree-sitter-provider.ts +2 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callee-display-name.ts +165 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callees.ts +67 -9
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +2 -0
- package/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +19 -18
- package/node_modules/yaml/browser/dist/nodes/Alias.js +25 -23
- package/node_modules/yaml/dist/compose/resolve-flow-scalar.js +19 -18
- package/node_modules/yaml/dist/nodes/Alias.js +25 -23
- package/node_modules/yaml/package.json +1 -1
- package/package.json +5 -5
- package/src/analysis/health/diagnostics.ts +1 -2
- package/src/analysis/health/file-scope.ts +4 -1
- package/src/analysis/health/server-status.ts +1 -1
- package/src/analysis/relations/callees.ts +17 -8
- package/src/analysis/relations/implementations.ts +1 -2
- package/src/analysis/relations/references.ts +8 -4
- package/src/analysis/relations/types.ts +6 -30
- package/src/analysis/target/anchored.ts +9 -1
- package/src/analysis/target/symbol.ts +29 -11
- package/src/analysis/target/types.ts +14 -6
- package/src/api.ts +2 -0
- package/src/session/graph/collect.ts +18 -3
- package/src/session/health-refresh.ts +27 -11
- package/src/session/health-types.ts +21 -4
- package/src/session/health-workflow.ts +28 -22
- package/src/session/orientation-types.ts +5 -6
- package/src/session/orientation-workflow.ts +10 -2
- package/src/session/session.ts +12 -5
- package/src/session/target-workflow.ts +9 -6
- package/src/substrate/lsp/maintenance.ts +53 -47
- package/src/substrate/lsp/source-tracking.ts +252 -0
- package/src/tool/code_find/guidance.ts +3 -3
- package/src/tool/code_find/spec.ts +5 -4
- package/src/tool/code_find/tui.ts +7 -1
- package/src/tool/code_graph/details.ts +32 -0
- package/src/tool/code_graph/display.ts +54 -0
- package/src/tool/code_graph/format.ts +60 -0
- package/src/tool/code_graph/guidance.ts +2 -2
- package/src/tool/code_graph/markdown.ts +76 -198
- package/src/tool/code_graph/read-next.ts +65 -0
- package/src/tool/code_graph/result.ts +118 -83
- package/src/tool/code_graph/tui.ts +216 -54
- package/src/tool/code_health/guidance.ts +3 -5
- package/src/tool/code_health/markdown.ts +90 -57
- package/src/tool/code_health/refresh-outcome.ts +51 -0
- package/src/tool/code_health/refresh-status.ts +130 -43
- package/src/tool/code_health/scope.ts +78 -0
- package/src/tool/code_health/spec.ts +1 -1
- package/src/tool/code_health/tui.ts +29 -38
- package/src/tool/code_inspect/guidance.ts +5 -3
- package/src/tool/code_inspect/tui.ts +7 -1
- package/src/tool/code_orientation/guidance.ts +3 -4
- package/src/tool/code_orientation/result.ts +31 -8
- package/src/tool/code_orientation/tui.ts +26 -5
- package/src/tool/code_refactor_apply/guidance.ts +1 -1
- package/src/tool/code_refactor_apply/tui.ts +7 -3
- package/src/tool/code_refactor_plan/guidance.ts +3 -5
- package/src/tool/code_refactor_plan/tui.ts +7 -1
- package/src/tool/code_resolve/guidance.ts +3 -5
- package/src/tool/code_resolve/result.ts +13 -10
- package/src/tool/code_resolve/tui.ts +18 -1
- package/src/tool/guidance.ts +11 -9
- package/src/tool/infra/truncate.ts +39 -13
- package/src/tool/result/candidate-row.ts +27 -0
- package/src/tool/result/errors.ts +21 -6
- package/src/tool/result/types.ts +7 -3
- package/src/tool/schemas.ts +5 -0
- package/src/types/execution.ts +2 -0
- package/src/types/index.ts +2 -0
- package/src/ui/tui/candidate-legacy-body.ts +69 -0
- package/src/ui/tui/candidate-selection.ts +366 -0
- package/src/ui/tui/common.ts +26 -31
- package/src/ui/tui/execution-error.ts +92 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { statSync } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
type CodeRequestControl,
|
|
5
|
+
throwIfCodeRequestInterrupted,
|
|
6
|
+
} from "@mrclrchtr/supi-code-runtime/api";
|
|
7
|
+
import { isWithinOrEqual } from "@mrclrchtr/supi-core/api";
|
|
8
|
+
import type {
|
|
9
|
+
BulkTrackFileOutcome,
|
|
10
|
+
WorkspaceLspRuntime,
|
|
11
|
+
WorkspaceSourceInventory,
|
|
12
|
+
} from "@mrclrchtr/supi-lsp/api";
|
|
13
|
+
import { isMissingFileError, MAX_BULK_TRACK_FILES } from "@mrclrchtr/supi-lsp/api";
|
|
14
|
+
|
|
15
|
+
/** Typed session state for sentinel maintenance and automatic source tracking. */
|
|
16
|
+
export interface LspMaintenanceState {
|
|
17
|
+
readonly sentinelSnapshot: Map<string, number>;
|
|
18
|
+
readonly sourceBaseline: ReadonlySet<string> | null;
|
|
19
|
+
readonly createdSourceQueue: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Source discovery and tracking facts from one broad diagnostic refresh. */
|
|
23
|
+
export interface SourceTrackingReport {
|
|
24
|
+
readonly status: WorkspaceSourceInventory["status"];
|
|
25
|
+
readonly reason: WorkspaceSourceInventory["reason"];
|
|
26
|
+
readonly observedFileCount: number;
|
|
27
|
+
readonly discovered: readonly string[];
|
|
28
|
+
readonly tracked: readonly string[];
|
|
29
|
+
/**
|
|
30
|
+
* Candidates skipped by automatic policy or tracking preconditions. This can
|
|
31
|
+
* include policy exclusions, unsupported automatic routes, and paths that
|
|
32
|
+
* are no longer regular; it is not a server capability result.
|
|
33
|
+
*/
|
|
34
|
+
readonly skipped: readonly string[];
|
|
35
|
+
readonly unavailable: readonly string[];
|
|
36
|
+
readonly deferred: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Create empty source state with an optional lifecycle-seeded sentinel snapshot. */
|
|
40
|
+
export function createLspMaintenanceState(
|
|
41
|
+
sentinelSnapshot: Map<string, number> = new Map(),
|
|
42
|
+
): LspMaintenanceState {
|
|
43
|
+
return {
|
|
44
|
+
sentinelSnapshot,
|
|
45
|
+
sourceBaseline: null,
|
|
46
|
+
createdSourceQueue: [],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Replace the sentinel portion of maintenance state without source state. */
|
|
51
|
+
export function withSentinelSnapshot(
|
|
52
|
+
state: LspMaintenanceState,
|
|
53
|
+
sentinelSnapshot: Map<string, number>,
|
|
54
|
+
): LspMaintenanceState {
|
|
55
|
+
return { ...state, sentinelSnapshot };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Discover source additions and process a bounded queue for one refresh. */
|
|
59
|
+
export async function trackCreatedSources(options: {
|
|
60
|
+
readonly runtime: WorkspaceLspRuntime;
|
|
61
|
+
readonly cwd: string;
|
|
62
|
+
readonly state: LspMaintenanceState;
|
|
63
|
+
readonly scope?: string | null;
|
|
64
|
+
readonly control?: CodeRequestControl;
|
|
65
|
+
}): Promise<{ state: LspMaintenanceState; report: SourceTrackingReport }> {
|
|
66
|
+
const inventory = await options.runtime.scanWorkspaceSources(options.control);
|
|
67
|
+
throwIfCodeRequestInterrupted(options.control);
|
|
68
|
+
if (inventory.status === "limited") {
|
|
69
|
+
return {
|
|
70
|
+
state: options.state,
|
|
71
|
+
report: createReport({
|
|
72
|
+
cwd: options.cwd,
|
|
73
|
+
inventory,
|
|
74
|
+
discovered: [],
|
|
75
|
+
tracked: [],
|
|
76
|
+
skipped: [],
|
|
77
|
+
unavailable: [],
|
|
78
|
+
deferred: options.state.createdSourceQueue,
|
|
79
|
+
control: options.control,
|
|
80
|
+
}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const discovered = discoverCreatedPaths(
|
|
85
|
+
options.state.sourceBaseline,
|
|
86
|
+
inventory.files,
|
|
87
|
+
options.control,
|
|
88
|
+
);
|
|
89
|
+
const queue = removeMissingPaths(
|
|
90
|
+
options.state.sourceBaseline === null
|
|
91
|
+
? []
|
|
92
|
+
: deduplicatePaths([...options.state.createdSourceQueue, ...discovered], options.control),
|
|
93
|
+
options.control,
|
|
94
|
+
);
|
|
95
|
+
const selected = selectScopedPaths(queue, options.cwd, options.scope, options.control).slice(
|
|
96
|
+
0,
|
|
97
|
+
MAX_BULK_TRACK_FILES,
|
|
98
|
+
);
|
|
99
|
+
const batch =
|
|
100
|
+
selected.length === 0
|
|
101
|
+
? { outcomes: [] as const }
|
|
102
|
+
: await options.runtime.bulkTrackFiles(selected, options.control);
|
|
103
|
+
const nextQueue = retainQueuePaths(queue, selected, batch.outcomes, options.control);
|
|
104
|
+
const nextState: LspMaintenanceState = {
|
|
105
|
+
sentinelSnapshot: options.state.sentinelSnapshot,
|
|
106
|
+
sourceBaseline: new Set(inventory.files),
|
|
107
|
+
createdSourceQueue: nextQueue,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const tracked = pathsForOutcome(batch.outcomes, "tracked");
|
|
111
|
+
const skipped = pathsForOutcome(batch.outcomes, "skipped");
|
|
112
|
+
const unavailable = pathsForOutcome(batch.outcomes, "unavailable");
|
|
113
|
+
return {
|
|
114
|
+
state: nextState,
|
|
115
|
+
report: createReport({
|
|
116
|
+
cwd: options.cwd,
|
|
117
|
+
inventory,
|
|
118
|
+
discovered,
|
|
119
|
+
tracked,
|
|
120
|
+
skipped,
|
|
121
|
+
unavailable,
|
|
122
|
+
deferred: nextQueue,
|
|
123
|
+
control: options.control,
|
|
124
|
+
}),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function discoverCreatedPaths(
|
|
129
|
+
baseline: ReadonlySet<string> | null,
|
|
130
|
+
current: readonly string[],
|
|
131
|
+
control?: CodeRequestControl,
|
|
132
|
+
): string[] {
|
|
133
|
+
if (baseline === null) return [];
|
|
134
|
+
const discovered: string[] = [];
|
|
135
|
+
for (const filePath of current) {
|
|
136
|
+
throwIfCodeRequestInterrupted(control);
|
|
137
|
+
if (!baseline.has(filePath)) discovered.push(filePath);
|
|
138
|
+
}
|
|
139
|
+
return discovered;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function selectScopedPaths(
|
|
143
|
+
queue: readonly string[],
|
|
144
|
+
cwd: string,
|
|
145
|
+
scope: string | null | undefined,
|
|
146
|
+
control?: CodeRequestControl,
|
|
147
|
+
): string[] {
|
|
148
|
+
const resolvedScope = scope === null || scope === undefined ? null : path.resolve(cwd, scope);
|
|
149
|
+
const selected: string[] = [];
|
|
150
|
+
for (const filePath of queue) {
|
|
151
|
+
throwIfCodeRequestInterrupted(control);
|
|
152
|
+
if (resolvedScope === null || isWithinOrEqual(resolvedScope, filePath)) selected.push(filePath);
|
|
153
|
+
}
|
|
154
|
+
return selected;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function retainQueuePaths(
|
|
158
|
+
queue: readonly string[],
|
|
159
|
+
selected: readonly string[],
|
|
160
|
+
outcomes: readonly BulkTrackFileOutcome[],
|
|
161
|
+
control?: CodeRequestControl,
|
|
162
|
+
): string[] {
|
|
163
|
+
const selectedSet = new Set(selected);
|
|
164
|
+
const outcomeByPath = new Map(outcomes.map((outcome) => [outcome.file, outcome] as const));
|
|
165
|
+
const unstarted: string[] = [];
|
|
166
|
+
const unavailable: string[] = [];
|
|
167
|
+
|
|
168
|
+
for (const filePath of queue) {
|
|
169
|
+
throwIfCodeRequestInterrupted(control);
|
|
170
|
+
if (!selectedSet.has(filePath)) {
|
|
171
|
+
unstarted.push(filePath);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const outcome = outcomeByPath.get(filePath);
|
|
175
|
+
if (!outcome) {
|
|
176
|
+
unstarted.push(filePath);
|
|
177
|
+
} else if (outcome.kind === "unavailable") {
|
|
178
|
+
unavailable.push(filePath);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return [...unstarted, ...unavailable];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function pathsForOutcome(
|
|
185
|
+
outcomes: readonly BulkTrackFileOutcome[],
|
|
186
|
+
kind: BulkTrackFileOutcome["kind"],
|
|
187
|
+
): string[] {
|
|
188
|
+
return outcomes.filter((outcome) => outcome.kind === kind).map((outcome) => outcome.file);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function createReport(options: {
|
|
192
|
+
cwd: string;
|
|
193
|
+
inventory: WorkspaceSourceInventory;
|
|
194
|
+
discovered: readonly string[];
|
|
195
|
+
tracked: readonly string[];
|
|
196
|
+
skipped: readonly string[];
|
|
197
|
+
unavailable: readonly string[];
|
|
198
|
+
deferred: readonly string[];
|
|
199
|
+
control?: CodeRequestControl;
|
|
200
|
+
}): SourceTrackingReport {
|
|
201
|
+
return {
|
|
202
|
+
status: options.inventory.status,
|
|
203
|
+
reason: options.inventory.reason,
|
|
204
|
+
observedFileCount: options.inventory.observedFileCount,
|
|
205
|
+
discovered: displayPaths(options.cwd, options.discovered, options.control),
|
|
206
|
+
tracked: displayPaths(options.cwd, options.tracked, options.control),
|
|
207
|
+
skipped: displayPaths(options.cwd, options.skipped, options.control),
|
|
208
|
+
unavailable: displayPaths(options.cwd, options.unavailable, options.control),
|
|
209
|
+
deferred: options.deferred.length,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function displayPaths(
|
|
214
|
+
cwd: string,
|
|
215
|
+
filePaths: readonly string[],
|
|
216
|
+
control?: CodeRequestControl,
|
|
217
|
+
): string[] {
|
|
218
|
+
const displayed: string[] = [];
|
|
219
|
+
for (const filePath of filePaths) {
|
|
220
|
+
throwIfCodeRequestInterrupted(control);
|
|
221
|
+
const relativePath = path.relative(cwd, filePath);
|
|
222
|
+
displayed.push((relativePath || path.basename(filePath)).replaceAll(path.sep, "/"));
|
|
223
|
+
}
|
|
224
|
+
return displayed;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function deduplicatePaths(filePaths: readonly string[], control?: CodeRequestControl): string[] {
|
|
228
|
+
const unique = new Set<string>();
|
|
229
|
+
for (const filePath of filePaths) {
|
|
230
|
+
throwIfCodeRequestInterrupted(control);
|
|
231
|
+
unique.add(filePath);
|
|
232
|
+
}
|
|
233
|
+
return [...unique];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function removeMissingPaths(filePaths: readonly string[], control?: CodeRequestControl): string[] {
|
|
237
|
+
const existing: string[] = [];
|
|
238
|
+
for (const filePath of filePaths) {
|
|
239
|
+
throwIfCodeRequestInterrupted(control);
|
|
240
|
+
if (!isMissingFile(filePath)) existing.push(filePath);
|
|
241
|
+
}
|
|
242
|
+
return existing;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function isMissingFile(filePath: string): boolean {
|
|
246
|
+
try {
|
|
247
|
+
statSync(filePath);
|
|
248
|
+
return false;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
return isMissingFileError(error);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export const toolDescription =
|
|
2
|
-
|
|
2
|
+
"Search workspace symbols in semantic mode, or declaration, import, export, and call names in AST mode. Use PI grep for literal or regular-expression file-content search. The selected mode does not switch to another search method.";
|
|
3
3
|
|
|
4
|
-
export const promptSnippet = "
|
|
4
|
+
export const promptSnippet = "search code structure or workspace symbols";
|
|
5
5
|
|
|
6
6
|
export const promptGuidelines = [
|
|
7
|
-
"Use code_find for
|
|
7
|
+
"Use code_find for broad code-aware discovery, code_resolve for target identity, and code_graph for relationships.",
|
|
8
8
|
];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
import type { CodeIntelToolExecCtx } from "../../types/index.ts";
|
|
4
|
-
import { FindScopeParam, MaxResultsParam
|
|
4
|
+
import { FindQueryParam, FindScopeParam, MaxResultsParam } from "../schemas.ts";
|
|
5
5
|
import { CODE_FIND_AST_KINDS } from "./ast-kinds.ts";
|
|
6
6
|
import { executeFindTool } from "./execute.ts";
|
|
7
7
|
import { CODE_FIND_MODES } from "./modes.ts";
|
|
@@ -16,14 +16,15 @@ export const codeFindSpec = {
|
|
|
16
16
|
label: CODE_FIND_TOOL_LABEL,
|
|
17
17
|
parameters: Type.Object(
|
|
18
18
|
{
|
|
19
|
-
query:
|
|
19
|
+
query: FindQueryParam,
|
|
20
20
|
scope: Type.Optional(FindScopeParam),
|
|
21
21
|
mode: StringEnum(CODE_FIND_MODES, {
|
|
22
|
-
description:
|
|
22
|
+
description:
|
|
23
|
+
"Required code-aware search mode. AST mode requires `kind`; semantic mode rejects `kind`.",
|
|
23
24
|
}),
|
|
24
25
|
kind: Type.Optional(
|
|
25
26
|
StringEnum(CODE_FIND_AST_KINDS, {
|
|
26
|
-
description: 'AST kind for mode:"ast".',
|
|
27
|
+
description: 'AST structure kind; required only for mode:"ast".',
|
|
27
28
|
}),
|
|
28
29
|
),
|
|
29
30
|
maxResults: Type.Optional(MaxResultsParam),
|
|
@@ -37,5 +37,11 @@ export function renderFindResult(
|
|
|
37
37
|
theme: Theme,
|
|
38
38
|
context: ToolRendererContext | undefined,
|
|
39
39
|
): ReturnType<typeof renderSimpleResult> {
|
|
40
|
-
return renderSimpleResult(
|
|
40
|
+
return renderSimpleResult(
|
|
41
|
+
result,
|
|
42
|
+
options,
|
|
43
|
+
theme,
|
|
44
|
+
{ progress: "Searching…", failure: "code_find failed" },
|
|
45
|
+
context,
|
|
46
|
+
);
|
|
41
47
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { EvidenceListMetadata } from "../../analysis/evidence.ts";
|
|
2
|
+
import type { ReadNextItem } from "../../analysis/read-next.ts";
|
|
3
|
+
import type { CalleeScope } from "../../analysis/relations/types.ts";
|
|
4
|
+
import type { GraphRelationKind } from "../../session/graph-types.ts";
|
|
5
|
+
|
|
6
|
+
/** File heading for the next count rows in the relation's bounded display section. */
|
|
7
|
+
export interface GraphFileGroup {
|
|
8
|
+
file: string;
|
|
9
|
+
count: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Relation status and context kept for the human transcript. Counts live in evidenceLists. */
|
|
13
|
+
export interface GraphSectionDetails {
|
|
14
|
+
rel: GraphRelationKind;
|
|
15
|
+
source: "semantic" | "structural";
|
|
16
|
+
status: "complete" | "partial" | "unavailable";
|
|
17
|
+
message: string | null;
|
|
18
|
+
externalCount: number;
|
|
19
|
+
enclosingScope: CalleeScope | null;
|
|
20
|
+
depth: "direct" | "deep" | null;
|
|
21
|
+
/** Absent in older results whose display rows already contain full paths. */
|
|
22
|
+
fileGroups?: GraphFileGroup[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Persisted graph facts. The TUI does not read or parse agent Markdown. */
|
|
26
|
+
export interface GraphDetails {
|
|
27
|
+
targetName: string;
|
|
28
|
+
targetFile: string;
|
|
29
|
+
sections: GraphSectionDetails[];
|
|
30
|
+
evidenceLists: EvidenceListMetadata[];
|
|
31
|
+
readNext: ReadNextItem[];
|
|
32
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { CallEntry, ReferenceEntry } from "../../analysis/relations/types.ts";
|
|
2
|
+
import { toDisplayPath } from "../../analysis/search/paths.ts";
|
|
3
|
+
import { createToolDisplaySection } from "../result/display.ts";
|
|
4
|
+
import type { ToolDisplaySection } from "../result/types.ts";
|
|
5
|
+
import type { GraphFileGroup } from "./details.ts";
|
|
6
|
+
import { compactGraphLabel } from "./format.ts";
|
|
7
|
+
import type { AssembledGraphSection } from "./result.ts";
|
|
8
|
+
|
|
9
|
+
/** Bound sites before grouping them. Each file group partitions the display rows. */
|
|
10
|
+
export function graphDisplaySection(
|
|
11
|
+
section: AssembledGraphSection,
|
|
12
|
+
cwd: string,
|
|
13
|
+
): {
|
|
14
|
+
display: ToolDisplaySection;
|
|
15
|
+
fileGroups: GraphFileGroup[];
|
|
16
|
+
} {
|
|
17
|
+
if (section.kind === "unavailable") {
|
|
18
|
+
return {
|
|
19
|
+
display: createToolDisplaySection({
|
|
20
|
+
key: `graph.${section.rel}`,
|
|
21
|
+
title: section.rel,
|
|
22
|
+
items: [],
|
|
23
|
+
format: () => "",
|
|
24
|
+
}),
|
|
25
|
+
fileGroups: [],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const items = section.evidence.items as readonly (CallEntry | ReferenceEntry)[];
|
|
29
|
+
const display = createToolDisplaySection({
|
|
30
|
+
key: `graph.${section.rel}`,
|
|
31
|
+
title: section.rel,
|
|
32
|
+
items,
|
|
33
|
+
totalCount: section.evidence.metadata.totalCount,
|
|
34
|
+
omittedCount: section.evidence.metadata.omittedCount,
|
|
35
|
+
partialReason: section.evidence.metadata.partialReason,
|
|
36
|
+
format: (item) => {
|
|
37
|
+
const site = `L${item.line}:${item.character}`;
|
|
38
|
+
if (section.rel !== "callees") return site;
|
|
39
|
+
const call = item as CallEntry;
|
|
40
|
+
return `${site} — ${compactGraphLabel(call.displayName ?? call.name)}`;
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
const groups = new Map<string, string[]>();
|
|
44
|
+
for (let index = 0; index < display.shownCount; index++) {
|
|
45
|
+
const file = toDisplayPath(cwd, items[index].file);
|
|
46
|
+
const rows = groups.get(file) ?? [];
|
|
47
|
+
rows.push(display.lines[index]);
|
|
48
|
+
groups.set(file, rows);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
display: { ...display, lines: [...groups.values()].flat() },
|
|
52
|
+
fileGroups: [...groups].map(([file, rows]) => ({ file, count: rows.length })),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { EvidenceListMetadata } from "../../analysis/evidence.ts";
|
|
2
|
+
|
|
3
|
+
/** Format graph counts and all known limits in one place. */
|
|
4
|
+
export function formatGraphEvidence(
|
|
5
|
+
metadata: Omit<EvidenceListMetadata, "partialReason"> & { partialReason: string | null },
|
|
6
|
+
noun: "locations" | "call sites" | "candidates",
|
|
7
|
+
externalCount = 0,
|
|
8
|
+
): string {
|
|
9
|
+
const { shownCount, totalCount, omittedCount, partialReason, invalidLocationCount } = metadata;
|
|
10
|
+
const count = totalCount ?? shownCount;
|
|
11
|
+
const label = count === 1 ? singularGraphNoun(noun) : noun;
|
|
12
|
+
let text =
|
|
13
|
+
totalCount === null
|
|
14
|
+
? `${shownCount} ${label} shown${omittedCount ? `; ${omittedCount} collected omitted` : ""}; more may exist — ${partialReason}`
|
|
15
|
+
: omittedCount
|
|
16
|
+
? `${shownCount} of ${totalCount} ${label} shown; ${omittedCount} omitted`
|
|
17
|
+
: `${totalCount} ${label}`;
|
|
18
|
+
if (externalCount > 0)
|
|
19
|
+
text += `; ${externalCount} external location${externalCount === 1 ? "" : "s"}`;
|
|
20
|
+
if (invalidLocationCount) {
|
|
21
|
+
const invalidNoun = invalidLocationCount === 1 ? "location" : "locations";
|
|
22
|
+
text += `; ${invalidLocationCount} invalid provider ${invalidNoun} omitted (invalid-provider-location)`;
|
|
23
|
+
}
|
|
24
|
+
return text;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function singularGraphNoun(noun: "locations" | "call sites" | "candidates"): string {
|
|
28
|
+
switch (noun) {
|
|
29
|
+
case "locations":
|
|
30
|
+
return "location";
|
|
31
|
+
case "call sites":
|
|
32
|
+
return "call site";
|
|
33
|
+
case "candidates":
|
|
34
|
+
return "candidate";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Format a 1-based source-line range for either graph presentation. */
|
|
39
|
+
export function formatGraphRange(scope: { startLine: number; endLine: number }): string {
|
|
40
|
+
return scope.startLine === scope.endLine
|
|
41
|
+
? `L${scope.startLine}`
|
|
42
|
+
: `L${scope.startLine}–L${scope.endLine}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Bound a source label while keeping both ends of a chained expression. */
|
|
46
|
+
export function compactGraphLabel(value: string, limit = 100): string {
|
|
47
|
+
const text = value.replace(/\s+/g, " ").trim();
|
|
48
|
+
if (text.length <= limit) return text;
|
|
49
|
+
const tail = Math.floor(limit / 3);
|
|
50
|
+
return `${text.slice(0, limit - tail - 1)}…${text.slice(-tail)}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Quote source text that can contain Markdown backticks. */
|
|
54
|
+
export function graphCodeSpan(text: string): string {
|
|
55
|
+
const runs = text.match(/`+/g) ?? [];
|
|
56
|
+
const delimiter = "`".repeat(Math.max(0, ...runs.map((run) => run.length)) + 1);
|
|
57
|
+
return text.startsWith("`") || text.endsWith("`")
|
|
58
|
+
? `${delimiter} ${text} ${delimiter}`
|
|
59
|
+
: `${delimiter}${text}${delimiter}`;
|
|
60
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const toolDescription =
|
|
2
|
-
"
|
|
2
|
+
"Find semantic references and implementations, or non-symbol-aware structural calls written inside a target's enclosing scope.";
|
|
3
3
|
|
|
4
|
-
export const promptSnippet = "
|
|
4
|
+
export const promptSnippet = "trace code relationships";
|
|
5
5
|
|
|
6
6
|
export const promptGuidelines: string[] = [];
|