@mariozechner/pi-coding-agent 0.37.2 → 0.37.3

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 (54) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +10 -1
  3. package/dist/core/agent-session.d.ts +11 -1
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +39 -0
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/extensions/index.d.ts +1 -1
  8. package/dist/core/extensions/index.d.ts.map +1 -1
  9. package/dist/core/extensions/index.js.map +1 -1
  10. package/dist/core/extensions/loader.d.ts.map +1 -1
  11. package/dist/core/extensions/loader.js +14 -3
  12. package/dist/core/extensions/loader.js.map +1 -1
  13. package/dist/core/extensions/runner.d.ts +2 -1
  14. package/dist/core/extensions/runner.d.ts.map +1 -1
  15. package/dist/core/extensions/runner.js +2 -0
  16. package/dist/core/extensions/runner.js.map +1 -1
  17. package/dist/core/extensions/types.d.ts +15 -0
  18. package/dist/core/extensions/types.d.ts.map +1 -1
  19. package/dist/core/extensions/types.js.map +1 -1
  20. package/dist/core/sdk.d.ts.map +1 -1
  21. package/dist/core/sdk.js +35 -1
  22. package/dist/core/sdk.js.map +1 -1
  23. package/dist/core/settings-manager.d.ts +3 -0
  24. package/dist/core/settings-manager.d.ts.map +1 -1
  25. package/dist/core/settings-manager.js +24 -14
  26. package/dist/core/settings-manager.js.map +1 -1
  27. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  28. package/dist/modes/interactive/components/footer.js +31 -7
  29. package/dist/modes/interactive/components/footer.js.map +1 -1
  30. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  31. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  32. package/dist/modes/interactive/components/settings-selector.js +12 -0
  33. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  34. package/dist/modes/interactive/interactive-mode.d.ts +5 -0
  35. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  36. package/dist/modes/interactive/interactive-mode.js +45 -8
  37. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  38. package/dist/modes/print-mode.d.ts.map +1 -1
  39. package/dist/modes/print-mode.js +5 -0
  40. package/dist/modes/print-mode.js.map +1 -1
  41. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  42. package/dist/modes/rpc/rpc-mode.js +8 -0
  43. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  44. package/dist/utils/clipboard-image.d.ts +11 -0
  45. package/dist/utils/clipboard-image.d.ts.map +1 -0
  46. package/dist/utils/clipboard-image.js +117 -0
  47. package/dist/utils/clipboard-image.js.map +1 -0
  48. package/docs/extensions.md +37 -2
  49. package/examples/extensions/README.md +1 -0
  50. package/examples/extensions/custom-footer.ts +86 -0
  51. package/examples/extensions/send-user-message.ts +97 -0
  52. package/examples/extensions/with-deps/package-lock.json +2 -2
  53. package/examples/extensions/with-deps/package.json +1 -1
  54. package/package.json +5 -4
@@ -6,7 +6,6 @@ import * as crypto from "node:crypto";
6
6
  import * as fs from "node:fs";
7
7
  import * as os from "node:os";
8
8
  import * as path from "node:path";
9
- import Clipboard from "@crosscopy/clipboard";
10
9
  import { getOAuthProviders } from "@mariozechner/pi-ai";
11
10
  import { CombinedAutocompleteProvider, Container, getEditorKeybindings, Loader, Markdown, matchesKey, ProcessTerminal, Spacer, Text, TruncatedText, TUI, visibleWidth, } from "@mariozechner/pi-tui";
12
11
  import { spawn, spawnSync } from "child_process";
@@ -18,6 +17,7 @@ import { loadSkills } from "../../core/skills.js";
18
17
  import { loadProjectContextFiles } from "../../core/system-prompt.js";
19
18
  import { getChangelogPath, parseChangelog } from "../../utils/changelog.js";
20
19
  import { copyToClipboard } from "../../utils/clipboard.js";
20
+ import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
21
21
  import { ArminComponent } from "./components/armin.js";
22
22
  import { AssistantMessageComponent } from "./components/assistant-message.js";
23
23
  import { BashExecutionComponent } from "./components/bash-execution.js";
@@ -97,6 +97,8 @@ export class InteractiveMode {
97
97
  // Extension widgets (components rendered above the editor)
98
98
  extensionWidgets = new Map();
99
99
  widgetContainer;
100
+ // Custom footer from extension (undefined = use built-in footer)
101
+ customFooter = undefined;
100
102
  // Convenience accessors
101
103
  get agent() {
102
104
  return this.session.agent;
@@ -340,6 +342,11 @@ export class InteractiveMode {
340
342
  this.showError(`Extension sendMessage failed: ${err instanceof Error ? err.message : String(err)}`);
341
343
  });
342
344
  },
345
+ sendUserMessageHandler: (content, options) => {
346
+ this.session.sendUserMessage(content, options).catch((err) => {
347
+ this.showError(`Extension sendUserMessage failed: ${err instanceof Error ? err.message : String(err)}`);
348
+ });
349
+ },
343
350
  appendEntryHandler: (customType, data) => {
344
351
  this.sessionManager.appendCustomEntry(customType, data);
345
352
  },
@@ -523,6 +530,33 @@ export class InteractiveMode {
523
530
  }
524
531
  this.ui.requestRender();
525
532
  }
533
+ /**
534
+ * Set a custom footer component, or restore the built-in footer.
535
+ */
536
+ setExtensionFooter(factory) {
537
+ // Dispose existing custom footer
538
+ if (this.customFooter?.dispose) {
539
+ this.customFooter.dispose();
540
+ }
541
+ // Remove current footer from UI
542
+ if (this.customFooter) {
543
+ this.ui.removeChild(this.customFooter);
544
+ }
545
+ else {
546
+ this.ui.removeChild(this.footer);
547
+ }
548
+ if (factory) {
549
+ // Create and add custom footer
550
+ this.customFooter = factory(this.ui, theme);
551
+ this.ui.addChild(this.customFooter);
552
+ }
553
+ else {
554
+ // Restore built-in footer
555
+ this.customFooter = undefined;
556
+ this.ui.addChild(this.footer);
557
+ }
558
+ this.ui.requestRender();
559
+ }
526
560
  /**
527
561
  * Create the ExtensionUIContext for extensions.
528
562
  */
@@ -534,6 +568,7 @@ export class InteractiveMode {
534
568
  notify: (message, type) => this.showExtensionNotify(message, type),
535
569
  setStatus: (key, text) => this.setExtensionStatus(key, text),
536
570
  setWidget: (key, content) => this.setExtensionWidget(key, content),
571
+ setFooter: (factory) => this.setExtensionFooter(factory),
537
572
  setTitle: (title) => this.ui.terminal.setTitle(title),
538
573
  custom: (factory) => this.showExtensionCustom(factory),
539
574
  setEditorText: (text) => this.editor.setText(text),
@@ -763,18 +798,16 @@ export class InteractiveMode {
763
798
  }
764
799
  async handleClipboardImagePaste() {
765
800
  try {
766
- if (!Clipboard.hasImage()) {
767
- return;
768
- }
769
- const imageData = await Clipboard.getImageBinary();
770
- if (!imageData || imageData.length === 0) {
801
+ const image = await readClipboardImage();
802
+ if (!image) {
771
803
  return;
772
804
  }
773
805
  // Write to temp file
774
806
  const tmpDir = os.tmpdir();
775
- const fileName = `pi-clipboard-${crypto.randomUUID()}.png`;
807
+ const ext = extensionForImageMimeType(image.mimeType) ?? "png";
808
+ const fileName = `pi-clipboard-${crypto.randomUUID()}.${ext}`;
776
809
  const filePath = path.join(tmpDir, fileName);
777
- fs.writeFileSync(filePath, Buffer.from(imageData));
810
+ fs.writeFileSync(filePath, Buffer.from(image.bytes));
778
811
  // Insert file path directly
779
812
  this.editor.insertTextAtCursor(filePath);
780
813
  this.ui.requestRender();
@@ -1657,6 +1690,7 @@ export class InteractiveMode {
1657
1690
  autoCompact: this.session.autoCompactionEnabled,
1658
1691
  showImages: this.settingsManager.getShowImages(),
1659
1692
  autoResizeImages: this.settingsManager.getImageAutoResize(),
1693
+ blockImages: this.settingsManager.getBlockImages(),
1660
1694
  steeringMode: this.session.steeringMode,
1661
1695
  followUpMode: this.session.followUpMode,
1662
1696
  thinkingLevel: this.session.thinkingLevel,
@@ -1682,6 +1716,9 @@ export class InteractiveMode {
1682
1716
  onAutoResizeImagesChange: (enabled) => {
1683
1717
  this.settingsManager.setImageAutoResize(enabled);
1684
1718
  },
1719
+ onBlockImagesChange: (blocked) => {
1720
+ this.settingsManager.setBlockImages(blocked);
1721
+ },
1685
1722
  onSteeringModeChange: (mode) => {
1686
1723
  this.session.setSteeringMode(mode);
1687
1724
  },