pi-edit-session-in-place 0.1.15 → 0.1.17

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 CHANGED
@@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## [0.1.17] - 2026-06-04
8
+
9
+ ### Fixed
10
+ - fixed the editor hotkey command dispatch when duplicate installs suffix the command as `/edit-turn:1`, `/edit-turn:2`, etc.
11
+ - removed the local project package setting accidentally left by release verification so the repo no longer loads a duplicate project copy during local reloads
12
+
13
+ ## [0.1.16] - 2026-06-04
14
+
15
+ ### Fixed
16
+ - fixed `Ctrl+Shift+E` after the Pi 0.78.1 update by removing the registered shortcut handler that consumed the key and only showed the placeholder notification
17
+ - added regression coverage that verifies the extension no longer registers a conflicting shortcut handler and still installs the custom editor hotkey path
18
+
19
+ ### Changed
20
+ - removed the custom main-editor wrapper path and returned to the focused custom-editor hotkey path used by the working releases
21
+
7
22
  ## [0.1.15] - 2026-06-04
8
23
 
9
24
  ### Changed
package/README.md CHANGED
@@ -81,7 +81,7 @@ If you clear the message and submit an empty value, the selected message is effe
81
81
  - If the selected message contains images, the extension warns that re-editing or deleting it will drop the images and keep only text behavior
82
82
  - The extension only offers text-bearing user messages for editing; image-only or whitespace-only user messages are skipped
83
83
  - Queued messages must be cleared before using the command
84
- - If another extension has already customized the main editor, this extension wraps it instead of replacing it
84
+ - The `Ctrl+Shift+E` hotkey is handled by this extension's main-editor component so Pi's registered shortcut dispatcher does not consume it first
85
85
 
86
86
  ## Development
87
87
 
@@ -15,7 +15,6 @@ import {
15
15
  DynamicBorder,
16
16
  keyHint,
17
17
  rawKeyHint,
18
- type AppKeybinding,
19
18
  type ExtensionAPI,
20
19
  type ExtensionCommandContext,
21
20
  type KeybindingsManager,
@@ -30,8 +29,6 @@ import {
30
29
  Spacer,
31
30
  Text,
32
31
  matchesKey,
33
- type AutocompleteProvider,
34
- type EditorComponent,
35
32
  type EditorTheme,
36
33
  type Focusable,
37
34
  type TUI,
@@ -572,166 +569,32 @@ const handleEditTurn = async (ctx: ExtensionCommandContext) => {
572
569
  );
573
570
  };
574
571
 
575
- const triggerEditTurnCommand = (editor: Pick<EditorComponent, "getText" | "setText" | "handleInput">) => {
576
- draftBeforeHotkey = editor.getText();
577
- editor.setText(COMMAND_TEXT);
578
- editor.handleInput("\r");
572
+ export const getEditTurnCommandText = (commands: Array<{ name: string }>) => {
573
+ const candidates = commands
574
+ .map((command) => command.name)
575
+ .filter((name) => name === COMMAND_NAME || name.startsWith(`${COMMAND_NAME}:`));
576
+ return `/${candidates.at(-1) ?? COMMAND_NAME}`;
579
577
  };
580
578
 
581
579
  class EditSessionInPlaceEditor extends CustomEditor {
582
- handleInput(data: string): void {
583
- if (matchesKey(data, HOTKEY)) {
584
- triggerEditTurnCommand(this);
585
- return;
586
- }
587
-
588
- super.handleInput(data);
589
- }
590
- }
591
-
592
- type AutocompleteAwareEditor = EditorComponent & {
593
- isShowingAutocomplete?: () => boolean;
594
- };
595
-
596
- class EditSessionInPlaceEditorWrapper implements EditorComponent, Focusable {
597
- public actionHandlers: Map<AppKeybinding, () => void> = new Map();
598
- public onEscape?: () => void;
599
- public onCtrlD?: () => void;
600
- public onPasteImage?: () => void;
601
- public onExtensionShortcut?: (data: string) => boolean | undefined;
602
-
603
580
  constructor(
604
- private readonly base: EditorComponent,
605
- private readonly keybindings: KeybindingsManager,
606
- ) {}
607
-
608
- get focused(): boolean {
609
- return "focused" in this.base && typeof this.base.focused === "boolean" ? this.base.focused : false;
610
- }
611
-
612
- set focused(value: boolean) {
613
- if ("focused" in this.base) {
614
- (this.base as EditorComponent & Focusable).focused = value;
615
- }
616
- }
617
-
618
- get wantsKeyRelease(): boolean | undefined {
619
- return this.base.wantsKeyRelease;
620
- }
621
-
622
- set wantsKeyRelease(value: boolean | undefined) {
623
- this.base.wantsKeyRelease = value;
624
- }
625
-
626
- get onSubmit(): ((text: string) => void) | undefined {
627
- return this.base.onSubmit;
628
- }
629
-
630
- set onSubmit(value: ((text: string) => void) | undefined) {
631
- this.base.onSubmit = value;
632
- }
633
-
634
- get onChange(): ((text: string) => void) | undefined {
635
- return this.base.onChange;
636
- }
637
-
638
- set onChange(value: ((text: string) => void) | undefined) {
639
- this.base.onChange = value;
640
- }
641
-
642
- get borderColor(): ((str: string) => string) | undefined {
643
- return this.base.borderColor;
644
- }
645
-
646
- set borderColor(value: ((str: string) => string) | undefined) {
647
- this.base.borderColor = value;
648
- }
649
-
650
- render(width: number): string[] {
651
- return this.base.render(width);
652
- }
653
-
654
- invalidate(): void {
655
- this.base.invalidate();
656
- }
657
-
658
- getText(): string {
659
- return this.base.getText();
660
- }
661
-
662
- setText(text: string): void {
663
- this.base.setText(text);
581
+ tui: TUI,
582
+ theme: EditorTheme,
583
+ keybindings: KeybindingsManager,
584
+ private readonly getCommandText: () => string,
585
+ ) {
586
+ super(tui, theme, keybindings);
664
587
  }
665
588
 
666
589
  handleInput(data: string): void {
667
590
  if (matchesKey(data, HOTKEY)) {
668
- triggerEditTurnCommand(this.base);
669
- return;
670
- }
671
-
672
- if (this.onExtensionShortcut?.(data)) {
591
+ draftBeforeHotkey = this.getText();
592
+ this.setText(this.getCommandText());
593
+ super.handleInput("\r");
673
594
  return;
674
595
  }
675
596
 
676
- if (this.keybindings.matches(data, "app.clipboard.pasteImage")) {
677
- this.onPasteImage?.();
678
- return;
679
- }
680
-
681
- if (this.keybindings.matches(data, "app.interrupt")) {
682
- const isShowingAutocomplete = (this.base as AutocompleteAwareEditor).isShowingAutocomplete?.() ?? false;
683
- if (!isShowingAutocomplete) {
684
- const handler = this.onEscape ?? this.actionHandlers.get("app.interrupt");
685
- if (handler) {
686
- handler();
687
- return;
688
- }
689
- }
690
-
691
- this.base.handleInput(data);
692
- return;
693
- }
694
-
695
- if (this.keybindings.matches(data, "app.exit") && this.base.getText().length === 0) {
696
- const handler = this.onCtrlD ?? this.actionHandlers.get("app.exit");
697
- if (handler) {
698
- handler();
699
- }
700
- return;
701
- }
702
-
703
- for (const [action, handler] of this.actionHandlers) {
704
- if (action !== "app.interrupt" && action !== "app.exit" && this.keybindings.matches(data, action)) {
705
- handler();
706
- return;
707
- }
708
- }
709
-
710
- this.base.handleInput(data);
711
- }
712
-
713
- addToHistory(text: string): void {
714
- this.base.addToHistory?.(text);
715
- }
716
-
717
- insertTextAtCursor(text: string): void {
718
- this.base.insertTextAtCursor?.(text);
719
- }
720
-
721
- getExpandedText(): string {
722
- return this.base.getExpandedText?.() ?? this.base.getText();
723
- }
724
-
725
- setAutocompleteProvider(provider: AutocompleteProvider): void {
726
- this.base.setAutocompleteProvider?.(provider);
727
- }
728
-
729
- setPaddingX(padding: number): void {
730
- this.base.setPaddingX?.(padding);
731
- }
732
-
733
- setAutocompleteMaxVisible(maxVisible: number): void {
734
- this.base.setAutocompleteMaxVisible?.(maxVisible);
597
+ super.handleInput(data);
735
598
  }
736
599
  }
737
600
 
@@ -743,27 +606,12 @@ export default function editSessionInPlace(pi: ExtensionAPI) {
743
606
  },
744
607
  });
745
608
 
746
- // Shortcut handlers receive ExtensionContext, so the custom editor hotkey path performs
747
- // the command execution while this registration keeps the hotkey discoverable.
748
- pi.registerShortcut(HOTKEY, {
749
- description: `Edit a previous user message (${HOTKEY_LABEL})`,
750
- handler: (ctx) => {
751
- if (!ctx.hasUI) {
752
- return;
753
- }
754
-
755
- ctx.ui.notify(`Press ${HOTKEY_LABEL} in the main editor to edit a previous message.`, "info");
756
- },
757
- });
758
-
759
609
  pi.on("session_start", (_event, ctx) => {
760
610
  clearSavedDraft();
761
611
  if (ctx.mode === "tui") {
762
- const previousEditor = ctx.ui.getEditorComponent();
763
- ctx.ui.setEditorComponent((tui, theme, keybindings) => {
764
- const baseEditor = previousEditor?.(tui, theme, keybindings);
765
- return baseEditor ? new EditSessionInPlaceEditorWrapper(baseEditor, keybindings) : new EditSessionInPlaceEditor(tui, theme, keybindings);
766
- });
612
+ ctx.ui.setEditorComponent((tui, theme, keybindings) =>
613
+ new EditSessionInPlaceEditor(tui, theme, keybindings, () => getEditTurnCommandText(pi.getCommands())),
614
+ );
767
615
  }
768
616
  });
769
617
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-edit-session-in-place",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "pi extension that lets you re-edit or delete an earlier user message in the current session branch",
5
5
  "author": "Mitch Fultz (https://github.com/fitchmultz)",
6
6
  "license": "MIT",