termdock 1.4.193 → 1.4.194

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.
@@ -1,4 +1,4 @@
1
- import { buildBracketedSubmitBytes } from './promptDelivery.js';
1
+ import { normalizePromptForPaste } from './promptDelivery.js';
2
2
  const TMUX_KEY_NAMES = {
3
3
  enter: 'Enter', escape: 'Escape', space: 'Space', left: 'Left', right: 'Right', up: 'Up', down: 'Down',
4
4
  };
@@ -54,12 +54,28 @@ export async function writeCollaborationTmuxPane(run, pane, prompt) {
54
54
  // than `send-keys -l`: while a pane is in copy-mode, literal bytes are
55
55
  // routed to the mode's key table (they scroll or do nothing) and never
56
56
  // reach the app, whereas paste-buffer writes into the pty regardless of
57
- // mode and leaves the mode and scroll position untouched. paste-buffer
58
- // does not bracket on its own, so the payload carries its own
59
- // `\x1b[200~ \x1b[201~` wrapper plus the submitting CR.
57
+ // mode and leaves the mode and scroll position untouched.
58
+ //
59
+ // The bracketed-paste wrapper is left to tmux (-p) instead of riding in the
60
+ // payload. tmux adds the pair exactly when the application has bracketed
61
+ // paste on and adds nothing when it does not — so an agent TUI sees one
62
+ // paste while a plain shell sees clean text — and the marker bytes never
63
+ // enter the buffer, where tmux 3.7+ would run them through vis(3) and land
64
+ // a literal `^[` in the pane instead of a control byte. The same vis pass
65
+ // is why the body must carry no ESC: escape bytes are exactly what it
66
+ // rewrites, and an ESC-free body makes the pass a byte-for-byte no-op on
67
+ // every tmux version.
60
68
  const buffer = `termdock-collab-${process.pid}-${bufferSequence++}`;
61
69
  try {
62
- await run(['set-buffer', '-b', buffer, '--', buildBracketedSubmitBytes(prompt)]);
70
+ await run(['set-buffer', '-b', buffer, '--', normalizePromptForPaste(prompt)]);
71
+ // -r keeps LF as LF rather than the separator default of CR. The
72
+ // normalizer already folded every line break to CR, so no LF is left for
73
+ // it to rewrite — the flag is insurance, not the mechanism.
74
+ await run(['paste-buffer', '-p', '-r', '-d', '-b', buffer, '-t', pane.paneId]);
75
+ // The submit key rides outside the paste block: inside it, an editor
76
+ // inserts a pasted CR as text instead of acting on it. Pasting the bare
77
+ // CR (no -p) keeps the key in the same mode-proof channel as the text.
78
+ await run(['set-buffer', '-b', buffer, '--', '\r']);
63
79
  await run(['paste-buffer', '-d', '-b', buffer, '-t', pane.paneId]);
64
80
  }
65
81
  finally {
@@ -1,12 +1,20 @@
1
+ /**
2
+ * Fold a prompt into the single-channel form both tmux and agent TUIs expect:
3
+ * every line break becomes one CR (commits a line inside the editor, and is
4
+ * never a paste-end candidate), and a raw ESC becomes the visible ␛ glyph so
5
+ * no byte sequence in the body can be mistaken for terminal control — notably
6
+ * not our own bracketed-paste markers.
7
+ */
8
+ export function normalizePromptForPaste(prompt) {
9
+ return prompt.replace(/\r\n|\r|\n/g, '\r').replace(/\x1b/g, '␛');
10
+ }
1
11
  /**
2
12
  * Encode a prompt as one bracketed-paste block followed by one real Enter.
3
13
  * Agent TUIs then keep embedded newlines inside the editor instead of treating
4
14
  * each line as a separate submission.
5
15
  */
6
16
  export function buildBracketedSubmitBytes(prompt) {
7
- const normalized = prompt.replace(/\r\n|\r|\n/g, '\r');
8
- const escaped = normalized.replace(/\x1b/g, '␛');
9
- return `\x1b[200~${escaped}\x1b[201~\r`;
17
+ return `\x1b[200~${normalizePromptForPaste(prompt)}\x1b[201~\r`;
10
18
  }
11
19
  /**
12
20
  * Process detection and hook events are independent Agent signals. A target is
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termdock",
3
- "version": "1.4.193",
3
+ "version": "1.4.194",
4
4
  "description": "A complete web-based terminal application with modern UI",
5
5
  "type": "module",
6
6
  "main": ".desktop-dist/main.js",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "packageName": "termdock",
4
- "version": "1.4.193",
4
+ "version": "1.4.194",
5
5
  "runtimeProtocolVersion": 1,
6
6
  "minimumDesktopVersion": "1.4.46",
7
7
  "nodeMajor": 22,
8
8
  "dependencyHash": "sha256-K4KyYJuVoQDpZsBM8ZX1Rw3MddOxAzVdp/cPm0iGZz0=",
9
- "serverBundleHash": "sha256-grEE01C40LqZFNdPE78QJXxG3gYtDw6ADT1aW+lm58I=",
9
+ "serverBundleHash": "sha256-2Y3XSbsDOzYXhEe57Szt3L16aZzGBDb1ZA/6TsYIiOQ=",
10
10
  "clientBundleHash": "sha256-wpGsT/oJup/G4MyJSKqpHBJlzc2Ha3wFIWmtp4vc/Wc=",
11
11
  "entrypoint": "dist/server/cli.js",
12
12
  "clientEntrypoint": "dist/client/index.html"