sweet-search 2.5.7 → 2.5.8

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.
@@ -127,6 +127,7 @@ const CLEAR_EOL = '\x1b[K';
127
127
  const liveBars = new Map(); // label -> { current, total }; insertion order = display order
128
128
  let regionLines = 0; // bar lines currently pinned at the bottom (TTY)
129
129
  let lastLoggedPercent = {};
130
+ let deferredLogs = []; // lines held back while parallel bars run (flushed on commit)
130
131
 
131
132
  function renderBar(current, total, label) {
132
133
  const ratio = total > 0 ? Math.max(0, Math.min(1, current / total)) : 1;
@@ -151,7 +152,15 @@ export function log(message, color = 'reset') {
151
152
  if (quietMode) return;
152
153
  const line = `${colors[color]}${message}${colors.reset}`;
153
154
  if (regionLines > 0 && process.stdout.isTTY) {
154
- // Print the line above the pinned bars, then redraw the bars below it.
155
+ if (liveBars.size > 1) {
156
+ // Parallel bars are live: defer the line. Printing it now would scroll the
157
+ // region and freeze a duplicate bar-pair into scrollback (e.g. the "✓ Late
158
+ // interaction index built" line when LI finishes before Embedding). Flushed
159
+ // once every bar in the region completes.
160
+ deferredLogs.push(line);
161
+ return;
162
+ }
163
+ // Single bar: print the line above it, then redraw the bar below.
155
164
  let out = `\x1b[${regionLines}A\r${line}${CLEAR_EOL}\n`;
156
165
  for (const [label, b] of liveBars) out += renderBar(b.current, b.total, label) + CLEAR_EOL + '\n';
157
166
  process.stdout.write(out);
@@ -182,6 +191,12 @@ export function logProgress(current, total, label) {
182
191
  for (const k of liveBars.keys()) lastLoggedPercent[k] = 0;
183
192
  liveBars.clear();
184
193
  regionLines = 0;
194
+ // Flush any lines deferred while the parallel bars were running — now below
195
+ // the finished bars, in arrival order.
196
+ if (deferredLogs.length) {
197
+ for (const l of deferredLogs) console.log(l);
198
+ deferredLogs = [];
199
+ }
185
200
  }
186
201
  }
187
202
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sweet-search",
3
- "version": "2.5.7",
3
+ "version": "2.5.8",
4
4
  "description": "Sweet Search - SOTA Hybrid Code Search Engine with WASM CatBoost Query Router, Semantic/Lexical/Structural Search, and Multilingual Support",
5
5
  "type": "module",
6
6
  "main": "core/search/sweet-search.js",
@@ -163,12 +163,12 @@
163
163
  },
164
164
  "optionalDependencies": {
165
165
  "usearch": "^2.21.4",
166
- "@sweet-search/native-darwin-arm64": "2.5.7",
167
- "@sweet-search/native-darwin-x64": "2.5.7",
168
- "@sweet-search/native-linux-arm64-gnu": "2.5.7",
169
- "@sweet-search/native-linux-arm64-gnu-cuda": "2.5.7",
170
- "@sweet-search/native-linux-x64-gnu": "2.5.7",
171
- "@sweet-search/native-linux-x64-gnu-cuda": "2.5.7"
166
+ "@sweet-search/native-darwin-arm64": "2.5.8",
167
+ "@sweet-search/native-darwin-x64": "2.5.8",
168
+ "@sweet-search/native-linux-arm64-gnu": "2.5.8",
169
+ "@sweet-search/native-linux-arm64-gnu-cuda": "2.5.8",
170
+ "@sweet-search/native-linux-x64-gnu": "2.5.8",
171
+ "@sweet-search/native-linux-x64-gnu-cuda": "2.5.8"
172
172
  },
173
173
  "engines": {
174
174
  "node": ">=18.0.0"
@@ -2,33 +2,51 @@
2
2
  /**
3
3
  * postinstall — print a short "what next" message after install.
4
4
  *
5
- * Deliberately plain text: during `npm install` npm writes its own progress
6
- * spinner to the terminal CONCURRENTLY with this script, which would interrupt
7
- * any graphics/animation escape sequence mid-stream and leak its payload as
8
- * garbage text. So the rich animated banner is reserved for `sweet-search init`
9
- * and `sweet-search index` (where we own the TTY); install just prints a clean,
10
- * escape-light pointer. Best-effort; always exits 0 so it can't fail an install.
5
+ * npm pipes postinstall stdout (and swallows it for `-g`), so we write to the
6
+ * controlling terminal (/dev/tty) directly same reason the message vanished
7
+ * when we used process.stdout. It is deliberately PLAIN TEXT (no graphics /
8
+ * animation): during `npm install` npm writes its own spinner to the same
9
+ * terminal concurrently, which would corrupt a large chunked escape sequence
10
+ * (the base64 garbage we saw) a short text line is atomic and safe. The rich
11
+ * animated banner is reserved for `sweet-search init` / `index`, where we own
12
+ * the TTY. Best-effort; never throws.
11
13
  */
12
14
  import process from 'node:process';
15
+ import { openSync, writeSync, closeSync } from 'node:fs';
13
16
 
14
17
  function run() {
15
18
  const env = process.env;
16
19
  if (env.NO_BANNER || env.SWEET_SEARCH_NO_BANNER) return;
20
+
21
+ // Choose a real-terminal sink: stdout if it's already a TTY (foreground
22
+ // scripts), otherwise the controlling terminal. Windows has no /dev/tty →
23
+ // the banner shows on `init`/`index` instead.
24
+ let fd = -1;
25
+ const useStdout = !!process.stdout.isTTY;
26
+ if (!useStdout) {
27
+ if (process.platform === 'win32') return;
28
+ try { fd = openSync('/dev/tty', 'w'); } catch { return; } // no controlling terminal → skip
29
+ }
30
+
31
+ const c = (n, s) => `\x1b[${n}m${s}\x1b[0m`;
32
+ const msg = [
33
+ '',
34
+ ` ${c('1;38;5;213', 'sweet-search')} installed ${c('2', '— SOTA hybrid code search')}`,
35
+ '',
36
+ ` ${c('1', 'Get started:')}`,
37
+ ` ${c('36', 'sweet-search init')} set up the current project`,
38
+ ` ${c('36', 'sweet-search index')} build the search index`,
39
+ ` ${c('36', 'sweet-search "query"')} search your code`,
40
+ ` ${c('2', '(installed locally? prefix with')} ${c('2;36', 'npx')}${c('2', ')')}`,
41
+ '',
42
+ '',
43
+ ].join('\n');
44
+
17
45
  try {
18
- const c = (n, s) => (process.stdout.isTTY ? `\x1b[${n}m${s}\x1b[0m` : s);
19
- const lines = [
20
- '',
21
- ` ${c('1;38;5;213', 'sweet-search')} installed ${c('2', '— SOTA hybrid code search')}`,
22
- '',
23
- ` ${c('1', 'Get started:')}`,
24
- ` ${c('36', 'sweet-search init')} set up the current project`,
25
- ` ${c('36', 'sweet-search index')} build the search index`,
26
- ` ${c('36', 'sweet-search "query"')} search your code`,
27
- ` ${c('2', '(installed locally? prefix with')} ${c('2;36', 'npx')}${c('2', ', e.g. `npx sweet-search init`)')}`,
28
- '',
29
- ];
30
- process.stdout.write(lines.join('\n') + '\n');
31
- } catch { /* never break an install */ }
46
+ if (useStdout) process.stdout.write(msg);
47
+ else { writeSync(fd, msg); }
48
+ } catch { /* best-effort */ }
49
+ finally { if (fd >= 0) { try { closeSync(fd); } catch { /* noop */ } } }
32
50
  }
33
51
 
34
52
  run();