pi-copy-message 2.0.0 → 2.1.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/CHANGELOG.md +5 -0
- package/README.md +4 -3
- package/extensions/copy-message.ts +18 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.1.0 - 2026-08-17
|
|
4
|
+
|
|
5
|
+
- Add an `Alt+C` picker filter and `MessageVisibility.showCustom` option for showing or hiding custom messages.
|
|
6
|
+
- Hide picker shortcut hints that collide with configured selection bindings.
|
|
7
|
+
|
|
3
8
|
## 2.0.0 - 2026-08-06
|
|
4
9
|
|
|
5
10
|
- Set pi 0.84.0 as the minimum supported version and refresh the local coding-agent and TUI development baseline.
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ A [pi](https://github.com/earendil-works/pi-mono) extension that adds `/copy-mes
|
|
|
11
11
|
- Copies raw stored session message text, not rendered terminal lines
|
|
12
12
|
- Shows messages in chat order: oldest at top, newest at bottom
|
|
13
13
|
- Selects the newest visible message by default
|
|
14
|
-
- Supports role filters for user, assistant,
|
|
14
|
+
- Supports role filters for user, assistant, tool/bash, and custom messages
|
|
15
15
|
- Hides tool/bash messages by default
|
|
16
16
|
- Supports type-to-filter search across role and message text, with `time:<term>` for timestamp search
|
|
17
17
|
- Supports Home/End jumps for oldest/newest visible messages
|
|
@@ -103,6 +103,7 @@ Copy with role and timestamp metadata instead of raw text only:
|
|
|
103
103
|
| `Ctrl+U` | Toggle user messages |
|
|
104
104
|
| `Ctrl+A` | Toggle assistant messages |
|
|
105
105
|
| `Ctrl+T` | Toggle tool/bash messages |
|
|
106
|
+
| `Alt+C` | Toggle custom messages |
|
|
106
107
|
| `Tab` | Toggle a wrapped preview of the selected message |
|
|
107
108
|
| `Alt+M` | Toggle raw vs metadata copy format |
|
|
108
109
|
| Configured `tui.select.confirm` (default: `Enter`) | Copy selected message text |
|
|
@@ -116,9 +117,9 @@ Copy with role and timestamp metadata instead of raw text only:
|
|
|
116
117
|
- General search does not match timestamps; use `time:<term>` when you want to search by displayed time.
|
|
117
118
|
- Filter labels honor the active pi theme.
|
|
118
119
|
- Selection key hints show the active Pi bindings. Configured selection actions take precedence if they collide with the picker's filter, preview, or format shortcuts.
|
|
119
|
-
-
|
|
120
|
+
- Only custom messages with `display: true` can appear or be copied from current `custom_message` entries or legacy message-wrapped entries; visible ones can be toggled with `Alt+C`.
|
|
120
121
|
- Copy notifications include the role and a short preview so you can verify what was copied.
|
|
121
|
-
- `/copy-message latest`
|
|
122
|
+
- `/copy-message latest` and numbered selectors include user, assistant, and visible custom messages by default while hiding tool/bash messages. `Alt+C` only affects the picker. If only hidden messages exist, `latest` falls back to the newest message so the command still does something useful.
|
|
122
123
|
- `/copy-message` with no direct selector requires interactive TUI mode because the picker is a custom TUI component.
|
|
123
124
|
- Direct commands such as `/copy-user`, `/copy-message latest`, and `/copy-message 3` do not require TUI mode, though non-UI modes may not display notifications.
|
|
124
125
|
|
|
@@ -241,12 +241,14 @@ export interface MessageVisibility {
|
|
|
241
241
|
showAssistant: boolean;
|
|
242
242
|
showUser: boolean;
|
|
243
243
|
showTools: boolean;
|
|
244
|
+
showCustom: boolean;
|
|
244
245
|
}
|
|
245
246
|
|
|
246
247
|
function isVisibleMessage(message: CopyableMessage, visibility: MessageVisibility): boolean {
|
|
247
248
|
if (isToolMessage(message)) return visibility.showTools;
|
|
248
249
|
if (message.role === "assistant") return visibility.showAssistant;
|
|
249
250
|
if (message.role === "user") return visibility.showUser;
|
|
251
|
+
if (message.role === "custom") return visibility.showCustom;
|
|
250
252
|
return true;
|
|
251
253
|
}
|
|
252
254
|
|
|
@@ -274,7 +276,7 @@ export function filteredMessages(messages: CopyableMessage[], visibility: Messag
|
|
|
274
276
|
}
|
|
275
277
|
|
|
276
278
|
export function defaultVisibleMessages(messages: CopyableMessage[]): CopyableMessage[] {
|
|
277
|
-
return filteredMessages(messages, { showAssistant: true, showUser: true, showTools: false });
|
|
279
|
+
return filteredMessages(messages, { showAssistant: true, showUser: true, showTools: false, showCustom: true });
|
|
278
280
|
}
|
|
279
281
|
|
|
280
282
|
export function latestDefaultMessage(messages: CopyableMessage[]): CopyableMessage | undefined {
|
|
@@ -370,7 +372,7 @@ function bindingHint(keybindings: PickerKeybindings | undefined, action: "up" |
|
|
|
370
372
|
return keys.reduce((shortest, key) => visibleWidth(key) < visibleWidth(shortest) ? key : shortest, keys[0] ?? "unbound");
|
|
371
373
|
}
|
|
372
374
|
|
|
373
|
-
function helpLines(width: number, keybindings
|
|
375
|
+
function helpLines(width: number, keybindings: PickerKeybindings | undefined, tuiMode: TuiMode, hasCustomMessages: boolean): string[] {
|
|
374
376
|
const up = bindingHint(keybindings, "up");
|
|
375
377
|
const down = bindingHint(keybindings, "down");
|
|
376
378
|
const confirm = bindingHint(keybindings, "confirm");
|
|
@@ -390,7 +392,8 @@ function helpLines(width: number, keybindings?: PickerKeybindings, tuiMode: TuiM
|
|
|
390
392
|
{ hint: "T", data: "\x14" },
|
|
391
393
|
].filter(({ data }) => available(data));
|
|
392
394
|
const filterHint = filters.length > 0 ? `Ctrl+${filters.map(({ hint }) => hint).join("/")} filters` : undefined;
|
|
393
|
-
const
|
|
395
|
+
const custom = hasCustomMessages && available("\x1b[99;3u") ? "Alt+C custom" : undefined;
|
|
396
|
+
const meta = available("\x1b[109;3u") ? "Alt+M meta" : undefined;
|
|
394
397
|
const jumps = (tuiMode === "fullscreen"
|
|
395
398
|
? [
|
|
396
399
|
{ hint: "Ctrl+Home", data: "\x1b[1;5H" },
|
|
@@ -415,7 +418,7 @@ function helpLines(width: number, keybindings?: PickerKeybindings, tuiMode: TuiM
|
|
|
415
418
|
return lines;
|
|
416
419
|
}
|
|
417
420
|
|
|
418
|
-
for (const hint of width < 74 ? [jumpHint, peek, filterHint, meta] : ["type search", jumpHint, peek, filterHint, meta]) {
|
|
421
|
+
for (const hint of width < 74 ? [jumpHint, peek, filterHint, custom, meta] : ["type search", jumpHint, peek, filterHint, custom, meta]) {
|
|
419
422
|
if (hint && visibleWidth(join(...optional, hint, ...core)) <= width) optional.push(hint);
|
|
420
423
|
}
|
|
421
424
|
|
|
@@ -429,6 +432,7 @@ export class CopyMessagePickerState {
|
|
|
429
432
|
showAssistant: true,
|
|
430
433
|
showUser: true,
|
|
431
434
|
showTools: false,
|
|
435
|
+
showCustom: true,
|
|
432
436
|
};
|
|
433
437
|
search = "";
|
|
434
438
|
visibleMessages: CopyableMessage[];
|
|
@@ -456,6 +460,7 @@ export class CopyMessagePickerState {
|
|
|
456
460
|
const maxVisible = Math.min(this.visibleMessages.length, MAX_VISIBLE_MESSAGES);
|
|
457
461
|
const start = maxVisible === 0 ? 0 : Math.max(0, Math.min(this.selectedIndex - maxVisible + 1, this.visibleMessages.length - maxVisible));
|
|
458
462
|
const end = Math.min(this.visibleMessages.length, start + maxVisible);
|
|
463
|
+
const hasCustomMessages = this.messages.some((message) => message.role === "custom");
|
|
459
464
|
const userState = filterLabel(theme, "user", this.visibility.showUser, "warning");
|
|
460
465
|
const assistantState = filterLabel(theme, "assistant", this.visibility.showAssistant, "accent");
|
|
461
466
|
const toolState = filterLabel(theme, "tools", this.visibility.showTools, "dim");
|
|
@@ -481,9 +486,11 @@ export class CopyMessagePickerState {
|
|
|
481
486
|
}
|
|
482
487
|
|
|
483
488
|
const position = this.visibleMessages.length === 0 ? "0/0" : `${this.selectedIndex + 1}/${this.visibleMessages.length}`;
|
|
484
|
-
|
|
489
|
+
const filters = [userState, assistantState, toolState];
|
|
490
|
+
if (hasCustomMessages) filters.push(filterLabel(theme, "custom", this.visibility.showCustom, "dim"));
|
|
491
|
+
lines.push([theme.fg("dim", `(${position})`), ...filters, searchState, formatState].join(" · "));
|
|
485
492
|
lines.push("");
|
|
486
|
-
lines.push(...helpLines(width, keybindings, tuiMode).map((line) => hotkeyHint(theme, line)));
|
|
493
|
+
lines.push(...helpLines(width, keybindings, tuiMode, hasCustomMessages).map((line) => hotkeyHint(theme, line)));
|
|
487
494
|
lines.push("");
|
|
488
495
|
return lines.map((line) => truncateToWidth(line, width, ""));
|
|
489
496
|
}
|
|
@@ -524,6 +531,11 @@ export class CopyMessagePickerState {
|
|
|
524
531
|
this.refreshMessages();
|
|
525
532
|
return "render";
|
|
526
533
|
}
|
|
534
|
+
if (matchesKey(data, "alt+c")) {
|
|
535
|
+
this.visibility.showCustom = !this.visibility.showCustom;
|
|
536
|
+
this.refreshMessages();
|
|
537
|
+
return "render";
|
|
538
|
+
}
|
|
527
539
|
if (matchesKey(data, "alt+m")) {
|
|
528
540
|
this.format = this.format === "raw" ? "metadata" : "raw";
|
|
529
541
|
return "render";
|
package/package.json
CHANGED