@mrclrchtr/supi-code-intelligence 4.0.0 → 4.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/README.md +8 -3
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -5
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
- 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-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
- package/node_modules/@mrclrchtr/supi-lsp/package.json +3 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/utils.ts +2 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +5 -5
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -5
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
- 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-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +3 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/language.ts +2 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/operation-support.ts +19 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/syntax-node.ts +1 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-c-family.ts +230 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-html-sql.ts +186 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-jvm.ts +311 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-polyglot.ts +218 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-scripting.ts +307 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline.ts +9 -5
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +6 -2
- package/package.json +6 -5
- package/src/analysis/search/pattern.ts +2 -2
- package/src/analysis/target/symbol.ts +5 -2
- package/src/app/app.ts +4 -1
- package/src/extension.ts +6 -84
- package/src/headless.ts +41 -0
- package/src/session/orientation/collect.ts +134 -180
- package/src/session/orientation/context-sections.ts +14 -48
- package/src/session/orientation-types.ts +14 -4
- package/src/session/orientation-workflow.ts +20 -48
- package/src/substrate/lsp/lifecycle.ts +25 -39
- package/src/substrate/lsp/state.ts +3 -0
- package/src/substrate/workspace-provider-host.ts +129 -0
- package/src/tool/graph/execute.ts +1 -1
- package/src/tool/graph/markdown.ts +222 -0
- package/src/tool/orientation/markdown.ts +66 -11
- package/src/tool/register.ts +10 -0
- package/src/ui/markdown/overview-data.ts +3 -15
- package/src/ui/markdown/overview.ts +4 -10
- package/src/ui/markdown/types.ts +0 -1
- package/src/substrate/tree-sitter/lifecycle.ts +0 -52
- package/src/tool/graph/calls-md.ts +0 -41
- package/src/tool/graph/implementations-md.ts +0 -57
- package/src/tool/graph/markdown-base.ts +0 -88
- package/src/tool/graph/provider-location-md.ts +0 -9
- package/src/tool/graph/references-md.ts +0 -41
|
@@ -1,30 +1,85 @@
|
|
|
1
|
+
import type { EvidenceListMetadata } from "../../analysis/evidence.ts";
|
|
1
2
|
import { renderReadNextSection } from "../../analysis/read-next.ts";
|
|
3
|
+
import type {
|
|
4
|
+
OrientationItem,
|
|
5
|
+
OrientationProvenance,
|
|
6
|
+
OrientationSectionData,
|
|
7
|
+
} from "../../session/orientation-types.ts";
|
|
2
8
|
import { assembledReadNext } from "../result/assembly.ts";
|
|
3
9
|
import type { OrientationResultAssembly } from "../result/orientation.ts";
|
|
4
10
|
|
|
5
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Sole model-facing markdown adapter for Orientation.
|
|
13
|
+
*
|
|
14
|
+
* Collectors emit presentation-neutral facts (title, notes, and per-section
|
|
15
|
+
* {@link OrientationItem}s); this adapter owns all document framing — the
|
|
16
|
+
* leading notes, the h1 title, the optional Focus section, and each section's
|
|
17
|
+
* h2 heading + status note.
|
|
18
|
+
*/
|
|
6
19
|
export function renderOrientationResult(assembly: OrientationResultAssembly): string {
|
|
7
20
|
const data = assembly.assembled.data;
|
|
8
21
|
const lines: string[] = [];
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
22
|
+
|
|
23
|
+
for (const note of data.notes) lines.push(note);
|
|
24
|
+
if (data.notes.length > 0) lines.push("");
|
|
25
|
+
|
|
26
|
+
lines.push(`# ${data.title}`, "");
|
|
27
|
+
|
|
28
|
+
if (data.target && data.focusTarget) {
|
|
29
|
+
lines.push("## Focus", `- \`${data.focusTarget}\``, "");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (const section of data.sections) {
|
|
33
|
+
lines.push(`## ${section.title}`, formatSectionNote(section));
|
|
34
|
+
renderItems(lines, section.items);
|
|
35
|
+
lines.push("");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
lines.push(...renderReadNextSection(assembledReadNext(assembly.assembled)));
|
|
39
|
+
return lines.join("\n").trimEnd();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function renderItems(lines: string[], items: readonly OrientationItem[]): void {
|
|
43
|
+
for (const item of items) {
|
|
44
|
+
switch (item.kind) {
|
|
14
45
|
case "paragraph":
|
|
15
|
-
lines.push(
|
|
46
|
+
lines.push(item.text);
|
|
16
47
|
break;
|
|
17
48
|
case "list-item":
|
|
18
|
-
lines.push(`- ${
|
|
49
|
+
lines.push(`- ${item.text}`);
|
|
50
|
+
break;
|
|
51
|
+
case "subheading":
|
|
52
|
+
lines.push(`### ${item.text}`);
|
|
19
53
|
break;
|
|
20
54
|
case "code":
|
|
21
|
-
lines.push(`\`\`\`${
|
|
55
|
+
lines.push(`\`\`\`${item.language ?? ""}`, ...item.lines, "```");
|
|
22
56
|
break;
|
|
23
57
|
case "blank":
|
|
24
58
|
lines.push("");
|
|
25
59
|
break;
|
|
26
60
|
}
|
|
27
61
|
}
|
|
28
|
-
|
|
29
|
-
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Render the same section status/provenance metadata stored in result details. */
|
|
65
|
+
function formatSectionNote(section: OrientationSectionData): string {
|
|
66
|
+
const facts = section.evidenceLists.map(evidenceSummary).join("; ");
|
|
67
|
+
const provenance = section.provenance.map(formatProvenance).join(", ");
|
|
68
|
+
return `_(status: ${section.status}; provenance: ${provenance || "none"}${section.reason ? `; ${section.reason}` : ""}${facts ? `; ${facts}` : ""})_`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function evidenceSummary(metadata: EvidenceListMetadata): string {
|
|
72
|
+
if (metadata.totalCount === null) {
|
|
73
|
+
const omitted = metadata.omittedCount ? `; ${metadata.omittedCount} collected omitted` : "";
|
|
74
|
+
return `showing ${metadata.shownCount}${omitted}; more may exist — ${metadata.partialReason ?? "partial"}`;
|
|
75
|
+
}
|
|
76
|
+
if ((metadata.omittedCount ?? 0) > 0) {
|
|
77
|
+
return `showing ${metadata.shownCount} of ${metadata.totalCount}; ${metadata.omittedCount} omitted`;
|
|
78
|
+
}
|
|
79
|
+
return `${metadata.totalCount} observed`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function formatProvenance(provenance: OrientationProvenance): string {
|
|
83
|
+
const detail = provenance.detail ? ` \`${provenance.detail}\`` : "";
|
|
84
|
+
return `${provenance.source}${provenance.capability ? ` (${provenance.capability})` : ""}${detail}`;
|
|
30
85
|
}
|
package/src/tool/register.ts
CHANGED
|
@@ -74,12 +74,22 @@ function getToolRenderer(name: string): ToolRenderer {
|
|
|
74
74
|
* @param getOrCreateSession — session factory; production passes the app-managed
|
|
75
75
|
* sessions, tests pass a `createSessionCache`-backed factory.
|
|
76
76
|
*/
|
|
77
|
+
const registeredPis = new WeakSet<object>();
|
|
78
|
+
|
|
77
79
|
export function registerCodeIntelligenceTools(
|
|
78
80
|
pi: ExtensionAPI,
|
|
79
81
|
getOrCreateSession: (cwd: string) => WorkspaceCodeIntelligenceSession,
|
|
80
82
|
promptSurfaces: CodeIntelligenceToolPromptSurfaceMap = CODE_INTELLIGENCE_TOOL_PROMPT_SURFACES,
|
|
81
83
|
specs: readonly CodeIntelligenceToolDefinitionSpec[] = CODE_INTELLIGENCE_TOOL_SPECS,
|
|
82
84
|
): void {
|
|
85
|
+
// Skip when another copy is already loaded (e.g. standalone install + bundled
|
|
86
|
+
// copy inside supi-review). Pi loads packages with separate module roots, so
|
|
87
|
+
// module-level state is not shared. Key on the pi object: both copies receive
|
|
88
|
+
// the same ExtensionAPI in one process, while tests get fresh mocks.
|
|
89
|
+
// ponytail: WeakSet on pi identity; getAllTools() is not callable during load.
|
|
90
|
+
if (registeredPis.has(pi)) return;
|
|
91
|
+
registeredPis.add(pi);
|
|
92
|
+
|
|
83
93
|
for (const spec of specs) {
|
|
84
94
|
const surface = promptSurfaces[spec.name];
|
|
85
95
|
pi.registerTool({
|
|
@@ -10,11 +10,6 @@ import type {
|
|
|
10
10
|
} from "../../analysis/architecture/model.ts";
|
|
11
11
|
import type { OverviewData, OverviewModule } from "./types.ts";
|
|
12
12
|
|
|
13
|
-
/** Maximum number of modules shown in the overview. */
|
|
14
|
-
const MAX_MODULES = 8;
|
|
15
|
-
/** Maximum characters per module description before truncation. */
|
|
16
|
-
const MAX_DESCRIPTION_LENGTH = 60;
|
|
17
|
-
|
|
18
13
|
/** Grammar ID to short language tag for the overview. */
|
|
19
14
|
const GRAMMAR_LANGUAGE_TAGS: Record<string, string> = {
|
|
20
15
|
javascript: "js",
|
|
@@ -44,14 +39,13 @@ export function buildOverviewData(model: ArchitectureModel): OverviewData | null
|
|
|
44
39
|
const sorted = [...model.modules].sort((left, right) =>
|
|
45
40
|
left.relativePath.localeCompare(right.relativePath),
|
|
46
41
|
);
|
|
47
|
-
const modules = sorted.
|
|
48
|
-
const detectedLanguages = detectModuleLanguages(sorted
|
|
42
|
+
const modules = sorted.map((module) => overviewModule(module, model));
|
|
43
|
+
const detectedLanguages = detectModuleLanguages(sorted);
|
|
49
44
|
|
|
50
45
|
return {
|
|
51
46
|
projectName: model.name,
|
|
52
47
|
projectDescription: model.description,
|
|
53
48
|
modules,
|
|
54
|
-
omittedModuleCount: Math.max(0, model.modules.length - MAX_MODULES),
|
|
55
49
|
detectedLanguages: detectedLanguages.length > 0 ? detectedLanguages : null,
|
|
56
50
|
};
|
|
57
51
|
}
|
|
@@ -61,7 +55,7 @@ function overviewModule(module: ModuleInfo, model: ArchitectureModel): OverviewM
|
|
|
61
55
|
return {
|
|
62
56
|
name,
|
|
63
57
|
shortName: module.name?.replace(/^@[^/]+\//, "") ?? module.relativePath,
|
|
64
|
-
description:
|
|
58
|
+
description: module.description,
|
|
65
59
|
declaredDependencies: model.edges
|
|
66
60
|
.filter((edge) => edge.from === module.name)
|
|
67
61
|
.map((edge) => edge.to),
|
|
@@ -99,12 +93,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
99
93
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
100
94
|
}
|
|
101
95
|
|
|
102
|
-
function truncateDescription(description: string | null): string | null {
|
|
103
|
-
if (!description) return null;
|
|
104
|
-
if (description.length <= MAX_DESCRIPTION_LENGTH) return description;
|
|
105
|
-
return `${description.slice(0, MAX_DESCRIPTION_LENGTH - 1)}…`;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
96
|
/**
|
|
109
97
|
* Detect languages present in the first two levels of each module directory.
|
|
110
98
|
*
|
|
@@ -7,8 +7,8 @@ import type { OverviewData } from "./types.ts";
|
|
|
7
7
|
const OVERVIEW_TOKEN_BUDGET = 600;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Render the
|
|
11
|
-
*
|
|
10
|
+
* Render the complete manifest-derived architecture overview for first-turn injection.
|
|
11
|
+
* Output is never truncated; callers may warn when it exceeds the soft token budget.
|
|
12
12
|
*/
|
|
13
13
|
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: module-edge overview rendering with multiple formatting paths is clearer as one function
|
|
14
14
|
export function renderOverview(data: OverviewData): string {
|
|
@@ -40,19 +40,13 @@ export function renderOverview(data: OverviewData): string {
|
|
|
40
40
|
`- **${mod.shortName}**${entrypointSuffix}${mod.description ? ` — ${mod.description}` : ""}`,
|
|
41
41
|
);
|
|
42
42
|
} else {
|
|
43
|
-
const depNames = deps.
|
|
44
|
-
const depStr = depNames.join(", ");
|
|
45
|
-
const suffix = deps.length > 4 ? ` +${deps.length - 4} more` : "";
|
|
43
|
+
const depNames = deps.map((dependency) => dependency.replace(/^@[^/]+\//, ""));
|
|
46
44
|
lines.push(
|
|
47
|
-
`- **${mod.shortName}** → ${
|
|
45
|
+
`- **${mod.shortName}** → ${depNames.join(", ")}${entrypointSuffix}${mod.description ? ` — ${mod.description}` : ""}`,
|
|
48
46
|
);
|
|
49
47
|
}
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
if (data.omittedModuleCount > 0) {
|
|
53
|
-
lines.push(`- _+${data.omittedModuleCount} more modules omitted_`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
50
|
lines.push("");
|
|
57
51
|
|
|
58
52
|
if (data.detectedLanguages && data.detectedLanguages.length > 0) {
|
package/src/ui/markdown/types.ts
CHANGED
|
@@ -22,7 +22,6 @@ export interface OverviewData {
|
|
|
22
22
|
projectName: string | null;
|
|
23
23
|
projectDescription: string | null;
|
|
24
24
|
modules: OverviewModule[];
|
|
25
|
-
omittedModuleCount: number;
|
|
26
25
|
/** Detected source languages (e.g. ["ts", "js", "py"]). */
|
|
27
26
|
detectedLanguages: string[] | null;
|
|
28
27
|
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// Tree-sitter session lifecycle — uses TreeSitterRuntimeController from @mrclrchtr/supi-tree-sitter/api.
|
|
2
|
-
|
|
3
|
-
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
import { getDefaultWorkspaceRuntime } from "@mrclrchtr/supi-code-runtime/api";
|
|
5
|
-
import { TreeSitterRuntimeController } from "@mrclrchtr/supi-tree-sitter/api";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Tree-sitter adapter state for the umbrella extension.
|
|
9
|
-
*/
|
|
10
|
-
export interface TsAdapterState {
|
|
11
|
-
controller: TreeSitterRuntimeController | null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function createTsAdapterState(): TsAdapterState {
|
|
15
|
-
return { controller: null };
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Register Tree-sitter session lifecycle handlers.
|
|
20
|
-
*
|
|
21
|
-
* - session_start: creates TreeSitterRuntimeController, starts it, registers tools
|
|
22
|
-
* - session_shutdown: shuts down the controller
|
|
23
|
-
*/
|
|
24
|
-
export function registerTsSessionLifecycle(pi: ExtensionAPI, state: TsAdapterState): void {
|
|
25
|
-
pi.on("session_start", async (_event, ctx: ExtensionContext) => {
|
|
26
|
-
const cwd = ctx.cwd;
|
|
27
|
-
const runtime = getDefaultWorkspaceRuntime();
|
|
28
|
-
|
|
29
|
-
// Shut down any existing controller
|
|
30
|
-
if (state.controller) {
|
|
31
|
-
await state.controller.shutdown();
|
|
32
|
-
state.controller = null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const controller = new TreeSitterRuntimeController(cwd, runtime);
|
|
36
|
-
const result = await controller.start();
|
|
37
|
-
|
|
38
|
-
if (result.kind === "ready") {
|
|
39
|
-
state.controller = controller;
|
|
40
|
-
} else {
|
|
41
|
-
await controller.shutdown();
|
|
42
|
-
state.controller = null;
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
pi.on("session_shutdown", async () => {
|
|
47
|
-
if (state.controller) {
|
|
48
|
-
await state.controller.shutdown();
|
|
49
|
-
state.controller = null;
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/** Calls markdown renderer — renders assembled structural-call evidence. */
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
type EvidenceList,
|
|
5
|
-
type EvidenceListMetadata,
|
|
6
|
-
renderEvidenceListMetadataDisclosure,
|
|
7
|
-
} from "../../analysis/evidence.ts";
|
|
8
|
-
import type { CallEntry, CalleeScope } from "../../analysis/relations/types.ts";
|
|
9
|
-
|
|
10
|
-
export function renderCallsResult(
|
|
11
|
-
enclosingScope: CalleeScope,
|
|
12
|
-
calls: EvidenceList<CallEntry>,
|
|
13
|
-
relPath: string,
|
|
14
|
-
depth: "direct" | "deep" = "direct",
|
|
15
|
-
): { content: string; evidenceList: EvidenceListMetadata } {
|
|
16
|
-
const lines: string[] = [];
|
|
17
|
-
const depthLabel = depth === "deep" ? "Deep structural calls" : "Direct structural calls";
|
|
18
|
-
const depthNote =
|
|
19
|
-
depth === "deep"
|
|
20
|
-
? "_Deep: includes calls from nested function/method/callback scopes within the enclosing scope._"
|
|
21
|
-
: "_Structural only: call expressions are reported by source shape, not symbol identity; calls inside nested function/method/callback scopes are excluded from this enclosing scope._";
|
|
22
|
-
const total = calls.metadata.totalCount ?? calls.metadata.shownCount;
|
|
23
|
-
|
|
24
|
-
lines.push(`# ${depthLabel} from \`${enclosingScope.name}\``, "");
|
|
25
|
-
lines.push(
|
|
26
|
-
`**${total} ${depth === "deep" ? "" : "direct "}structural call${total === 1 ? "" : "s"}** from enclosing scope \`${enclosingScope.name}\` (${formatScopeRange(enclosingScope)}) in \`${relPath}\``,
|
|
27
|
-
"",
|
|
28
|
-
depthNote,
|
|
29
|
-
"",
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
for (const call of calls.items) lines.push(`- \`${call.name}\` (L${call.line})`);
|
|
33
|
-
const disclosure = renderEvidenceListMetadataDisclosure(calls.metadata);
|
|
34
|
-
if (disclosure) lines.push(disclosure);
|
|
35
|
-
return { content: lines.join("\n"), evidenceList: calls.metadata };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function formatScopeRange(scope: CalleeScope): string {
|
|
39
|
-
if (scope.startLine === scope.endLine) return `L${scope.startLine}`;
|
|
40
|
-
return `L${scope.startLine}–L${scope.endLine}`;
|
|
41
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/** Implementations markdown renderer over assembled semantic evidence. */
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
type EvidenceList,
|
|
5
|
-
type EvidenceListMetadata,
|
|
6
|
-
renderEvidenceListMetadataDisclosure,
|
|
7
|
-
} from "../../analysis/evidence.ts";
|
|
8
|
-
import { compactLineRanges } from "../../analysis/references/semantic-refs.ts";
|
|
9
|
-
import type { ImplementationEntry } from "../../analysis/relations/types.ts";
|
|
10
|
-
import { toDisplayPath } from "../../analysis/search/paths.ts";
|
|
11
|
-
import { renderInvalidProviderLocations } from "./provider-location-md.ts";
|
|
12
|
-
|
|
13
|
-
function groupByFile(impls: readonly ImplementationEntry[], cwd: string): Map<string, number[]> {
|
|
14
|
-
const byFile = new Map<string, number[]>();
|
|
15
|
-
for (const impl of impls) {
|
|
16
|
-
const displayPath = toDisplayPath(cwd, impl.file);
|
|
17
|
-
const group = byFile.get(displayPath) ?? [];
|
|
18
|
-
group.push(impl.line);
|
|
19
|
-
byFile.set(displayPath, group);
|
|
20
|
-
}
|
|
21
|
-
return byFile;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function renderImplementationsResult(options: {
|
|
25
|
-
implementations: EvidenceList<ImplementationEntry>;
|
|
26
|
-
externalCount: number;
|
|
27
|
-
cwd: string;
|
|
28
|
-
targetName?: string;
|
|
29
|
-
}): { content: string; evidenceList: EvidenceListMetadata } {
|
|
30
|
-
const lines: string[] = [
|
|
31
|
-
options.targetName
|
|
32
|
-
? `# Implementations of \`${options.targetName}\` (semantic)`
|
|
33
|
-
: "# Implementations (semantic)",
|
|
34
|
-
"",
|
|
35
|
-
];
|
|
36
|
-
const total =
|
|
37
|
-
options.implementations.metadata.totalCount ?? options.implementations.metadata.shownCount;
|
|
38
|
-
if (total > 0) {
|
|
39
|
-
lines.push(`**${total} implementation${total === 1 ? "" : "s"}** in the project`, "");
|
|
40
|
-
for (const [file, locations] of groupByFile(options.implementations.items, options.cwd)) {
|
|
41
|
-
lines.push(`### ${file}`, `- ${compactLineRanges(locations)}`, "");
|
|
42
|
-
}
|
|
43
|
-
const disclosure = renderEvidenceListMetadataDisclosure(options.implementations.metadata);
|
|
44
|
-
if (disclosure) lines.push(disclosure);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (options.externalCount > 0) {
|
|
48
|
-
lines.push(
|
|
49
|
-
`_+${options.externalCount} external location${options.externalCount === 1 ? "" : "s"} (outside this project)_`,
|
|
50
|
-
"",
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
const invalidDisclosure = renderInvalidProviderLocations(options.implementations.metadata);
|
|
54
|
-
if (invalidDisclosure) lines.push(invalidDisclosure, "");
|
|
55
|
-
|
|
56
|
-
return { content: lines.join("\n"), evidenceList: options.implementations.metadata };
|
|
57
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/** Markdown adapter for assembled code_graph evidence. */
|
|
2
|
-
|
|
3
|
-
import { renderReadNextSection } from "../../analysis/read-next.ts";
|
|
4
|
-
import type { GraphResultAssembly } from "../result/graph.ts";
|
|
5
|
-
import { renderCallsResult } from "./calls-md.ts";
|
|
6
|
-
import { renderImplementationsResult } from "./implementations-md.ts";
|
|
7
|
-
import { renderReferencesResult } from "./references-md.ts";
|
|
8
|
-
|
|
9
|
-
/** Render an assembled graph result. */
|
|
10
|
-
export function renderGraphResult(assembly: GraphResultAssembly): string {
|
|
11
|
-
const lines = [
|
|
12
|
-
`# Graph of \`${assembly.displayName}\``,
|
|
13
|
-
"",
|
|
14
|
-
`_File: \`${assembly.resolvedDisplayFile}\`_`,
|
|
15
|
-
"",
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
const available = assembly.sections.filter((section) => section.kind === "ok");
|
|
19
|
-
if (available.length > 0) {
|
|
20
|
-
lines.push(
|
|
21
|
-
available
|
|
22
|
-
.map(
|
|
23
|
-
(section) =>
|
|
24
|
-
`**${section.rel}**: ${sectionCount(section)} result${sectionCount(section) === 1 ? "" : "s"}`,
|
|
25
|
-
)
|
|
26
|
-
.join(" | "),
|
|
27
|
-
"",
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const unavailable = assembly.sections.filter((section) => section.kind === "unavailable");
|
|
32
|
-
if (unavailable.length > 0) {
|
|
33
|
-
lines.push(
|
|
34
|
-
`_Unavailable: ${unavailable.map((section) => `\`${section.rel}\``).join(", ")}_`,
|
|
35
|
-
"",
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
for (const section of assembly.sections) {
|
|
40
|
-
if (section.kind === "unavailable") {
|
|
41
|
-
lines.push(`**${section.rel}**: ${section.message}`, "");
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
switch (section.rel) {
|
|
46
|
-
case "references": {
|
|
47
|
-
const rendered = renderReferencesResult({
|
|
48
|
-
symbolName: assembly.displayName,
|
|
49
|
-
references: section.evidence,
|
|
50
|
-
externalCount: section.data.externalCount,
|
|
51
|
-
confidence: section.data.confidence,
|
|
52
|
-
cwd: assembly.cwd,
|
|
53
|
-
});
|
|
54
|
-
lines.push(rendered.content, "");
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
case "callees": {
|
|
58
|
-
const rendered = renderCallsResult(
|
|
59
|
-
section.data.enclosingScope,
|
|
60
|
-
section.evidence,
|
|
61
|
-
assembly.resolvedDisplayFile,
|
|
62
|
-
section.data.depth,
|
|
63
|
-
);
|
|
64
|
-
lines.push(rendered.content, "");
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
case "implements": {
|
|
68
|
-
const rendered = renderImplementationsResult({
|
|
69
|
-
implementations: section.evidence,
|
|
70
|
-
externalCount: section.data.externalCount,
|
|
71
|
-
cwd: assembly.cwd,
|
|
72
|
-
targetName: assembly.displayName,
|
|
73
|
-
});
|
|
74
|
-
lines.push(rendered.content, "");
|
|
75
|
-
break;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
lines.push(...renderReadNextSection(available.flatMap((section) => section.readNext)));
|
|
81
|
-
return lines.join("\n");
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function sectionCount(
|
|
85
|
-
section: Extract<GraphResultAssembly["sections"][number], { kind: "ok" }>,
|
|
86
|
-
): number {
|
|
87
|
-
return section.evidence.metadata.totalCount ?? section.evidence.metadata.shownCount;
|
|
88
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { EvidenceListMetadata } from "../../analysis/evidence.ts";
|
|
2
|
-
|
|
3
|
-
/** Render an explicit disclosure for unusable semantic-provider locations. */
|
|
4
|
-
export function renderInvalidProviderLocations(metadata: EvidenceListMetadata): string | null {
|
|
5
|
-
const count = metadata.invalidLocationCount ?? 0;
|
|
6
|
-
if (count <= 0 || metadata.partialReason === null) return null;
|
|
7
|
-
const noun = count === 1 ? "location" : "locations";
|
|
8
|
-
return `_${count} invalid provider ${noun} omitted (${metadata.partialReason})_`;
|
|
9
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/** References markdown renderer over assembled semantic evidence. */
|
|
2
|
-
|
|
3
|
-
import type { EvidenceList, EvidenceListMetadata } from "../../analysis/evidence.ts";
|
|
4
|
-
import { formatAssembledReferenceList } from "../../analysis/references/semantic-refs.ts";
|
|
5
|
-
import type { ReferenceEntry } from "../../analysis/relations/types.ts";
|
|
6
|
-
import { toDisplayPath } from "../../analysis/search/paths.ts";
|
|
7
|
-
import { renderInvalidProviderLocations } from "./provider-location-md.ts";
|
|
8
|
-
|
|
9
|
-
export function renderReferencesResult(options: {
|
|
10
|
-
symbolName: string;
|
|
11
|
-
references: EvidenceList<ReferenceEntry>;
|
|
12
|
-
externalCount: number;
|
|
13
|
-
confidence: string;
|
|
14
|
-
cwd: string;
|
|
15
|
-
}): { content: string; evidenceList: EvidenceListMetadata | null } {
|
|
16
|
-
const total = options.references.metadata.totalCount ?? options.references.metadata.shownCount;
|
|
17
|
-
const lines = [
|
|
18
|
-
`# References of \`${options.symbolName}\``,
|
|
19
|
-
"",
|
|
20
|
-
`**${total} reference${total === 1 ? "" : "s"}** (${options.confidence})`,
|
|
21
|
-
];
|
|
22
|
-
if (options.externalCount > 0) {
|
|
23
|
-
lines.push(
|
|
24
|
-
`_+${options.externalCount} external reference${options.externalCount === 1 ? "" : "s"}_`,
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
const invalidDisclosure = renderInvalidProviderLocations(options.references.metadata);
|
|
28
|
-
if (invalidDisclosure) lines.push(invalidDisclosure);
|
|
29
|
-
lines.push("");
|
|
30
|
-
|
|
31
|
-
const displayEvidence = {
|
|
32
|
-
key: options.references.key,
|
|
33
|
-
items: options.references.items.map((reference) => ({
|
|
34
|
-
file: toDisplayPath(options.cwd, reference.file),
|
|
35
|
-
line: reference.line,
|
|
36
|
-
})),
|
|
37
|
-
metadata: options.references.metadata,
|
|
38
|
-
};
|
|
39
|
-
const evidenceList = formatAssembledReferenceList(lines, displayEvidence);
|
|
40
|
-
return { content: lines.join("\n"), evidenceList };
|
|
41
|
-
}
|