@levu/snap 0.3.8 → 0.3.9
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
|
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.3.9] - 2026-02-28
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Added multiline paste recovery for cases where readline submit flow only exposes the last pasted line.
|
|
12
|
+
- Recovery now uses recent raw paste chunks to reconstruct full multi-line content when the submit payload is unexpectedly single-line.
|
|
13
|
+
- Added regression coverage for the “last line only after multiline paste” scenario.
|
|
14
|
+
|
|
8
15
|
## [0.3.8] - 2026-02-26
|
|
9
16
|
|
|
10
17
|
### Fixed
|
|
@@ -36,6 +36,8 @@ export const createMultilineTextPrompt = () => {
|
|
|
36
36
|
let pendingEnterSubmit = false;
|
|
37
37
|
let pendingEnterSubmitTimer;
|
|
38
38
|
let recentPasteBurstUntil = 0;
|
|
39
|
+
let sawPasteLikeRawInput = false;
|
|
40
|
+
let recentPasteRawBuffer = '';
|
|
39
41
|
const cleanup = () => {
|
|
40
42
|
if (pendingEnterSubmitTimer) {
|
|
41
43
|
clearTimeout(pendingEnterSubmitTimer);
|
|
@@ -114,8 +116,35 @@ export const createMultilineTextPrompt = () => {
|
|
|
114
116
|
const normalizeGhosttyInlineTokens = (raw) => {
|
|
115
117
|
return raw.replace(/(?:\u001b\[13;2u|\[13;2u|\u001b\[27;2;13~|\[27;2;13~|13~|~13)/g, '\n');
|
|
116
118
|
};
|
|
119
|
+
const stripAnsiControls = (raw) => {
|
|
120
|
+
return String(raw || '')
|
|
121
|
+
.replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g, '')
|
|
122
|
+
.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, '');
|
|
123
|
+
};
|
|
124
|
+
const recoverMultilineFromRawPaste = (primary) => {
|
|
125
|
+
if (!sawPasteLikeRawInput)
|
|
126
|
+
return '';
|
|
127
|
+
if (primary.includes('\n'))
|
|
128
|
+
return '';
|
|
129
|
+
if (!recentPasteRawBuffer)
|
|
130
|
+
return '';
|
|
131
|
+
const recoveredLines = stripAnsiControls(recentPasteRawBuffer)
|
|
132
|
+
.replace(/\r/g, '\n')
|
|
133
|
+
.split('\n')
|
|
134
|
+
.map((line) => line.trim())
|
|
135
|
+
.filter(Boolean);
|
|
136
|
+
if (recoveredLines.length < 2)
|
|
137
|
+
return '';
|
|
138
|
+
const normalizedPrimary = String(primary || '').trim();
|
|
139
|
+
const recoveredLastLine = recoveredLines[recoveredLines.length - 1] || '';
|
|
140
|
+
if (normalizedPrimary && recoveredLastLine !== normalizedPrimary)
|
|
141
|
+
return '';
|
|
142
|
+
return recoveredLines.join('\n');
|
|
143
|
+
};
|
|
117
144
|
const buildSubmitValue = () => {
|
|
118
|
-
|
|
145
|
+
const primary = normalizeGhosttyInlineTokens(lines.concat(getLiveLine()).join('\n'));
|
|
146
|
+
const recovered = recoverMultilineFromRawPaste(primary);
|
|
147
|
+
return recovered || primary;
|
|
119
148
|
};
|
|
120
149
|
const absorbLine = (line) => {
|
|
121
150
|
if (line.trim() === '') {
|
|
@@ -143,6 +172,7 @@ export const createMultilineTextPrompt = () => {
|
|
|
143
172
|
const BRACKET_PASTE_END = '\u001b[201~';
|
|
144
173
|
const BRACKET_PASTE_PROBE_MAX = 96;
|
|
145
174
|
const PASTE_BURST_WINDOW_MS = 70;
|
|
175
|
+
const RAW_PASTE_BUFFER_MAX = 8192;
|
|
146
176
|
const updateBracketPasteState = (chunk) => {
|
|
147
177
|
if (!chunk)
|
|
148
178
|
return;
|
|
@@ -173,6 +203,8 @@ export const createMultilineTextPrompt = () => {
|
|
|
173
203
|
// In raw mode, normal typing usually arrives as single-byte chunks.
|
|
174
204
|
// Multi-byte chunks and newlines are strong signals that input is a paste burst.
|
|
175
205
|
if (normalized.length > 1 || /[\r\n]/.test(normalized)) {
|
|
206
|
+
sawPasteLikeRawInput = true;
|
|
207
|
+
recentPasteRawBuffer = `${recentPasteRawBuffer}${normalized}`.slice(-RAW_PASTE_BUFFER_MAX);
|
|
176
208
|
recentPasteBurstUntil = Math.max(recentPasteBurstUntil, Date.now() + PASTE_BURST_WINDOW_MS);
|
|
177
209
|
}
|
|
178
210
|
};
|