@danypops/pi-lector 0.13.11 → 0.15.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/extension/src/apply-patch/rendering.ts +2 -1
- package/extension/src/code-intelligence/rendering.ts +12 -7
- package/extension/src/cross-workspace-search/model-content.ts +69 -0
- package/extension/src/cross-workspace-search/rendering.ts +7 -2
- package/extension/src/external-search/rendering.ts +46 -12
- package/extension/src/find-files/rendering.ts +2 -1
- package/extension/src/find-symbols/rendering.ts +2 -1
- package/extension/src/git/rendering.ts +7 -5
- package/extension/src/index.ts +143 -64
- package/extension/src/line-edit/rendering.ts +2 -1
- package/extension/src/package-source/rendering.ts +4 -3
- package/extension/src/presentation/model-content.ts +62 -0
- package/extension/src/presentation/presentation-contract.ts +148 -0
- package/extension/src/presentation/tool-presentation.ts +171 -0
- package/extension/src/reference-based-rename/rendering.ts +21 -0
- package/extension/src/repo-cache/rendering.ts +4 -3
- package/extension/src/search/rendering.ts +2 -1
- package/extension/src/workspace-cache/operations.ts +24 -3
- package/extension/src/workspace-cache/rendering.ts +23 -5
- package/package.json +2 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EditOutcome } from "@danypops/lector";
|
|
2
2
|
import { renderDiffLines, renderTruncatedList, type TextMeasure } from "malevich-tui-components";
|
|
3
3
|
import type { LectorTheme } from "../lector-tui-theme.ts";
|
|
4
|
+
import { presentationTitle } from "../presentation/tool-presentation.ts";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* The applied result (EditOutcome) only carries a hash transition, not the
|
|
@@ -15,7 +16,7 @@ const DEFAULT_VISIBLE_PATCH_LINES = 12;
|
|
|
15
16
|
|
|
16
17
|
export function formatApplyPatchCall(args: { path?: unknown; patchText?: unknown }, theme: LectorTheme, measure?: TextMeasure): string {
|
|
17
18
|
const path = typeof args.path === "string" ? args.path : "";
|
|
18
|
-
const header = `${theme.fg("toolTitle", theme.bold("apply_patch"))} ${theme.fg("accent", path)}`;
|
|
19
|
+
const header = `${theme.fg("toolTitle", theme.bold(presentationTitle("apply_patch")))} ${theme.fg("accent", path)}`;
|
|
19
20
|
if (typeof args.patchText !== "string" || args.patchText.length === 0) return header;
|
|
20
21
|
|
|
21
22
|
const styledLines = renderDiffLines(
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
import { keyHint, type ThemeColor } from "@earendil-works/pi-coding-agent";
|
|
15
15
|
import { renderTruncatedList } from "malevich-tui-components";
|
|
16
16
|
import { colorForKind, formatLocation, type LectorTheme } from "../lector-tui-theme.ts";
|
|
17
|
+
import { presentationTitle } from "../presentation/tool-presentation.ts";
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Custom TUI rendering for the code-intelligence tools: go_to_definition,
|
|
@@ -41,7 +42,7 @@ function formatPositionalCall(toolName: string, args: { path?: unknown; line?: u
|
|
|
41
42
|
const path = typeof args.path === "string" ? args.path : "";
|
|
42
43
|
const line = typeof args.line === "number" ? args.line : "?";
|
|
43
44
|
const character = typeof args.character === "number" ? args.character : "?";
|
|
44
|
-
return `${theme.fg("toolTitle", theme.bold(toolName))} ${theme.fg("accent", `${path}:${line}:${character}`)}`;
|
|
45
|
+
return `${theme.fg("toolTitle", theme.bold(presentationTitle(toolName)))} ${theme.fg("accent", `${path}:${line}:${character}`)}`;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
function moreLine(theme: LectorTheme): (hidden: number) => string {
|
|
@@ -110,7 +111,7 @@ export function formatHoverResult(hover: Hover | undefined, expanded: boolean, t
|
|
|
110
111
|
|
|
111
112
|
export function formatDocumentSymbolsCall(args: { path?: unknown }, theme: LectorTheme): string {
|
|
112
113
|
const path = typeof args.path === "string" ? args.path : "";
|
|
113
|
-
return `${theme.fg("toolTitle", theme.bold("document_symbols"))} ${theme.fg("accent", path)}`;
|
|
114
|
+
return `${theme.fg("toolTitle", theme.bold(presentationTitle("document_symbols")))} ${theme.fg("accent", path)}`;
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
/** Flattens a hierarchical DocumentSymbolEntry[] into (depth, entry) pairs, depth-first, for bounded rendering. */
|
|
@@ -149,7 +150,7 @@ export function formatDocumentSymbolsResult(symbols: readonly DocumentSymbolEntr
|
|
|
149
150
|
|
|
150
151
|
export function formatDiagnosticsCall(args: { path?: unknown }, theme: LectorTheme): string {
|
|
151
152
|
const path = typeof args.path === "string" ? args.path : "";
|
|
152
|
-
return `${theme.fg("toolTitle", theme.bold("diagnostics"))} ${theme.fg("accent", path)}`;
|
|
153
|
+
return `${theme.fg("toolTitle", theme.bold(presentationTitle("diagnostics")))} ${theme.fg("accent", path)}`;
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
export function formatDiagnosticsResult(diagnostics: readonly Diagnostic[] | undefined, expanded: boolean, theme: LectorTheme): string {
|
|
@@ -175,7 +176,7 @@ export function formatDiagnosticsResult(diagnostics: readonly Diagnostic[] | und
|
|
|
175
176
|
|
|
176
177
|
function formatPathCall(toolName: string, args: { path?: unknown }, theme: LectorTheme, qualifier = ""): string {
|
|
177
178
|
const path = typeof args.path === "string" ? args.path : "";
|
|
178
|
-
return `${theme.fg("toolTitle", theme.bold(toolName))}${qualifier ? ` ${theme.fg("muted", qualifier)}` : ""} ${theme.fg("accent", path)}`;
|
|
179
|
+
return `${theme.fg("toolTitle", theme.bold(presentationTitle(toolName)))}${qualifier ? ` ${theme.fg("muted", qualifier)}` : ""} ${theme.fg("accent", path)}`;
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
export function formatCodeActionPreviewCall(
|
|
@@ -249,7 +250,11 @@ export function formatDiagnosticDeltaResult(result: OperationOutputs["workspace.
|
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
export function formatTypeHierarchyCall(args: { direction?: unknown; path?: unknown; line?: unknown; character?: unknown }, theme: LectorTheme): string {
|
|
252
|
-
|
|
253
|
+
const direction = typeof args.direction === "string" ? args.direction : undefined;
|
|
254
|
+
const path = typeof args.path === "string" ? args.path : "";
|
|
255
|
+
const line = typeof args.line === "number" ? args.line : "?";
|
|
256
|
+
const character = typeof args.character === "number" ? args.character : "?";
|
|
257
|
+
return `${theme.fg("toolTitle", theme.bold(presentationTitle("type_hierarchy", direction)))} ${theme.fg("accent", `${path}:${line}:${character}`)}`;
|
|
253
258
|
}
|
|
254
259
|
|
|
255
260
|
export function formatTypeHierarchyResult(
|
|
@@ -311,7 +316,7 @@ export function formatCallHierarchyCall(args: { direction?: unknown; path?: unkn
|
|
|
311
316
|
const path = typeof args.path === "string" ? args.path : "";
|
|
312
317
|
const line = typeof args.line === "number" ? args.line : "?";
|
|
313
318
|
const character = typeof args.character === "number" ? args.character : "?";
|
|
314
|
-
return `${theme.fg("toolTitle", theme.bold("call_hierarchy"
|
|
319
|
+
return `${theme.fg("toolTitle", theme.bold(presentationTitle("call_hierarchy", direction)))} ${theme.fg("accent", `${path}:${line}:${character}`)}`;
|
|
315
320
|
}
|
|
316
321
|
|
|
317
322
|
function formatPrepareCallHierarchyResult(items: readonly CallHierarchyEntry[] | undefined, theme: LectorTheme): string {
|
|
@@ -384,7 +389,7 @@ export function formatReachableFromResult(symbols: readonly SymbolNode[] | undef
|
|
|
384
389
|
export function formatWorkspaceMapCall(args: { path?: unknown; maxEntries?: unknown }, theme: LectorTheme): string {
|
|
385
390
|
const path = typeof args.path === "string" ? args.path : "";
|
|
386
391
|
const maxEntries = typeof args.maxEntries === "number" ? ` (top ${args.maxEntries})` : "";
|
|
387
|
-
return `${theme.fg("toolTitle", theme.bold("workspace_map"))} ${theme.fg("dim", path)}${theme.fg("muted", maxEntries)}`;
|
|
392
|
+
return `${theme.fg("toolTitle", theme.bold(presentationTitle("workspace_map")))} ${theme.fg("dim", path)}${theme.fg("muted", maxEntries)}`;
|
|
388
393
|
}
|
|
389
394
|
|
|
390
395
|
export function formatWorkspaceMapResult(result: WorkspaceMapResult | undefined, expanded: boolean, theme: LectorTheme): string {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { SymbolSearchResult, TextSearchResult } from "@danypops/lector";
|
|
2
|
+
import { boundModelContentText, DEFAULT_MODEL_CONTENT_BYTES } from "../presentation/model-content.ts";
|
|
3
|
+
import type { CrossWorkspaceOutcome } from "./operations.ts";
|
|
4
|
+
|
|
5
|
+
const MAX_RESULTS_PER_PROJECT = 10;
|
|
6
|
+
|
|
7
|
+
function appendOutcomeHeader<T>(lines: string[], entry: CrossWorkspaceOutcome<T>): boolean {
|
|
8
|
+
const { outcome } = entry;
|
|
9
|
+
switch (outcome.status) {
|
|
10
|
+
case "ready":
|
|
11
|
+
lines.push(`${entry.directory} -- ready`);
|
|
12
|
+
break;
|
|
13
|
+
case "loading":
|
|
14
|
+
lines.push(`${entry.directory} -- loading: ${outcome.message}`);
|
|
15
|
+
return false;
|
|
16
|
+
case "error":
|
|
17
|
+
lines.push(`${entry.directory} -- error: ${outcome.message}`);
|
|
18
|
+
return false;
|
|
19
|
+
default: {
|
|
20
|
+
const exhaustive: never = outcome;
|
|
21
|
+
throw new Error(`unhandled workspace query outcome: ${JSON.stringify(exhaustive)}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (entry.collapsedWith.length > 0) lines.push(` same workspace as: ${entry.collapsedWith.join(", ")}`);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Formats cross-project symbol outcomes with concrete, independently bounded results for model consumption. */
|
|
29
|
+
export function formatFindSymbolsAcrossProjectsModelContent(
|
|
30
|
+
results: readonly CrossWorkspaceOutcome<SymbolSearchResult>[],
|
|
31
|
+
maxBytes = DEFAULT_MODEL_CONTENT_BYTES,
|
|
32
|
+
): string {
|
|
33
|
+
const lines = ["Find Symbols Across Projects", `projects: ${results.length}`];
|
|
34
|
+
for (const entry of results) {
|
|
35
|
+
if (!appendOutcomeHeader(lines, entry)) continue;
|
|
36
|
+
if (entry.outcome.status !== "ready") continue;
|
|
37
|
+
const { result } = entry.outcome;
|
|
38
|
+
lines.push(` provenance: ${result.provenance.fidelity} via ${result.provenance.backend}`);
|
|
39
|
+
lines.push(` upstream truncated: ${result.truncated}`);
|
|
40
|
+
for (const item of result.symbols.slice(0, MAX_RESULTS_PER_PROJECT)) {
|
|
41
|
+
lines.push(` ${item.kind} ${item.name} -- ${item.location.path}:${item.location.line}:${item.location.character}`);
|
|
42
|
+
}
|
|
43
|
+
if (result.symbols.length > MAX_RESULTS_PER_PROJECT) lines.push(` ${result.symbols.length - MAX_RESULTS_PER_PROJECT} more symbols omitted`);
|
|
44
|
+
if (result.symbols.length === 0) lines.push(" no symbols matched");
|
|
45
|
+
}
|
|
46
|
+
return boundModelContentText(lines.join("\n"), maxBytes);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Formats cross-project text outcomes with concrete, independently bounded matches for model consumption. */
|
|
50
|
+
export function formatSearchTextAcrossProjectsModelContent(
|
|
51
|
+
results: readonly CrossWorkspaceOutcome<TextSearchResult>[],
|
|
52
|
+
maxBytes = DEFAULT_MODEL_CONTENT_BYTES,
|
|
53
|
+
): string {
|
|
54
|
+
const lines = ["Search Code Across Projects", `projects: ${results.length}`];
|
|
55
|
+
for (const entry of results) {
|
|
56
|
+
if (!appendOutcomeHeader(lines, entry)) continue;
|
|
57
|
+
if (entry.outcome.status !== "ready") continue;
|
|
58
|
+
const { result } = entry.outcome;
|
|
59
|
+
if (result.provenance) lines.push(` provenance: lexical via ${result.provenance.backend} (${result.provenance.indexState})`);
|
|
60
|
+
lines.push(` upstream truncated: ${result.truncated}`);
|
|
61
|
+
for (const item of result.matches.slice(0, MAX_RESULTS_PER_PROJECT)) {
|
|
62
|
+
const line = item.line.replace(/\n$/, "");
|
|
63
|
+
lines.push(` ${item.path}:${item.lineNumber}: ${line}${item.lineTruncated ? " (line truncated)" : ""}`);
|
|
64
|
+
}
|
|
65
|
+
if (result.matches.length > MAX_RESULTS_PER_PROJECT) lines.push(` ${result.matches.length - MAX_RESULTS_PER_PROJECT} more matches omitted`);
|
|
66
|
+
if (result.matches.length === 0) lines.push(" no matches");
|
|
67
|
+
}
|
|
68
|
+
return boundModelContentText(lines.join("\n"), maxBytes);
|
|
69
|
+
}
|
|
@@ -3,14 +3,19 @@ import { keyHint } from "@earendil-works/pi-coding-agent";
|
|
|
3
3
|
import { renderTruncatedList } from "malevich-tui-components";
|
|
4
4
|
import { describeFindSymbolSources } from "../find-symbols/rendering.ts";
|
|
5
5
|
import type { LectorTheme } from "../lector-tui-theme.ts";
|
|
6
|
+
import { presentationTitle } from "../presentation/tool-presentation.ts";
|
|
6
7
|
import type { CrossWorkspaceOutcome } from "./operations.ts";
|
|
7
8
|
|
|
8
9
|
const DEFAULT_VISIBLE_PER_WORKSPACE = 10;
|
|
9
10
|
|
|
10
|
-
export function formatCrossWorkspaceCall(
|
|
11
|
+
export function formatCrossWorkspaceCall(
|
|
12
|
+
toolName: "find_symbols_across_projects" | "search_code_across_projects",
|
|
13
|
+
args: { directories?: unknown; query?: unknown },
|
|
14
|
+
theme: LectorTheme,
|
|
15
|
+
): string {
|
|
11
16
|
const directories = Array.isArray(args.directories) ? args.directories.filter((d): d is string => typeof d === "string") : [];
|
|
12
17
|
const query = typeof args.query === "string" ? args.query : "";
|
|
13
|
-
return `${theme.fg("accent", `"${query}"`)} ${theme.fg("dim", `across ${directories.length} project(s)`)}`;
|
|
18
|
+
return `${theme.fg("toolTitle", theme.bold(presentationTitle(toolName)))} ${theme.fg("accent", `"${query}"`)} ${theme.fg("dim", `across ${directories.length} project(s)`)}`;
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
function formatOutcomeHeader(entry: CrossWorkspaceOutcome<unknown>, theme: LectorTheme): string {
|
|
@@ -1,27 +1,61 @@
|
|
|
1
1
|
import type { GithubRepoSearchResult, NpmPackageCandidate, SourcegraphCodeCandidate } from "@danypops/lector";
|
|
2
2
|
import type { LectorTheme } from "../lector-tui-theme.ts";
|
|
3
|
+
import { presentationTitle } from "../presentation/tool-presentation.ts";
|
|
3
4
|
|
|
4
5
|
type ExternalSearchAction = "github_repos" | "npm_packages" | "sourcegraph_code";
|
|
5
6
|
|
|
6
7
|
export function formatExternalSearchCall(action: ExternalSearchAction, args: { query?: unknown }, theme: LectorTheme): string {
|
|
7
|
-
const label = theme.fg("toolTitle", theme.bold("external_search"));
|
|
8
|
+
const label = theme.fg("toolTitle", theme.bold(presentationTitle("external_search", action)));
|
|
8
9
|
const query = typeof args.query === "string" ? args.query : "";
|
|
9
|
-
return `${label} ${theme.fg("accent",
|
|
10
|
+
return `${label} ${theme.fg("accent", `"${query}"`)}`;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
const VISIBLE_CANDIDATES = 8;
|
|
14
|
+
|
|
15
|
+
function boundedCandidates<T>(candidates: readonly T[], expanded: boolean): { visible: readonly T[]; more: number } {
|
|
16
|
+
const visible = expanded ? candidates : candidates.slice(0, VISIBLE_CANDIDATES);
|
|
17
|
+
return { visible, more: candidates.length - visible.length };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function formatGithubRepoSearchResult(result: GithubRepoSearchResult | undefined, expanded: boolean, theme: LectorTheme): string {
|
|
13
21
|
if (!result) return theme.fg("dim", "No result.");
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
22
|
+
if (result.candidates.length === 0) return theme.fg("dim", "no repositories matched");
|
|
23
|
+
const { visible, more } = boundedCandidates(result.candidates, expanded);
|
|
24
|
+
const lines = visible.map(
|
|
25
|
+
(candidate) =>
|
|
26
|
+
`${theme.fg("accent", `${candidate.host}/${candidate.owner}/${candidate.repo}`)} · ${candidate.stars} stars${candidate.language ? ` · ${candidate.language}` : ""}${candidate.description ? `\n ${candidate.description}` : ""}`,
|
|
27
|
+
);
|
|
28
|
+
if (more > 0) lines.push(theme.fg("muted", `… ${more} more (expand to show)`));
|
|
29
|
+
if (!result.authenticated) lines.push(theme.fg("warning", "unauthenticated -- lower rate limit"));
|
|
30
|
+
return lines.join("\n");
|
|
17
31
|
}
|
|
18
32
|
|
|
19
|
-
export function formatNpmPackageSearchResult(
|
|
20
|
-
|
|
21
|
-
|
|
33
|
+
export function formatNpmPackageSearchResult(
|
|
34
|
+
result: { candidates: readonly NpmPackageCandidate[] } | undefined,
|
|
35
|
+
expanded: boolean,
|
|
36
|
+
theme: LectorTheme,
|
|
37
|
+
): string {
|
|
38
|
+
if (!result || result.candidates.length === 0) return theme.fg("dim", "no packages matched");
|
|
39
|
+
const { visible, more } = boundedCandidates(result.candidates, expanded);
|
|
40
|
+
const lines = visible.map(
|
|
41
|
+
(candidate) =>
|
|
42
|
+
`${theme.fg("accent", `${candidate.name}@${candidate.version}`)} · score ${candidate.score.toFixed(3)}${candidate.description ? `\n ${candidate.description}` : ""}`,
|
|
43
|
+
);
|
|
44
|
+
if (more > 0) lines.push(theme.fg("muted", `… ${more} more (expand to show)`));
|
|
45
|
+
return lines.join("\n");
|
|
22
46
|
}
|
|
23
47
|
|
|
24
|
-
export function formatSourcegraphCodeSearchResult(
|
|
25
|
-
|
|
26
|
-
|
|
48
|
+
export function formatSourcegraphCodeSearchResult(
|
|
49
|
+
result: { candidates: readonly SourcegraphCodeCandidate[] } | undefined,
|
|
50
|
+
expanded: boolean,
|
|
51
|
+
theme: LectorTheme,
|
|
52
|
+
): string {
|
|
53
|
+
if (!result || result.candidates.length === 0) return theme.fg("dim", "no code matches");
|
|
54
|
+
const { visible, more } = boundedCandidates(result.candidates, expanded);
|
|
55
|
+
const lines = visible.map((candidate) => {
|
|
56
|
+
const matches = candidate.lineMatches.slice(0, expanded ? candidate.lineMatches.length : 3);
|
|
57
|
+
return `${theme.fg("accent", `${candidate.repository}/${candidate.path}`)}\n${matches.map((match) => ` ${match.line}: ${match.preview}`).join("\n")}`;
|
|
58
|
+
});
|
|
59
|
+
if (more > 0) lines.push(theme.fg("muted", `… ${more} more (expand to show)`));
|
|
60
|
+
return lines.join("\n");
|
|
27
61
|
}
|
|
@@ -2,13 +2,14 @@ import type { FindFilesResult } from "@danypops/lector";
|
|
|
2
2
|
import { keyHint } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { renderTruncatedList } from "malevich-tui-components";
|
|
4
4
|
import type { LectorTheme } from "../lector-tui-theme.ts";
|
|
5
|
+
import { presentationTitle } from "../presentation/tool-presentation.ts";
|
|
5
6
|
|
|
6
7
|
const DEFAULT_VISIBLE_PATHS = 40;
|
|
7
8
|
|
|
8
9
|
export function formatFindFilesCall(args: { directory?: unknown; patterns?: unknown }, theme: LectorTheme): string {
|
|
9
10
|
const directory = typeof args.directory === "string" ? args.directory : "";
|
|
10
11
|
const patterns = Array.isArray(args.patterns) ? args.patterns.filter((p): p is string => typeof p === "string") : [];
|
|
11
|
-
return `${theme.fg("toolTitle", theme.bold("find_files"))} ${theme.fg("accent", patterns.map((p) => `"${p}"`).join(", "))} ${theme.fg("dim", directory)}`;
|
|
12
|
+
return `${theme.fg("toolTitle", theme.bold(presentationTitle("find_files")))} ${theme.fg("accent", patterns.map((p) => `"${p}"`).join(", "))} ${theme.fg("dim", directory)}`;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export function formatFindFilesResult(result: FindFilesResult | undefined, expanded: boolean, theme: LectorTheme): string {
|
|
@@ -2,6 +2,7 @@ import type { SymbolSearchResult, WorkspaceSymbol } from "@danypops/lector";
|
|
|
2
2
|
import { keyHint } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { renderTruncatedList } from "malevich-tui-components";
|
|
4
4
|
import { colorForKind, formatLocation, type LectorTheme } from "../lector-tui-theme.ts";
|
|
5
|
+
import { presentationTitle } from "../presentation/tool-presentation.ts";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Custom TUI rendering for find_symbols -- the one Lector-backed tool with
|
|
@@ -18,7 +19,7 @@ const DEFAULT_VISIBLE_RESULTS = 8;
|
|
|
18
19
|
|
|
19
20
|
export function formatFindSymbolsCall(args: { query?: unknown; directory?: unknown }, theme: FindSymbolsTheme): string {
|
|
20
21
|
const query = typeof args.query === "string" ? args.query : "";
|
|
21
|
-
let content = `${theme.fg("toolTitle", theme.bold("find_symbols"))} ${theme.fg("accent", `"${query}"`)}`;
|
|
22
|
+
let content = `${theme.fg("toolTitle", theme.bold(presentationTitle("find_symbols")))} ${theme.fg("accent", `"${query}"`)}`;
|
|
22
23
|
if (typeof args.directory === "string" && args.directory.length > 0) {
|
|
23
24
|
content += ` ${theme.fg("muted", `in ${args.directory}`)}`;
|
|
24
25
|
}
|
|
@@ -3,6 +3,7 @@ import { keyHint } from "@earendil-works/pi-coding-agent";
|
|
|
3
3
|
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
4
4
|
import { renderDiffLines, renderTruncatedList, type TextMeasure } from "malevich-tui-components";
|
|
5
5
|
import type { LectorTheme } from "../lector-tui-theme.ts";
|
|
6
|
+
import { presentationTitle } from "../presentation/tool-presentation.ts";
|
|
6
7
|
|
|
7
8
|
/** Real ANSI-aware measurement, not Malevich's own ASCII-only default -- every diff line renderDiffLines receives is already theme.fg-styled. */
|
|
8
9
|
const measure: TextMeasure = { visibleWidth, truncateToWidth };
|
|
@@ -61,31 +62,32 @@ export function formatGitCall(
|
|
|
61
62
|
theme: LectorTheme,
|
|
62
63
|
): string {
|
|
63
64
|
const action = typeof args.action === "string" ? args.action : "";
|
|
65
|
+
const label = theme.fg("toolTitle", theme.bold(presentationTitle("git", action)));
|
|
64
66
|
const directory = typeof args.directory === "string" ? args.directory : "";
|
|
65
67
|
if (action === "compare-symbol") {
|
|
66
68
|
const path = typeof args.path === "string" ? args.path : "";
|
|
67
69
|
const symbol = typeof args.symbol === "string" ? args.symbol : "";
|
|
68
70
|
const fromRef = typeof args.fromRef === "string" ? args.fromRef : "";
|
|
69
71
|
const toRef = typeof args.toRef === "string" ? ` -> ${args.toRef}` : "";
|
|
70
|
-
return `${
|
|
72
|
+
return `${label} ${theme.fg("accent", `${directory}/${path}`)} (${symbol}) ${fromRef}${toRef}`;
|
|
71
73
|
}
|
|
72
74
|
if (action === "is-ancestor") {
|
|
73
75
|
const ancestorRef = typeof args.ancestorRef === "string" ? args.ancestorRef : "";
|
|
74
76
|
const ref = typeof args.ref === "string" ? args.ref : "";
|
|
75
|
-
return `${
|
|
77
|
+
return `${label} ${theme.fg("accent", directory)} ${ancestorRef} -> ${ref}`;
|
|
76
78
|
}
|
|
77
79
|
if (action === "grep-ref" || action === "grep-history") {
|
|
78
80
|
const ref = action === "grep-ref" && typeof args.ref === "string" ? `${args.ref} ` : "";
|
|
79
81
|
const pattern = typeof args.pattern === "string" ? args.pattern : "";
|
|
80
|
-
return `${
|
|
82
|
+
return `${label} ${theme.fg("accent", directory)} ${ref}"${pattern}"`;
|
|
81
83
|
}
|
|
82
84
|
if (action === "show") {
|
|
83
85
|
const ref = typeof args.ref === "string" ? args.ref : "";
|
|
84
86
|
const path = typeof args.path === "string" ? args.path : "";
|
|
85
|
-
return `${
|
|
87
|
+
return `${label} ${theme.fg("accent", `${directory}/${path}`)} @ ${ref}`;
|
|
86
88
|
}
|
|
87
89
|
const ref = typeof args.ref === "string" ? ` ${args.ref}` : "";
|
|
88
|
-
return `${
|
|
90
|
+
return `${label} ${theme.fg("accent", directory)}${ref}`;
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
function formatGitWorktreeAddResult(result: GitWorktreeAddResult | undefined, theme: LectorTheme): string {
|