@owlburtoe/pi-cc-tools 1.1.2 → 1.1.6
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 +6 -10
- package/config/config.example.json +0 -2
- package/extensions/index.ts +29 -74
- package/extensions/message-chrome.ts +0 -11
- package/extensions/spinner.ts +0 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Claude Code inspired tool rendering for Pi — Shiki-powered diffs, status dots,
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **Compact
|
|
7
|
+
- **Compact Claude Code-like tool rendering** for `read`, `bash`, `grep`, `find`, `ls`, `edit`, and `write`, including `⏺ Tool(args)` headers and `⎿` result rows
|
|
8
8
|
- **Semantic bash display** that renders common read-only shell one-liners like `nl -ba file | sed -n '1,200p'` as Claude Code-style `Read file (lines 1-200)` rows
|
|
9
9
|
- **Read-only inspection grouping** that collapses consecutive `read`/`grep`/`find`/`ls` rows into one Claude-style `Inspect` block, capped to five visible entries by default
|
|
10
10
|
- **Claude-style OpenAI tool rendering** for `apply_patch` plus common Pi/OpenAI-style tools like `webfetch`, `web_search`, `fetch_content`, task tools, and context tools
|
|
@@ -13,7 +13,7 @@ Claude Code inspired tool rendering for Pi — Shiki-powered diffs, status dots,
|
|
|
13
13
|
- **Diff stat bar** with colored add/remove summary and hunk metadata
|
|
14
14
|
- **Progressive collapsed diff hints** that shorten on narrow terminals
|
|
15
15
|
- **Thinking labels** during streaming and final messages, with context sanitization
|
|
16
|
-
- **Claude-style transcript grammar controls** for assistant/thinking prefixes, message spacing, hidden thinking labels
|
|
16
|
+
- **Claude-style transcript grammar controls** for assistant/thinking prefixes, message spacing, and hidden thinking labels
|
|
17
17
|
- **MCP-aware rendering** with hidden, summary, and preview modes
|
|
18
18
|
- **Configurable output modes** for read, search, bash, and MCP results
|
|
19
19
|
- **Transparent tool backgrounds** in `transparent` or `border` mode
|
|
@@ -27,7 +27,7 @@ Set in `.pi/settings.json` or `~/.pi/settings.json`:
|
|
|
27
27
|
|
|
28
28
|
```json
|
|
29
29
|
{
|
|
30
|
-
"toolBackground": "
|
|
30
|
+
"toolBackground": "transparent",
|
|
31
31
|
"readOutputMode": "preview",
|
|
32
32
|
"searchOutputMode": "preview",
|
|
33
33
|
"mcpOutputMode": "preview",
|
|
@@ -48,8 +48,6 @@ Set in `.pi/settings.json` or `~/.pi/settings.json`:
|
|
|
48
48
|
"assistantPrefix": "●",
|
|
49
49
|
"thinkingPrefix": "✻",
|
|
50
50
|
"messageSpacing": "comfortable",
|
|
51
|
-
"workingTipEnabled": true,
|
|
52
|
-
"workingTipText": "Run /install-github-app to tag @claude right from your GitHub issues and PRs",
|
|
53
51
|
"hiddenThinkingLabel": "Pondering..."
|
|
54
52
|
}
|
|
55
53
|
```
|
|
@@ -116,13 +114,10 @@ Color selections are persisted as `spinnerColor` / `spinnerStatusColor` in `~/.p
|
|
|
116
114
|
/cc-message assistant-prefix ● # set assistant paragraph prefix
|
|
117
115
|
/cc-message thinking-prefix ✻ # set visible thinking prefix
|
|
118
116
|
/cc-message hidden-thinking-label Pondering...
|
|
119
|
-
/cc-message tip on # show active working tip line
|
|
120
|
-
/cc-message tip off # hide active working tip line
|
|
121
|
-
/cc-message tip text Run /help for tips # set active working tip text
|
|
122
117
|
/cc-message reset # restore message chrome defaults
|
|
123
118
|
```
|
|
124
119
|
|
|
125
|
-
`messageStyle: "claude"` trims leading/trailing blank render lines, collapses paragraph gaps, and aligns wrapped assistant/thinking lines under the message body, matching Claude Code's sparse transcript grammar. `messageStyle: "classic"` keeps the previous package behavior.
|
|
120
|
+
`messageStyle: "claude"` trims leading/trailing blank render lines, collapses paragraph gaps, and aligns wrapped assistant/thinking lines under the message body, matching Claude Code's sparse transcript grammar. `messageStyle: "classic"` keeps the previous package behavior.
|
|
126
121
|
|
|
127
122
|
### Tool background modes
|
|
128
123
|
|
|
@@ -130,7 +125,8 @@ Color selections are persisted as `spinnerColor` / `spinnerStatusColor` in `~/.p
|
|
|
130
125
|
|-------|----------|
|
|
131
126
|
| `default` | Standard Pi tool backgrounds |
|
|
132
127
|
| `transparent` | Transparent tool backgrounds |
|
|
133
|
-
| `border` | Transparent backgrounds with top/bottom border lines |
|
|
128
|
+
| `border` | Transparent backgrounds with top/bottom border lines (alias for `outlines`) |
|
|
129
|
+
| `outlines` | Transparent backgrounds with top/bottom border lines |
|
|
134
130
|
|
|
135
131
|
### Output modes
|
|
136
132
|
|
|
@@ -23,7 +23,5 @@
|
|
|
23
23
|
"assistantPrefix": "●",
|
|
24
24
|
"thinkingPrefix": "✻",
|
|
25
25
|
"messageSpacing": "comfortable",
|
|
26
|
-
"workingTipEnabled": true,
|
|
27
|
-
"workingTipText": "Run /install-github-app to tag @claude right from your GitHub issues and PRs",
|
|
28
26
|
"hiddenThinkingLabel": "Pondering..."
|
|
29
27
|
}
|
package/extensions/index.ts
CHANGED
|
@@ -71,7 +71,12 @@ const WRAP_MARK = "\uE000";
|
|
|
71
71
|
const KITTY_IMAGE_PREFIX = "\x1b_G";
|
|
72
72
|
const ITERM2_IMAGE_PREFIX = "\x1b]1337;File=";
|
|
73
73
|
|
|
74
|
-
let toolBackgroundMode: "default" | "transparent" | "outlines" = "
|
|
74
|
+
let toolBackgroundMode: "default" | "transparent" | "outlines" = "transparent";
|
|
75
|
+
|
|
76
|
+
const CLAUDE_TOOL_GLYPH = "⏺";
|
|
77
|
+
const CLAUDE_RESULT_GLYPH = "⎿";
|
|
78
|
+
const CLAUDE_RESULT_PREFIX = ` ${CLAUDE_RESULT_GLYPH} `;
|
|
79
|
+
const CLAUDE_RESULT_CONTINUATION = " ".repeat(CLAUDE_RESULT_PREFIX.length);
|
|
75
80
|
|
|
76
81
|
type SpinnerVerbMode = "append" | "replace";
|
|
77
82
|
|
|
@@ -129,10 +134,6 @@ interface SettingsFile {
|
|
|
129
134
|
thinkingPrefix?: string;
|
|
130
135
|
/** Blank-line normalization in assistant/thinking transcript blocks. */
|
|
131
136
|
messageSpacing?: MessageSpacing;
|
|
132
|
-
/** Whether the active working spinner may show a subordinate Claude-style tip line. */
|
|
133
|
-
workingTipEnabled?: boolean;
|
|
134
|
-
/** Custom subordinate tip line text for the active working spinner. */
|
|
135
|
-
workingTipText?: string;
|
|
136
137
|
/** Label shown when thinking blocks are hidden by the Pi UI. */
|
|
137
138
|
hiddenThinkingLabel?: string;
|
|
138
139
|
}
|
|
@@ -273,7 +274,7 @@ function syncToolBackgroundMode(): void {
|
|
|
273
274
|
const settings = readSettings();
|
|
274
275
|
// Backward compat: "border" was renamed to "outlines"
|
|
275
276
|
const raw = settings.toolBackground === "border" ? "outlines" : settings.toolBackground;
|
|
276
|
-
toolBackgroundMode = raw ?? "
|
|
277
|
+
toolBackgroundMode = raw ?? "transparent";
|
|
277
278
|
}
|
|
278
279
|
|
|
279
280
|
function setThemeBg(theme: unknown, key: string, value: string): void {
|
|
@@ -538,14 +539,14 @@ function renderInspectionGroup(group: unknown[], width: number): string[] {
|
|
|
538
539
|
const limit = readOnlyToolGroupLimit();
|
|
539
540
|
const shown = group.slice(0, limit);
|
|
540
541
|
const remaining = group.length - shown.length;
|
|
541
|
-
const core: string[] = [` ${WRAP_MARK}
|
|
542
|
+
const core: string[] = [` ${WRAP_MARK}${CLAUDE_TOOL_GLYPH} Inspect(${plural(group.length, "tool use")})`];
|
|
542
543
|
for (let index = 0; index < shown.length; index++) {
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
core.push(` ${TOOL_RULE}${branch}${TRANSPARENT_RESET} ${WRAP_MARK}${summarizeReadOnlyInspectionTool(shown[index])}`);
|
|
544
|
+
const prefix = index === 0 ? `${TOOL_RULE}${CLAUDE_RESULT_PREFIX}${TRANSPARENT_RESET}` : CLAUDE_RESULT_CONTINUATION;
|
|
545
|
+
core.push(`${prefix}${WRAP_MARK}${summarizeReadOnlyInspectionTool(shown[index])}`);
|
|
546
546
|
}
|
|
547
547
|
if (remaining > 0) {
|
|
548
|
-
|
|
548
|
+
const prefix = shown.length === 0 ? `${TOOL_RULE}${CLAUDE_RESULT_PREFIX}${TRANSPARENT_RESET}` : CLAUDE_RESULT_CONTINUATION;
|
|
549
|
+
core.push(`${prefix}${WRAP_MARK}… ${remaining} more inspection${remaining === 1 ? "" : "s"}`);
|
|
549
550
|
}
|
|
550
551
|
const renderedCore = core.flatMap((line) => wrapMarkedLine(line, width)).map((line) => padToWidth(line, width));
|
|
551
552
|
if (toolBackgroundMode === "outlines") return [" ".repeat(width), borderLine(width), ...renderedCore, borderLine(width)];
|
|
@@ -1251,7 +1252,7 @@ function toolHeader(tool: string, summary: string, theme: Theme, prefix = ""): s
|
|
|
1251
1252
|
applyThemePaletteIfNeeded(theme);
|
|
1252
1253
|
const label = theme.fg("toolTitle", theme.bold(tool));
|
|
1253
1254
|
if (!summary) return `${prefix}${label}`;
|
|
1254
|
-
return `${prefix}${label} ${WRAP_MARK}${theme.fg("accent", summary)}`;
|
|
1255
|
+
return `${prefix}${label}${theme.fg("muted", "(")}${WRAP_MARK}${theme.fg("accent", summary)}${theme.fg("muted", ")")}`;
|
|
1255
1256
|
}
|
|
1256
1257
|
|
|
1257
1258
|
function setToolStatus(ctx: any, status: "pending" | "success" | "error"): void {
|
|
@@ -1315,8 +1316,8 @@ function getWriteWasNewFile(ctx: any, cwd: string, filePath: string, reveal = sh
|
|
|
1315
1316
|
|
|
1316
1317
|
function toolStatusDot(ctx: any, theme: Theme): string {
|
|
1317
1318
|
const status = ctx.state?._toolStatus as "pending" | "success" | "error" | undefined;
|
|
1318
|
-
if (status === "
|
|
1319
|
-
if (status === "
|
|
1319
|
+
if (status === "error") return `${theme.fg("error", CLAUDE_TOOL_GLYPH)} `;
|
|
1320
|
+
if (status === "success") return `${theme.fg("accent", CLAUDE_TOOL_GLYPH)} `;
|
|
1320
1321
|
return `${blinkDot(ctx, theme)} `;
|
|
1321
1322
|
}
|
|
1322
1323
|
|
|
@@ -1324,13 +1325,12 @@ function toolStatusDot(ctx: any, theme: Theme): string {
|
|
|
1324
1325
|
// Branch connector — visual tree from header to output
|
|
1325
1326
|
// ---------------------------------------------------------------------------
|
|
1326
1327
|
|
|
1327
|
-
function branchIndent(text: string,
|
|
1328
|
-
|
|
1329
|
-
return `${prefix}${WRAP_MARK}${text}`;
|
|
1328
|
+
function branchIndent(text: string, _continued = false): string {
|
|
1329
|
+
return `${CLAUDE_RESULT_CONTINUATION}${WRAP_MARK}${text}`;
|
|
1330
1330
|
}
|
|
1331
1331
|
|
|
1332
|
-
function branchLead(text: string,
|
|
1333
|
-
return `${TOOL_RULE}${
|
|
1332
|
+
function branchLead(text: string, _continued = false): string {
|
|
1333
|
+
return `${TOOL_RULE}${CLAUDE_RESULT_PREFIX}${TRANSPARENT_RESET}${WRAP_MARK}${text}`;
|
|
1334
1334
|
}
|
|
1335
1335
|
|
|
1336
1336
|
function withBranch(content: string, _theme: Theme, _isError = false, continued = false): string {
|
|
@@ -1343,20 +1343,11 @@ function withBranch(content: string, _theme: Theme, _isError = false, continued
|
|
|
1343
1343
|
}
|
|
1344
1344
|
|
|
1345
1345
|
function withFinalBranchBlock(content: string, theme: Theme, isError = false): string {
|
|
1346
|
-
|
|
1347
|
-
const lines = content.split("\n");
|
|
1348
|
-
const first = lines[0] ?? "";
|
|
1349
|
-
if (lines.length === 1) return branchLead(first, false);
|
|
1350
|
-
const middle = lines.slice(1, -1).map((line) => branchIndent(line, true));
|
|
1351
|
-
const last = lines[lines.length - 1] ?? "";
|
|
1352
|
-
return [branchLead(first, true), ...middle, branchLead(last, false)].join("\n");
|
|
1346
|
+
return withBranch(content, theme, isError);
|
|
1353
1347
|
}
|
|
1354
1348
|
|
|
1355
1349
|
function indentBranchBlock(block: string): string {
|
|
1356
|
-
return block
|
|
1357
|
-
.split("\n")
|
|
1358
|
-
.map((line) => (line ? ` ${line}` : line))
|
|
1359
|
-
.join("\n");
|
|
1350
|
+
return block;
|
|
1360
1351
|
}
|
|
1361
1352
|
|
|
1362
1353
|
// ---------------------------------------------------------------------------
|
|
@@ -1458,8 +1449,8 @@ function clearBlinkTimer(ctx: any): void {
|
|
|
1458
1449
|
function blinkDot(ctx: any, theme: Theme): string {
|
|
1459
1450
|
setupBlinkTimer(ctx);
|
|
1460
1451
|
const key = getBlinkKey(ctx);
|
|
1461
|
-
if (key?._blinkActive !== true) return theme.fg("muted",
|
|
1462
|
-
return _globalBlinkPhase ? theme.fg("
|
|
1452
|
+
if (key?._blinkActive !== true) return theme.fg("muted", CLAUDE_TOOL_GLYPH);
|
|
1453
|
+
return _globalBlinkPhase ? theme.fg("accent", CLAUDE_TOOL_GLYPH) : theme.fg("muted", CLAUDE_TOOL_GLYPH);
|
|
1463
1454
|
}
|
|
1464
1455
|
|
|
1465
1456
|
// ---------------------------------------------------------------------------
|
|
@@ -1545,6 +1536,8 @@ function markedContinuationPrefix(prefix: string): string {
|
|
|
1545
1536
|
if (branchMatch) {
|
|
1546
1537
|
return `${branchMatch[1]}${TOOL_RULE}│${TRANSPARENT_RESET} `;
|
|
1547
1538
|
}
|
|
1539
|
+
const resultMatch = /^(\s*)⎿\s+/.exec(plain);
|
|
1540
|
+
if (resultMatch) return " ".repeat(visibleWidth(prefix));
|
|
1548
1541
|
return " ".repeat(visibleWidth(prefix));
|
|
1549
1542
|
}
|
|
1550
1543
|
|
|
@@ -4498,7 +4491,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
4498
4491
|
},
|
|
4499
4492
|
});
|
|
4500
4493
|
|
|
4501
|
-
const MESSAGE_COMMANDS = ["style", "spacing", "assistant-prefix", "thinking-prefix", "
|
|
4494
|
+
const MESSAGE_COMMANDS = ["style", "spacing", "assistant-prefix", "thinking-prefix", "hidden-thinking-label", "reset", "status"] as const;
|
|
4502
4495
|
pi.registerCommand("cc-message", {
|
|
4503
4496
|
description: "Configure Claude-style assistant/thinking transcript chrome",
|
|
4504
4497
|
getArgumentCompletions(prefix: string) {
|
|
@@ -4515,7 +4508,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
4515
4508
|
: c === "spacing" ? "Set blank-line rhythm: compact or comfortable"
|
|
4516
4509
|
: c === "assistant-prefix" ? "Set assistant paragraph prefix glyph/text"
|
|
4517
4510
|
: c === "thinking-prefix" ? "Set visible thinking prefix glyph/text"
|
|
4518
|
-
: c === "tip" ? "Enable, disable, or customize active working tip line"
|
|
4519
4511
|
: c === "hidden-thinking-label" ? "Set label shown when thinking is hidden"
|
|
4520
4512
|
: c === "reset" ? "Reset message chrome settings"
|
|
4521
4513
|
: "Show current message chrome settings",
|
|
@@ -4533,12 +4525,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
4533
4525
|
.filter((v) => v.startsWith(valuePrefix))
|
|
4534
4526
|
.map((v) => ({ value: `spacing ${v}`, label: v, description: v === "comfortable" ? "Preserve one blank line between paragraphs" : "Remove blank lines inside assistant/thinking blocks" }));
|
|
4535
4527
|
}
|
|
4536
|
-
if (parts[0] === "tip") {
|
|
4537
|
-
const valuePrefix = (parts[1] ?? "").toLowerCase();
|
|
4538
|
-
return ["on", "off", "text", "reset"]
|
|
4539
|
-
.filter((v) => v.startsWith(valuePrefix))
|
|
4540
|
-
.map((v) => ({ value: `tip ${v}`, label: v, description: v === "text" ? "Set custom active working tip text" : `${v} working tip line` }));
|
|
4541
|
-
}
|
|
4542
4528
|
return [];
|
|
4543
4529
|
},
|
|
4544
4530
|
async handler(args: string, ctx: any) {
|
|
@@ -4553,8 +4539,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
4553
4539
|
`Assistant prefix: ${current.assistantPrefix}`,
|
|
4554
4540
|
`Thinking prefix: ${current.thinkingPrefix}`,
|
|
4555
4541
|
`Spacing: ${current.messageSpacing}`,
|
|
4556
|
-
`Working tip: ${current.workingTipEnabled ? "on" : "off"}`,
|
|
4557
|
-
`Tip text: ${current.workingTipText}`,
|
|
4558
4542
|
`Hidden thinking label: ${current.hiddenThinkingLabel}`,
|
|
4559
4543
|
].join("\n"), "info");
|
|
4560
4544
|
};
|
|
@@ -4565,7 +4549,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
4565
4549
|
}
|
|
4566
4550
|
|
|
4567
4551
|
if (sub === "reset") {
|
|
4568
|
-
for (const key of ["messageStyle", "assistantPrefix", "thinkingPrefix", "messageSpacing", "
|
|
4552
|
+
for (const key of ["messageStyle", "assistantPrefix", "thinkingPrefix", "messageSpacing", "hiddenThinkingLabel"]) {
|
|
4569
4553
|
writeSettingsKey(key, undefined);
|
|
4570
4554
|
}
|
|
4571
4555
|
bustSpinnerSettingsCache();
|
|
@@ -4581,8 +4565,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
4581
4565
|
return;
|
|
4582
4566
|
}
|
|
4583
4567
|
writeSettingsKey("messageStyle", value);
|
|
4584
|
-
writeSettingsKey("workingTipEnabled", value === "classic" ? false : undefined);
|
|
4585
|
-
bustSpinnerSettingsCache();
|
|
4586
4568
|
if (ctx.hasUI) ctx.ui.notify(`Message style → ${value}`, "info");
|
|
4587
4569
|
return;
|
|
4588
4570
|
}
|
|
@@ -4607,33 +4589,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
4607
4589
|
return;
|
|
4608
4590
|
}
|
|
4609
4591
|
|
|
4610
|
-
if (sub === "tip") {
|
|
4611
|
-
const action = (parts[1] ?? "").toLowerCase();
|
|
4612
|
-
if (action === "on" || action === "off") {
|
|
4613
|
-
writeSettingsKey("workingTipEnabled", action === "on");
|
|
4614
|
-
bustSpinnerSettingsCache();
|
|
4615
|
-
if (ctx.hasUI) ctx.ui.notify(`Working tip → ${action}`, "info");
|
|
4616
|
-
return;
|
|
4617
|
-
}
|
|
4618
|
-
if (action === "reset") {
|
|
4619
|
-
writeSettingsKey("workingTipEnabled", undefined);
|
|
4620
|
-
writeSettingsKey("workingTipText", undefined);
|
|
4621
|
-
bustSpinnerSettingsCache();
|
|
4622
|
-
if (ctx.hasUI) ctx.ui.notify("Working tip reset", "info");
|
|
4623
|
-
return;
|
|
4624
|
-
}
|
|
4625
|
-
if (action === "text") {
|
|
4626
|
-
const textArg = rawArgs.match(/^tip\s+text(?:\s+(.+))?$/i)?.[1] ?? "";
|
|
4627
|
-
const value = resolveMessageChromeSettings({ workingTipText: textArg }).workingTipText;
|
|
4628
|
-
writeSettingsKey("workingTipText", value);
|
|
4629
|
-
bustSpinnerSettingsCache();
|
|
4630
|
-
if (ctx.hasUI) ctx.ui.notify(`Working tip text → ${value}`, "info");
|
|
4631
|
-
return;
|
|
4632
|
-
}
|
|
4633
|
-
if (ctx.hasUI) ctx.ui.notify("Usage: /cc-message tip on|off|reset|text <text>", "error");
|
|
4634
|
-
return;
|
|
4635
|
-
}
|
|
4636
|
-
|
|
4637
4592
|
if (sub === "hidden-thinking-label") {
|
|
4638
4593
|
const textArg = rawArgs.match(/^hidden-thinking-label(?:\s+(.+))?$/i)?.[1] ?? "";
|
|
4639
4594
|
const value = resolveMessageChromeSettings({ hiddenThinkingLabel: textArg }).hiddenThinkingLabel;
|
|
@@ -4643,7 +4598,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
4643
4598
|
return;
|
|
4644
4599
|
}
|
|
4645
4600
|
|
|
4646
|
-
if (ctx.hasUI) ctx.ui.notify("Usage: /cc-message style|spacing|assistant-prefix|thinking-prefix|
|
|
4601
|
+
if (ctx.hasUI) ctx.ui.notify("Usage: /cc-message style|spacing|assistant-prefix|thinking-prefix|hidden-thinking-label|reset|status", "error");
|
|
4647
4602
|
},
|
|
4648
4603
|
});
|
|
4649
4604
|
|
|
@@ -5066,7 +5021,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
5066
5021
|
const revealSummary = shouldRevealCallArgs(ctx) || (!!fp && hasOwnArg(args, "edits"));
|
|
5067
5022
|
const summary = stableCallSummary(ctx, "_callSummary", () => shouldRevealCallArgs(ctx) && operations.length > 1 ? `${sp(fp)} ${theme.fg("muted", `(${operations.length} edits)`)}` : sp(fp), revealSummary);
|
|
5068
5023
|
syncToolCallStatus(ctx);
|
|
5069
|
-
const hdr = toolHeader("Edit", summary, theme,
|
|
5024
|
+
const hdr = toolHeader("Edit", summary, theme, toolStatusDot(ctx, theme));
|
|
5070
5025
|
if (!(ctx.argsComplete && operations.length > 0)) return makeText(ctx.lastComponent, hdr);
|
|
5071
5026
|
const diffWidth = branchDiffWidth();
|
|
5072
5027
|
const key = `edit:${fp}:${hashText(operations.map((edit) => `${edit.oldText}\u0000${edit.newText}`).join("\u0001"))}:${diffWidth}:${ctx.expanded ? 1 : 0}`;
|
|
@@ -6,8 +6,6 @@ export interface MessageChromeInput {
|
|
|
6
6
|
assistantPrefix?: unknown;
|
|
7
7
|
thinkingPrefix?: unknown;
|
|
8
8
|
messageSpacing?: unknown;
|
|
9
|
-
workingTipEnabled?: unknown;
|
|
10
|
-
workingTipText?: unknown;
|
|
11
9
|
hiddenThinkingLabel?: unknown;
|
|
12
10
|
}
|
|
13
11
|
|
|
@@ -16,8 +14,6 @@ export interface MessageChromeSettings {
|
|
|
16
14
|
assistantPrefix: string;
|
|
17
15
|
thinkingPrefix: string;
|
|
18
16
|
messageSpacing: MessageSpacing;
|
|
19
|
-
workingTipEnabled: boolean;
|
|
20
|
-
workingTipText: string;
|
|
21
17
|
hiddenThinkingLabel: string;
|
|
22
18
|
}
|
|
23
19
|
|
|
@@ -28,7 +24,6 @@ export interface TranscriptLineOptions {
|
|
|
28
24
|
visibleWidth?: (text: string) => number;
|
|
29
25
|
}
|
|
30
26
|
|
|
31
|
-
export const DEFAULT_WORKING_TIP_TEXT = "Run /install-github-app to tag @claude right from your GitHub issues and PRs";
|
|
32
27
|
export const DEFAULT_HIDDEN_THINKING_LABEL = "Pondering...";
|
|
33
28
|
|
|
34
29
|
const DEFAULT_MESSAGE_CHROME: MessageChromeSettings = {
|
|
@@ -36,8 +31,6 @@ const DEFAULT_MESSAGE_CHROME: MessageChromeSettings = {
|
|
|
36
31
|
assistantPrefix: "●",
|
|
37
32
|
thinkingPrefix: "✻",
|
|
38
33
|
messageSpacing: "comfortable",
|
|
39
|
-
workingTipEnabled: true,
|
|
40
|
-
workingTipText: DEFAULT_WORKING_TIP_TEXT,
|
|
41
34
|
hiddenThinkingLabel: DEFAULT_HIDDEN_THINKING_LABEL,
|
|
42
35
|
};
|
|
43
36
|
|
|
@@ -45,7 +38,6 @@ const ANSI_ESCAPE_SEQUENCE_RE = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]|\][^\x07]*
|
|
|
45
38
|
const ANSI_SGR_RE = /\x1b\[[0-9;]*m/g;
|
|
46
39
|
const CONTROL_CHARS_RE = /[\u0000-\u001F\u007F-\u009F]/g;
|
|
47
40
|
const MAX_PREFIX_GRAPHEMES = 8;
|
|
48
|
-
const MAX_TIP_GRAPHEMES = 160;
|
|
49
41
|
const MAX_LABEL_GRAPHEMES = 80;
|
|
50
42
|
|
|
51
43
|
function stripAnsi(text: string): string {
|
|
@@ -81,14 +73,11 @@ export function sanitizeMessagePrefix(value: unknown, fallback: string): string
|
|
|
81
73
|
export function resolveMessageChromeSettings(input: MessageChromeInput = {}): MessageChromeSettings {
|
|
82
74
|
const messageStyle: MessageStyle = input.messageStyle === "classic" ? "classic" : "claude";
|
|
83
75
|
const messageSpacing: MessageSpacing = input.messageSpacing === "compact" ? "compact" : "comfortable";
|
|
84
|
-
const defaultWorkingTipEnabled = messageStyle === "classic" ? false : DEFAULT_MESSAGE_CHROME.workingTipEnabled;
|
|
85
76
|
return {
|
|
86
77
|
messageStyle,
|
|
87
78
|
assistantPrefix: sanitizeMessagePrefix(input.assistantPrefix, DEFAULT_MESSAGE_CHROME.assistantPrefix),
|
|
88
79
|
thinkingPrefix: sanitizeMessagePrefix(input.thinkingPrefix, DEFAULT_MESSAGE_CHROME.thinkingPrefix),
|
|
89
80
|
messageSpacing,
|
|
90
|
-
workingTipEnabled: typeof input.workingTipEnabled === "boolean" ? input.workingTipEnabled : defaultWorkingTipEnabled,
|
|
91
|
-
workingTipText: sanitizeTextSetting(input.workingTipText, DEFAULT_MESSAGE_CHROME.workingTipText, MAX_TIP_GRAPHEMES),
|
|
92
81
|
hiddenThinkingLabel: sanitizeTextSetting(input.hiddenThinkingLabel, DEFAULT_MESSAGE_CHROME.hiddenThinkingLabel, MAX_LABEL_GRAPHEMES),
|
|
93
82
|
};
|
|
94
83
|
}
|
package/extensions/spinner.ts
CHANGED
|
@@ -3,8 +3,6 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
3
3
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
4
4
|
import { Loader } from "@mariozechner/pi-tui";
|
|
5
5
|
|
|
6
|
-
import { resolveMessageChromeSettings } from "./message-chrome.ts";
|
|
7
|
-
|
|
8
6
|
// ---------------------------------------------------------------------------
|
|
9
7
|
// Patch built-in Loader with Claude/OpenBrawd-style glyphs.
|
|
10
8
|
// Keep animation cadence constant so the spinner doesn't appear to slow down
|
|
@@ -28,8 +26,6 @@ interface SpinnerSettings {
|
|
|
28
26
|
verbColor: string;
|
|
29
27
|
statusColor: string;
|
|
30
28
|
verbs: readonly string[];
|
|
31
|
-
workingTipEnabled: boolean;
|
|
32
|
-
workingTipText: string;
|
|
33
29
|
}
|
|
34
30
|
|
|
35
31
|
let _spinnerSettingsCache: { value: SpinnerSettings; expires: number } | null = null;
|
|
@@ -100,9 +96,6 @@ function readSpinnerSettings(): SpinnerSettings {
|
|
|
100
96
|
let statusColor = "muted";
|
|
101
97
|
let customVerbs: string[] | null = null;
|
|
102
98
|
let verbMode: SpinnerVerbMode = "append";
|
|
103
|
-
let messageStyle: string | undefined;
|
|
104
|
-
let workingTipEnabled: boolean | undefined;
|
|
105
|
-
let workingTipText: string | undefined;
|
|
106
99
|
const paths = [`${process.cwd()}/.pi/settings.json`, `${process.env.HOME ?? ""}/.pi/settings.json`];
|
|
107
100
|
for (const p of paths) {
|
|
108
101
|
try {
|
|
@@ -115,20 +108,14 @@ function readSpinnerSettings(): SpinnerSettings {
|
|
|
115
108
|
if (typeof raw.spinnerStatusColor === "string" && raw.spinnerStatusColor.length > 0) statusColor = raw.spinnerStatusColor;
|
|
116
109
|
if (raw.spinnerVerbMode === "append" || raw.spinnerVerbMode === "replace") verbMode = raw.spinnerVerbMode;
|
|
117
110
|
if (Array.isArray(raw.spinnerVerbs)) customVerbs = sanitizeSpinnerVerbs(raw.spinnerVerbs);
|
|
118
|
-
if (typeof raw.messageStyle === "string") messageStyle = raw.messageStyle;
|
|
119
|
-
if (typeof raw.workingTipEnabled === "boolean") workingTipEnabled = raw.workingTipEnabled;
|
|
120
|
-
if (typeof raw.workingTipText === "string") workingTipText = raw.workingTipText;
|
|
121
111
|
}
|
|
122
112
|
} catch { /* ignore */ }
|
|
123
113
|
}
|
|
124
|
-
const messageChrome = resolveMessageChromeSettings({ messageStyle, workingTipEnabled, workingTipText });
|
|
125
114
|
const value: SpinnerSettings = {
|
|
126
115
|
adaptive,
|
|
127
116
|
verbColor,
|
|
128
117
|
statusColor,
|
|
129
118
|
verbs: resolveSpinnerVerbs(customVerbs, verbMode),
|
|
130
|
-
workingTipEnabled: messageChrome.workingTipEnabled,
|
|
131
|
-
workingTipText: messageChrome.workingTipText,
|
|
132
119
|
};
|
|
133
120
|
_spinnerSettingsCache = { value, expires: now + SPINNER_SETTINGS_TTL_MS };
|
|
134
121
|
return value;
|
|
@@ -567,10 +554,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
567
554
|
if (statusParts.length > 0) {
|
|
568
555
|
message += statusText(` (${statusParts.join(" · ")})`);
|
|
569
556
|
}
|
|
570
|
-
const { workingTipEnabled, workingTipText } = readSpinnerSettings();
|
|
571
|
-
if (workingTipEnabled && workingTipText) {
|
|
572
|
-
message += `\n${STATUS_DIM} └─ Tip: ${workingTipText}${RESET}`;
|
|
573
|
-
}
|
|
574
557
|
return message;
|
|
575
558
|
}
|
|
576
559
|
|
package/package.json
CHANGED