pi-paster 0.1.4 → 0.1.5
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/dist/index.mjs +20 -12
- package/package.json +2 -2
- package/src/index.ts +19 -10
- package/src/preview.ts +13 -5
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { randomUUID } from "node:crypto";
|
|
|
3
3
|
import { existsSync, readFileSync, statSync, unlinkSync } from "node:fs";
|
|
4
4
|
import { homedir, tmpdir } from "node:os";
|
|
5
5
|
import { isAbsolute, join, resolve } from "node:path";
|
|
6
|
-
import { Image, getCellDimensions, getImageDimensions, truncateToWidth } from "@earendil-works/pi-tui";
|
|
6
|
+
import { Image, getCellDimensions, getImageDimensions, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
7
7
|
import { CustomEditor } from "@earendil-works/pi-coding-agent";
|
|
8
8
|
//#region src/types.ts
|
|
9
9
|
const EXTENSION_NAME = "paster";
|
|
@@ -408,6 +408,11 @@ var PasterEditor = class extends CustomEditor {
|
|
|
408
408
|
};
|
|
409
409
|
//#endregion
|
|
410
410
|
//#region src/preview.ts
|
|
411
|
+
function formatAttachmentLine(attachment, width, style) {
|
|
412
|
+
const maxWidth = Math.max(1, width);
|
|
413
|
+
const line = style(`Attached ${attachment.placeholder} ${attachment.originalPath}`);
|
|
414
|
+
return visibleWidth(line) > maxWidth ? truncateToWidth(line, maxWidth, "") : line;
|
|
415
|
+
}
|
|
411
416
|
var ImagePreviewMessage = class {
|
|
412
417
|
images;
|
|
413
418
|
constructor(attachments, theme) {
|
|
@@ -423,7 +428,7 @@ var ImagePreviewMessage = class {
|
|
|
423
428
|
const lines = [];
|
|
424
429
|
for (let index = 0; index < this.attachments.length; index++) {
|
|
425
430
|
const attachment = this.attachments[index];
|
|
426
|
-
lines.push(this.theme.fallbackColor
|
|
431
|
+
lines.push(formatAttachmentLine(attachment, width, this.theme.fallbackColor));
|
|
427
432
|
lines.push(...this.images[index].render(width));
|
|
428
433
|
}
|
|
429
434
|
return lines;
|
|
@@ -448,8 +453,7 @@ var CursorImagePreviewWidget = class {
|
|
|
448
453
|
this.image.invalidate();
|
|
449
454
|
}
|
|
450
455
|
headerLine(width) {
|
|
451
|
-
|
|
452
|
-
return this.theme.title(truncateToWidth(title, Math.max(1, width), ""));
|
|
456
|
+
return formatAttachmentLine(this.attachment, width, this.theme.title);
|
|
453
457
|
}
|
|
454
458
|
createImage(attachment, maxWidthCells = 60) {
|
|
455
459
|
return new Image(attachment.data, attachment.mimeType, { fallbackColor: this.theme.accent }, {
|
|
@@ -607,12 +611,21 @@ function paster(pi, config = {}) {
|
|
|
607
611
|
}
|
|
608
612
|
store.clear();
|
|
609
613
|
});
|
|
614
|
+
function previewMessage(attachments) {
|
|
615
|
+
return {
|
|
616
|
+
customType: "paster-preview",
|
|
617
|
+
content: "",
|
|
618
|
+
display: true,
|
|
619
|
+
details: { placeholders: attachments.map((attachment) => attachment.placeholder) }
|
|
620
|
+
};
|
|
621
|
+
}
|
|
610
622
|
pi.on("input", (event, ctx) => {
|
|
611
623
|
if (event.source === "extension") return { action: "continue" };
|
|
612
624
|
if (ctx.hasUI) activeEditor?.clearCursorPreview();
|
|
613
625
|
const attachments = store.matchingPlaceholders(event.text);
|
|
614
626
|
if (attachments.length === 0) return { action: "continue" };
|
|
615
|
-
pendingPreview = attachments;
|
|
627
|
+
if (ctx.isIdle()) pendingPreview = attachments;
|
|
628
|
+
else pi.sendMessage(previewMessage(attachments), { deliverAs: "followUp" });
|
|
616
629
|
return {
|
|
617
630
|
action: "transform",
|
|
618
631
|
text: event.text,
|
|
@@ -621,14 +634,9 @@ function paster(pi, config = {}) {
|
|
|
621
634
|
});
|
|
622
635
|
pi.on("before_agent_start", () => {
|
|
623
636
|
if (pendingPreview.length === 0) return;
|
|
624
|
-
const
|
|
637
|
+
const message = previewMessage(pendingPreview);
|
|
625
638
|
pendingPreview = [];
|
|
626
|
-
return { message
|
|
627
|
-
customType: "paster-preview",
|
|
628
|
-
content: "",
|
|
629
|
-
display: true,
|
|
630
|
-
details: { placeholders }
|
|
631
|
-
} };
|
|
639
|
+
return { message };
|
|
632
640
|
});
|
|
633
641
|
}
|
|
634
642
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-paster",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Pi extension that turns pasted image paths into first-class image attachments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"image-attachments",
|
|
@@ -55,6 +55,6 @@
|
|
|
55
55
|
"extensions": [
|
|
56
56
|
"./src/index.ts"
|
|
57
57
|
],
|
|
58
|
-
"image": "https://unpkg.com/pi-paster@0.1.
|
|
58
|
+
"image": "https://unpkg.com/pi-paster@0.1.5/docs/preview.png"
|
|
59
59
|
}
|
|
60
60
|
}
|
package/src/index.ts
CHANGED
|
@@ -110,6 +110,15 @@ export default function paster(pi: ExtensionAPI, config: PasterConfig = {}): voi
|
|
|
110
110
|
store.clear();
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
+
function previewMessage(attachments: ImageAttachment[]) {
|
|
114
|
+
return {
|
|
115
|
+
customType: "paster-preview",
|
|
116
|
+
content: "",
|
|
117
|
+
display: true,
|
|
118
|
+
details: { placeholders: attachments.map((attachment) => attachment.placeholder) },
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
113
122
|
pi.on("input", (event, ctx) => {
|
|
114
123
|
if (event.source === "extension") return { action: "continue" as const };
|
|
115
124
|
if (ctx.hasUI) {
|
|
@@ -118,7 +127,14 @@ export default function paster(pi: ExtensionAPI, config: PasterConfig = {}): voi
|
|
|
118
127
|
|
|
119
128
|
const attachments = store.matchingPlaceholders(event.text);
|
|
120
129
|
if (attachments.length === 0) return { action: "continue" as const };
|
|
121
|
-
|
|
130
|
+
|
|
131
|
+
if (ctx.isIdle()) {
|
|
132
|
+
pendingPreview = attachments;
|
|
133
|
+
} else {
|
|
134
|
+
// Queued steer/follow-up messages do not fire before_agent_start when they are
|
|
135
|
+
// later delivered by the running agent, so enqueue the preview alongside them now.
|
|
136
|
+
pi.sendMessage(previewMessage(attachments), { deliverAs: "followUp" });
|
|
137
|
+
}
|
|
122
138
|
|
|
123
139
|
return {
|
|
124
140
|
action: "transform" as const,
|
|
@@ -129,15 +145,8 @@ export default function paster(pi: ExtensionAPI, config: PasterConfig = {}): voi
|
|
|
129
145
|
|
|
130
146
|
pi.on("before_agent_start", () => {
|
|
131
147
|
if (pendingPreview.length === 0) return;
|
|
132
|
-
const
|
|
148
|
+
const message = previewMessage(pendingPreview);
|
|
133
149
|
pendingPreview = [];
|
|
134
|
-
return {
|
|
135
|
-
message: {
|
|
136
|
-
customType: "paster-preview",
|
|
137
|
-
content: "",
|
|
138
|
-
display: true,
|
|
139
|
-
details: { placeholders },
|
|
140
|
-
},
|
|
141
|
-
};
|
|
150
|
+
return { message };
|
|
142
151
|
});
|
|
143
152
|
}
|
package/src/preview.ts
CHANGED
|
@@ -4,9 +4,20 @@ import {
|
|
|
4
4
|
type Component,
|
|
5
5
|
type ImageTheme,
|
|
6
6
|
truncateToWidth,
|
|
7
|
+
visibleWidth,
|
|
7
8
|
} from "@earendil-works/pi-tui";
|
|
8
9
|
import type { ImageAttachment } from "./types.ts";
|
|
9
10
|
|
|
11
|
+
function formatAttachmentLine(
|
|
12
|
+
attachment: ImageAttachment,
|
|
13
|
+
width: number,
|
|
14
|
+
style: (text: string) => string,
|
|
15
|
+
): string {
|
|
16
|
+
const maxWidth = Math.max(1, width);
|
|
17
|
+
const line = style(`Attached ${attachment.placeholder} ${attachment.originalPath}`);
|
|
18
|
+
return visibleWidth(line) > maxWidth ? truncateToWidth(line, maxWidth, "") : line;
|
|
19
|
+
}
|
|
20
|
+
|
|
10
21
|
export class ImagePreviewMessage implements Component {
|
|
11
22
|
private readonly images: Image[];
|
|
12
23
|
|
|
@@ -28,9 +39,7 @@ export class ImagePreviewMessage implements Component {
|
|
|
28
39
|
const lines: string[] = [];
|
|
29
40
|
for (let index = 0; index < this.attachments.length; index++) {
|
|
30
41
|
const attachment = this.attachments[index]!;
|
|
31
|
-
lines.push(
|
|
32
|
-
this.theme.fallbackColor(`Attached ${attachment.placeholder} ${attachment.originalPath}`),
|
|
33
|
-
);
|
|
42
|
+
lines.push(formatAttachmentLine(attachment, width, this.theme.fallbackColor));
|
|
34
43
|
lines.push(...this.images[index]!.render(width));
|
|
35
44
|
}
|
|
36
45
|
return lines;
|
|
@@ -68,8 +77,7 @@ export class CursorImagePreviewWidget implements Component {
|
|
|
68
77
|
}
|
|
69
78
|
|
|
70
79
|
private headerLine(width: number): string {
|
|
71
|
-
|
|
72
|
-
return this.theme.title(truncateToWidth(title, Math.max(1, width), ""));
|
|
80
|
+
return formatAttachmentLine(this.attachment, width, this.theme.title);
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
private createImage(attachment: ImageAttachment, maxWidthCells = 60): Image {
|