xtrm-tools 0.7.12 → 0.7.13
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/hooks/specialists/specialists-memory-cache-sync.mjs +57 -0
- package/.xtrm/registry.json +477 -389
- package/.xtrm/skills/default/premortem/SKILL.md +218 -0
- package/.xtrm/skills/default/releasing/SKILL.md +90 -0
- package/.xtrm/skills/default/sync-docs/SKILL.md +88 -208
- package/.xtrm/skills/default/sync-docs/scripts/pre-context.sh +17 -0
- package/.xtrm/skills/default/update-specialists/SKILL.md +228 -36
- package/.xtrm/skills/default/update-xt/SKILL.md +34 -0
- package/.xtrm/skills/default/using-kpi/SKILL.md +150 -0
- package/.xtrm/skills/default/using-specialists-v2/SKILL.md +683 -0
- package/cli/dist/index.cjs +839 -429
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/package.json +2 -2
- package/packages/pi-extensions/.serena/project.yml +119 -0
- package/packages/pi-extensions/extensions/pi-serena-compact/index.ts +4 -12
- package/packages/pi-extensions/extensions/xtrm-loader/index.ts +0 -1
- package/packages/pi-extensions/extensions/xtrm-ui/index.ts +201 -36
- package/packages/pi-extensions/extensions/xtrm-ui/themes/pidex-dark-flattools.json +79 -0
- package/packages/pi-extensions/extensions/xtrm-ui/themes/pidex-dark.json +85 -0
- package/packages/pi-extensions/extensions/xtrm-ui/themes/pidex-light-flattools.json +79 -0
- package/packages/pi-extensions/extensions/xtrm-ui/themes/pidex-light.json +85 -0
- package/packages/pi-extensions/package.json +1 -1
- package/packages/pi-extensions/themes/xtrm-ui/pidex-dark-flattools.json +79 -0
- package/packages/pi-extensions/themes/xtrm-ui/pidex-dark.json +3 -3
- package/packages/pi-extensions/themes/xtrm-ui/pidex-light-flattools.json +79 -0
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
createWriteTool,
|
|
33
33
|
} from "@mariozechner/pi-coding-agent";
|
|
34
34
|
import { Box, Text, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
35
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
35
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
36
36
|
import { basename, join } from "node:path";
|
|
37
37
|
import {
|
|
38
38
|
cleanOutputLines,
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
// Types
|
|
55
55
|
// ============================================================================
|
|
56
56
|
|
|
57
|
-
export type XtrmThemeName = "pidex-dark" | "pidex-light";
|
|
57
|
+
export type XtrmThemeName = "pidex-dark" | "pidex-light" | "pidex-dark-flattools" | "pidex-light-flattools";
|
|
58
58
|
export type XtrmDensity = "compact" | "comfortable";
|
|
59
59
|
|
|
60
60
|
export interface XtrmUiPrefs {
|
|
@@ -64,6 +64,8 @@ export interface XtrmUiPrefs {
|
|
|
64
64
|
compactTools: boolean;
|
|
65
65
|
showFooter: boolean; // Our key addition - when false, skip setFooter()
|
|
66
66
|
forceTheme: boolean; // When false, skip setTheme (allow external theme override)
|
|
67
|
+
toolRowBg: boolean; // Subtle background behind tool text rows (no padding)
|
|
68
|
+
compactExternalToolResults: boolean; // Compact extension tool results (disables full expand output)
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
// ============================================================================
|
|
@@ -79,6 +81,8 @@ export const DEFAULT_PREFS: XtrmUiPrefs = {
|
|
|
79
81
|
compactTools: true,
|
|
80
82
|
showFooter: false, // XTRM: disable pi-dex footer, use custom-footer
|
|
81
83
|
forceTheme: true,
|
|
84
|
+
toolRowBg: false,
|
|
85
|
+
compactExternalToolResults: true,
|
|
82
86
|
};
|
|
83
87
|
|
|
84
88
|
// ============================================================================
|
|
@@ -95,12 +99,15 @@ function normalizePrefs(input: unknown): XtrmUiPrefs {
|
|
|
95
99
|
if (!input || typeof input !== "object") return { ...DEFAULT_PREFS };
|
|
96
100
|
const source = input as Partial<XtrmUiPrefs>;
|
|
97
101
|
return {
|
|
98
|
-
themeName: source.themeName === "pidex-light" ? "pidex-light" : "pidex-dark",
|
|
102
|
+
themeName: source.themeName === "pidex-light" || source.themeName === "pidex-light-flattools" ? "pidex-light" : "pidex-dark",
|
|
99
103
|
density: source.density === "comfortable" ? "comfortable" : "compact",
|
|
100
104
|
showHeader: source.showHeader ?? DEFAULT_PREFS.showHeader,
|
|
101
105
|
compactTools: source.compactTools ?? DEFAULT_PREFS.compactTools,
|
|
102
106
|
showFooter: source.showFooter ?? DEFAULT_PREFS.showFooter,
|
|
103
107
|
forceTheme: source.forceTheme ?? DEFAULT_PREFS.forceTheme,
|
|
108
|
+
toolRowBg: source.toolRowBg ?? DEFAULT_PREFS.toolRowBg,
|
|
109
|
+
compactExternalToolResults:
|
|
110
|
+
source.compactExternalToolResults ?? DEFAULT_PREFS.compactExternalToolResults,
|
|
104
111
|
};
|
|
105
112
|
}
|
|
106
113
|
|
|
@@ -127,6 +134,12 @@ function fitVisible(text: string, width: number): string {
|
|
|
127
134
|
return truncated + " ".repeat(Math.max(0, width - visibleWidth(truncated)));
|
|
128
135
|
}
|
|
129
136
|
|
|
137
|
+
function resolveThemeForPrefs(prefs: XtrmUiPrefs): XtrmThemeName {
|
|
138
|
+
const base = prefs.themeName === "pidex-light" || prefs.themeName === "pidex-light-flattools" ? "pidex-light" : "pidex-dark";
|
|
139
|
+
if (!prefs.toolRowBg) return (base + "-flattools") as XtrmThemeName;
|
|
140
|
+
return base as XtrmThemeName;
|
|
141
|
+
}
|
|
142
|
+
|
|
130
143
|
function formatThinking(level: string): string {
|
|
131
144
|
return level === "off" ? "standard" : level;
|
|
132
145
|
}
|
|
@@ -137,7 +150,7 @@ function applyXtrmChrome(
|
|
|
137
150
|
getThinkingLevel: () => string
|
|
138
151
|
): void {
|
|
139
152
|
// Theme
|
|
140
|
-
|
|
153
|
+
ctx.ui.setTheme(resolveThemeForPrefs(prefs));
|
|
141
154
|
|
|
142
155
|
// Tool expansion
|
|
143
156
|
ctx.ui.setToolsExpanded(!prefs.compactTools);
|
|
@@ -222,6 +235,20 @@ function applyXtrmChrome(
|
|
|
222
235
|
// If showFooter is false, we do NOT call setFooter - custom-footer will handle it
|
|
223
236
|
}
|
|
224
237
|
|
|
238
|
+
|
|
239
|
+
function writeExternalCompactFlag(enabled: boolean): void {
|
|
240
|
+
try {
|
|
241
|
+
const settingsPath = join(process.env.HOME ?? "", ".pi", "agent", "settings.json");
|
|
242
|
+
if (!settingsPath) return;
|
|
243
|
+
let settings: Record<string, unknown> = {};
|
|
244
|
+
if (existsSync(settingsPath)) {
|
|
245
|
+
try { settings = JSON.parse(readFileSync(settingsPath, "utf8")); } catch {}
|
|
246
|
+
}
|
|
247
|
+
settings.xtrmExternalCompact = enabled;
|
|
248
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
249
|
+
} catch {}
|
|
250
|
+
}
|
|
251
|
+
|
|
225
252
|
// ============================================================================
|
|
226
253
|
// Tool Render Helpers
|
|
227
254
|
// ============================================================================
|
|
@@ -318,6 +345,8 @@ function registerCommands(pi: ExtensionAPI, getPrefs: () => XtrmUiPrefs, setPref
|
|
|
318
345
|
`Compact tools: ${prefs.compactTools ? "on" : "off"}`,
|
|
319
346
|
`Show header: ${prefs.showHeader ? "yes" : "no"}`,
|
|
320
347
|
`Show footer: ${prefs.showFooter ? "yes" : "no"} (custom-footer handles this)`,
|
|
348
|
+
`Tool row background: ${prefs.toolRowBg ? "on" : "off"}`,
|
|
349
|
+
`Compact external tool results: ${prefs.compactExternalToolResults ? "on" : "off"}`,
|
|
321
350
|
`Model: ${ctx.model?.id ?? "none"}`,
|
|
322
351
|
`Context: ${contextUsage?.tokens ?? "unknown"}/${contextUsage?.contextWindow ?? "unknown"}`,
|
|
323
352
|
];
|
|
@@ -357,9 +386,10 @@ function registerCommands(pi: ExtensionAPI, getPrefs: () => XtrmUiPrefs, setPref
|
|
|
357
386
|
ctx.ui.notify("Usage: /xtrm-ui-density compact|comfortable", "warning");
|
|
358
387
|
return;
|
|
359
388
|
}
|
|
360
|
-
const prefs = { ...getPrefs(), density };
|
|
389
|
+
const prefs = { ...getPrefs(), density, compactExternalToolResults: density === "compact" };
|
|
361
390
|
setPrefs(prefs);
|
|
362
391
|
persistPrefs(pi, prefs);
|
|
392
|
+
writeExternalCompactFlag(prefs.compactExternalToolResults);
|
|
363
393
|
applyXtrmChrome(ctx, prefs, getThinkingLevel);
|
|
364
394
|
ctx.ui.notify(`XTRM UI density set to ${density}`, "info");
|
|
365
395
|
},
|
|
@@ -402,6 +432,51 @@ function registerCommands(pi: ExtensionAPI, getPrefs: () => XtrmUiPrefs, setPref
|
|
|
402
432
|
},
|
|
403
433
|
});
|
|
404
434
|
|
|
435
|
+
pi.registerCommand("xtrm-ui-rowbg", {
|
|
436
|
+
description: "Toggle subtle tool-row background: on|off",
|
|
437
|
+
getArgumentCompletions: (prefix) => {
|
|
438
|
+
const values = ["on", "off"].filter((item) => item.startsWith(prefix));
|
|
439
|
+
return values.length > 0 ? values.map((value) => ({ value, label: value })) : null;
|
|
440
|
+
},
|
|
441
|
+
handler: async (args, ctx) => {
|
|
442
|
+
const normalized = args.trim().toLowerCase();
|
|
443
|
+
if (normalized !== "on" && normalized !== "off") {
|
|
444
|
+
ctx.ui.notify("Usage: /xtrm-ui-rowbg on|off", "warning");
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const toolRowBg = normalized === "on";
|
|
448
|
+
const prefs = { ...getPrefs(), toolRowBg };
|
|
449
|
+
setPrefs(prefs);
|
|
450
|
+
persistPrefs(pi, prefs);
|
|
451
|
+
applyXtrmChrome(ctx, prefs, getThinkingLevel);
|
|
452
|
+
ctx.ui.notify(`Tool row background ${toolRowBg ? "enabled" : "disabled"}.`, "info");
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
pi.registerCommand("xtrm-ui-compact-tools", {
|
|
457
|
+
description: "Compact extension tool results: on|off (off keeps full Ctrl+O expand output)",
|
|
458
|
+
getArgumentCompletions: (prefix) => {
|
|
459
|
+
const values = ["on", "off"].filter((item) => item.startsWith(prefix));
|
|
460
|
+
return values.length > 0 ? values.map((value) => ({ value, label: value })) : null;
|
|
461
|
+
},
|
|
462
|
+
handler: async (args, ctx) => {
|
|
463
|
+
const normalized = args.trim().toLowerCase();
|
|
464
|
+
if (normalized !== "on" && normalized !== "off") {
|
|
465
|
+
ctx.ui.notify("Usage: /xtrm-ui-compact-tools on|off", "warning");
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const compactExternalToolResults = normalized === "on";
|
|
469
|
+
const prefs = { ...getPrefs(), compactExternalToolResults };
|
|
470
|
+
setPrefs(prefs);
|
|
471
|
+
persistPrefs(pi, prefs);
|
|
472
|
+
writeExternalCompactFlag(compactExternalToolResults);
|
|
473
|
+
ctx.ui.notify(
|
|
474
|
+
`Compact external tool results ${compactExternalToolResults ? "enabled" : "disabled"}.`,
|
|
475
|
+
"info",
|
|
476
|
+
);
|
|
477
|
+
},
|
|
478
|
+
});
|
|
479
|
+
|
|
405
480
|
pi.registerCommand("xtrm-ui-reset", {
|
|
406
481
|
description: "Restore XTRM UI defaults",
|
|
407
482
|
handler: async (_args, ctx) => {
|
|
@@ -743,8 +818,84 @@ function summarizeSerenaToolResult(
|
|
|
743
818
|
}
|
|
744
819
|
}
|
|
745
820
|
|
|
746
|
-
|
|
821
|
+
|
|
822
|
+
function formatHierarchyText(text: string): string {
|
|
823
|
+
const lines = text.split("\n");
|
|
824
|
+
const out: string[] = [];
|
|
825
|
+
for (const raw of lines) {
|
|
826
|
+
const line = raw.trimEnd();
|
|
827
|
+
if (!line.trim()) {
|
|
828
|
+
out.push("");
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
if (line.startsWith("● ")) {
|
|
832
|
+
out.push(line);
|
|
833
|
+
continue;
|
|
834
|
+
}
|
|
835
|
+
if (/^(Read|Searched|Listed|Update\(|File must be read first|Now )/.test(line.trimStart())) {
|
|
836
|
+
out.push(` └─ ${line.trimStart()}`);
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
839
|
+
out.push(line);
|
|
840
|
+
}
|
|
841
|
+
return out.join("\n");
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
function normalizeToolLabel(toolName: string): string {
|
|
845
|
+
const gitnexusMap: Record<string, string> = {
|
|
846
|
+
gitnexus_query: "gitnexus query",
|
|
847
|
+
gitnexus_context: "gitnexus context",
|
|
848
|
+
gitnexus_impact: "gitnexus impact",
|
|
849
|
+
gitnexus_detect_changes: "gitnexus detect_changes",
|
|
850
|
+
gitnexus_list_repos: "gitnexus list_repos",
|
|
851
|
+
gitnexus_rename: "gitnexus rename",
|
|
852
|
+
gitnexus_cypher: "gitnexus cypher",
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
if (gitnexusMap[toolName]) return gitnexusMap[toolName];
|
|
856
|
+
|
|
857
|
+
if (toolName.startsWith("gitnexus_")) {
|
|
858
|
+
return `gitnexus ${toolName.slice("gitnexus_".length)}`;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
const idx = toolName.indexOf("_");
|
|
862
|
+
if (idx > 0) {
|
|
863
|
+
const head = toolName.slice(0, idx);
|
|
864
|
+
const tail = toolName.slice(idx + 1);
|
|
865
|
+
if (head && tail) return `${head} ${tail}`;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
return toolName;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
function summarizeGenericToolResult(
|
|
872
|
+
toolName: string,
|
|
873
|
+
input: Record<string, unknown>,
|
|
874
|
+
text: string,
|
|
875
|
+
durationMs: number | undefined,
|
|
876
|
+
): string {
|
|
877
|
+
const payload = parseJson(text);
|
|
878
|
+
const duration = formatDuration(durationMs);
|
|
879
|
+
const subject = summarizeToolSubject(toolName, input) ?? summarizeSerenaSubject(toolName, input);
|
|
880
|
+
const count = countJsonItems(payload) ?? countLines(text);
|
|
881
|
+
const label = formatLineLabel(count, "line");
|
|
882
|
+
const joined = joinMeta([label, duration]);
|
|
883
|
+
const normalized = normalizeToolLabel(toolName);
|
|
884
|
+
return `• ${normalized}${subject ? ` ${subject}` : ""}${joined ? ` · ${joined}` : ""}`;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
const XTRM_BUILTIN_TOOLS = new Set(["bash", "read", "edit", "write", "find", "grep", "ls"]);
|
|
888
|
+
|
|
889
|
+
function registerXtrmUiTools(pi: ExtensionAPI, getPrefs: () => XtrmUiPrefs): void {
|
|
747
890
|
const activeToolCalls = new Map<string, string>();
|
|
891
|
+
|
|
892
|
+
const toolRowText = (theme: any, text: string) =>
|
|
893
|
+
new Text(
|
|
894
|
+
text,
|
|
895
|
+
0,
|
|
896
|
+
0,
|
|
897
|
+
getPrefs().toolRowBg ? (line: string) => theme.bg("selectedBg", line) : undefined,
|
|
898
|
+
);
|
|
748
899
|
const activeSignatureCounts = new Map<string, number>();
|
|
749
900
|
const toolCallStartTimes = new Map<string, number>();
|
|
750
901
|
|
|
@@ -769,7 +920,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
769
920
|
activeSignatureCounts.has(stableToolSignature(toolName, args));
|
|
770
921
|
|
|
771
922
|
const renderPendingCallIfActive = (toolName: string, args: Record<string, unknown>, theme: any) =>
|
|
772
|
-
isToolCallActive(toolName, args) ? renderPendingCall(toolName, args, theme) :
|
|
923
|
+
isToolCallActive(toolName, args) ? renderPendingCall(toolName, args, theme) : toolRowText(theme, "");
|
|
773
924
|
|
|
774
925
|
pi.on("tool_call", async (event) => {
|
|
775
926
|
trackToolCallStart(event.toolCallId, event.toolName, event.input as Record<string, unknown>);
|
|
@@ -779,20 +930,28 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
779
930
|
trackToolCallEnd(event.toolCallId);
|
|
780
931
|
});
|
|
781
932
|
|
|
782
|
-
pi.on("tool_result", async (event: ToolResultEvent,
|
|
783
|
-
if (!SERENA_COMPACT_TOOLS.has(event.toolName)) return undefined;
|
|
784
|
-
if (ctx.ui.getToolsExpanded()) return undefined;
|
|
933
|
+
pi.on("tool_result", async (event: ToolResultEvent, _ctx) => {
|
|
785
934
|
if (event.isError) return undefined;
|
|
935
|
+
if (XTRM_BUILTIN_TOOLS.has(event.toolName)) return undefined;
|
|
786
936
|
|
|
787
937
|
const text = getTextContent({ content: event.content as Array<{ type: string; text?: string }> });
|
|
788
|
-
if (!text.trim()) return undefined;
|
|
789
|
-
|
|
790
938
|
const startedAt = toolCallStartTimes.get(event.toolCallId);
|
|
791
939
|
const durationMs = startedAt != null ? Date.now() - startedAt : undefined;
|
|
792
|
-
|
|
940
|
+
|
|
941
|
+
const fallbackText = "[non-text result]";
|
|
942
|
+
const sourceText = text.trim() ? text : fallbackText;
|
|
943
|
+
|
|
944
|
+
const safeInput =
|
|
945
|
+
event.input && typeof event.input === "object" && !Array.isArray(event.input)
|
|
946
|
+
? (event.input as Record<string, unknown>)
|
|
947
|
+
: {};
|
|
948
|
+
|
|
949
|
+
const compactText = SERENA_COMPACT_TOOLS.has(event.toolName)
|
|
950
|
+
? summarizeSerenaToolResult(event.toolName, safeInput, sourceText, durationMs)
|
|
951
|
+
: summarizeGenericToolResult(event.toolName, safeInput, sourceText, durationMs);
|
|
793
952
|
|
|
794
953
|
return {
|
|
795
|
-
content: [{ type: "text", text: compactText }],
|
|
954
|
+
content: [{ type: "text", text: formatHierarchyText(compactText) }],
|
|
796
955
|
details: event.details,
|
|
797
956
|
};
|
|
798
957
|
});
|
|
@@ -802,6 +961,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
802
961
|
label: "bash",
|
|
803
962
|
description: getTools(process.cwd()).bash.description,
|
|
804
963
|
parameters: getTools(process.cwd()).bash.parameters,
|
|
964
|
+
renderShell: "self",
|
|
805
965
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
806
966
|
const started = Date.now();
|
|
807
967
|
const result = await getTools(ctx.cwd).bash.execute(toolCallId, params, signal, onUpdate);
|
|
@@ -813,7 +973,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
813
973
|
const meta = getXtrmMeta<BashToolDetails, Record<string, unknown>>(details);
|
|
814
974
|
const command = shortenCommand(String(meta?.args.command ?? ""));
|
|
815
975
|
if (isPartial) {
|
|
816
|
-
return
|
|
976
|
+
return toolRowText(theme, `${theme.fg("accent", "•")} ${theme.fg("toolTitle", "Running ")}${theme.fg("accent", command)}${theme.fg("toolTitle", " in bash")}`);
|
|
817
977
|
}
|
|
818
978
|
const output = getTextContent(result as any);
|
|
819
979
|
const outputLines = cleanOutputLines(output);
|
|
@@ -824,7 +984,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
824
984
|
let text = `${bullet} ${theme.fg("toolTitle", "Ran ")}${theme.fg("accent", command)}`;
|
|
825
985
|
if (summary) text += theme.fg("dim", ` · ${summary}`);
|
|
826
986
|
if (expanded && outputLines.length > 0) text += `\n${renderVerticalPreview(theme, outputLines, 10)}`;
|
|
827
|
-
return
|
|
987
|
+
return toolRowText(theme, text);
|
|
828
988
|
},
|
|
829
989
|
});
|
|
830
990
|
|
|
@@ -833,6 +993,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
833
993
|
label: "read",
|
|
834
994
|
description: getTools(process.cwd()).read.description,
|
|
835
995
|
parameters: getTools(process.cwd()).read.parameters,
|
|
996
|
+
renderShell: "self",
|
|
836
997
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
837
998
|
const started = Date.now();
|
|
838
999
|
const result = await getTools(ctx.cwd).read.execute(toolCallId, params, signal, onUpdate);
|
|
@@ -840,7 +1001,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
840
1001
|
},
|
|
841
1002
|
renderCall: (args, theme) => renderPendingCallIfActive("read", args as Record<string, unknown>, theme),
|
|
842
1003
|
renderResult(result, { expanded, isPartial }, theme) {
|
|
843
|
-
if (isPartial) return
|
|
1004
|
+
if (isPartial) return toolRowText(theme, renderToolSummary(theme, "pending", "read", "loading", undefined));
|
|
844
1005
|
const details = (result.details ?? {}) as DetailsWithXtrmMeta<ReadToolDetails, Record<string, unknown>>;
|
|
845
1006
|
const meta = getXtrmMeta<ReadToolDetails, Record<string, unknown>>(details);
|
|
846
1007
|
const subjectBase = shortenPath(String(meta?.args.path ?? ""));
|
|
@@ -848,13 +1009,13 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
848
1009
|
const subject = range ? `${subjectBase}:${range}` : subjectBase;
|
|
849
1010
|
const first = result.content[0];
|
|
850
1011
|
if (first?.type === "image") {
|
|
851
|
-
return
|
|
1012
|
+
return toolRowText(theme, renderToolSummary(theme, "success", "read", subject, joinMeta(["image", formatDuration(meta?.durationMs)])));
|
|
852
1013
|
}
|
|
853
1014
|
const textContent = getTextContent(result as any);
|
|
854
1015
|
const lines = textContent.split("\n");
|
|
855
1016
|
let text = renderToolSummary(theme, "success", "read", subject, joinMeta([formatLineLabel(lines.length, "line"), formatDuration(meta?.durationMs), details.truncation?.truncated ? `from ${details.truncation.totalLines}` : undefined]));
|
|
856
1017
|
if (expanded && textContent.length > 0) text += `\n${renderOutputPreview(theme, previewLines(textContent, 14), 14)}`;
|
|
857
|
-
return
|
|
1018
|
+
return toolRowText(theme, text);
|
|
858
1019
|
},
|
|
859
1020
|
});
|
|
860
1021
|
|
|
@@ -863,6 +1024,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
863
1024
|
label: "edit",
|
|
864
1025
|
description: getTools(process.cwd()).edit.description,
|
|
865
1026
|
parameters: getTools(process.cwd()).edit.parameters,
|
|
1027
|
+
renderShell: "self",
|
|
866
1028
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
867
1029
|
const started = Date.now();
|
|
868
1030
|
const result = await getTools(ctx.cwd).edit.execute(toolCallId, params, signal, onUpdate);
|
|
@@ -870,17 +1032,17 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
870
1032
|
},
|
|
871
1033
|
renderCall: (args, theme) => renderPendingCallIfActive("edit", args as Record<string, unknown>, theme),
|
|
872
1034
|
renderResult(result, { expanded, isPartial }, theme) {
|
|
873
|
-
if (isPartial) return
|
|
1035
|
+
if (isPartial) return toolRowText(theme, renderToolSummary(theme, "pending", "edit", "applying", undefined));
|
|
874
1036
|
const details = (result.details ?? {}) as DetailsWithXtrmMeta<EditToolDetails, Record<string, unknown>>;
|
|
875
1037
|
const meta = getXtrmMeta<EditToolDetails, Record<string, unknown>>(details);
|
|
876
1038
|
const textContent = getTextContent(result as any);
|
|
877
1039
|
if (/^error/i.test(textContent.trim())) {
|
|
878
|
-
return
|
|
1040
|
+
return toolRowText(theme, renderToolSummary(theme, "error", "edit", shortenPath(String(meta?.args.path ?? "")), textContent.split("\n")[0]));
|
|
879
1041
|
}
|
|
880
1042
|
const stats = details.diff ? diffStats(details.diff) : { additions: 0, removals: 0 };
|
|
881
1043
|
let text = renderToolSummary(theme, "success", "edit", shortenPath(String(meta?.args.path ?? "")), joinMeta([`+${stats.additions}`, `-${stats.removals}`, formatDuration(meta?.durationMs)]));
|
|
882
1044
|
if (expanded && details.diff) text += `\n${renderRichDiffPreview(theme, details.diff, 18)}`;
|
|
883
|
-
return
|
|
1045
|
+
return toolRowText(theme, text);
|
|
884
1046
|
},
|
|
885
1047
|
});
|
|
886
1048
|
|
|
@@ -889,6 +1051,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
889
1051
|
label: "write",
|
|
890
1052
|
description: getTools(process.cwd()).write.description,
|
|
891
1053
|
parameters: getTools(process.cwd()).write.parameters,
|
|
1054
|
+
renderShell: "self",
|
|
892
1055
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
893
1056
|
const started = Date.now();
|
|
894
1057
|
const args = params as Record<string, unknown>;
|
|
@@ -901,19 +1064,19 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
901
1064
|
},
|
|
902
1065
|
renderCall: (args, theme) => renderPendingCallIfActive("write", args as Record<string, unknown>, theme),
|
|
903
1066
|
renderResult(result, { expanded, isPartial }, theme) {
|
|
904
|
-
if (isPartial) return
|
|
1067
|
+
if (isPartial) return toolRowText(theme, renderToolSummary(theme, "pending", "write", "writing", undefined));
|
|
905
1068
|
const details = (result.details ?? {}) as DetailsWithXtrmMeta<Record<string, never>, Record<string, unknown>>;
|
|
906
1069
|
const meta = getXtrmMeta<Record<string, never>, Record<string, unknown>>(details);
|
|
907
1070
|
const textContent = getTextContent(result as any);
|
|
908
1071
|
if (/^error/i.test(textContent.trim())) {
|
|
909
|
-
return
|
|
1072
|
+
return toolRowText(theme, renderToolSummary(theme, "error", "write", shortenPath(String(meta?.args.path ?? "")), textContent.split("\n")[0]));
|
|
910
1073
|
}
|
|
911
1074
|
|
|
912
1075
|
const subject = shortenPath(String(meta?.args.path ?? ""));
|
|
913
1076
|
const preview = details.xtrmWritePreview;
|
|
914
1077
|
|
|
915
1078
|
if (preview?.kind === "unchanged") {
|
|
916
|
-
return
|
|
1079
|
+
return toolRowText(theme, renderToolSummary(theme, "success", "write", subject, joinMeta(["no changes", formatDuration(meta?.durationMs)])));
|
|
917
1080
|
}
|
|
918
1081
|
|
|
919
1082
|
if (preview?.kind === "updated") {
|
|
@@ -925,15 +1088,14 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
925
1088
|
joinMeta([`+${preview.additions}`, `-${preview.removals}`, formatDuration(meta?.durationMs)]),
|
|
926
1089
|
);
|
|
927
1090
|
if (expanded && preview.diff) text += `\n${renderRichDiffPreview(theme, preview.diff, 18)}`;
|
|
928
|
-
return
|
|
1091
|
+
return toolRowText(theme, text);
|
|
929
1092
|
}
|
|
930
1093
|
|
|
931
1094
|
const lines = preview?.kind === "created"
|
|
932
1095
|
? preview.lineCount
|
|
933
1096
|
: lineCount(String(meta?.args.content ?? ""));
|
|
934
1097
|
|
|
935
|
-
return
|
|
936
|
-
renderToolSummary(
|
|
1098
|
+
return toolRowText(theme, renderToolSummary(
|
|
937
1099
|
theme,
|
|
938
1100
|
"success",
|
|
939
1101
|
"write",
|
|
@@ -951,6 +1113,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
951
1113
|
label: "find",
|
|
952
1114
|
description: getTools(process.cwd()).find.description,
|
|
953
1115
|
parameters: getTools(process.cwd()).find.parameters,
|
|
1116
|
+
renderShell: "self",
|
|
954
1117
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
955
1118
|
const started = Date.now();
|
|
956
1119
|
const result = await getTools(ctx.cwd).find.execute(toolCallId, params, signal, onUpdate);
|
|
@@ -958,14 +1121,14 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
958
1121
|
},
|
|
959
1122
|
renderCall: (args, theme) => renderPendingCallIfActive("find", args as Record<string, unknown>, theme),
|
|
960
1123
|
renderResult(result, { expanded, isPartial }, theme) {
|
|
961
|
-
if (isPartial) return
|
|
1124
|
+
if (isPartial) return toolRowText(theme, renderToolSummary(theme, "pending", "find", "searching", undefined));
|
|
962
1125
|
const details = (result.details ?? {}) as DetailsWithXtrmMeta<FindToolDetails, Record<string, unknown>>;
|
|
963
1126
|
const meta = getXtrmMeta<FindToolDetails, Record<string, unknown>>(details);
|
|
964
1127
|
const textContent = getTextContent(result as any);
|
|
965
1128
|
const count = summarizeCount(textContent);
|
|
966
1129
|
let text = renderToolSummary(theme, "success", "find", String(meta?.args.pattern ?? ""), joinMeta([formatLineLabel(count, "match"), formatDuration(meta?.durationMs), details.resultLimitReached ? "limit reached" : undefined]));
|
|
967
1130
|
if (expanded && count > 0) text += `\n${renderOutputPreview(theme, previewLines(textContent, 10), 10)}`;
|
|
968
|
-
return
|
|
1131
|
+
return toolRowText(theme, text);
|
|
969
1132
|
},
|
|
970
1133
|
});
|
|
971
1134
|
|
|
@@ -974,6 +1137,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
974
1137
|
label: "grep",
|
|
975
1138
|
description: getTools(process.cwd()).grep.description,
|
|
976
1139
|
parameters: getTools(process.cwd()).grep.parameters,
|
|
1140
|
+
renderShell: "self",
|
|
977
1141
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
978
1142
|
const started = Date.now();
|
|
979
1143
|
const result = await getTools(ctx.cwd).grep.execute(toolCallId, params, signal, onUpdate);
|
|
@@ -981,14 +1145,14 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
981
1145
|
},
|
|
982
1146
|
renderCall: (args, theme) => renderPendingCallIfActive("grep", args as Record<string, unknown>, theme),
|
|
983
1147
|
renderResult(result, { expanded, isPartial }, theme) {
|
|
984
|
-
if (isPartial) return
|
|
1148
|
+
if (isPartial) return toolRowText(theme, renderToolSummary(theme, "pending", "grep", "searching", undefined));
|
|
985
1149
|
const details = (result.details ?? {}) as DetailsWithXtrmMeta<GrepToolDetails, Record<string, unknown>>;
|
|
986
1150
|
const meta = getXtrmMeta<GrepToolDetails, Record<string, unknown>>(details);
|
|
987
1151
|
const textContent = getTextContent(result as any);
|
|
988
1152
|
const count = countPrefixedItems(textContent, ["-- "]) || summarizeCount(textContent);
|
|
989
1153
|
let text = renderToolSummary(theme, "success", "grep", String(meta?.args.pattern ?? ""), joinMeta([formatLineLabel(count, "match"), formatDuration(meta?.durationMs), details.matchLimitReached ? "limit reached" : undefined]));
|
|
990
1154
|
if (expanded && textContent.length > 0) text += `\n${renderOutputPreview(theme, previewLines(textContent, 12), 12)}`;
|
|
991
|
-
return
|
|
1155
|
+
return toolRowText(theme, text);
|
|
992
1156
|
},
|
|
993
1157
|
});
|
|
994
1158
|
|
|
@@ -997,6 +1161,7 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
997
1161
|
label: "ls",
|
|
998
1162
|
description: getTools(process.cwd()).ls.description,
|
|
999
1163
|
parameters: getTools(process.cwd()).ls.parameters,
|
|
1164
|
+
renderShell: "self",
|
|
1000
1165
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
1001
1166
|
const started = Date.now();
|
|
1002
1167
|
const result = await getTools(ctx.cwd).ls.execute(toolCallId, params, signal, onUpdate);
|
|
@@ -1004,14 +1169,14 @@ function registerXtrmUiTools(pi: ExtensionAPI): void {
|
|
|
1004
1169
|
},
|
|
1005
1170
|
renderCall: (args, theme) => renderPendingCallIfActive("ls", args as Record<string, unknown>, theme),
|
|
1006
1171
|
renderResult(result, { expanded, isPartial }, theme) {
|
|
1007
|
-
if (isPartial) return
|
|
1172
|
+
if (isPartial) return toolRowText(theme, renderToolSummary(theme, "pending", "ls", "listing", undefined));
|
|
1008
1173
|
const details = (result.details ?? {}) as DetailsWithXtrmMeta<LsToolDetails, Record<string, unknown>>;
|
|
1009
1174
|
const meta = getXtrmMeta<LsToolDetails, Record<string, unknown>>(details);
|
|
1010
1175
|
const textContent = getTextContent(result as any);
|
|
1011
1176
|
const count = summarizeCount(textContent);
|
|
1012
1177
|
let text = renderToolSummary(theme, "success", "ls", shortenPath(String(meta?.args.path ?? ".")), joinMeta([formatLineLabel(count, "entry"), formatDuration(meta?.durationMs), details.entryLimitReached ? "limit reached" : undefined]));
|
|
1013
1178
|
if (expanded && count > 0) text += `\n${renderOutputPreview(theme, previewLines(textContent, 12), 12)}`;
|
|
1014
|
-
return
|
|
1179
|
+
return toolRowText(theme, text);
|
|
1015
1180
|
},
|
|
1016
1181
|
});
|
|
1017
1182
|
}
|
|
@@ -1033,7 +1198,7 @@ export default function xtrmUiExtension(pi: ExtensionAPI): void {
|
|
|
1033
1198
|
const setPrefs = (p: XtrmUiPrefs) => { prefs = p; };
|
|
1034
1199
|
const getThinkingLevel = () => formatThinking(pi.getThinkingLevel());
|
|
1035
1200
|
|
|
1036
|
-
registerXtrmUiTools(pi);
|
|
1201
|
+
registerXtrmUiTools(pi, getPrefs);
|
|
1037
1202
|
registerCommands(pi, getPrefs, setPrefs, getThinkingLevel);
|
|
1038
1203
|
|
|
1039
1204
|
const refresh = (ctx: ExtensionContext) => {
|
|
@@ -1052,7 +1217,7 @@ export default function xtrmUiExtension(pi: ExtensionAPI): void {
|
|
|
1052
1217
|
refresh(ctx);
|
|
1053
1218
|
|
|
1054
1219
|
setTimeout(() => {
|
|
1055
|
-
|
|
1220
|
+
ctx.ui.setTheme(resolveThemeForPrefs(prefs));
|
|
1056
1221
|
}, 0);
|
|
1057
1222
|
});
|
|
1058
1223
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
3
|
+
"name": "pidex-dark-flattools",
|
|
4
|
+
"vars": {
|
|
5
|
+
"accentBlue": "#b8d3ff",
|
|
6
|
+
"accentCyan": "#b8d3ff",
|
|
7
|
+
"accentTeal": "#c7d2e0",
|
|
8
|
+
"successGreen": "#9fd59f",
|
|
9
|
+
"errorRed": "#ff9a9a",
|
|
10
|
+
"warningAmber": "#d2b48c",
|
|
11
|
+
"surface": "#000000",
|
|
12
|
+
"surfaceAlt": "#111111",
|
|
13
|
+
"surfaceMuted": "#1a1a1a",
|
|
14
|
+
"surfaceUser": "#1f1f1f",
|
|
15
|
+
"surfaceCustom": "#161616",
|
|
16
|
+
"gray": "#a7a7a7",
|
|
17
|
+
"dimGray": "#8a8a8a",
|
|
18
|
+
"borderGray": "#666666",
|
|
19
|
+
"borderBright": "#9a9a9a"
|
|
20
|
+
},
|
|
21
|
+
"colors": {
|
|
22
|
+
"accent": "accentBlue",
|
|
23
|
+
"border": "borderGray",
|
|
24
|
+
"borderAccent": "borderBright",
|
|
25
|
+
"borderMuted": "borderGray",
|
|
26
|
+
"success": "successGreen",
|
|
27
|
+
"error": "errorRed",
|
|
28
|
+
"warning": "warningAmber",
|
|
29
|
+
"muted": "gray",
|
|
30
|
+
"dim": "dimGray",
|
|
31
|
+
"text": "",
|
|
32
|
+
"thinkingText": "gray",
|
|
33
|
+
"selectedBg": "surfaceMuted",
|
|
34
|
+
"userMessageBg": "surfaceUser",
|
|
35
|
+
"userMessageText": "",
|
|
36
|
+
"customMessageBg": "surfaceCustom",
|
|
37
|
+
"customMessageText": "",
|
|
38
|
+
"customMessageLabel": "accentBlue",
|
|
39
|
+
"toolPendingBg": "",
|
|
40
|
+
"toolSuccessBg": "",
|
|
41
|
+
"toolErrorBg": "",
|
|
42
|
+
"toolTitle": "",
|
|
43
|
+
"toolOutput": "gray",
|
|
44
|
+
"mdHeading": "warningAmber",
|
|
45
|
+
"mdLink": "accentBlue",
|
|
46
|
+
"mdLinkUrl": "dimGray",
|
|
47
|
+
"mdCode": "accentCyan",
|
|
48
|
+
"mdCodeBlock": "gray",
|
|
49
|
+
"mdCodeBlockBorder": "borderGray",
|
|
50
|
+
"mdQuote": "gray",
|
|
51
|
+
"mdQuoteBorder": "borderGray",
|
|
52
|
+
"mdHr": "borderGray",
|
|
53
|
+
"mdListBullet": "accentTeal",
|
|
54
|
+
"toolDiffAdded": "successGreen",
|
|
55
|
+
"toolDiffRemoved": "errorRed",
|
|
56
|
+
"toolDiffContext": "gray",
|
|
57
|
+
"syntaxComment": "#6b7280",
|
|
58
|
+
"syntaxKeyword": "#7aa2f7",
|
|
59
|
+
"syntaxFunction": "#c0caf5",
|
|
60
|
+
"syntaxVariable": "#a9b1d6",
|
|
61
|
+
"syntaxString": "#9ece6a",
|
|
62
|
+
"syntaxNumber": "#ff9e64",
|
|
63
|
+
"syntaxType": "#73daca",
|
|
64
|
+
"syntaxOperator": "#c0caf5",
|
|
65
|
+
"syntaxPunctuation": "#8f9bb3",
|
|
66
|
+
"thinkingOff": "borderGray",
|
|
67
|
+
"thinkingMinimal": "#707070",
|
|
68
|
+
"thinkingLow": "#7a7a7a",
|
|
69
|
+
"thinkingMedium": "#858585",
|
|
70
|
+
"thinkingHigh": "#8f8f8f",
|
|
71
|
+
"thinkingXhigh": "#999999",
|
|
72
|
+
"bashMode": "accentTeal"
|
|
73
|
+
},
|
|
74
|
+
"export": {
|
|
75
|
+
"pageBg": "#12161d",
|
|
76
|
+
"cardBg": "#171b22",
|
|
77
|
+
"infoBg": "#28230f"
|
|
78
|
+
}
|
|
79
|
+
}
|