@mariozechner/pi-coding-agent 0.49.0 → 0.49.2

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.
Files changed (81) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +14 -2
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +6 -0
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/export-html/template.css +19 -0
  7. package/dist/core/export-html/template.js +70 -5
  8. package/dist/core/extensions/index.d.ts +1 -1
  9. package/dist/core/extensions/index.d.ts.map +1 -1
  10. package/dist/core/extensions/index.js.map +1 -1
  11. package/dist/core/extensions/runner.d.ts +2 -2
  12. package/dist/core/extensions/runner.d.ts.map +1 -1
  13. package/dist/core/extensions/runner.js +49 -24
  14. package/dist/core/extensions/runner.js.map +1 -1
  15. package/dist/core/extensions/types.d.ts +10 -3
  16. package/dist/core/extensions/types.d.ts.map +1 -1
  17. package/dist/core/extensions/types.js.map +1 -1
  18. package/dist/core/model-registry.d.ts +2 -0
  19. package/dist/core/model-registry.d.ts.map +1 -1
  20. package/dist/core/model-registry.js +36 -5
  21. package/dist/core/model-registry.js.map +1 -1
  22. package/dist/core/sdk.d.ts.map +1 -1
  23. package/dist/core/sdk.js +9 -1
  24. package/dist/core/sdk.js.map +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/main.d.ts.map +1 -1
  29. package/dist/main.js +2 -1
  30. package/dist/main.js.map +1 -1
  31. package/dist/modes/interactive/components/extension-input.d.ts +5 -2
  32. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  33. package/dist/modes/interactive/components/extension-input.js +9 -0
  34. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  35. package/dist/modes/interactive/components/login-dialog.d.ts +5 -2
  36. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  37. package/dist/modes/interactive/components/login-dialog.js +9 -0
  38. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  39. package/dist/modes/interactive/components/model-selector.d.ts +14 -2
  40. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  41. package/dist/modes/interactive/components/model-selector.js +94 -39
  42. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  43. package/dist/modes/interactive/components/scoped-models-selector.d.ts +5 -2
  44. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  45. package/dist/modes/interactive/components/scoped-models-selector.js +9 -0
  46. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  47. package/dist/modes/interactive/components/session-selector.d.ts +23 -5
  48. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  49. package/dist/modes/interactive/components/session-selector.js +327 -55
  50. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  51. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  52. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  53. package/dist/modes/interactive/components/settings-selector.js +10 -0
  54. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  55. package/dist/modes/interactive/components/tree-selector.d.ts +5 -2
  56. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  57. package/dist/modes/interactive/components/tree-selector.js +23 -0
  58. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  59. package/dist/modes/interactive/interactive-mode.d.ts +5 -2
  60. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  61. package/dist/modes/interactive/interactive-mode.js +54 -29
  62. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  63. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  64. package/dist/modes/rpc/rpc-mode.js +2 -1
  65. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  66. package/dist/modes/rpc/rpc-types.d.ts +1 -0
  67. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  68. package/dist/modes/rpc/rpc-types.js.map +1 -1
  69. package/dist/utils/photon.d.ts +3 -2
  70. package/dist/utils/photon.d.ts.map +1 -1
  71. package/dist/utils/photon.js +85 -3
  72. package/dist/utils/photon.js.map +1 -1
  73. package/docs/extensions.md +5 -3
  74. package/docs/session.md +6 -0
  75. package/docs/tui.md +36 -3
  76. package/examples/extensions/README.md +1 -0
  77. package/examples/extensions/question.ts +9 -22
  78. package/examples/extensions/widget-placement.ts +17 -0
  79. package/examples/extensions/with-deps/package-lock.json +2 -2
  80. package/examples/extensions/with-deps/package.json +1 -1
  81. package/package.json +5 -5
@@ -108,9 +108,11 @@ export class InteractiveMode {
108
108
  extensionSelector = undefined;
109
109
  extensionInput = undefined;
110
110
  extensionEditor = undefined;
111
- // Extension widgets (components rendered above the editor)
112
- extensionWidgets = new Map();
113
- widgetContainer;
111
+ // Extension widgets (components rendered above/below the editor)
112
+ extensionWidgetsAbove = new Map();
113
+ extensionWidgetsBelow = new Map();
114
+ widgetContainerAbove;
115
+ widgetContainerBelow;
114
116
  // Custom footer from extension (undefined = use built-in footer)
115
117
  customFooter = undefined;
116
118
  // Built-in header (logo + keybinding hints + changelog)
@@ -135,7 +137,8 @@ export class InteractiveMode {
135
137
  this.chatContainer = new Container();
136
138
  this.pendingMessagesContainer = new Container();
137
139
  this.statusContainer = new Container();
138
- this.widgetContainer = new Container();
140
+ this.widgetContainerAbove = new Container();
141
+ this.widgetContainerBelow = new Container();
139
142
  this.keybindings = KeybindingsManager.create();
140
143
  const editorPaddingX = this.settingsManager.getEditorPaddingX();
141
144
  this.defaultEditor = new CustomEditor(this.ui, getEditorTheme(), this.keybindings, { paddingX: editorPaddingX });
@@ -298,9 +301,10 @@ export class InteractiveMode {
298
301
  this.ui.addChild(this.chatContainer);
299
302
  this.ui.addChild(this.pendingMessagesContainer);
300
303
  this.ui.addChild(this.statusContainer);
301
- this.ui.addChild(this.widgetContainer);
302
304
  this.renderWidgets(); // Initialize with default spacer
305
+ this.ui.addChild(this.widgetContainerAbove);
303
306
  this.ui.addChild(this.editorContainer);
307
+ this.ui.addChild(this.widgetContainerBelow);
304
308
  this.ui.addChild(this.footer);
305
309
  this.ui.setFocus(this.editor);
306
310
  this.setupKeyHandlers();
@@ -639,7 +643,7 @@ export class InteractiveMode {
639
643
  * Set up keyboard shortcuts registered by extensions.
640
644
  */
641
645
  setupExtensionShortcuts(extensionRunner) {
642
- const shortcuts = extensionRunner.getShortcuts();
646
+ const shortcuts = extensionRunner.getShortcuts(this.keybindings.getEffectiveConfig());
643
647
  if (shortcuts.size === 0)
644
648
  return;
645
649
  // Create a context for shortcut handlers
@@ -697,15 +701,22 @@ export class InteractiveMode {
697
701
  /**
698
702
  * Set an extension widget (string array or custom component).
699
703
  */
700
- setExtensionWidget(key, content) {
701
- // Dispose and remove existing widget
702
- const existing = this.extensionWidgets.get(key);
703
- if (existing?.dispose)
704
- existing.dispose();
704
+ setExtensionWidget(key, content, options) {
705
+ const placement = options?.placement ?? "aboveEditor";
706
+ const removeExisting = (map) => {
707
+ const existing = map.get(key);
708
+ if (existing?.dispose)
709
+ existing.dispose();
710
+ map.delete(key);
711
+ };
712
+ removeExisting(this.extensionWidgetsAbove);
713
+ removeExisting(this.extensionWidgetsBelow);
705
714
  if (content === undefined) {
706
- this.extensionWidgets.delete(key);
715
+ this.renderWidgets();
716
+ return;
707
717
  }
708
- else if (Array.isArray(content)) {
718
+ let component;
719
+ if (Array.isArray(content)) {
709
720
  // Wrap string array in a Container with Text components
710
721
  const container = new Container();
711
722
  for (const line of content.slice(0, InteractiveMode.MAX_WIDGET_LINES)) {
@@ -714,13 +725,14 @@ export class InteractiveMode {
714
725
  if (content.length > InteractiveMode.MAX_WIDGET_LINES) {
715
726
  container.addChild(new Text(theme.fg("muted", "... (widget truncated)"), 1, 0));
716
727
  }
717
- this.extensionWidgets.set(key, container);
728
+ component = container;
718
729
  }
719
730
  else {
720
731
  // Factory function - create component
721
- const component = content(this.ui, theme);
722
- this.extensionWidgets.set(key, component);
732
+ component = content(this.ui, theme);
723
733
  }
734
+ const targetMap = placement === "belowEditor" ? this.extensionWidgetsBelow : this.extensionWidgetsAbove;
735
+ targetMap.set(key, component);
724
736
  this.renderWidgets();
725
737
  }
726
738
  // Maximum total widget lines to prevent viewport overflow
@@ -729,19 +741,26 @@ export class InteractiveMode {
729
741
  * Render all extension widgets to the widget container.
730
742
  */
731
743
  renderWidgets() {
732
- if (!this.widgetContainer)
744
+ if (!this.widgetContainerAbove || !this.widgetContainerBelow)
733
745
  return;
734
- this.widgetContainer.clear();
735
- if (this.extensionWidgets.size === 0) {
736
- this.widgetContainer.addChild(new Spacer(1));
737
- this.ui.requestRender();
746
+ this.renderWidgetContainer(this.widgetContainerAbove, this.extensionWidgetsAbove, true, true);
747
+ this.renderWidgetContainer(this.widgetContainerBelow, this.extensionWidgetsBelow, false, false);
748
+ this.ui.requestRender();
749
+ }
750
+ renderWidgetContainer(container, widgets, spacerWhenEmpty, leadingSpacer) {
751
+ container.clear();
752
+ if (widgets.size === 0) {
753
+ if (spacerWhenEmpty) {
754
+ container.addChild(new Spacer(1));
755
+ }
738
756
  return;
739
757
  }
740
- this.widgetContainer.addChild(new Spacer(1));
741
- for (const [_key, component] of this.extensionWidgets) {
742
- this.widgetContainer.addChild(component);
758
+ if (leadingSpacer) {
759
+ container.addChild(new Spacer(1));
760
+ }
761
+ for (const component of widgets.values()) {
762
+ container.addChild(component);
743
763
  }
744
- this.ui.requestRender();
745
764
  }
746
765
  /**
747
766
  * Set a custom footer component, or restore the built-in footer.
@@ -821,7 +840,7 @@ export class InteractiveMode {
821
840
  }
822
841
  }
823
842
  },
824
- setWidget: (key, content) => this.setExtensionWidget(key, content),
843
+ setWidget: (key, content, options) => this.setExtensionWidget(key, content, options),
825
844
  setFooter: (factory) => this.setExtensionFooter(factory),
826
845
  setHeader: (factory) => this.setExtensionHeader(factory),
827
846
  setTitle: (title) => this.ui.terminal.setTitle(title),
@@ -2179,6 +2198,7 @@ export class InteractiveMode {
2179
2198
  doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
2180
2199
  showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
2181
2200
  editorPaddingX: this.settingsManager.getEditorPaddingX(),
2201
+ quietStartup: this.settingsManager.getQuietStartup(),
2182
2202
  }, {
2183
2203
  onAutoCompactChange: (enabled) => {
2184
2204
  this.session.setAutoCompactionEnabled(enabled);
@@ -2242,6 +2262,9 @@ export class InteractiveMode {
2242
2262
  onCollapseChangelogChange: (collapsed) => {
2243
2263
  this.settingsManager.setCollapseChangelog(collapsed);
2244
2264
  },
2265
+ onQuietStartupChange: (enabled) => {
2266
+ this.settingsManager.setQuietStartup(enabled);
2267
+ },
2245
2268
  onDoubleEscapeActionChange: (action) => {
2246
2269
  this.settingsManager.setDoubleEscapeAction(action);
2247
2270
  },
@@ -2590,7 +2613,7 @@ export class InteractiveMode {
2590
2613
  this.ui.requestRender();
2591
2614
  }, () => {
2592
2615
  void this.shutdown();
2593
- }, () => this.ui.requestRender());
2616
+ }, () => this.ui.requestRender(), this.sessionManager.getSessionFile());
2594
2617
  return { component: selector, focus: selector.getSessionList() };
2595
2618
  });
2596
2619
  }
@@ -2817,7 +2840,7 @@ export class InteractiveMode {
2817
2840
  return;
2818
2841
  }
2819
2842
  // Create the preview URL
2820
- const previewUrl = `https://buildwithpi.ai/session?${gistId}`;
2843
+ const previewUrl = `https://buildwithpi.ai/session/#${gistId}`;
2821
2844
  this.showStatus(`Share URL: ${previewUrl}\nGist: ${gistUrl}`);
2822
2845
  }
2823
2846
  catch (error) {
@@ -2949,6 +2972,7 @@ export class InteractiveMode {
2949
2972
  const deleteToLineEnd = this.getEditorKeyDisplay("deleteToLineEnd");
2950
2973
  const yank = this.getEditorKeyDisplay("yank");
2951
2974
  const yankPop = this.getEditorKeyDisplay("yankPop");
2975
+ const undo = this.getEditorKeyDisplay("undo");
2952
2976
  const tab = this.getEditorKeyDisplay("tab");
2953
2977
  // App keybindings
2954
2978
  const interrupt = this.getAppKeyDisplay("interrupt");
@@ -2982,6 +3006,7 @@ export class InteractiveMode {
2982
3006
  | \`${deleteToLineEnd}\` | Delete to end of line |
2983
3007
  | \`${yank}\` | Paste the most-recently-deleted text |
2984
3008
  | \`${yankPop}\` | Cycle through the deleted text after pasting |
3009
+ | \`${undo}\` | Undo |
2985
3010
 
2986
3011
  **Other**
2987
3012
  | Key | Action |
@@ -3006,7 +3031,7 @@ export class InteractiveMode {
3006
3031
  // Add extension-registered shortcuts
3007
3032
  const extensionRunner = this.session.extensionRunner;
3008
3033
  if (extensionRunner) {
3009
- const shortcuts = extensionRunner.getShortcuts();
3034
+ const shortcuts = extensionRunner.getShortcuts(this.keybindings.getEffectiveConfig());
3010
3035
  if (shortcuts.size > 0) {
3011
3036
  hotkeys += `
3012
3037
  **Extensions**