scripter-x 1.0.35 → 1.0.38

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scripter-x",
3
- "version": "1.0.35",
3
+ "version": "1.0.38",
4
4
  "description": "ScripterX — local Flipkart session extractor (runs on your residential IP, syncs to marthunt)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -37,6 +37,9 @@ export function FullScreen({ children }) {
37
37
  // We register restore on exit + the kill signals so it runs no matter how we leave.
38
38
  export function enterAltScreen() {
39
39
  process.stdout.write('\x1b[?1049h'); // switch to alternate buffer
40
+ process.stdout.write('\x1b[r'); // reset scroll region to full screen (in case a prior
41
+ // session — e.g. an update-restart — left DECSTBM set,
42
+ // which would push our output to the bottom of the screen)
40
43
  process.stdout.write('\x1b[2J\x1b[H'); // clear + home
41
44
  process.stdout.write('\x1b[?25l'); // hide cursor (we draw our own ▏)
42
45
  let restored = false;
@@ -44,7 +47,10 @@ export function enterAltScreen() {
44
47
  if (restored) return;
45
48
  restored = true;
46
49
  try {
47
- process.stdout.write('\x1b[?1000l\x1b[?1003l\x1b[?1006l'); // disable ALL mouse modes
50
+ process.stdout.write('\x1b[?1000l\x1b[?1003l\x1b[?1006l\x1b[?1015l'); // disable ALL mouse modes
51
+ process.stdout.write('\x1b[?2004l'); // disable bracketed-paste
52
+ process.stdout.write('\x1b[r'); // reset scroll region (so typed text isn't stuck at the bottom)
53
+ process.stdout.write('\x1b[?7h'); // restore line wrap
48
54
  process.stdout.write('\x1b[?25h'); // show cursor
49
55
  process.stdout.write('\x1b[?1049l'); // back to normal buffer (history intact)
50
56
  } catch { /* */ }
package/src/update.js CHANGED
@@ -95,10 +95,18 @@ function npmCliPath() {
95
95
  function resetTerminal() {
96
96
  try {
97
97
  if (process.stdout.isTTY) {
98
- // disable button/motion/SGR mouse modes (the source of the coordinate-code garbage)
99
- process.stdout.write('\x1b[?1000l\x1b[?1003l\x1b[?1006l');
100
- process.stdout.write('\x1b[?25h'); // show cursor
101
- process.stdout.write('\x1b[?1049l'); // leave alt-screen → normal buffer
98
+ // Order matters. We must undo EVERY terminal mode the ink/fullscreen UI set, not just
99
+ // mouse + alt-screen — a leftover scroll region (DECSTBM) or bracketed-paste mode makes
100
+ // typed characters land at the bottom of the screen instead of at the prompt.
101
+ const w = (s) => process.stdout.write(s);
102
+ w('\x1b[?1000l\x1b[?1003l\x1b[?1006l\x1b[?1015l'); // disable ALL mouse modes
103
+ w('\x1b[?2004l'); // disable bracketed-paste mode
104
+ w('\x1b[r'); // reset scroll region (DECSTBM) to the full screen ← the bottom-text fix
105
+ w('\x1b[?7h'); // re-enable line wrap (autowrap)
106
+ w('\x1b[0m'); // reset SGR (colors/attrs)
107
+ w('\x1b[?1049l'); // leave alt-screen → normal buffer (history intact)
108
+ w('\x1b[?25h'); // show cursor
109
+ w('\x1b[!p'); // DECSTR: soft terminal reset (restores sane default modes)
102
110
  }
103
111
  } catch { /* */ }
104
112
  try {
@@ -113,53 +121,55 @@ function resetTerminal() {
113
121
  } catch { /* */ }
114
122
  }
115
123
 
116
- // Re-exec the CLI so the just-installed version takes over. Spawns a fresh, DETACHED
117
- // process that inherits this terminal, then exits the current one. The caller MUST have
118
- // already torn down the ink/alt-screen UI before calling this.
124
+ // Re-exec the CLI so the just-installed version takes over, keeping the SAME controlling
125
+ // terminal so input goes to the new process not back to the shell.
119
126
  //
120
- // We re-run the CURRENT entry file with node (`process.argv[1]`): after `npm install -g`,
121
- // the global bin symlink points at the new version, so this loads the updated code. If
122
- // that entry path is somehow missing, we fall back to the `scripterx` bin on PATH.
127
+ // THE BUG this fixes: the old code spawned the child with `detached:true` + `child.unref()`,
128
+ // which puts the child in its OWN session and RELINQUISHES the controlling TTY. The child
129
+ // then can't be the foreground job, so the user's shell (zsh) stays in the foreground and
130
+ // echoes every keystroke at the bottom of the screen, while the orphaned child renders the
131
+ // banner in the background. That's exactly the "typing shows at the bottom" symptom.
123
132
  //
124
- // ORDERING is what makes the restart clean: we resetTerminal() FIRST (cooked TTY, mouse off,
125
- // stdin drained), THEN spawn the child, THEN exit immediately on the next tick. The child
126
- // only sets up raw mode / mouse tracking after it boots by which point the parent is gone,
127
- // so the two never fight over the TTY. No more leaked keystrokes.
133
+ // Correct pattern for a TTY hand-off: spawn the child ATTACHED (not detached, no unref) with
134
+ // inherited stdio, and keep THIS process alive as its parent until it exits, then mirror its
135
+ // exit code. The child is a normal foreground job sharing our controlling terminal, so it
136
+ // owns stdin and raw mode works. We reset the terminal first so it boots onto a clean screen.
128
137
  //
129
- // NOTE: on success it exits the process and never returns. Returns false only if BOTH
130
- // spawn attempts throw synchronously, so the caller can show "restart manually".
138
+ // We re-run the CURRENT entry file with node (`process.argv[1]`): after `npm install -g`, the
139
+ // global bin symlink points at the new version, so this loads the updated code; if that entry
140
+ // path is missing we fall back to the `scripterx` bin on PATH.
141
+ //
142
+ // NOTE: on success this never returns (it waits, then process.exit mirrors the child). Returns
143
+ // false only if BOTH spawn attempts throw synchronously.
131
144
  export function restartCli({ binName = 'scripterx' } = {}) {
132
- // Re-run with the SAME args the user launched with (drop node + the script path), so
133
- // `scripterx` → interactive shell, `scripterx zepto` → zepto, etc.
134
145
  const argv = process.argv.slice(2);
135
146
  const entry = process.argv[1];
136
147
 
137
- // Clean the terminal BEFORE spawning so the child never inherits raw mode / mouse mode.
148
+ // Clean the terminal BEFORE spawning so the child boots onto a clean, cooked screen.
138
149
  resetTerminal();
139
150
 
140
- const trySpawn = (cmd, args) => {
141
- const child = spawn(cmd, args, { stdio: 'inherit', detached: true, shell: false });
142
- child.unref();
143
- return child;
144
- };
151
+ // ATTACHED spawn: child shares our controlling TTY and becomes the foreground job. We keep
152
+ // running as its parent and exit with its code when it finishes — so the shell prompt only
153
+ // returns after the (new) CLI actually quits.
154
+ const trySpawn = (cmd, args) => spawn(cmd, args, { stdio: 'inherit', shell: false });
145
155
 
146
- const exitSoon = () => {
147
- // Exit on the next tick (not after a long timer) so we don't linger on the TTY. The
148
- // detached child has already inherited the (now clean) fds and takes over.
149
- setImmediate(() => process.exit(0));
156
+ const supervise = (child) => {
157
+ child.on('exit', (code, signal) => {
158
+ if (signal) { try { process.kill(process.pid, signal); } catch { process.exit(1); } }
159
+ else process.exit(code == null ? 0 : code);
160
+ });
150
161
  };
151
162
 
152
163
  try {
153
164
  const primary = trySpawn(process.execPath, [entry, ...argv]);
154
165
  primary.on('error', () => {
155
- try { trySpawn(binName, argv); } catch { /* nothing more we can do */ }
166
+ try { supervise(trySpawn(binName, argv)); } catch { process.exit(1); }
156
167
  });
157
- exitSoon();
168
+ supervise(primary);
158
169
  return true;
159
170
  } catch {
160
171
  try {
161
- trySpawn(binName, argv);
162
- exitSoon();
172
+ supervise(trySpawn(binName, argv));
163
173
  return true;
164
174
  } catch {
165
175
  return false;