xtrm-tools 0.7.7 → 0.7.9
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/.xtrm/config/hooks.json +0 -3
- package/.xtrm/registry.json +537 -565
- package/.xtrm/skills/default/gitnexus-cli/SKILL.md +82 -0
- package/.xtrm/skills/default/gitnexus-exploring/SKILL.md +78 -0
- package/.xtrm/skills/default/gitnexus-guide/SKILL.md +64 -0
- package/.xtrm/skills/default/init-session/SKILL.md +3 -0
- package/.xtrm/skills/default/last30days/SKILL.md +1 -1
- package/.xtrm/skills/default/last30days/scripts/lib/youtube_yt.py +59 -40
- package/.xtrm/skills/default/sync-docs/references/doc-structure.md +1 -1
- package/.xtrm/skills/default/sync-docs/references/schema.md +1 -1
- package/.xtrm/skills/default/sync-docs/scripts/doc_structure_analyzer.py +2 -2
- package/.xtrm/skills/default/using-specialists/SKILL.md +346 -138
- package/.xtrm/skills/default/using-specialists/SKILL.safe.md +1082 -0
- package/.xtrm/skills/default/using-specialists/SKILL.ultra.md +1082 -0
- package/.xtrm/skills/default/vaultctl/SKILL.md +150 -0
- package/CHANGELOG.md +4 -4
- package/cli/dist/index.cjs +328 -192
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/package.json +8 -8
- package/packages/pi-extensions/MIGRATION_NOTES.md +39 -0
- package/packages/pi-extensions/README.md +43 -0
- package/packages/pi-extensions/extensions/README.md +5 -0
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/beads/index.ts +1 -1
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/beads/package.json +1 -4
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/custom-footer/index.ts +1 -1
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/custom-footer/package.json +1 -4
- package/packages/pi-extensions/extensions/custom-provider-qwen-cli/package.json +16 -0
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/pi-serena-compact/package.json +9 -2
- package/{.xtrm/ext-src → packages/pi-extensions/extensions}/quality-gates/index.ts +1 -1
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/quality-gates/package.json +1 -4
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/service-skills/index.ts +1 -1
- package/{.xtrm/ext-src → packages/pi-extensions/extensions}/service-skills/package.json +1 -4
- package/{.xtrm/ext-src → packages/pi-extensions/extensions}/session-flow/index.ts +1 -1
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/session-flow/package.json +1 -4
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-loader/index.ts +1 -1
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-loader/package.json +1 -4
- package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-ui/index.ts +1 -1
- package/packages/pi-extensions/package.json +46 -0
- package/packages/pi-extensions/src/core/README.md +9 -0
- package/{.xtrm/ext-src/core/lib.ts → packages/pi-extensions/src/core/index.ts} +3 -1
- package/packages/pi-extensions/src/extensions/auto-session-name.ts +3 -0
- package/packages/pi-extensions/src/extensions/auto-update.ts +3 -0
- package/packages/pi-extensions/src/extensions/beads.ts +3 -0
- package/packages/pi-extensions/src/extensions/compact-header.ts +3 -0
- package/packages/pi-extensions/src/extensions/custom-footer.ts +3 -0
- package/packages/pi-extensions/src/extensions/custom-provider-qwen-cli.ts +3 -0
- package/packages/pi-extensions/src/extensions/git-checkpoint.ts +3 -0
- package/packages/pi-extensions/src/extensions/lsp-bootstrap.ts +3 -0
- package/packages/pi-extensions/src/extensions/pi-serena-compact.ts +3 -0
- package/packages/pi-extensions/src/extensions/quality-gates.ts +3 -0
- package/packages/pi-extensions/src/extensions/service-skills.ts +3 -0
- package/packages/pi-extensions/src/extensions/session-flow.ts +3 -0
- package/packages/pi-extensions/src/extensions/xtrm-loader.ts +3 -0
- package/packages/pi-extensions/src/extensions/xtrm-ui.ts +3 -0
- package/packages/pi-extensions/src/index.ts +9 -0
- package/packages/pi-extensions/src/registry.ts +52 -0
- package/packages/pi-extensions/src/shared/index.ts +1 -0
- package/packages/pi-extensions/src/shared/legacy-path-map.ts +23 -0
- package/.xtrm/config/pi/extensions/core/package.json +0 -18
- package/.xtrm/config/pi/extensions/custom-provider-qwen-cli/package.json +0 -1
- package/.xtrm/config/pi/extensions/quality-gates/index.ts +0 -66
- package/.xtrm/config/pi/extensions/service-skills/package.json +0 -19
- package/.xtrm/config/pi/extensions/session-flow/index.ts +0 -96
- package/.xtrm/config/pi/extensions/xtrm-ui/themes/pidex-dark.json +0 -89
- package/.xtrm/config/pi/extensions/xtrm-ui/themes/pidex-light.json +0 -89
- package/.xtrm/ext-src/auto-session-name/index.ts +0 -29
- package/.xtrm/ext-src/auto-session-name/package.json +0 -16
- package/.xtrm/ext-src/auto-update/index.ts +0 -71
- package/.xtrm/ext-src/auto-update/package.json +0 -16
- package/.xtrm/ext-src/beads/index.ts +0 -232
- package/.xtrm/ext-src/beads/package.json +0 -19
- package/.xtrm/ext-src/compact-header/index.ts +0 -69
- package/.xtrm/ext-src/compact-header/package.json +0 -16
- package/.xtrm/ext-src/core/adapter.ts +0 -52
- package/.xtrm/ext-src/core/guard-rules.ts +0 -100
- package/.xtrm/ext-src/core/logger.ts +0 -45
- package/.xtrm/ext-src/core/package.json +0 -18
- package/.xtrm/ext-src/core/runner.ts +0 -71
- package/.xtrm/ext-src/core/session-state.ts +0 -59
- package/.xtrm/ext-src/custom-footer/index.ts +0 -398
- package/.xtrm/ext-src/custom-footer/package.json +0 -19
- package/.xtrm/ext-src/custom-provider-qwen-cli/index.ts +0 -363
- package/.xtrm/ext-src/custom-provider-qwen-cli/package.json +0 -1
- package/.xtrm/ext-src/git-checkpoint/index.ts +0 -53
- package/.xtrm/ext-src/git-checkpoint/package.json +0 -16
- package/.xtrm/ext-src/lsp-bootstrap/index.ts +0 -134
- package/.xtrm/ext-src/lsp-bootstrap/package.json +0 -17
- package/.xtrm/ext-src/pi-serena-compact/index.ts +0 -121
- package/.xtrm/ext-src/pi-serena-compact/package.json +0 -16
- package/.xtrm/ext-src/quality-gates/package.json +0 -19
- package/.xtrm/ext-src/service-skills/index.ts +0 -108
- package/.xtrm/ext-src/session-flow/package.json +0 -19
- package/.xtrm/ext-src/xtrm-loader/index.ts +0 -152
- package/.xtrm/ext-src/xtrm-loader/package.json +0 -19
- package/.xtrm/ext-src/xtrm-ui/format.ts +0 -282
- package/.xtrm/ext-src/xtrm-ui/index.ts +0 -1112
- package/.xtrm/ext-src/xtrm-ui/package.json +0 -21
- /package/.xtrm/{ext-src → config/pi/extensions}/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.combined.log +0 -0
- /package/.xtrm/{ext-src → config/pi/extensions}/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.stderr.log +0 -0
- /package/.xtrm/{ext-src → config/pi/extensions}/custom-footer/.pi/structured-returns/83051fe4-97da-4e2c-bdaa-343b32f4e714.stdout.log +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-session-name/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-session-name/package.json +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-update/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/auto-update/package.json +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/compact-header/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/compact-header/package.json +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/custom-provider-qwen-cli/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/git-checkpoint/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/git-checkpoint/package.json +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/lsp-bootstrap/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/lsp-bootstrap/package.json +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/pi-serena-compact/index.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-ui/format.ts +0 -0
- /package/{.xtrm/config/pi → packages/pi-extensions}/extensions/xtrm-ui/package.json +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/adapter.ts +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/guard-rules.ts +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/lib.ts +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/logger.ts +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/runner.ts +0 -0
- /package/{.xtrm/config/pi/extensions → packages/pi-extensions/src}/core/session-state.ts +0 -0
- /package/{.xtrm/ext-src/xtrm-ui/themes → packages/pi-extensions/themes/xtrm-ui}/pidex-dark.json +0 -0
- /package/{.xtrm/ext-src/xtrm-ui/themes → packages/pi-extensions/themes/xtrm-ui}/pidex-light.json +0 -0
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
export interface DiffStats {
|
|
2
|
-
additions: number;
|
|
3
|
-
removals: number;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
// pi-diff compatibility adapter:
|
|
7
|
-
// @heyhuynhgiabuu/pi-diff currently exposes extension-first entrypoints
|
|
8
|
-
// (no stable library export surface), so xtrm-ui vendors this renderer to
|
|
9
|
-
// keep write/edit previews deterministic while preserving single-wrapper ownership.
|
|
10
|
-
interface DiffTheme {
|
|
11
|
-
fg(color: string, text: string): string;
|
|
12
|
-
bold?(text: string): string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface HunkCursor {
|
|
16
|
-
oldLine: number;
|
|
17
|
-
newLine: number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function shortenHome(path: string): string {
|
|
21
|
-
const home = process.env.HOME;
|
|
22
|
-
if (home && path.startsWith(home)) return `~${path.slice(home.length)}`;
|
|
23
|
-
return path;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function shortenPath(path: string, max = 56): string {
|
|
27
|
-
const normalized = shortenHome(path);
|
|
28
|
-
if (normalized.length <= max) return normalized;
|
|
29
|
-
const parts = normalized.split("/").filter(Boolean);
|
|
30
|
-
if (parts.length <= 2) return `…${normalized.slice(-(max - 1))}`;
|
|
31
|
-
const tail = parts.slice(-2).join("/");
|
|
32
|
-
const head = parts[0]?.startsWith("~") ? "~/" : "…/";
|
|
33
|
-
const candidate = `${head}${tail}`;
|
|
34
|
-
if (candidate.length <= max) return candidate;
|
|
35
|
-
return `…${candidate.slice(-(max - 1))}`;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function shortenCommand(command: string, max = 72): string {
|
|
39
|
-
const singleLine = command.replace(/\s+/g, " ").trim();
|
|
40
|
-
if (singleLine.length <= max) return singleLine;
|
|
41
|
-
return `${singleLine.slice(0, Math.max(0, max - 1))}…`;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function lineCount(text: string): number {
|
|
45
|
-
if (!text) return 0;
|
|
46
|
-
return text.split("\n").length;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function previewLines(text: string, count: number): string[] {
|
|
50
|
-
return text.split("\n").slice(0, count);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function cleanOutputLines(text: string): string[] {
|
|
54
|
-
return text
|
|
55
|
-
.split("\n")
|
|
56
|
-
.filter((line) => line.trim().length > 0)
|
|
57
|
-
.filter((line) => !/^exit code:\s*-?\d+$/i.test(line.trim()));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function countPrefixedItems(text: string, prefixes: string[]): number {
|
|
61
|
-
return text.split("\n").filter((line) => prefixes.some((prefix) => line.startsWith(prefix))).length;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function diffStats(diff: string): DiffStats {
|
|
65
|
-
let additions = 0;
|
|
66
|
-
let removals = 0;
|
|
67
|
-
for (const line of diff.split("\n")) {
|
|
68
|
-
if (line.startsWith("+") && !line.startsWith("+++")) additions++;
|
|
69
|
-
if (line.startsWith("-") && !line.startsWith("---")) removals++;
|
|
70
|
-
}
|
|
71
|
-
return { additions, removals };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function createUnifiedLineDiff(oldContent: string, newContent: string): string {
|
|
75
|
-
if (oldContent === newContent) return "";
|
|
76
|
-
|
|
77
|
-
const oldLines = oldContent.split("\n");
|
|
78
|
-
const newLines = newContent.split("\n");
|
|
79
|
-
const out: string[] = ["--- a/file", "+++ b/file", `@@ -1,${oldLines.length} +1,${newLines.length} @@`];
|
|
80
|
-
|
|
81
|
-
let oldIndex = 0;
|
|
82
|
-
let newIndex = 0;
|
|
83
|
-
|
|
84
|
-
while (oldIndex < oldLines.length || newIndex < newLines.length) {
|
|
85
|
-
const oldLine = oldLines[oldIndex];
|
|
86
|
-
const newLine = newLines[newIndex];
|
|
87
|
-
|
|
88
|
-
if (oldLine === newLine) {
|
|
89
|
-
out.push(` ${oldLine ?? ""}`);
|
|
90
|
-
oldIndex++;
|
|
91
|
-
newIndex++;
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (oldIndex + 1 < oldLines.length && oldLines[oldIndex + 1] === newLine) {
|
|
96
|
-
out.push(`-${oldLine ?? ""}`);
|
|
97
|
-
oldIndex++;
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (newIndex + 1 < newLines.length && oldLine === newLines[newIndex + 1]) {
|
|
102
|
-
out.push(`+${newLine ?? ""}`);
|
|
103
|
-
newIndex++;
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (oldIndex < oldLines.length) {
|
|
108
|
-
out.push(`-${oldLine ?? ""}`);
|
|
109
|
-
oldIndex++;
|
|
110
|
-
}
|
|
111
|
-
if (newIndex < newLines.length) {
|
|
112
|
-
out.push(`+${newLine ?? ""}`);
|
|
113
|
-
newIndex++;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return out.join("\n");
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function parseHunkHeader(line: string): HunkCursor | undefined {
|
|
121
|
-
const match = line.match(/^@@\s+-(\d+)(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);
|
|
122
|
-
if (!match) return undefined;
|
|
123
|
-
return {
|
|
124
|
-
oldLine: Number.parseInt(match[1] ?? "1", 10),
|
|
125
|
-
newLine: Number.parseInt(match[2] ?? "1", 10),
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function renderLineNumbers(theme: DiffTheme, oldLine: number | null, newLine: number | null): string {
|
|
130
|
-
const format = (value: number | null) => (value == null ? " " : String(value).padStart(4, " "));
|
|
131
|
-
return theme.fg("muted", `${format(oldLine)} ${format(newLine)} │`);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function safeBold(theme: DiffTheme, text: string): string {
|
|
135
|
-
return theme.bold ? theme.bold(text) : text;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function splitChangedSegment(before: string, after: string): { before: string; beforeMid: string; beforeTail: string; after: string; afterMid: string; afterTail: string } {
|
|
139
|
-
let prefixLength = 0;
|
|
140
|
-
const minLength = Math.min(before.length, after.length);
|
|
141
|
-
|
|
142
|
-
while (prefixLength < minLength && before[prefixLength] === after[prefixLength]) {
|
|
143
|
-
prefixLength++;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
let suffixLength = 0;
|
|
147
|
-
while (
|
|
148
|
-
suffixLength < minLength - prefixLength &&
|
|
149
|
-
before[before.length - 1 - suffixLength] === after[after.length - 1 - suffixLength]
|
|
150
|
-
) {
|
|
151
|
-
suffixLength++;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
before: before.slice(0, prefixLength),
|
|
156
|
-
beforeMid: before.slice(prefixLength, before.length - suffixLength),
|
|
157
|
-
beforeTail: before.slice(before.length - suffixLength),
|
|
158
|
-
after: after.slice(0, prefixLength),
|
|
159
|
-
afterMid: after.slice(prefixLength, after.length - suffixLength),
|
|
160
|
-
afterTail: after.slice(after.length - suffixLength),
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function renderWordHighlightedPair(theme: DiffTheme, removed: string, added: string): { removed: string; added: string } {
|
|
165
|
-
const segments = splitChangedSegment(removed, added);
|
|
166
|
-
const removedContent = `${segments.before}${segments.beforeMid ? safeBold(theme, segments.beforeMid) : ""}${segments.beforeTail}`;
|
|
167
|
-
const addedContent = `${segments.after}${segments.afterMid ? safeBold(theme, segments.afterMid) : ""}${segments.afterTail}`;
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
removed: theme.fg("toolDiffRemoved", `-${removedContent}`),
|
|
171
|
-
added: theme.fg("toolDiffAdded", `+${addedContent}`),
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export function renderRichDiffPreview(theme: DiffTheme, diff: string, maxLines: number): string {
|
|
176
|
-
const lines = diff.split("\n");
|
|
177
|
-
const rendered: string[] = [];
|
|
178
|
-
let shown = 0;
|
|
179
|
-
let oldLine = 1;
|
|
180
|
-
let newLine = 1;
|
|
181
|
-
|
|
182
|
-
for (let index = 0; index < lines.length && shown < maxLines; index++) {
|
|
183
|
-
const line = lines[index] ?? "";
|
|
184
|
-
|
|
185
|
-
if (line.startsWith("@@")) {
|
|
186
|
-
const cursor = parseHunkHeader(line);
|
|
187
|
-
if (cursor) {
|
|
188
|
-
oldLine = cursor.oldLine;
|
|
189
|
-
newLine = cursor.newLine;
|
|
190
|
-
}
|
|
191
|
-
rendered.push(`${renderLineNumbers(theme, null, null)} ${theme.fg("muted", line)}`);
|
|
192
|
-
shown++;
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (line.startsWith("---") || line.startsWith("+++")) {
|
|
197
|
-
rendered.push(`${renderLineNumbers(theme, null, null)} ${theme.fg("toolDiffContext", line)}`);
|
|
198
|
-
shown++;
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (line.startsWith("-") && !line.startsWith("---") && shown + 1 <= maxLines) {
|
|
203
|
-
const nextLine = lines[index + 1] ?? "";
|
|
204
|
-
if (nextLine.startsWith("+") && !nextLine.startsWith("+++")) {
|
|
205
|
-
const pair = renderWordHighlightedPair(theme, line.slice(1), nextLine.slice(1));
|
|
206
|
-
rendered.push(`${renderLineNumbers(theme, oldLine, null)} ${pair.removed}`);
|
|
207
|
-
rendered.push(`${renderLineNumbers(theme, null, newLine)} ${pair.added}`);
|
|
208
|
-
oldLine++;
|
|
209
|
-
newLine++;
|
|
210
|
-
index++;
|
|
211
|
-
shown += 2;
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (line.startsWith("-") && !line.startsWith("---")) {
|
|
217
|
-
rendered.push(`${renderLineNumbers(theme, oldLine, null)} ${theme.fg("toolDiffRemoved", line)}`);
|
|
218
|
-
oldLine++;
|
|
219
|
-
shown++;
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
224
|
-
rendered.push(`${renderLineNumbers(theme, null, newLine)} ${theme.fg("toolDiffAdded", line)}`);
|
|
225
|
-
newLine++;
|
|
226
|
-
shown++;
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (line.startsWith(" ")) {
|
|
231
|
-
rendered.push(`${renderLineNumbers(theme, oldLine, newLine)} ${theme.fg("toolDiffContext", line)}`);
|
|
232
|
-
oldLine++;
|
|
233
|
-
newLine++;
|
|
234
|
-
shown++;
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
rendered.push(`${renderLineNumbers(theme, null, null)} ${theme.fg("toolDiffContext", line)}`);
|
|
239
|
-
shown++;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (lines.length > shown) {
|
|
243
|
-
rendered.push(theme.fg("muted", ` … +${lines.length - shown} more`));
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return rendered.join("\n");
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
export function formatDuration(durationMs: number | undefined): string | undefined {
|
|
250
|
-
if (!durationMs || durationMs < 0) return undefined;
|
|
251
|
-
if (durationMs < 1000) return `${durationMs}ms`;
|
|
252
|
-
const seconds = durationMs / 1000;
|
|
253
|
-
if (seconds < 10) return `${seconds.toFixed(1)}s`;
|
|
254
|
-
return `${Math.round(seconds)}s`;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
export function formatLineLabel(count: number, noun: string): string {
|
|
258
|
-
return `${count} ${noun}${count === 1 ? "" : "s"}`;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export function renderToolSummary(
|
|
262
|
-
theme: { fg(color: string, text: string): string; bold(text: string): string },
|
|
263
|
-
status: "pending" | "success" | "error" | "muted",
|
|
264
|
-
label: string,
|
|
265
|
-
subject?: string,
|
|
266
|
-
meta?: string,
|
|
267
|
-
): string {
|
|
268
|
-
const color =
|
|
269
|
-
status === "pending" ? "accent"
|
|
270
|
-
: status === "error" ? "error"
|
|
271
|
-
: status === "success" ? "success"
|
|
272
|
-
: "muted";
|
|
273
|
-
let text = `${theme.fg(color, "•")} ${theme.fg("toolTitle", theme.bold(label))}`;
|
|
274
|
-
if (subject) text += ` ${theme.fg("accent", subject)}`;
|
|
275
|
-
if (meta) text += theme.fg("muted", ` · ${meta}`);
|
|
276
|
-
return text;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
export function joinMeta(parts: Array<string | undefined | false>): string | undefined {
|
|
280
|
-
const filtered = parts.filter((part): part is string => typeof part === "string" && part.length > 0);
|
|
281
|
-
return filtered.length > 0 ? filtered.join(" · ") : undefined;
|
|
282
|
-
}
|