@mariozechner/pi-coding-agent 0.37.2 → 0.37.4
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 +32 -0
- package/README.md +13 -1
- package/dist/core/agent-session.d.ts +11 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +39 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -6
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +15 -3
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +2 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +3 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +19 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +36 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +24 -14
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +20 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +31 -7
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +1 -1
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +12 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +11 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +88 -12
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +5 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +11 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts +11 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -0
- package/dist/utils/clipboard-image.js +117 -0
- package/dist/utils/clipboard-image.js.map +1 -0
- package/docs/extensions.md +37 -2
- package/examples/extensions/README.md +1 -0
- package/examples/extensions/custom-footer.ts +86 -0
- package/examples/extensions/custom-header.ts +72 -0
- package/examples/extensions/send-user-message.ts +97 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- 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,12 @@ 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;
|
|
102
|
+
// Built-in header (logo + keybinding hints + changelog)
|
|
103
|
+
builtInHeader = undefined;
|
|
104
|
+
// Custom header from extension (undefined = use built-in header)
|
|
105
|
+
customHeader = undefined;
|
|
100
106
|
// Convenience accessors
|
|
101
107
|
get agent() {
|
|
102
108
|
return this.session.agent;
|
|
@@ -197,7 +203,7 @@ export class InteractiveMode {
|
|
|
197
203
|
theme.fg("muted", " to suspend") +
|
|
198
204
|
"\n" +
|
|
199
205
|
theme.fg("dim", deleteToLineEnd) +
|
|
200
|
-
theme.fg("muted", " to delete
|
|
206
|
+
theme.fg("muted", " to delete to end") +
|
|
201
207
|
"\n" +
|
|
202
208
|
theme.fg("dim", cycleThinkingLevel) +
|
|
203
209
|
theme.fg("muted", " to cycle thinking") +
|
|
@@ -223,6 +229,9 @@ export class InteractiveMode {
|
|
|
223
229
|
theme.fg("dim", "!") +
|
|
224
230
|
theme.fg("muted", " to run bash") +
|
|
225
231
|
"\n" +
|
|
232
|
+
theme.fg("dim", "!!") +
|
|
233
|
+
theme.fg("muted", " to run bash (no context)") +
|
|
234
|
+
"\n" +
|
|
226
235
|
theme.fg("dim", followUp) +
|
|
227
236
|
theme.fg("muted", " to queue follow-up") +
|
|
228
237
|
"\n" +
|
|
@@ -231,10 +240,10 @@ export class InteractiveMode {
|
|
|
231
240
|
"\n" +
|
|
232
241
|
theme.fg("dim", "drop files") +
|
|
233
242
|
theme.fg("muted", " to attach");
|
|
234
|
-
|
|
243
|
+
this.builtInHeader = new Text(`${logo}\n${instructions}`, 1, 0);
|
|
235
244
|
// Setup UI layout
|
|
236
245
|
this.ui.addChild(new Spacer(1));
|
|
237
|
-
this.ui.addChild(
|
|
246
|
+
this.ui.addChild(this.builtInHeader);
|
|
238
247
|
this.ui.addChild(new Spacer(1));
|
|
239
248
|
// Add changelog if provided
|
|
240
249
|
if (this.changelogMarkdown) {
|
|
@@ -340,6 +349,11 @@ export class InteractiveMode {
|
|
|
340
349
|
this.showError(`Extension sendMessage failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
341
350
|
});
|
|
342
351
|
},
|
|
352
|
+
sendUserMessageHandler: (content, options) => {
|
|
353
|
+
this.session.sendUserMessage(content, options).catch((err) => {
|
|
354
|
+
this.showError(`Extension sendUserMessage failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
355
|
+
});
|
|
356
|
+
},
|
|
343
357
|
appendEntryHandler: (customType, data) => {
|
|
344
358
|
this.sessionManager.appendCustomEntry(customType, data);
|
|
345
359
|
},
|
|
@@ -523,6 +537,64 @@ export class InteractiveMode {
|
|
|
523
537
|
}
|
|
524
538
|
this.ui.requestRender();
|
|
525
539
|
}
|
|
540
|
+
/**
|
|
541
|
+
* Set a custom footer component, or restore the built-in footer.
|
|
542
|
+
*/
|
|
543
|
+
setExtensionFooter(factory) {
|
|
544
|
+
// Dispose existing custom footer
|
|
545
|
+
if (this.customFooter?.dispose) {
|
|
546
|
+
this.customFooter.dispose();
|
|
547
|
+
}
|
|
548
|
+
// Remove current footer from UI
|
|
549
|
+
if (this.customFooter) {
|
|
550
|
+
this.ui.removeChild(this.customFooter);
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
this.ui.removeChild(this.footer);
|
|
554
|
+
}
|
|
555
|
+
if (factory) {
|
|
556
|
+
// Create and add custom footer
|
|
557
|
+
this.customFooter = factory(this.ui, theme);
|
|
558
|
+
this.ui.addChild(this.customFooter);
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
// Restore built-in footer
|
|
562
|
+
this.customFooter = undefined;
|
|
563
|
+
this.ui.addChild(this.footer);
|
|
564
|
+
}
|
|
565
|
+
this.ui.requestRender();
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Set a custom header component, or restore the built-in header.
|
|
569
|
+
*/
|
|
570
|
+
setExtensionHeader(factory) {
|
|
571
|
+
// Header may not be initialized yet if called during early initialization
|
|
572
|
+
if (!this.builtInHeader) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
// Dispose existing custom header
|
|
576
|
+
if (this.customHeader?.dispose) {
|
|
577
|
+
this.customHeader.dispose();
|
|
578
|
+
}
|
|
579
|
+
// Remove current header from UI
|
|
580
|
+
if (this.customHeader) {
|
|
581
|
+
this.ui.removeChild(this.customHeader);
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
this.ui.removeChild(this.builtInHeader);
|
|
585
|
+
}
|
|
586
|
+
if (factory) {
|
|
587
|
+
// Create and add custom header at position 1 (after initial spacer)
|
|
588
|
+
this.customHeader = factory(this.ui, theme);
|
|
589
|
+
this.ui.children.splice(1, 0, this.customHeader);
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
// Restore built-in header at position 1
|
|
593
|
+
this.customHeader = undefined;
|
|
594
|
+
this.ui.children.splice(1, 0, this.builtInHeader);
|
|
595
|
+
}
|
|
596
|
+
this.ui.requestRender();
|
|
597
|
+
}
|
|
526
598
|
/**
|
|
527
599
|
* Create the ExtensionUIContext for extensions.
|
|
528
600
|
*/
|
|
@@ -534,6 +606,8 @@ export class InteractiveMode {
|
|
|
534
606
|
notify: (message, type) => this.showExtensionNotify(message, type),
|
|
535
607
|
setStatus: (key, text) => this.setExtensionStatus(key, text),
|
|
536
608
|
setWidget: (key, content) => this.setExtensionWidget(key, content),
|
|
609
|
+
setFooter: (factory) => this.setExtensionFooter(factory),
|
|
610
|
+
setHeader: (factory) => this.setExtensionHeader(factory),
|
|
537
611
|
setTitle: (title) => this.ui.terminal.setTitle(title),
|
|
538
612
|
custom: (factory) => this.showExtensionCustom(factory),
|
|
539
613
|
setEditorText: (text) => this.editor.setText(text),
|
|
@@ -763,18 +837,16 @@ export class InteractiveMode {
|
|
|
763
837
|
}
|
|
764
838
|
async handleClipboardImagePaste() {
|
|
765
839
|
try {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
}
|
|
769
|
-
const imageData = await Clipboard.getImageBinary();
|
|
770
|
-
if (!imageData || imageData.length === 0) {
|
|
840
|
+
const image = await readClipboardImage();
|
|
841
|
+
if (!image) {
|
|
771
842
|
return;
|
|
772
843
|
}
|
|
773
844
|
// Write to temp file
|
|
774
845
|
const tmpDir = os.tmpdir();
|
|
775
|
-
const
|
|
846
|
+
const ext = extensionForImageMimeType(image.mimeType) ?? "png";
|
|
847
|
+
const fileName = `pi-clipboard-${crypto.randomUUID()}.${ext}`;
|
|
776
848
|
const filePath = path.join(tmpDir, fileName);
|
|
777
|
-
fs.writeFileSync(filePath, Buffer.from(
|
|
849
|
+
fs.writeFileSync(filePath, Buffer.from(image.bytes));
|
|
778
850
|
// Insert file path directly
|
|
779
851
|
this.editor.insertTextAtCursor(filePath);
|
|
780
852
|
this.ui.requestRender();
|
|
@@ -955,7 +1027,6 @@ export class InteractiveMode {
|
|
|
955
1027
|
}
|
|
956
1028
|
else if (event.message.role === "user") {
|
|
957
1029
|
this.addMessageToChat(event.message);
|
|
958
|
-
this.editor.setText("");
|
|
959
1030
|
this.updatePendingMessagesDisplay();
|
|
960
1031
|
this.ui.requestRender();
|
|
961
1032
|
}
|
|
@@ -1657,6 +1728,7 @@ export class InteractiveMode {
|
|
|
1657
1728
|
autoCompact: this.session.autoCompactionEnabled,
|
|
1658
1729
|
showImages: this.settingsManager.getShowImages(),
|
|
1659
1730
|
autoResizeImages: this.settingsManager.getImageAutoResize(),
|
|
1731
|
+
blockImages: this.settingsManager.getBlockImages(),
|
|
1660
1732
|
steeringMode: this.session.steeringMode,
|
|
1661
1733
|
followUpMode: this.session.followUpMode,
|
|
1662
1734
|
thinkingLevel: this.session.thinkingLevel,
|
|
@@ -1682,6 +1754,9 @@ export class InteractiveMode {
|
|
|
1682
1754
|
onAutoResizeImagesChange: (enabled) => {
|
|
1683
1755
|
this.settingsManager.setImageAutoResize(enabled);
|
|
1684
1756
|
},
|
|
1757
|
+
onBlockImagesChange: (blocked) => {
|
|
1758
|
+
this.settingsManager.setBlockImages(blocked);
|
|
1759
|
+
},
|
|
1685
1760
|
onSteeringModeChange: (mode) => {
|
|
1686
1761
|
this.session.setSteeringMode(mode);
|
|
1687
1762
|
},
|
|
@@ -2254,6 +2329,7 @@ export class InteractiveMode {
|
|
|
2254
2329
|
| \`Ctrl+V\` | Paste image from clipboard |
|
|
2255
2330
|
| \`/\` | Slash commands |
|
|
2256
2331
|
| \`!\` | Run bash command |
|
|
2332
|
+
| \`!!\` | Run bash command (excluded from context) |
|
|
2257
2333
|
`;
|
|
2258
2334
|
// Add extension-registered shortcuts
|
|
2259
2335
|
const extensionRunner = this.session.extensionRunner;
|