pi-image-tools 1.3.0 → 1.4.0

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
@@ -1,115 +1,135 @@
1
- # Changelog
2
-
3
- ## [1.3.0] - 2026-06-01
4
-
5
- ### Added
6
- - Added a provider registry for platform-specific clipboard readers.
7
- - Added macOS `pngpaste` and `osascript` clipboard fallbacks.
8
- - Added an inline preview queue and chat component for user image previews.
9
-
10
- ### Changed
11
- - Deferred preview, clipboard, and recent-image module loading from the extension entrypoint.
12
- - Made shortcut conflict defaults platform-aware.
13
- - Updated Pi peer dependency ranges and the optional clipboard dependency for 0.78-compatible runtimes.
14
-
15
- ### Fixed
16
- - Improved shell and session handling for clipboard command providers.
17
-
18
- ## [1.2.1] - 2026-05-26
19
-
20
- ### Changed
21
- - Widened `@earendil-works/pi-coding-agent` and `@earendil-works/pi-tui` peer dependency ranges to `^0.74.0 || ^0.75.0`.
22
-
23
- ## [1.2.0] - 2026-05-22
24
-
25
- ### Added
26
- - Added Linux Sixel previews through `img2sixel` detection and conversion when the converter is available on `PATH`.
27
- - Added asynchronous image preview conversion so user-message previews can fall back without blocking the TUI.
28
-
29
- ### Changed
30
- - Updated Pi peer dependencies and runtime imports to the `@earendil-works` scope.
31
- - Improved preview setup diagnostics so missing Sixel converters report actionable fallback warnings.
32
-
33
- ### Fixed
34
- - Hardened debug logging with redaction and asynchronous file writes while keeping logging disabled by default.
35
-
36
- ## [1.1.0] - 2026-05-03
37
-
38
- ### Added
39
- - Added centralized image MIME, image-size, PowerShell, and error utilities used by clipboard, preview, attachment, and recent-image flows.
40
- - Added size-limit enforcement for image attachments, recent-cache writes, recent-image loads, and Sixel preview conversion through `PI_IMAGE_TOOLS_MAX_IMAGE_BYTES`.
41
-
42
- ### Changed
43
- - Reworked recent-image caching to use an extension-owned cache directory with safe pruning that preserves user files.
44
- - Reworked Sixel preview rendering to use an existing PowerShell `Sixel` module only, normalize converter output into complete terminal sequences, and fall back to native previews with actionable warnings.
45
- - Reworked terminal image width resolution to honor Pi project/global `terminal.imageWidthCells` settings with a documented default fallback.
46
-
47
- ### Fixed
48
- - Prevented extension debug logging from writing terminal output; debug events now remain file-based and disabled by default.
49
- - Preserved Sixel, Kitty, and iTerm inline image protocol rows during preview width fitting.
50
-
51
- ## [1.0.11] - 2026-04-25
52
-
53
- ### Changed
54
- - Avoid Pi's built-in image paste shortcut by default while preserving the previous primary shortcut when users disable or rebind `app.clipboard.pasteImage` (thanks to @danielcherubini for reporting this in PR #3).
55
- - Replaced the placeholder `enabled` config with validated `debug`, explicit `shortcuts.pasteImage`, configurable built-in conflict avoidance, and built-in warning suppression settings.
56
- - Removed obsolete packaged README image assets now that the README uses a GitHub-hosted image.
57
-
58
- ## [1.0.9] - 2026-04-01
59
-
60
- ### Changed
61
- - Updated README image to use HTML tag for better npm display compatibility
62
- - Added npm keywords for improved package discoverability
63
- - Added Related Pi Extensions cross-linking section to README
64
-
65
- ## [1.0.8] - 2026-04-01
66
-
67
- ### Changed
68
- - Updated `@mariozechner/pi-coding-agent` and `@mariozechner/pi-tui` peer dependencies to ^0.64.0
69
-
70
- ## [1.0.7] - 2026-03-23
71
-
72
- ### Changed
73
- - Updated `@mariozechner/pi-coding-agent` and `@mariozechner/pi-tui` peer dependencies to ^0.62.0
74
-
75
- ## [1.0.6] - 2026-03-12
76
-
77
- ### Changed
78
- - Updated AWS SDK client-bedrock-runtime to 3.1005.0
79
-
80
- ## [1.0.5] - 2026-03-12
81
-
82
- ### Changed
83
- - Updated AWS SDK client-bedrock-runtime to 3.1005.0
84
-
85
- ## [1.0.4] - 2026-03-07
86
-
87
- ### Added
88
- - Added Linux clipboard image support via `wl-paste` and `xclip` fallback readers.
89
- - Added Linux and macOS default recent-image discovery locations so the recent picker works beyond Windows.
90
- - Added non-Windows image paste shortcuts including `Ctrl+V` in addition to the existing alternate bindings.
91
-
92
- ### Changed
93
- - Updated README documentation to reflect current cross-platform support, clipboard backends, recent-image discovery behavior, and inline preview details.
94
-
95
- ### Fixed
96
- - Removed the Windows-only extension gate so supported non-Windows platforms can register commands and shortcuts.
97
- - Preserved Kitty and iTerm inline image protocol rows during preview width fitting, alongside the existing Sixel-safe handling.
98
- - Improved clipboard reader error handling so unsupported environments report missing backends more clearly.
99
-
100
- ## [1.0.3] - 2026-03-04
101
-
102
- ### Fixed
103
- - Use absolute GitHub raw URL for README image to fix npm display
104
-
105
- ## [1.0.2] - 2026-03-04
106
-
107
- ### Changed
108
- - Rewrote README.md with professional documentation standards
109
- - Added comprehensive feature documentation, configuration reference, and usage examples
110
-
111
- ## 1.0.0
112
-
113
- - Standardized repository layout to `src/` + root shim entrypoint.
114
- - Added TypeScript/Bundler project config, package metadata, and publish whitelist.
115
- - Added standard docs, license, and initial runtime config files.
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## [1.4.0] - 2026-07-03
6
+
7
+ ### Added
8
+ - Added an `enabled` config toggle to disable the extension without uninstalling. ([7c176b9](https://github.com/MasuRii/pi-image-tools/commit/7c176b9402e0681f23e91258fde4b5f8139aa14d))
9
+
10
+ ### Changed
11
+ - Widened Pi peer dependency ranges to 0.80 and added security dependency overrides. ([04f6847](https://github.com/MasuRii/pi-image-tools/commit/04f6847f3d29f50c63d5b069293b2dbff2f7bc64))
12
+ - Extracted a shared provider base class and preview logging to reduce duplication. ([7c176b9](https://github.com/MasuRii/pi-image-tools/commit/7c176b9402e0681f23e91258fde4b5f8139aa14d))
13
+
14
+ ### Fixed
15
+ - Restricted clipboard and transcode commands to an allowlist to prevent command injection. ([27c9a0b](https://github.com/MasuRii/pi-image-tools/commit/27c9a0b7f549bb248ff2544243c5f0dc7299b562))
16
+
17
+ ## [1.3.1] - 2026-06-16
18
+
19
+ ### Fixed
20
+ - Default paste-image shortcuts now avoid Pi built-in shortcut conflicts on all platforms, including macOS. Previously macOS defaulted to overriding Pi's built-in `ctrl+v` image paste binding and printed a startup conflict warning. (reported by @gaodes in [#8](https://github.com/MasuRii/pi-image-tools/issues/8))
21
+ - Transcode clipboard images that arrive in MIME types model providers reject (most notably `image/bmp` from WSLg's Wayland clipboard bridge for Windows clipboard images, and `image/tiff` from some macOS sources) into PNG via ImageMagick before attaching them. Previously, pasting a Windows screenshot inside WSL produced an `Unknown image type: image/bmp` error from the model provider that blocked the message from being sent. (contributed by @codeviking428 in [#9](https://github.com/MasuRii/pi-image-tools/pull/9))
22
+
23
+ ## [1.3.0] - 2026-06-01
24
+
25
+ ### Added
26
+ - Added a provider registry for platform-specific clipboard readers.
27
+ - Added macOS `pngpaste` and `osascript` clipboard fallbacks.
28
+ - Added an inline preview queue and chat component for user image previews.
29
+
30
+ ### Changed
31
+ - Deferred preview, clipboard, and recent-image module loading from the extension entrypoint.
32
+ - Made shortcut conflict defaults platform-aware.
33
+ - Updated Pi peer dependency ranges and the optional clipboard dependency for 0.78-compatible runtimes.
34
+
35
+ ### Fixed
36
+ - Improved shell and session handling for clipboard command providers.
37
+
38
+ ## [1.2.1] - 2026-05-26
39
+
40
+ ### Changed
41
+ - Widened `@earendil-works/pi-coding-agent` and `@earendil-works/pi-tui` peer dependency ranges to `^0.74.0 || ^0.75.0`.
42
+
43
+ ## [1.2.0] - 2026-05-22
44
+
45
+ ### Added
46
+ - Added Linux Sixel previews through `img2sixel` detection and conversion when the converter is available on `PATH`.
47
+ - Added asynchronous image preview conversion so user-message previews can fall back without blocking the TUI.
48
+
49
+ ### Changed
50
+ - Updated Pi peer dependencies and runtime imports to the `@earendil-works` scope.
51
+ - Improved preview setup diagnostics so missing Sixel converters report actionable fallback warnings.
52
+
53
+ ### Fixed
54
+ - Hardened debug logging with redaction and asynchronous file writes while keeping logging disabled by default.
55
+
56
+ ## [1.1.0] - 2026-05-03
57
+
58
+ ### Added
59
+ - Added centralized image MIME, image-size, PowerShell, and error utilities used by clipboard, preview, attachment, and recent-image flows.
60
+ - Added size-limit enforcement for image attachments, recent-cache writes, recent-image loads, and Sixel preview conversion through `PI_IMAGE_TOOLS_MAX_IMAGE_BYTES`.
61
+
62
+ ### Changed
63
+ - Reworked recent-image caching to use an extension-owned cache directory with safe pruning that preserves user files.
64
+ - Reworked Sixel preview rendering to use an existing PowerShell `Sixel` module only, normalize converter output into complete terminal sequences, and fall back to native previews with actionable warnings.
65
+ - Reworked terminal image width resolution to honor Pi project/global `terminal.imageWidthCells` settings with a documented default fallback.
66
+
67
+ ### Fixed
68
+ - Prevented extension debug logging from writing terminal output; debug events now remain file-based and disabled by default.
69
+ - Preserved Sixel, Kitty, and iTerm inline image protocol rows during preview width fitting.
70
+
71
+ ## [1.0.11] - 2026-04-25
72
+
73
+ ### Changed
74
+ - Avoid Pi's built-in image paste shortcut by default while preserving the previous primary shortcut when users disable or rebind `app.clipboard.pasteImage` (thanks to @danielcherubini for reporting this in PR #3).
75
+ - Replaced the placeholder `enabled` config with validated `debug`, explicit `shortcuts.pasteImage`, configurable built-in conflict avoidance, and built-in warning suppression settings.
76
+ - Removed obsolete packaged README image assets now that the README uses a GitHub-hosted image.
77
+
78
+ ## [1.0.9] - 2026-04-01
79
+
80
+ ### Changed
81
+ - Updated README image to use HTML tag for better npm display compatibility
82
+ - Added npm keywords for improved package discoverability
83
+ - Added Related Pi Extensions cross-linking section to README
84
+
85
+ ## [1.0.8] - 2026-04-01
86
+
87
+ ### Changed
88
+ - Updated `@mariozechner/pi-coding-agent` and `@mariozechner/pi-tui` peer dependencies to ^0.64.0
89
+
90
+ ## [1.0.7] - 2026-03-23
91
+
92
+ ### Changed
93
+ - Updated `@mariozechner/pi-coding-agent` and `@mariozechner/pi-tui` peer dependencies to ^0.62.0
94
+
95
+ ## [1.0.6] - 2026-03-12
96
+
97
+ ### Changed
98
+ - Updated AWS SDK client-bedrock-runtime to 3.1005.0
99
+
100
+ ## [1.0.5] - 2026-03-12
101
+
102
+ ### Changed
103
+ - Updated AWS SDK client-bedrock-runtime to 3.1005.0
104
+
105
+ ## [1.0.4] - 2026-03-07
106
+
107
+ ### Added
108
+ - Added Linux clipboard image support via `wl-paste` and `xclip` fallback readers.
109
+ - Added Linux and macOS default recent-image discovery locations so the recent picker works beyond Windows.
110
+ - Added non-Windows image paste shortcuts including `Ctrl+V` in addition to the existing alternate bindings.
111
+
112
+ ### Changed
113
+ - Updated README documentation to reflect current cross-platform support, clipboard backends, recent-image discovery behavior, and inline preview details.
114
+
115
+ ### Fixed
116
+ - Removed the Windows-only extension gate so supported non-Windows platforms can register commands and shortcuts.
117
+ - Preserved Kitty and iTerm inline image protocol rows during preview width fitting, alongside the existing Sixel-safe handling.
118
+ - Improved clipboard reader error handling so unsupported environments report missing backends more clearly.
119
+
120
+ ## [1.0.3] - 2026-03-04
121
+
122
+ ### Fixed
123
+ - Use absolute GitHub raw URL for README image to fix npm display
124
+
125
+ ## [1.0.2] - 2026-03-04
126
+
127
+ ### Changed
128
+ - Rewrote README.md with professional documentation standards
129
+ - Added comprehensive feature documentation, configuration reference, and usage examples
130
+
131
+ ## 1.0.0
132
+
133
+ - Standardized repository layout to `src/` + root shim entrypoint.
134
+ - Added TypeScript/Bundler project config, package metadata, and publish whitelist.
135
+ - Added standard docs, license, and initial runtime config files.
package/README.md CHANGED
@@ -1,13 +1,18 @@
1
- # 🖼️ pi-image-tools
1
+ <div align="center">
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/pi-image-tools?style=flat-square)](https://www.npmjs.com/package/pi-image-tools) [![License](https://img.shields.io/github/license/MasuRii/pi-image-tools?style=flat-square)](LICENSE)
3
+ # pi-image-tools
4
4
 
5
- Image attachment and preview extension for the **Pi coding agent**.
5
+ [![npm version](https://img.shields.io/npm/v/pi-image-tools?style=for-the-badge)](https://www.npmjs.com/package/pi-image-tools)
6
+ [![License](https://img.shields.io/github/license/MasuRii/pi-image-tools?style=for-the-badge)](LICENSE)
7
+ [![Platform](https://img.shields.io/badge/Platform-macOS%20%7C%20Linux%20%7C%20Windows-blue?style=for-the-badge)]()
6
8
 
7
- `pi-image-tools` lets you attach clipboard images or recent screenshots to your next user message, then preview them inline in the TUI before the message is sent.
9
+ [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Y8Y01PSSVR)
8
10
 
11
+ Image attachment and preview extension for the **Pi coding agent**.
12
+ `pi-image-tools` lets you attach clipboard images or recent screenshots to your next user message, then preview them inline in the TUI before the message is sent.
9
13
  <img width="1360" height="752" alt="image" src="https://github.com/user-attachments/assets/c7b462c4-6316-495e-a3fa-5a7e22edd91f" />
10
14
 
15
+ </div>
11
16
 
12
17
  ## Features
13
18
 
@@ -25,6 +30,7 @@ Image attachment and preview extension for the **Pi coding agent**.
25
30
  |----------|-----------------|---------------------|-------|
26
31
  | Windows | Yes | Yes | Uses native clipboard module first, then PowerShell fallback |
27
32
  | Linux | Yes | Yes | Requires a graphical session; uses `wl-paste` or `xclip`, then native module fallback |
33
+ | WSL2 (WSLg) | Yes | Yes | Linux providers see Windows clipboard images as `image/bmp`; install ImageMagick (`magick`/`convert`) so they can be transcoded to PNG before attaching |
28
34
  | macOS | Yes | Yes | Uses `pngpaste` first, then `osascript` and native module fallbacks |
29
35
  | Termux / headless Linux | No | Limited | Clipboard image paste is disabled without a graphical session |
30
36
 
@@ -122,13 +128,15 @@ $env:PI_IMAGE_TOOLS_RECENT_DIRS = "C:\Users\me\Pictures\Screenshots;D:\Shares\Sc
122
128
 
123
129
  ### Runtime config
124
130
 
125
- A config file can be placed at:
131
+ A config file can be placed at the `pi-image-tools` package/install root next to `index.ts`. For npm-installed extensions this is the package directory under Pi's npm install area, for example:
126
132
 
127
133
  ```text
128
- Default global path: ~/.pi/agent/extensions/pi-image-tools/config.json
129
- Actual global path: $PI_CODING_AGENT_DIR/extensions/pi-image-tools/config.json when PI_CODING_AGENT_DIR is set
134
+ ~/.pi/agent/npm/node_modules/pi-image-tools/config.json
135
+ $PI_CODING_AGENT_DIR/npm/node_modules/pi-image-tools/config.json when PI_CODING_AGENT_DIR is set
130
136
  ```
131
137
 
138
+ For a local checkout or extension path, place `config.json` in that `pi-image-tools` directory.
139
+
132
140
  Starter template:
133
141
 
134
142
  ```json
@@ -346,4 +354,4 @@ npm run check
346
354
 
347
355
  ## License
348
356
 
349
- MIT
357
+ [MIT](LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-image-tools",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Image attachment and rendering extension for Pi TUI",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -20,7 +20,8 @@
20
20
  "build": "npm run typecheck",
21
21
  "lint": "npm run typecheck",
22
22
  "test": "node --test test/*.test.js test/providers/*.test.js",
23
- "check": "npm run build && npm run test"
23
+ "check": "npm run build && npm run test",
24
+ "postinstall": "node -e \"const fs=require('fs'),cp=require('child_process'),p=require('path');const cwd=process.cwd();const normalized=cwd.split(p.sep).join('/');if(!normalized.includes('/.pi/agent/extensions/'))process.exit(0);const s=p.resolve(cwd,'../../scripts/patch-vulnerable-deps.mjs');if(!fs.existsSync(s))process.exit(0);const r=cp.spawnSync(process.execPath,[s,'--target',cwd,'--quiet'],{stdio:'inherit'});process.exit(r.status||0)\""
24
25
  },
25
26
  "keywords": [
26
27
  "pi-package",
@@ -60,10 +61,18 @@
60
61
  ]
61
62
  },
62
63
  "peerDependencies": {
63
- "@earendil-works/pi-coding-agent": "^0.74.0 || ^0.75.0 || ^0.77.0 || ^0.78.0",
64
- "@earendil-works/pi-tui": "^0.74.0 || ^0.75.0 || ^0.77.0 || ^0.78.0"
64
+ "@earendil-works/pi-coding-agent": "^0.74.0 || ^0.75.0 || ^0.77.0 || ^0.78.0 || ^0.79.0 || ^0.80.0",
65
+ "@earendil-works/pi-tui": "^0.74.0 || ^0.75.0 || ^0.77.0 || ^0.78.0 || ^0.79.0 || ^0.80.0"
65
66
  },
66
67
  "optionalDependencies": {
67
68
  "@mariozechner/clipboard": "^0.3.9"
69
+ },
70
+ "overrides": {
71
+ "protobufjs": "7.6.3",
72
+ "ws": "8.21.0"
73
+ },
74
+ "devDependencies": {
75
+ "@earendil-works/pi-coding-agent": "^0.80.3",
76
+ "@earendil-works/pi-tui": "^0.80.3"
68
77
  }
69
78
  }
package/src/clipboard.ts CHANGED
@@ -1,89 +1,99 @@
1
- import { hasGraphicalSession, isWaylandSession } from "./shell-environment.js";
2
- import { NativeModuleProvider } from "./providers/native-module.js";
3
- import { OsascriptPngfProvider } from "./providers/mac-osascript-pngf.js";
4
- import { OsascriptPublicPngProvider } from "./providers/mac-osascript-publicpng.js";
5
- import { PngpasteProvider } from "./providers/mac-pngpaste.js";
6
- import { PowerShellFormsProvider } from "./providers/powershell-forms.js";
7
- import { ClipboardProviderRegistry } from "./providers/registry.js";
8
- import { WlPasteProvider } from "./providers/wl-paste.js";
9
- import { XclipProvider } from "./providers/xclip.js";
10
- import type { ClipboardImage } from "./types.js";
11
-
12
- export { hasGraphicalSession } from "./shell-environment.js";
13
-
14
- export function buildDefaultClipboardProviderRegistry(
15
- platform: NodeJS.Platform,
16
- environment: NodeJS.ProcessEnv,
17
- ): ClipboardProviderRegistry {
18
- const registry = new ClipboardProviderRegistry();
19
-
20
- if (platform === "win32") {
21
- registry
22
- .register(new NativeModuleProvider({ priority: 10 }))
23
- .register(new PowerShellFormsProvider({ priority: 20 }));
24
- return registry;
25
- }
26
-
27
- if (platform === "linux") {
28
- const waylandFirst = isWaylandSession(environment);
29
- registry
30
- .register(new WlPasteProvider({ priority: waylandFirst ? 10 : 20 }))
31
- .register(new XclipProvider({ priority: waylandFirst ? 20 : 10 }))
32
- .register(new NativeModuleProvider({ priority: 30 }));
33
- return registry;
34
- }
35
-
36
- if (platform === "darwin") {
37
- registry
38
- .register(new PngpasteProvider({ priority: 10 }))
39
- .register(new OsascriptPublicPngProvider({ priority: 20 }))
40
- .register(new OsascriptPngfProvider({ priority: 30 }))
41
- .register(new NativeModuleProvider({ priority: 40 }));
42
- return registry;
43
- }
44
-
45
- registry.register(new NativeModuleProvider({ priority: 100 }));
46
- return registry;
47
- }
48
-
49
- function getUnavailableReaderMessage(platform: NodeJS.Platform): string {
50
- switch (platform) {
51
- case "linux":
52
- return "No Linux clipboard image reader is available. Install wl-clipboard or xclip, or ensure @mariozechner/clipboard is installed.";
53
- case "darwin":
54
- return "No macOS clipboard image reader is available. Install pngpaste, ensure osascript is available, or ensure @mariozechner/clipboard is installed.";
55
- case "win32":
56
- return "No Windows clipboard image reader is available. Ensure PowerShell is available or @mariozechner/clipboard is installed.";
57
- default:
58
- return `Clipboard image paste is not supported on platform: ${platform}`;
59
- }
60
- }
61
-
62
- export async function readClipboardImage(options?: {
63
- environment?: NodeJS.ProcessEnv;
64
- platform?: NodeJS.Platform;
65
- registry?: ClipboardProviderRegistry;
66
- }): Promise<ClipboardImage | null> {
67
- const environment = options?.environment ?? process.env;
68
- const platform = options?.platform ?? process.platform;
69
-
70
- if (environment.TERMUX_VERSION) {
71
- return null;
72
- }
73
-
74
- if (!hasGraphicalSession(platform, environment)) {
75
- throw new Error("Clipboard image paste requires a graphical desktop session with DISPLAY or WAYLAND_DISPLAY.");
76
- }
77
-
78
- const registry = options?.registry ?? buildDefaultClipboardProviderRegistry(platform, environment);
79
- const result = await registry.read({ platform, environment });
80
- if (result.image) {
81
- return result.image;
82
- }
83
-
84
- if (result.attempts.some((attempt) => attempt.available)) {
85
- return null;
86
- }
87
-
88
- throw new Error(getUnavailableReaderMessage(platform));
89
- }
1
+ import { hasGraphicalSession, isWaylandSession } from "./shell-environment.js";
2
+ import { transcodeToSupportedFormat, type TranscodeOptions } from "./image-transcode.js";
3
+ import { NativeModuleProvider } from "./providers/native-module.js";
4
+ import { OsascriptPngfProvider } from "./providers/mac-osascript-pngf.js";
5
+ import { OsascriptPublicPngProvider } from "./providers/mac-osascript-publicpng.js";
6
+ import { PngpasteProvider } from "./providers/mac-pngpaste.js";
7
+ import { PowerShellFormsProvider } from "./providers/powershell-forms.js";
8
+ import { ClipboardProviderRegistry } from "./providers/registry.js";
9
+ import { WlPasteProvider } from "./providers/wl-paste.js";
10
+ import { XclipProvider } from "./providers/xclip.js";
11
+ import type { ClipboardImage } from "./types.js";
12
+
13
+ export { hasGraphicalSession } from "./shell-environment.js";
14
+
15
+ export function buildDefaultClipboardProviderRegistry(
16
+ platform: NodeJS.Platform,
17
+ environment: NodeJS.ProcessEnv,
18
+ ): ClipboardProviderRegistry {
19
+ const registry = new ClipboardProviderRegistry();
20
+
21
+ if (platform === "win32") {
22
+ registry
23
+ .register(new NativeModuleProvider({ priority: 10 }))
24
+ .register(new PowerShellFormsProvider({ priority: 20 }));
25
+ return registry;
26
+ }
27
+
28
+ if (platform === "linux") {
29
+ const waylandFirst = isWaylandSession(environment);
30
+ registry
31
+ .register(new WlPasteProvider({ priority: waylandFirst ? 10 : 20 }))
32
+ .register(new XclipProvider({ priority: waylandFirst ? 20 : 10 }))
33
+ .register(new NativeModuleProvider({ priority: 30 }));
34
+ return registry;
35
+ }
36
+
37
+ if (platform === "darwin") {
38
+ registry
39
+ .register(new PngpasteProvider({ priority: 10 }))
40
+ .register(new OsascriptPublicPngProvider({ priority: 20 }))
41
+ .register(new OsascriptPngfProvider({ priority: 30 }))
42
+ .register(new NativeModuleProvider({ priority: 40 }));
43
+ return registry;
44
+ }
45
+
46
+ registry.register(new NativeModuleProvider({ priority: 100 }));
47
+ return registry;
48
+ }
49
+
50
+ function getUnavailableReaderMessage(platform: NodeJS.Platform): string {
51
+ switch (platform) {
52
+ case "linux":
53
+ return "No Linux clipboard image reader is available. Install wl-clipboard or xclip, or ensure @mariozechner/clipboard is installed.";
54
+ case "darwin":
55
+ return "No macOS clipboard image reader is available. Install pngpaste, ensure osascript is available, or ensure @mariozechner/clipboard is installed.";
56
+ case "win32":
57
+ return "No Windows clipboard image reader is available. Ensure PowerShell is available or @mariozechner/clipboard is installed.";
58
+ default:
59
+ return `Clipboard image paste is not supported on platform: ${platform}`;
60
+ }
61
+ }
62
+
63
+ export async function readClipboardImage(options?: {
64
+ environment?: NodeJS.ProcessEnv;
65
+ platform?: NodeJS.Platform;
66
+ registry?: ClipboardProviderRegistry;
67
+ /**
68
+ * Hooks for the post-read transcoding step that normalizes images into a
69
+ * MIME type accepted by model providers. Mainly for tests; the default
70
+ * implementation shells out to ImageMagick only when the source format isn't
71
+ * already supported.
72
+ */
73
+ transcode?: TranscodeOptions;
74
+ }): Promise<ClipboardImage | null> {
75
+ const environment = options?.environment ?? process.env;
76
+ const platform = options?.platform ?? process.platform;
77
+
78
+ if (environment.TERMUX_VERSION) {
79
+ return null;
80
+ }
81
+
82
+ if (!hasGraphicalSession(platform, environment)) {
83
+ throw new Error("Clipboard image paste requires a graphical desktop session with DISPLAY or WAYLAND_DISPLAY.");
84
+ }
85
+
86
+ const registry = options?.registry ?? buildDefaultClipboardProviderRegistry(platform, environment);
87
+ const result = await registry.read({ platform, environment });
88
+ if (result.image) {
89
+ // Providers (notably wl-paste under WSLg) may return formats like
90
+ // image/bmp that model providers reject. Normalize to PNG when needed.
91
+ return transcodeToSupportedFormat(result.image, { platform, ...options?.transcode });
92
+ }
93
+
94
+ if (result.attempts.some((attempt) => attempt.available)) {
95
+ return null;
96
+ }
97
+
98
+ throw new Error(getUnavailableReaderMessage(platform));
99
+ }
package/src/config.ts CHANGED
@@ -14,6 +14,7 @@ export interface ImageToolsShortcutConfig {
14
14
  }
15
15
 
16
16
  export interface ImageToolsConfig {
17
+ enabled: boolean;
17
18
  debug: boolean;
18
19
  shortcuts: ImageToolsShortcutConfig;
19
20
  }
@@ -86,9 +87,9 @@ function parseShortcutList(value: unknown, property: string, path: string): KeyI
86
87
  return shortcuts;
87
88
  }
88
89
 
89
- function getDefaultShortcutConfig(platform: NodeJS.Platform): ImageToolsShortcutConfig {
90
+ function getDefaultShortcutConfig(_platform: NodeJS.Platform): ImageToolsShortcutConfig {
90
91
  return {
91
- avoidBuiltinConflicts: platform !== "darwin",
92
+ avoidBuiltinConflicts: true,
92
93
  suppressBuiltinConflictWarnings: false,
93
94
  };
94
95
  }
@@ -129,6 +130,7 @@ function parseConfig(rawConfig: unknown, path: string, platform: NodeJS.Platform
129
130
 
130
131
  return {
131
132
  debug: parseBoolean(rawConfig.debug, "debug", path),
133
+ enabled: parseBoolean(rawConfig.enabled, "enabled", path, true),
132
134
  shortcuts: parseShortcutConfig(rawConfig.shortcuts, path, platform),
133
135
  };
134
136
  }
@@ -137,6 +139,7 @@ export function loadImageToolsConfig(path = getConfigPath(), options: LoadImageT
137
139
  const platform = options.platform ?? process.platform;
138
140
  if (!existsSync(path)) {
139
141
  return {
142
+ enabled: true,
140
143
  debug: false,
141
144
  shortcuts: getDefaultShortcutConfig(platform),
142
145
  };
@@ -53,8 +53,10 @@ export class DebugLogger {
53
53
  () => this.appendLine(line),
54
54
  );
55
55
  void this.writeQueue.catch(() => undefined);
56
- } catch {
57
- // Debug logging must never affect extension behavior.
56
+ } catch (error) {
57
+ // Debug logging must never affect extension behavior; the write queue
58
+ // is left untouched so subsequent log calls continue to drain normally.
59
+ void error;
58
60
  }
59
61
  }
60
62