@oh-my-pi/pi-coding-agent 5.1.0 → 5.1.1

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
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.1.1] - 2026-01-14
6
+
7
+ ### Fixed
8
+
9
+ - Fixed clipboard image paste getting stuck on Wayland when no image is present (was falling back to X11 and timing out)
10
+
5
11
  ## [5.1.0] - 2026-01-14
6
12
 
7
13
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-coding-agent",
3
- "version": "5.1.0",
3
+ "version": "5.1.1",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "ompConfig": {
@@ -39,10 +39,10 @@
39
39
  "prepublishOnly": "bun run generate-template && bun run clean && bun run build"
40
40
  },
41
41
  "dependencies": {
42
- "@oh-my-pi/pi-agent-core": "5.1.0",
43
- "@oh-my-pi/pi-ai": "5.1.0",
44
- "@oh-my-pi/pi-git-tool": "5.1.0",
45
- "@oh-my-pi/pi-tui": "5.1.0",
42
+ "@oh-my-pi/pi-agent-core": "5.1.1",
43
+ "@oh-my-pi/pi-ai": "5.1.1",
44
+ "@oh-my-pi/pi-git-tool": "5.1.1",
45
+ "@oh-my-pi/pi-tui": "5.1.1",
46
46
  "@openai/agents": "^0.3.7",
47
47
  "@silvia-odwyer/photon-node": "^0.3.4",
48
48
  "@sinclair/typebox": "^0.34.46",
@@ -151,19 +151,29 @@ export async function readImageFromClipboard(): Promise<ClipboardImage | null> {
151
151
  return null;
152
152
  }
153
153
 
154
+ type ClipboardReadResult =
155
+ | { status: "found"; image: ClipboardImage }
156
+ | { status: "empty" } // Tools ran successfully, no image in clipboard
157
+ | { status: "unavailable" }; // Tools not found or failed to run
158
+
154
159
  async function readImageLinux(timeout: number): Promise<ClipboardImage | null> {
155
160
  const wayland = isWaylandSession();
156
161
  if (wayland) {
157
- const image = await readImageWayland(timeout);
158
- if (image) return image;
162
+ const result = await readImageWayland(timeout);
163
+ if (result.status === "found") return result.image;
164
+ if (result.status === "empty") return null; // Don't fall back to X11 if Wayland worked
159
165
  }
160
166
 
161
- return await readImageX11(timeout);
167
+ const result = await readImageX11(timeout);
168
+ return result.status === "found" ? result.image : null;
162
169
  }
163
170
 
164
- async function readImageWayland(timeout: number): Promise<ClipboardImage | null> {
165
- const types = await spawnAndRead(["wl-paste", "--list-types"], timeout);
166
- if (!types) return null;
171
+ async function readImageWayland(timeout: number): Promise<ClipboardReadResult> {
172
+ const wlPastePath = Bun.which("wl-paste");
173
+ if (!wlPastePath) return { status: "unavailable" };
174
+
175
+ const types = await spawnAndRead([wlPastePath, "--list-types"], timeout);
176
+ if (!types) return { status: "unavailable" }; // Command failed
167
177
 
168
178
  const typeList = types
169
179
  .toString("utf-8")
@@ -172,43 +182,46 @@ async function readImageWayland(timeout: number): Promise<ClipboardImage | null>
172
182
  .filter(Boolean);
173
183
 
174
184
  const selectedType = selectPreferredImageMimeType(typeList);
175
- if (!selectedType) return null;
185
+ if (!selectedType) return { status: "empty" }; // No image types available
176
186
 
177
- const imageData = await spawnAndRead(["wl-paste", "--type", selectedType, "--no-newline"], timeout);
178
- if (!imageData || imageData.length === 0) return null;
187
+ const imageData = await spawnAndRead([wlPastePath, "--type", selectedType, "--no-newline"], timeout);
188
+ if (!imageData || imageData.length === 0) return { status: "empty" };
179
189
 
180
190
  return {
181
- data: imageData.toString("base64"),
182
- mimeType: baseMimeType(selectedType),
191
+ status: "found",
192
+ image: {
193
+ data: imageData.toString("base64"),
194
+ mimeType: baseMimeType(selectedType),
195
+ },
183
196
  };
184
197
  }
185
198
 
186
- async function readImageX11(timeout: number): Promise<ClipboardImage | null> {
187
- const targets = await spawnAndRead(["xclip", "-selection", "clipboard", "-t", "TARGETS", "-o"], timeout);
199
+ async function readImageX11(timeout: number): Promise<ClipboardReadResult> {
200
+ const xclipPath = Bun.which("xclip");
201
+ if (!xclipPath) return { status: "unavailable" };
188
202
 
189
- let candidateTypes: string[] = [];
190
- if (targets) {
191
- candidateTypes = targets
192
- .toString("utf-8")
193
- .split(/\r?\n/)
194
- .map((t) => t.trim())
195
- .filter(Boolean);
196
- }
203
+ const targets = await spawnAndRead([xclipPath, "-selection", "clipboard", "-t", "TARGETS", "-o"], timeout);
204
+ if (!targets) return { status: "unavailable" }; // xclip failed (no X server?)
197
205
 
198
- const preferred = candidateTypes.length > 0 ? selectPreferredImageMimeType(candidateTypes) : null;
199
- const tryTypes = preferred ? [preferred, ...PREFERRED_IMAGE_MIME_TYPES] : [...PREFERRED_IMAGE_MIME_TYPES];
206
+ const candidateTypes = targets
207
+ .toString("utf-8")
208
+ .split(/\r?\n/)
209
+ .map((t) => t.trim())
210
+ .filter(Boolean);
200
211
 
201
- for (const mimeType of tryTypes) {
202
- const imageData = await spawnAndRead(["xclip", "-selection", "clipboard", "-t", mimeType, "-o"], timeout);
203
- if (imageData && imageData.length > 0) {
204
- return {
205
- data: imageData.toString("base64"),
206
- mimeType: baseMimeType(mimeType),
207
- };
208
- }
209
- }
212
+ const selectedType = selectPreferredImageMimeType(candidateTypes);
213
+ if (!selectedType) return { status: "empty" }; // Clipboard has no image types
210
214
 
211
- return null;
215
+ const imageData = await spawnAndRead([xclipPath, "-selection", "clipboard", "-t", selectedType, "-o"], timeout);
216
+ if (!imageData || imageData.length === 0) return { status: "empty" };
217
+
218
+ return {
219
+ status: "found",
220
+ image: {
221
+ data: imageData.toString("base64"),
222
+ mimeType: baseMimeType(selectedType),
223
+ },
224
+ };
212
225
  }
213
226
 
214
227
  async function readImageMacOS(timeout: number): Promise<ClipboardImage | null> {