@levu/snap 0.3.4 → 0.3.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/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.5] - 2026-02-26
9
+
10
+ ### Fixed
11
+ - Added an additional Ghostty/macOS fallback for `Shift+Enter` when emitted as plain `1`, `3`, `~` keypress chars (no modifier metadata).
12
+ - Added submit-time sanitation of residual Ghostty shift-enter tokens (`13~`, related escape variants) so pasted/echoed artifacts become real newlines in multiline prompts.
13
+ - Added regression coverage for plain-char `13~` keypress and residual token sanitation.
14
+
8
15
  ## [0.3.4] - 2026-02-26
9
16
 
10
17
  ### Fixed
@@ -98,6 +98,12 @@ export const createMultilineTextPrompt = () => {
98
98
  }
99
99
  return null;
100
100
  };
101
+ const normalizeGhosttyInlineTokens = (raw) => {
102
+ return raw.replace(/(?:\u001b\[13;2u|\[13;2u|\u001b\[27;2;13~|\[27;2;13~|13~|~13)/g, '\n');
103
+ };
104
+ const buildSubmitValue = () => {
105
+ return normalizeGhosttyInlineTokens(lines.concat(getLiveLine()).join('\n'));
106
+ };
101
107
  const insertNewline = () => {
102
108
  lines.push(getLiveLine());
103
109
  currentLine = '';
@@ -171,7 +177,7 @@ export const createMultilineTextPrompt = () => {
171
177
  const now = Date.now();
172
178
  // Check for double Enter to submit
173
179
  if (line === '' && now - lastEnterTime < DOUBLE_ENTER_TIMEOUT) {
174
- submit(lines.concat(getLiveLine()).join('\n'));
180
+ submit(buildSubmitValue());
175
181
  return;
176
182
  }
177
183
  lastEnterTime = now;
@@ -210,6 +216,20 @@ export const createMultilineTextPrompt = () => {
210
216
  keypressListener = async (str, key) => {
211
217
  if (cancelled)
212
218
  return;
219
+ // Some terminals emit Shift+Enter as literal chars "13~" with no key metadata.
220
+ // Readline may already have appended those chars into rl.line by the time we run.
221
+ if (!key?.ctrl && !key?.meta && key?.name !== 'enter' && key?.name !== 'return') {
222
+ const strippedLive = stripGhosttyShiftEnterSuffix(String(rl.line ?? ''));
223
+ if (strippedLive !== null) {
224
+ lines.push(strippedLive);
225
+ currentLine = '';
226
+ rl.line = '';
227
+ output.write('\r' + ' '.repeat(process.stdout.columns || 80) + '\r');
228
+ output.write(`${pc.dim('> ')}${strippedLive}`);
229
+ output.write(`\n${pc.dim('> ')}`);
230
+ return;
231
+ }
232
+ }
213
233
  // Detect Ctrl+V or Cmd+V for paste
214
234
  if ((key.ctrl && key.name === 'v') || (key.meta && key.name === 'v')) {
215
235
  const pasted = await handlePaste();
@@ -241,7 +261,7 @@ export const createMultilineTextPrompt = () => {
241
261
  insertNewline();
242
262
  return;
243
263
  }
244
- submit(lines.concat(getLiveLine()).join('\n'));
264
+ submit(buildSubmitValue());
245
265
  }
246
266
  else if (key.name === 'escape') {
247
267
  doCancel();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@levu/snap",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "snap": "./dist/cli-entry.js"