pi-superwhisper-paste 0.1.20 → 0.1.23
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 +147 -153
- package/README.md +135 -135
- package/docs/examples.md +1 -1
- package/extensions/index.ts +78 -19
- package/package.json +63 -63
package/CHANGELOG.md
CHANGED
|
@@ -1,160 +1,154 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
This project follows semantic versioning.
|
|
6
|
-
|
|
7
|
-
##
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
This project follows semantic versioning.
|
|
6
|
+
|
|
7
|
+
## [0.1.23] - 2026-09-27
|
|
8
|
+
|
|
9
|
+
- chore: periodic patch bump after 7+ days without npm publish
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
All notable changes to this project will be documented in this file.
|
|
14
|
+
|
|
15
|
+
This project follows semantic versioning.
|
|
16
|
+
## [0.1.22] - 2026-09-28
|
|
8
17
|
|
|
18
|
+
- chore: periodic patch bump after 7+ days without npm publish
|
|
19
|
+
## [0.1.21] - 2026-09-28
|
|
20
|
+
|
|
21
|
+
- chore: periodic patch bump after 7+ days without npm publish
|
|
9
22
|
## [0.1.20] - 2026-08-22
|
|
10
23
|
|
|
11
24
|
### Changed
|
|
12
25
|
|
|
13
26
|
- Support the TypeScript 7 compiler package by using Node's built-in type stripping in runtime-loading regression tests.
|
|
14
|
-
|
|
15
27
|
## [0.1.19] - 2026-08-04
|
|
16
|
-
|
|
17
|
-
### Changed
|
|
18
|
-
|
|
19
|
-
- Bump package version for the Discord release webhook verification.
|
|
20
|
-
- Align README pinned npm install example with `package.json` (#38).
|
|
21
|
-
- Add dotfield.xyz Discord community badge to README.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
## [0.1.
|
|
52
|
-
|
|
53
|
-
###
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
-
|
|
113
|
-
|
|
114
|
-
## [0.1.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
-
|
|
140
|
-
|
|
141
|
-
##
|
|
142
|
-
|
|
143
|
-
### Added
|
|
144
|
-
|
|
145
|
-
- Add automatic GitHub release creation for version bumps on `main`.
|
|
146
|
-
- Add manual and release-published npm publish entrypoints for Trusted Publishing.
|
|
147
|
-
|
|
148
|
-
### Changed
|
|
149
|
-
|
|
150
|
-
- Align CI and publish workflows with the maintained Pi OSS release pattern.
|
|
151
|
-
- Skip npm publish when the exact package version is already published.
|
|
152
|
-
|
|
153
|
-
## [0.1.0] - 2026-05-30
|
|
154
|
-
|
|
155
|
-
### Added
|
|
156
|
-
|
|
157
|
-
- Initial Superwhisper paste bridge extension for Pi on Windows.
|
|
158
|
-
- Default-on clipboard watcher with `/sw-paste:on` and `/sw-paste:off` controls.
|
|
159
|
-
- CI and npm Trusted Publishing workflow from the Pi extension template.
|
|
160
|
-
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Bump package version for the Discord release webhook verification.
|
|
32
|
+
- Align README pinned npm install example with `package.json` (#38).
|
|
33
|
+
- Add dotfield.xyz Discord community badge to README.
|
|
34
|
+
## [0.1.18] - 2026-07-21
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- Bump package version and align extension status version constant with `package.json`.
|
|
39
|
+
## [0.1.17] - 2026-07-04
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- Add Buy Me a Coffee sponsor button to README and native GitHub funding link via `.github/FUNDING.yml`.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- Align `EXTENSION_VERSION` in the extension with `package.json` so Pi status text no longer reports a stale build during debugging (#35).
|
|
48
|
+
## [0.1.16] - 2026-06-27
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- Align README with the current Pi extension template structure while preserving Windows install guidance and behavior notes.
|
|
53
|
+
## [0.1.15] - 2026-06-05
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- Remove stale template-maintenance docs (`github-template.md`, `repository-settings.md`, `typescript.md`) from the published package.
|
|
58
|
+
## [0.1.14] - 2026-06-05
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- Re-add `Code` / `Cursor` host processes to the clipboard-owner denylist so editor-hosted clipboard updates are blocked again during debugging.
|
|
63
|
+
## [0.1.13] - 2026-06-05
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
|
|
67
|
+
- Remove `Code.exe` / `Cursor.exe` from the terminal-owner denylist so editor-hosted Superwhisper clipboard updates are not blocked just because Pi is running inside Code/Cursor.
|
|
68
|
+
## [0.1.12] - 2026-06-05
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- Add an explicit `v0.1.12` marker to the status text so stale package loads are visible during live debugging.
|
|
73
|
+
## [0.1.11] - 2026-06-05
|
|
74
|
+
|
|
75
|
+
### Fixed
|
|
76
|
+
|
|
77
|
+
- Broaden the terminal clipboard-owner denylist with `OpenConsole` / explicit `.exe` variants.
|
|
78
|
+
- Surface the last clipboard decision in the Pi status text (`blocked ...`, `... via ...`) so real-machine owner mismatches can be diagnosed quickly.
|
|
79
|
+
## [0.1.10] - 2026-06-05
|
|
80
|
+
|
|
81
|
+
### Fixed
|
|
82
|
+
|
|
83
|
+
- Fix the Windows PowerShell clipboard-owner probe script so the owner-aware bridge works in real Pi sessions instead of failing on multiline `Add-Type` syntax.
|
|
84
|
+
## [0.1.9] - 2026-06-05
|
|
85
|
+
|
|
86
|
+
### Fixed
|
|
87
|
+
|
|
88
|
+
- Replace the strict Superwhisper owner allowlist with a terminal-owner denylist so unknown Superwhisper owner names still auto-paste while terminal/CLI clipboard owners stay blocked.
|
|
89
|
+
## [0.1.8] - 2026-06-05
|
|
90
|
+
|
|
91
|
+
### Fixed
|
|
92
|
+
|
|
93
|
+
- Filter clipboard updates by clipboard-owner process so Pi auto-pastes only when the clipboard owner looks like Superwhisper.
|
|
94
|
+
- Keep local terminal copy suppression as a fallback for forwarded copy shortcuts while blocking mouse/right-click terminal copies via owner filtering.
|
|
95
|
+
## [0.1.7] - 2026-06-05
|
|
96
|
+
|
|
97
|
+
### Fixed
|
|
98
|
+
|
|
99
|
+
- Suppress auto-paste for a short window after local terminal copy shortcuts so copying inside the active CLI no longer pastes into Pi.
|
|
100
|
+
- Refresh the clipboard baseline after local copy intent so the bridge keeps waiting for the next Superwhisper clipboard update.
|
|
101
|
+
## [0.1.6] - 2026-06-04
|
|
102
|
+
|
|
103
|
+
### Changed
|
|
104
|
+
|
|
105
|
+
- Added `version:check` PR guard support: package script + `scripts/check-version-bump.mjs`.
|
|
106
|
+
- Added CI verification that publishable changes must bump `package.json` and update `CHANGELOG.md` in the same PR.
|
|
107
|
+
|
|
108
|
+
### Fixed
|
|
109
|
+
|
|
110
|
+
- Truncate clipboard text in PowerShell before writing stdout so huge clipboards no longer exceed Node `maxBuffer` on extension load.
|
|
111
|
+
- Treat clipboard read failures (including `maxBuffer`) as empty reads so `session_start` never surfaces as an extension error.
|
|
112
|
+
## [0.1.5] - 2026-06-03
|
|
113
|
+
## [0.1.4] - 2026-06-03
|
|
114
|
+
|
|
115
|
+
### Changed
|
|
116
|
+
|
|
117
|
+
- Clarify that `pi-superwhisper-paste` is the Windows clipboard-based package.
|
|
118
|
+
- Point users to `@superwhisper/pi` only for the official deeplink/macOS flow.
|
|
119
|
+
- Update npm package metadata to match the revived Windows-focused positioning.
|
|
120
|
+
## [0.1.3] - 2026-06-03
|
|
121
|
+
|
|
122
|
+
### Changed
|
|
123
|
+
|
|
124
|
+
- Mark the package as archived in README and `package.json` description.
|
|
125
|
+
- Point new installs to the official Superwhisper Pi extension: `pi install npm:@superwhisper/pi`.
|
|
126
|
+
## [0.1.2] - 2026-06-01
|
|
127
|
+
|
|
128
|
+
### Fixed
|
|
129
|
+
|
|
130
|
+
- Register `/sw-paste:on` and `/sw-paste:off` as Pi slash commands so they appear in command autocomplete.
|
|
131
|
+
|
|
132
|
+
### Changed
|
|
133
|
+
|
|
134
|
+
- Clarify that the Superwhisper paste controls are slash-autocomplete commands.
|
|
135
|
+
## [0.1.1] - 2026-05-31
|
|
136
|
+
|
|
137
|
+
### Added
|
|
138
|
+
|
|
139
|
+
- Add automatic GitHub release creation for version bumps on `main`.
|
|
140
|
+
- Add manual and release-published npm publish entrypoints for Trusted Publishing.
|
|
141
|
+
|
|
142
|
+
### Changed
|
|
143
|
+
|
|
144
|
+
- Align CI and publish workflows with the maintained Pi OSS release pattern.
|
|
145
|
+
- Skip npm publish when the exact package version is already published.
|
|
146
|
+
## [0.1.0] - 2026-05-30
|
|
147
|
+
|
|
148
|
+
### Added
|
|
149
|
+
|
|
150
|
+
- Initial Superwhisper paste bridge extension for Pi on Windows.
|
|
151
|
+
- Default-on clipboard watcher with `/sw-paste:on` and `/sw-paste:off` controls.
|
|
152
|
+
- CI and npm Trusted Publishing workflow from the Pi extension template.
|
|
153
|
+
## Unreleased
|
|
154
|
+
|
package/README.md
CHANGED
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
# Pi Superwhisper Paste
|
|
2
|
-
|
|
3
|
-
[](https://discord.gg/4945dXZVW5)
|
|
4
|
-
|
|
5
|
-
[](https://github.com/eiei114/pi-superwhisper-paste/actions/workflows/ci.yml)
|
|
6
|
-
[](https://github.com/eiei114/pi-superwhisper-paste/actions/workflows/publish.yml)
|
|
7
|
-
[](https://www.npmjs.com/package/pi-superwhisper-paste)
|
|
8
|
-
[](https://www.npmjs.com/package/pi-superwhisper-paste)
|
|
9
|
-
[](LICENSE)
|
|
10
|
-
[](https://pi.dev/packages)
|
|
11
|
-
[](docs/release.md)
|
|
12
|
-
<a href="https://buymeacoffee.com/ekawano114m"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" width="217" height="60"></a>
|
|
13
|
-
|
|
14
|
-
> Windows-focused Pi bridge that pastes Superwhisper clipboard output into Pi's TUI editor.
|
|
15
|
-
|
|
16
|
-
## What this is
|
|
17
|
-
|
|
18
|
-
Superwhisper can paste dictated text into normal Windows apps, but terminal TUIs can be a rough edge. In the original case, dictation worked in Notepad and PowerShell, and Typeless worked in Pi, but Superwhisper's automatic paste did not reliably reach Pi's TUI editor without a manual `Ctrl+V`.
|
|
19
|
-
|
|
20
|
-
This package bridges that gap from the Pi side: it watches the Windows clipboard, detects new Superwhisper output, and inserts it into the active Pi editor with Pi's extension API.
|
|
21
|
-
|
|
22
|
-
The official Superwhisper Pi package (`@superwhisper/pi`) targets the deeplink/macOS flow. If you need the clipboard-based Windows workaround, use this package.
|
|
23
|
-
|
|
24
|
-
## Features
|
|
25
|
-
|
|
26
|
-
- Default-on after the extension loads on Windows.
|
|
27
|
-
- Slash commands: `/sw-paste:on` and `/sw-paste:off`.
|
|
28
|
-
- Windows clipboard polling with active-tab gating.
|
|
29
|
-
- Brief copy-suppression window so local terminal copy actions do not get auto-pasted back into Pi.
|
|
30
|
-
- Clipboard-owner filtering so terminal/CLI-owned clipboard updates stay blocked by default.
|
|
31
|
-
|
|
32
|
-
## Install
|
|
33
|
-
|
|
34
|
-
Install the published npm package with Pi:
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
pi install npm:pi-superwhisper-paste
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Pin a specific version when you want reproducible installs:
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
pi install npm:pi-superwhisper-paste@0.1.
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Install into the current project instead of your user Pi settings:
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
pi install npm:pi-superwhisper-paste -l
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Or install from GitHub:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
pi install git:github.com/eiei114/pi-superwhisper-paste
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Try it without permanently installing:
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
pi -e npm:pi-superwhisper-paste
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Official Superwhisper package
|
|
65
|
-
|
|
66
|
-
If you are using the official Superwhisper Pi integration instead:
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
pi install npm:@superwhisper/pi
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Docs: https://superwhisper.com/pi
|
|
73
|
-
|
|
74
|
-
## Quick start
|
|
75
|
-
|
|
76
|
-
After install, start Pi and dictate with Superwhisper. New Superwhisper clipboard output should auto-paste into the active Pi editor when the bridge is on.
|
|
77
|
-
|
|
78
|
-
Toggle the bridge at runtime:
|
|
79
|
-
|
|
80
|
-
```txt
|
|
81
|
-
/sw-paste:off
|
|
82
|
-
/sw-paste:on
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Try this package locally from a clone:
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
pi -e .
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Package contents
|
|
92
|
-
|
|
93
|
-
| Path | Purpose |
|
|
94
|
-
|---|---|
|
|
95
|
-
| `extensions/index.ts` | Pi TypeScript extension entrypoint |
|
|
96
|
-
| `docs/examples.md` | Usage examples |
|
|
97
|
-
| `docs/release.md` | Trusted Publishing release flow |
|
|
98
|
-
| `docs/template-checklist.md` | Maintainer template checklist |
|
|
99
|
-
| `CHANGELOG.md` | Version history |
|
|
100
|
-
| `LICENSE` | MIT license |
|
|
101
|
-
|
|
102
|
-
## Development
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
npm install
|
|
106
|
-
npm run ci
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
## Release
|
|
110
|
-
|
|
111
|
-
This package is set up for npm Trusted Publishing, so no `NPM_TOKEN` is required.
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
|
-
npm version patch
|
|
115
|
-
git push
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
See [`docs/release.md`](docs/release.md) for setup details.
|
|
119
|
-
|
|
120
|
-
## Security
|
|
121
|
-
|
|
122
|
-
Pi packages can execute code with your local permissions. Review extensions before installing third-party packages.
|
|
123
|
-
|
|
124
|
-
For vulnerability reporting, see [`SECURITY.md`](SECURITY.md).
|
|
125
|
-
|
|
126
|
-
## Links
|
|
127
|
-
|
|
128
|
-
- npm: https://www.npmjs.com/package/pi-superwhisper-paste
|
|
129
|
-
- GitHub: https://github.com/eiei114/pi-superwhisper-paste
|
|
130
|
-
- Issues: https://github.com/eiei114/pi-superwhisper-paste/issues
|
|
131
|
-
- Official Superwhisper Pi package: https://superwhisper.com/pi — `@superwhisper/pi` on npm (`pi install npm:@superwhisper/pi`)
|
|
132
|
-
|
|
133
|
-
## License
|
|
134
|
-
|
|
135
|
-
MIT
|
|
1
|
+
# Pi Superwhisper Paste
|
|
2
|
+
|
|
3
|
+
[](https://discord.gg/4945dXZVW5)
|
|
4
|
+
|
|
5
|
+
[](https://github.com/eiei114/pi-superwhisper-paste/actions/workflows/ci.yml)
|
|
6
|
+
[](https://github.com/eiei114/pi-superwhisper-paste/actions/workflows/publish.yml)
|
|
7
|
+
[](https://www.npmjs.com/package/pi-superwhisper-paste)
|
|
8
|
+
[](https://www.npmjs.com/package/pi-superwhisper-paste)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](https://pi.dev/packages)
|
|
11
|
+
[](docs/release.md)
|
|
12
|
+
<a href="https://buymeacoffee.com/ekawano114m"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" width="217" height="60"></a>
|
|
13
|
+
|
|
14
|
+
> Windows-focused Pi bridge that pastes Superwhisper clipboard output into Pi's TUI editor.
|
|
15
|
+
|
|
16
|
+
## What this is
|
|
17
|
+
|
|
18
|
+
Superwhisper can paste dictated text into normal Windows apps, but terminal TUIs can be a rough edge. In the original case, dictation worked in Notepad and PowerShell, and Typeless worked in Pi, but Superwhisper's automatic paste did not reliably reach Pi's TUI editor without a manual `Ctrl+V`.
|
|
19
|
+
|
|
20
|
+
This package bridges that gap from the Pi side: it watches the Windows clipboard, detects new Superwhisper output, and inserts it into the active Pi editor with Pi's extension API.
|
|
21
|
+
|
|
22
|
+
The official Superwhisper Pi package (`@superwhisper/pi`) targets the deeplink/macOS flow. If you need the clipboard-based Windows workaround, use this package.
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- Default-on after the extension loads on Windows.
|
|
27
|
+
- Slash commands: `/sw-paste:on` and `/sw-paste:off`.
|
|
28
|
+
- Windows clipboard polling with active-tab gating.
|
|
29
|
+
- Brief copy-suppression window so local terminal copy actions do not get auto-pasted back into Pi.
|
|
30
|
+
- Clipboard-owner filtering so terminal/CLI-owned clipboard updates stay blocked by default.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
Install the published npm package with Pi:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pi install npm:pi-superwhisper-paste
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Pin a specific version when you want reproducible installs:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pi install npm:pi-superwhisper-paste@0.1.23
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Install into the current project instead of your user Pi settings:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pi install npm:pi-superwhisper-paste -l
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or install from GitHub:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pi install git:github.com/eiei114/pi-superwhisper-paste
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Try it without permanently installing:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pi -e npm:pi-superwhisper-paste
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Official Superwhisper package
|
|
65
|
+
|
|
66
|
+
If you are using the official Superwhisper Pi integration instead:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pi install npm:@superwhisper/pi
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Docs: https://superwhisper.com/pi
|
|
73
|
+
|
|
74
|
+
## Quick start
|
|
75
|
+
|
|
76
|
+
After install, start Pi and dictate with Superwhisper. New Superwhisper clipboard output should auto-paste into the active Pi editor when the bridge is on.
|
|
77
|
+
|
|
78
|
+
Toggle the bridge at runtime:
|
|
79
|
+
|
|
80
|
+
```txt
|
|
81
|
+
/sw-paste:off
|
|
82
|
+
/sw-paste:on
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Try this package locally from a clone:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pi -e .
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Package contents
|
|
92
|
+
|
|
93
|
+
| Path | Purpose |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `extensions/index.ts` | Pi TypeScript extension entrypoint |
|
|
96
|
+
| `docs/examples.md` | Usage examples |
|
|
97
|
+
| `docs/release.md` | Trusted Publishing release flow |
|
|
98
|
+
| `docs/template-checklist.md` | Maintainer template checklist |
|
|
99
|
+
| `CHANGELOG.md` | Version history |
|
|
100
|
+
| `LICENSE` | MIT license |
|
|
101
|
+
|
|
102
|
+
## Development
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm install
|
|
106
|
+
npm run ci
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Release
|
|
110
|
+
|
|
111
|
+
This package is set up for npm Trusted Publishing, so no `NPM_TOKEN` is required.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npm version patch
|
|
115
|
+
git push
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
See [`docs/release.md`](docs/release.md) for setup details.
|
|
119
|
+
|
|
120
|
+
## Security
|
|
121
|
+
|
|
122
|
+
Pi packages can execute code with your local permissions. Review extensions before installing third-party packages.
|
|
123
|
+
|
|
124
|
+
For vulnerability reporting, see [`SECURITY.md`](SECURITY.md).
|
|
125
|
+
|
|
126
|
+
## Links
|
|
127
|
+
|
|
128
|
+
- npm: https://www.npmjs.com/package/pi-superwhisper-paste
|
|
129
|
+
- GitHub: https://github.com/eiei114/pi-superwhisper-paste
|
|
130
|
+
- Issues: https://github.com/eiei114/pi-superwhisper-paste/issues
|
|
131
|
+
- Official Superwhisper Pi package: https://superwhisper.com/pi — `@superwhisper/pi` on npm (`pi install npm:@superwhisper/pi`)
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
MIT
|
package/docs/examples.md
CHANGED
|
@@ -29,7 +29,7 @@ Run these commands inside Pi's input box:
|
|
|
29
29
|
| `PI_SUPERWHISPER_PASTE_INTERVAL_MS` | `800` | Clipboard polling interval. |
|
|
30
30
|
| `PI_SUPERWHISPER_PASTE_MAX_CHARS` | `8000` | Maximum clipboard text length to paste. |
|
|
31
31
|
| `PI_SUPERWHISPER_PASTE_IGNORE_COPY_MS` | `1500` | Ignore clipboard changes briefly after local terminal copy shortcuts. |
|
|
32
|
-
| `PI_SUPERWHISPER_PASTE_OWNER_DENYLIST` | `windowsterminal
|
|
32
|
+
| `PI_SUPERWHISPER_PASTE_OWNER_DENYLIST` | `windowsterminal, windows terminal, openconsole, wezterm, alacritty, mintty, conhost, cmd.exe, code, powershell, pwsh, bash, cursor, wsl (and .exe variants)` | Comma-separated clipboard owner process/path substrings blocked from auto-paste. |
|
|
33
33
|
|
|
34
34
|
## Expected workflow
|
|
35
35
|
|
package/extensions/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from "node:path";
|
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
7
|
|
|
8
8
|
const execFileAsync = promisify(execFile);
|
|
9
|
-
const EXTENSION_VERSION = "0.1.
|
|
9
|
+
const EXTENSION_VERSION = "0.1.23";
|
|
10
10
|
|
|
11
11
|
const STATUS_KEY = "superwhisper-paste";
|
|
12
12
|
const DEFAULT_INTERVAL_MS = 800;
|
|
@@ -34,6 +34,7 @@ const DEFAULT_OWNER_DENYLIST = [
|
|
|
34
34
|
"wsl",
|
|
35
35
|
];
|
|
36
36
|
const ACTIVE_STATE_FILE = "pi-superwhisper-paste-active.json";
|
|
37
|
+
const ACTIVE_STATE_PATH = join(tmpdir(), ACTIVE_STATE_FILE);
|
|
37
38
|
const FOCUS_IN = "\x1b[I";
|
|
38
39
|
const FOCUS_OUT = "\x1b[O";
|
|
39
40
|
const ENABLE_FOCUS_REPORTING = "\x1b[?1004h";
|
|
@@ -87,8 +88,21 @@ type BridgeState = {
|
|
|
87
88
|
lastClipboard?: string;
|
|
88
89
|
lastPasted?: string;
|
|
89
90
|
lastPasteSummary?: string;
|
|
91
|
+
activeTabCache?: { ok: boolean; checkedAt: number };
|
|
90
92
|
};
|
|
91
93
|
|
|
94
|
+
let cachedOwnerDenylistEnv: string | undefined;
|
|
95
|
+
let cachedOwnerDenylist: readonly string[] | undefined;
|
|
96
|
+
let cachedClipboardScript: { limit: number; script: string } | undefined;
|
|
97
|
+
|
|
98
|
+
type RuntimeConfig = {
|
|
99
|
+
intervalMs: number;
|
|
100
|
+
maxChars: number;
|
|
101
|
+
ignoreCopyMs: number;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
let cachedRuntimeConfig: RuntimeConfig | undefined;
|
|
105
|
+
|
|
92
106
|
const state: BridgeState = {
|
|
93
107
|
mode: defaultMode(),
|
|
94
108
|
generation: 0,
|
|
@@ -101,35 +115,60 @@ function defaultMode(): BridgeMode {
|
|
|
101
115
|
return ["0", "false", "no", "off"].includes(raw) ? "off" : "on";
|
|
102
116
|
}
|
|
103
117
|
|
|
118
|
+
/** Cached poll/copy limits parsed from env (hot path on every interval tick). */
|
|
119
|
+
function runtimeConfig(): RuntimeConfig {
|
|
120
|
+
if (cachedRuntimeConfig) return cachedRuntimeConfig;
|
|
121
|
+
|
|
122
|
+
const parsedInterval = Number(process.env.PI_SUPERWHISPER_PASTE_INTERVAL_MS);
|
|
123
|
+
const parsedMaxChars = Number(process.env.PI_SUPERWHISPER_PASTE_MAX_CHARS);
|
|
124
|
+
const parsedIgnoreCopy = Number(process.env.PI_SUPERWHISPER_PASTE_IGNORE_COPY_MS);
|
|
125
|
+
|
|
126
|
+
cachedRuntimeConfig = {
|
|
127
|
+
intervalMs:
|
|
128
|
+
Number.isFinite(parsedInterval) && parsedInterval > 0 ? parsedInterval : DEFAULT_INTERVAL_MS,
|
|
129
|
+
maxChars:
|
|
130
|
+
Number.isFinite(parsedMaxChars) && parsedMaxChars > 0 ? parsedMaxChars : DEFAULT_MAX_CHARS,
|
|
131
|
+
ignoreCopyMs:
|
|
132
|
+
Number.isFinite(parsedIgnoreCopy) && parsedIgnoreCopy >= 0
|
|
133
|
+
? parsedIgnoreCopy
|
|
134
|
+
: DEFAULT_IGNORE_COPY_MS,
|
|
135
|
+
};
|
|
136
|
+
return cachedRuntimeConfig;
|
|
137
|
+
}
|
|
138
|
+
|
|
104
139
|
/** Poll interval from env or default. */
|
|
105
140
|
function intervalMs(): number {
|
|
106
|
-
|
|
107
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_INTERVAL_MS;
|
|
141
|
+
return runtimeConfig().intervalMs;
|
|
108
142
|
}
|
|
109
143
|
|
|
110
144
|
/** Max pasted characters from env or default. */
|
|
111
145
|
function maxChars(): number {
|
|
112
|
-
|
|
113
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_MAX_CHARS;
|
|
146
|
+
return runtimeConfig().maxChars;
|
|
114
147
|
}
|
|
115
148
|
|
|
116
149
|
/** Ignore clipboard changes briefly after local copy shortcuts. */
|
|
117
150
|
function ignoreCopyMs(): number {
|
|
118
|
-
|
|
119
|
-
return Number.isFinite(parsed) && parsed >= 0 ? parsed : DEFAULT_IGNORE_COPY_MS;
|
|
151
|
+
return runtimeConfig().ignoreCopyMs;
|
|
120
152
|
}
|
|
121
153
|
|
|
122
154
|
/** Process-name/path substrings denied from triggering auto-paste. */
|
|
123
|
-
function ownerDenylist(): string[] {
|
|
124
|
-
const raw = process.env.PI_SUPERWHISPER_PASTE_OWNER_DENYLIST;
|
|
125
|
-
if (
|
|
155
|
+
function ownerDenylist(): readonly string[] {
|
|
156
|
+
const raw = process.env.PI_SUPERWHISPER_PASTE_OWNER_DENYLIST ?? "";
|
|
157
|
+
if (cachedOwnerDenylist && cachedOwnerDenylistEnv === raw) return cachedOwnerDenylist;
|
|
158
|
+
|
|
159
|
+
cachedOwnerDenylistEnv = raw;
|
|
160
|
+
if (!raw) {
|
|
161
|
+
cachedOwnerDenylist = DEFAULT_OWNER_DENYLIST;
|
|
162
|
+
return cachedOwnerDenylist;
|
|
163
|
+
}
|
|
126
164
|
|
|
127
165
|
const tokens = raw
|
|
128
166
|
.split(",")
|
|
129
167
|
.map((token) => token.trim().toLowerCase())
|
|
130
168
|
.filter(Boolean);
|
|
131
169
|
|
|
132
|
-
|
|
170
|
+
cachedOwnerDenylist = tokens.length > 0 ? tokens : DEFAULT_OWNER_DENYLIST;
|
|
171
|
+
return cachedOwnerDenylist;
|
|
133
172
|
}
|
|
134
173
|
|
|
135
174
|
/** Status bar label for the paste bridge. */
|
|
@@ -227,8 +266,17 @@ function markPasted(ctx: PiRuntimeContext, generation: number, text: string): vo
|
|
|
227
266
|
setStatus(ctx, generation);
|
|
228
267
|
}
|
|
229
268
|
|
|
269
|
+
/** Returns a cached PowerShell clipboard script for the current char limit. */
|
|
270
|
+
function clipboardPowerShellCommand(limit: number): string {
|
|
271
|
+
if (cachedClipboardScript?.limit === limit) return cachedClipboardScript.script;
|
|
272
|
+
|
|
273
|
+
const script = buildClipboardPowerShellScript(limit);
|
|
274
|
+
cachedClipboardScript = { limit, script };
|
|
275
|
+
return script;
|
|
276
|
+
}
|
|
277
|
+
|
|
230
278
|
/** Builds a PowerShell command that reads clipboard text truncated to `limit` characters. */
|
|
231
|
-
function
|
|
279
|
+
function buildClipboardPowerShellScript(limit: number): string {
|
|
232
280
|
return [
|
|
233
281
|
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8",
|
|
234
282
|
"$signature = @\"",
|
|
@@ -273,7 +321,7 @@ async function readClipboardSnapshot(): Promise<ClipboardSnapshot | undefined> {
|
|
|
273
321
|
try {
|
|
274
322
|
const result = await execFileAsync(
|
|
275
323
|
"powershell.exe",
|
|
276
|
-
["-NoProfile", "-Command",
|
|
324
|
+
["-NoProfile", "-Command", clipboardPowerShellCommand(limit)],
|
|
277
325
|
{
|
|
278
326
|
encoding: "utf8",
|
|
279
327
|
maxBuffer: limit * 4 + 1024,
|
|
@@ -300,9 +348,9 @@ async function readClipboardSnapshot(): Promise<ClipboardSnapshot | undefined> {
|
|
|
300
348
|
}
|
|
301
349
|
}
|
|
302
350
|
|
|
303
|
-
/**
|
|
304
|
-
function
|
|
305
|
-
|
|
351
|
+
/** Clears cached active-tab ownership between focus or session changes. */
|
|
352
|
+
function invalidateActiveTabCache(): void {
|
|
353
|
+
state.activeTabCache = undefined;
|
|
306
354
|
}
|
|
307
355
|
|
|
308
356
|
/** Writes this Pi instance as the active tab for paste gating. */
|
|
@@ -314,8 +362,11 @@ async function claimActiveTab(): Promise<void> {
|
|
|
314
362
|
};
|
|
315
363
|
|
|
316
364
|
try {
|
|
317
|
-
await writeFile(
|
|
365
|
+
await writeFile(ACTIVE_STATE_PATH, JSON.stringify(claim), "utf8");
|
|
366
|
+
// Cache only negative ownership: a cached positive claim could let another
|
|
367
|
+
// instance's overwrite go unnoticed and paste into an inactive tab.
|
|
318
368
|
} catch {
|
|
369
|
+
invalidateActiveTabCache();
|
|
319
370
|
// Focus tracking is best-effort; clipboard safety still falls back to local focus state.
|
|
320
371
|
}
|
|
321
372
|
}
|
|
@@ -324,10 +375,16 @@ async function claimActiveTab(): Promise<void> {
|
|
|
324
375
|
async function isActiveTab(): Promise<boolean> {
|
|
325
376
|
if (!state.terminalFocused) return false;
|
|
326
377
|
|
|
378
|
+
const now = Date.now();
|
|
379
|
+
const cache = state.activeTabCache;
|
|
380
|
+
if (cache?.ok === false && now - cache.checkedAt < intervalMs()) return false;
|
|
381
|
+
|
|
327
382
|
try {
|
|
328
|
-
const raw = await readFile(
|
|
383
|
+
const raw = await readFile(ACTIVE_STATE_PATH, "utf8");
|
|
329
384
|
const claim = JSON.parse(raw) as { instanceId?: string };
|
|
330
|
-
|
|
385
|
+
const ok = claim.instanceId === INSTANCE_ID;
|
|
386
|
+
state.activeTabCache = ok ? undefined : { ok: false, checkedAt: now };
|
|
387
|
+
return ok;
|
|
331
388
|
} catch {
|
|
332
389
|
await claimActiveTab();
|
|
333
390
|
return true;
|
|
@@ -506,6 +563,7 @@ function setupTerminalFocusTracking(ctx: PiRuntimeContext, generation: number):
|
|
|
506
563
|
|
|
507
564
|
if (data === FOCUS_OUT) {
|
|
508
565
|
state.terminalFocused = false;
|
|
566
|
+
invalidateActiveTabCache();
|
|
509
567
|
setStatus(ctx, generation);
|
|
510
568
|
return { consume: true };
|
|
511
569
|
}
|
|
@@ -551,6 +609,7 @@ function teardownSessionResources(): void {
|
|
|
551
609
|
state.baselineRefreshTimeout = undefined;
|
|
552
610
|
}
|
|
553
611
|
teardownTerminalFocusTracking();
|
|
612
|
+
invalidateActiveTabCache();
|
|
554
613
|
state.inFlightGeneration = undefined;
|
|
555
614
|
state.activatingGeneration = undefined;
|
|
556
615
|
state.suppressPasteUntil = undefined;
|
package/package.json
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pi-superwhisper-paste",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Superwhisper clipboard bridge for Pi on Windows.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"author": "Keisu",
|
|
8
|
-
"keywords": [
|
|
9
|
-
"pi",
|
|
10
|
-
"pi-package",
|
|
11
|
-
"pi-extension",
|
|
12
|
-
"superwhisper",
|
|
13
|
-
"clipboard",
|
|
14
|
-
"windows",
|
|
15
|
-
"typescript"
|
|
16
|
-
],
|
|
17
|
-
"repository": {
|
|
18
|
-
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/eiei114/pi-superwhisper-paste.git"
|
|
20
|
-
},
|
|
21
|
-
"bugs": {
|
|
22
|
-
"url": "https://github.com/eiei114/pi-superwhisper-paste/issues"
|
|
23
|
-
},
|
|
24
|
-
"homepage": "https://github.com/eiei114/pi-superwhisper-paste#readme",
|
|
25
|
-
"files": [
|
|
26
|
-
"extensions/",
|
|
27
|
-
"lib/",
|
|
28
|
-
"skills/",
|
|
29
|
-
"prompts/",
|
|
30
|
-
"themes/",
|
|
31
|
-
"docs/",
|
|
32
|
-
"README.md",
|
|
33
|
-
"LICENSE",
|
|
34
|
-
"CHANGELOG.md"
|
|
35
|
-
],
|
|
36
|
-
"scripts": {
|
|
37
|
-
"typecheck": "tsc --noEmit",
|
|
38
|
-
"test": "node --test tests/*.test.mjs",
|
|
39
|
-
"ci": "npm run typecheck && npm test && npm run pack:check",
|
|
40
|
-
"pack:check": "npm pack --dry-run",
|
|
41
|
-
"version:check": "node scripts/check-version-bump.mjs"
|
|
42
|
-
},
|
|
43
|
-
"pi": {
|
|
44
|
-
"extensions": [
|
|
45
|
-
"./extensions"
|
|
46
|
-
]
|
|
47
|
-
},
|
|
48
|
-
"publishConfig": {
|
|
49
|
-
"access": "public"
|
|
50
|
-
},
|
|
51
|
-
"peerDependencies": {
|
|
52
|
-
"@earendil-works/pi-ai": "*",
|
|
53
|
-
"@earendil-works/pi-coding-agent": "*",
|
|
54
|
-
"@earendil-works/pi-tui": "*"
|
|
55
|
-
},
|
|
56
|
-
"devDependencies": {
|
|
57
|
-
"@earendil-works/pi-ai": "latest",
|
|
58
|
-
"@earendil-works/pi-coding-agent": "latest",
|
|
59
|
-
"@earendil-works/pi-tui": "latest",
|
|
60
|
-
"@types/node": "^26.0.1",
|
|
61
|
-
"typescript": "^7.0.2"
|
|
62
|
-
}
|
|
63
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-superwhisper-paste",
|
|
3
|
+
"version": "0.1.23",
|
|
4
|
+
"description": "Superwhisper clipboard bridge for Pi on Windows.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Keisu",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"pi",
|
|
10
|
+
"pi-package",
|
|
11
|
+
"pi-extension",
|
|
12
|
+
"superwhisper",
|
|
13
|
+
"clipboard",
|
|
14
|
+
"windows",
|
|
15
|
+
"typescript"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/eiei114/pi-superwhisper-paste.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/eiei114/pi-superwhisper-paste/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/eiei114/pi-superwhisper-paste#readme",
|
|
25
|
+
"files": [
|
|
26
|
+
"extensions/",
|
|
27
|
+
"lib/",
|
|
28
|
+
"skills/",
|
|
29
|
+
"prompts/",
|
|
30
|
+
"themes/",
|
|
31
|
+
"docs/",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"CHANGELOG.md"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"typecheck": "tsc --noEmit",
|
|
38
|
+
"test": "node --test tests/*.test.mjs",
|
|
39
|
+
"ci": "npm run typecheck && npm test && npm run pack:check",
|
|
40
|
+
"pack:check": "npm pack --dry-run",
|
|
41
|
+
"version:check": "node scripts/check-version-bump.mjs"
|
|
42
|
+
},
|
|
43
|
+
"pi": {
|
|
44
|
+
"extensions": [
|
|
45
|
+
"./extensions"
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@earendil-works/pi-ai": "*",
|
|
53
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
54
|
+
"@earendil-works/pi-tui": "*"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@earendil-works/pi-ai": "latest",
|
|
58
|
+
"@earendil-works/pi-coding-agent": "latest",
|
|
59
|
+
"@earendil-works/pi-tui": "latest",
|
|
60
|
+
"@types/node": "^26.0.1",
|
|
61
|
+
"typescript": "^7.0.2"
|
|
62
|
+
}
|
|
63
|
+
}
|