sweet-search 2.5.7 → 2.5.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/core/indexing/indexer-utils.js +31 -12
- package/package.json +7 -7
- package/scripts/postinstall-banner.js +42 -20
|
@@ -123,10 +123,10 @@ export function isVerboseMode() {
|
|
|
123
123
|
const BAR_WIDTH = 30;
|
|
124
124
|
const LABEL_COL = 17; // pad "Label:" to this width so every bar's [ ] aligns
|
|
125
125
|
const SUB_BLOCKS = ['', '▏', '▎', '▍', '▌', '▋', '▊', '▉']; // eighth-block partial fills
|
|
126
|
-
const CLEAR_EOL = '\x1b[K';
|
|
127
126
|
const liveBars = new Map(); // label -> { current, total }; insertion order = display order
|
|
128
127
|
let regionLines = 0; // bar lines currently pinned at the bottom (TTY)
|
|
129
128
|
let lastLoggedPercent = {};
|
|
129
|
+
let deferredLogs = []; // lines held back while parallel bars run (flushed on commit)
|
|
130
130
|
|
|
131
131
|
function renderBar(current, total, label) {
|
|
132
132
|
const ratio = total > 0 ? Math.max(0, Math.min(1, current / total)) : 1;
|
|
@@ -140,21 +140,34 @@ function renderBar(current, total, label) {
|
|
|
140
140
|
return `${colors.cyan}${head}[${bar}${empty}] ${pct}% (${current}/${total})${colors.reset}`;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
// (Re)draw the live region in place (the `log-update` pattern). Invariant: the
|
|
144
|
+
// cursor enters and leaves at the END of the last bar line — NO trailing newline
|
|
145
|
+
// — so a redraw never pushes a stale copy of a bar into scrollback. Each redraw
|
|
146
|
+
// moves up to the first region line and erases to end-of-screen (\x1b[J) before
|
|
147
|
+
// rewriting. `aboveLine`, if given, scrolls one permanent line above the bars.
|
|
148
|
+
function regionEscape(aboveLine) {
|
|
149
|
+
const bars = [...liveBars].map(([l, b]) => renderBar(b.current, b.total, l));
|
|
150
|
+
let out = '';
|
|
151
|
+
if (regionLines > 1) out += `\x1b[${regionLines - 1}A`; // up to the first region line
|
|
152
|
+
out += '\r\x1b[J'; // col 0, erase region + everything below
|
|
153
|
+
if (aboveLine != null) out += aboveLine + '\n'; // permanent line above the bars
|
|
154
|
+
out += bars.join('\n'); // bars — no trailing newline
|
|
155
|
+
regionLines = bars.length;
|
|
156
|
+
return out;
|
|
148
157
|
}
|
|
149
158
|
|
|
150
159
|
export function log(message, color = 'reset') {
|
|
151
160
|
if (quietMode) return;
|
|
152
161
|
const line = `${colors[color]}${message}${colors.reset}`;
|
|
153
162
|
if (regionLines > 0 && process.stdout.isTTY) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
163
|
+
if (liveBars.size > 1) {
|
|
164
|
+
// Parallel bars live: defer the line so it can't disturb the region. Any
|
|
165
|
+
// mid-region print scrolls a stale bar-pair into scrollback. Flushed once
|
|
166
|
+
// every bar in the region finishes.
|
|
167
|
+
deferredLogs.push(line);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
process.stdout.write(regionEscape(line)); // single bar: line above, bar redrawn below
|
|
158
171
|
} else {
|
|
159
172
|
console.log(line);
|
|
160
173
|
}
|
|
@@ -172,16 +185,22 @@ export function logProgress(current, total, label) {
|
|
|
172
185
|
}
|
|
173
186
|
return;
|
|
174
187
|
}
|
|
175
|
-
// Interactive TTY: update this bar in the live region and redraw.
|
|
188
|
+
// Interactive TTY: update this bar in the live region and redraw in place.
|
|
176
189
|
liveBars.set(label, { current, total });
|
|
177
|
-
|
|
190
|
+
process.stdout.write(regionEscape());
|
|
178
191
|
// Once every live bar is complete, commit the region (leave it on screen).
|
|
179
192
|
let allDone = true;
|
|
180
193
|
for (const b of liveBars.values()) if (b.current < b.total) { allDone = false; break; }
|
|
181
194
|
if (allDone) {
|
|
195
|
+
process.stdout.write('\n'); // move below the finished bars (cursor was at their end)
|
|
182
196
|
for (const k of liveBars.keys()) lastLoggedPercent[k] = 0;
|
|
183
197
|
liveBars.clear();
|
|
184
198
|
regionLines = 0;
|
|
199
|
+
// Flush lines deferred while parallel bars ran — now below the finished bars.
|
|
200
|
+
if (deferredLogs.length) {
|
|
201
|
+
for (const l of deferredLogs) console.log(l);
|
|
202
|
+
deferredLogs = [];
|
|
203
|
+
}
|
|
185
204
|
}
|
|
186
205
|
}
|
|
187
206
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sweet-search",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.9",
|
|
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.
|
|
167
|
-
"@sweet-search/native-darwin-x64": "2.5.
|
|
168
|
-
"@sweet-search/native-linux-arm64-gnu": "2.5.
|
|
169
|
-
"@sweet-search/native-linux-arm64-gnu-cuda": "2.5.
|
|
170
|
-
"@sweet-search/native-linux-x64-gnu": "2.5.
|
|
171
|
-
"@sweet-search/native-linux-x64-gnu-cuda": "2.5.
|
|
166
|
+
"@sweet-search/native-darwin-arm64": "2.5.9",
|
|
167
|
+
"@sweet-search/native-darwin-x64": "2.5.9",
|
|
168
|
+
"@sweet-search/native-linux-arm64-gnu": "2.5.9",
|
|
169
|
+
"@sweet-search/native-linux-arm64-gnu-cuda": "2.5.9",
|
|
170
|
+
"@sweet-search/native-linux-x64-gnu": "2.5.9",
|
|
171
|
+
"@sweet-search/native-linux-x64-gnu-cuda": "2.5.9"
|
|
172
172
|
},
|
|
173
173
|
"engines": {
|
|
174
174
|
"node": ">=18.0.0"
|
|
@@ -2,33 +2,55 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* postinstall — print a short "what next" message after install.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
+
// SWEET SEARCH half-block wordmark (kept in sync with core/search/cli-decoration.js).
|
|
33
|
+
const L1 = '█▀▀ █ █ █ █▀▀ █▀▀ ▀█▀ █▀▀ █▀▀ ▄▀▄ █▀▄ █▀▀ █▄█';
|
|
34
|
+
const L2 = '▄▄█ ▀▄█▄▀ ██▄ ██▄ █ ▄▄█ ██▄ █▀█ ██▄ █▄▄ █▀█';
|
|
35
|
+
const msg = [
|
|
36
|
+
'',
|
|
37
|
+
` ${c('1;38;5;213', L1)}`,
|
|
38
|
+
` ${c('1;38;5;213', L2)}`,
|
|
39
|
+
'',
|
|
40
|
+
` ${c('1', 'Get started:')}`,
|
|
41
|
+
` ${c('36', 'sweet-search init')} set up the current project`,
|
|
42
|
+
` ${c('36', 'sweet-search index')} build the search index`,
|
|
43
|
+
` ${c('36', 'sweet-search "query"')} search your code`,
|
|
44
|
+
` ${c('2', '(installed locally? prefix with')} ${c('2;36', 'npx')}${c('2', ')')}`,
|
|
45
|
+
'',
|
|
46
|
+
'',
|
|
47
|
+
].join('\n');
|
|
48
|
+
|
|
17
49
|
try {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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 */ }
|
|
50
|
+
if (useStdout) process.stdout.write(msg);
|
|
51
|
+
else { writeSync(fd, msg); }
|
|
52
|
+
} catch { /* best-effort */ }
|
|
53
|
+
finally { if (fd >= 0) { try { closeSync(fd); } catch { /* noop */ } } }
|
|
32
54
|
}
|
|
33
55
|
|
|
34
56
|
run();
|