termsearch 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/bin/termsearch.js +40 -2
- package/frontend/dist/app.js +37 -5
- package/frontend/dist/style.css +2 -3
- package/package.json +1 -1
- package/scripts/postinstall.js +8 -2
package/bin/termsearch.js
CHANGED
|
@@ -209,7 +209,7 @@ async function cmdStart(flags) {
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
writeFileSync(paths.pid, String(child.pid));
|
|
212
|
-
ok(`
|
|
212
|
+
ok(`TermSearch v${VERSION} started (PID ${child.pid})`);
|
|
213
213
|
info(`${BOLD}${getUrl()}${RESET}`);
|
|
214
214
|
info(`Logs: ${paths.log}`);
|
|
215
215
|
}
|
|
@@ -242,10 +242,11 @@ async function cmdRestart(flags) {
|
|
|
242
242
|
await cmdStart(flags);
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
function cmdStatus() {
|
|
245
|
+
async function cmdStatus() {
|
|
246
246
|
const { running, pid } = getStatus();
|
|
247
247
|
const paths = getPaths();
|
|
248
248
|
console.log('');
|
|
249
|
+
console.log(` ${BOLD}TermSearch v${VERSION}${RESET}`);
|
|
249
250
|
if (running) {
|
|
250
251
|
ok(`${BOLD}Running${RESET} (PID ${pid})`);
|
|
251
252
|
info(`${getUrl()}`);
|
|
@@ -255,6 +256,7 @@ function cmdStatus() {
|
|
|
255
256
|
warn('Stopped');
|
|
256
257
|
info(`Run ${BOLD}termsearch start${RESET} to start`);
|
|
257
258
|
}
|
|
259
|
+
await printUpdateHint();
|
|
258
260
|
console.log('');
|
|
259
261
|
}
|
|
260
262
|
|
|
@@ -333,6 +335,9 @@ async function cmdDoctor() {
|
|
|
333
335
|
} catch (e) { err(`HTTP: cannot reach ${getUrl()} — ${e.message}`); allOk = false; }
|
|
334
336
|
}
|
|
335
337
|
|
|
338
|
+
// npm update check
|
|
339
|
+
await printUpdateHint();
|
|
340
|
+
|
|
336
341
|
console.log('');
|
|
337
342
|
if (allOk) { ok(`${GREEN}All checks passed${RESET}`); }
|
|
338
343
|
else { warn('Some checks failed — see above'); }
|
|
@@ -428,6 +433,39 @@ ${BOLD}URL:${RESET} http://localhost:3000
|
|
|
428
433
|
`);
|
|
429
434
|
}
|
|
430
435
|
|
|
436
|
+
// ─── Update check ─────────────────────────────────────────────────────────
|
|
437
|
+
|
|
438
|
+
async function checkNpmUpdate() {
|
|
439
|
+
try {
|
|
440
|
+
const ac = new AbortController();
|
|
441
|
+
setTimeout(() => ac.abort(), 4000);
|
|
442
|
+
const r = await fetch('https://registry.npmjs.org/termsearch/latest', { signal: ac.signal });
|
|
443
|
+
if (!r.ok) return null;
|
|
444
|
+
const data = await r.json();
|
|
445
|
+
const latest = data.version;
|
|
446
|
+
if (!latest) return null;
|
|
447
|
+
if (latest === VERSION) return { upToDate: true, latest };
|
|
448
|
+
// Simple semver compare: split, compare numerically
|
|
449
|
+
const cur = VERSION.split('.').map(Number);
|
|
450
|
+
const lat = latest.split('.').map(Number);
|
|
451
|
+
const newer = lat[0] > cur[0] || (lat[0] === cur[0] && lat[1] > cur[1]) || (lat[0] === cur[0] && lat[1] === cur[1] && lat[2] > cur[2]);
|
|
452
|
+
return { upToDate: !newer, latest };
|
|
453
|
+
} catch {
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
async function printUpdateHint() {
|
|
459
|
+
const update = await checkNpmUpdate();
|
|
460
|
+
if (!update) return;
|
|
461
|
+
if (update.upToDate) {
|
|
462
|
+
ok(`Up to date (v${VERSION})`);
|
|
463
|
+
} else {
|
|
464
|
+
warn(`Update available: v${VERSION} → v${update.latest}`);
|
|
465
|
+
info(`Run ${BOLD}npm install -g termsearch${RESET} to update`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
431
469
|
// ─── Utilities ────────────────────────────────────────────────────────────
|
|
432
470
|
|
|
433
471
|
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
|
package/frontend/dist/app.js
CHANGED
|
@@ -267,7 +267,6 @@ const AI_PRESETS = [
|
|
|
267
267
|
{ id: 'chutes', label: 'Chutes.ai TEE', api_base: 'https://llm.chutes.ai/v1', keyRequired: true, defaultModel: 'deepseek-ai/DeepSeek-V3.2-TEE' },
|
|
268
268
|
{ id: 'anthropic',label: 'Anthropic', api_base: 'https://api.anthropic.com/v1', keyRequired: true, defaultModel: 'claude-3-5-haiku-latest' },
|
|
269
269
|
{ id: 'openai', label: 'OpenAI', api_base: 'https://api.openai.com/v1', keyRequired: true, defaultModel: 'gpt-4o-mini' },
|
|
270
|
-
{ id: 'openrouter', label: 'OpenRoute/OpenRouter', api_base: 'https://openrouter.ai/api/v1', keyRequired: true, defaultModel: 'openai/gpt-4o-mini' },
|
|
271
270
|
];
|
|
272
271
|
|
|
273
272
|
const ENGINE_GROUPS = [
|
|
@@ -282,7 +281,7 @@ const ENGINE_GROUPS = [
|
|
|
282
281
|
|
|
283
282
|
const ENGINE_PRESETS = [
|
|
284
283
|
{ id: 'all', label: 'All', engines: [] },
|
|
285
|
-
{ id: 'balanced', label: 'Balanced', engines: ['duckduckgo', 'wikipedia', 'bing', '
|
|
284
|
+
{ id: 'balanced', label: 'Balanced', engines: ['duckduckgo', 'wikipedia', 'bing', 'brave', 'github', 'reddit', 'youtube'] },
|
|
286
285
|
{ id: 'github', label: 'GitHub Focus', engines: ['github-api', 'github', 'duckduckgo', 'wikipedia'] },
|
|
287
286
|
];
|
|
288
287
|
|
|
@@ -1054,12 +1053,12 @@ function renderApp() {
|
|
|
1054
1053
|
const mobileBar = el('div', { className: 'mobile-bar' },
|
|
1055
1054
|
el('div', { className: 'mobile-bar-search' }, SearchForm(state.query, (q, cat) => { state.query = q; doSearch(q, cat); })),
|
|
1056
1055
|
mobileTabs,
|
|
1057
|
-
el('div', { className: 'mobile-bar-engine' }, EnginePicker()),
|
|
1058
1056
|
el('div', { className: 'mobile-bar-row' },
|
|
1059
1057
|
el('div', {
|
|
1060
1058
|
className: 'mobile-logo',
|
|
1061
1059
|
onClick: () => { state.query = ''; state.category = 'web'; navigate('#/'); renderApp(); },
|
|
1062
1060
|
}, 'Term', el('strong', {}, 'Search')),
|
|
1061
|
+
EnginePicker(),
|
|
1063
1062
|
LangPicker(),
|
|
1064
1063
|
el('button', { className: 'btn-icon', title: 'Settings', onClick: () => navigate('#/settings') }, iconEl('settings')),
|
|
1065
1064
|
el('button', { className: 'btn-icon', title: 'Toggle theme', onClick: toggleTheme }, iconEl('theme')),
|
|
@@ -1161,6 +1160,9 @@ async function renderSettings() {
|
|
|
1161
1160
|
const brave = cfg.brave || {};
|
|
1162
1161
|
const mojeek = cfg.mojeek || {};
|
|
1163
1162
|
const searxng = cfg.searxng || {};
|
|
1163
|
+
const yandexCfg = cfg.yandex || {};
|
|
1164
|
+
const ahmiaCfg = cfg.ahmia || {};
|
|
1165
|
+
const marginaliaCfg = cfg.marginalia || {};
|
|
1164
1166
|
const detectedPreset = detectPresetFromBase(ai.api_base);
|
|
1165
1167
|
|
|
1166
1168
|
const header = el('div', { className: 'header' },
|
|
@@ -1338,6 +1340,9 @@ async function renderSettings() {
|
|
|
1338
1340
|
brave: { enabled: isChecked('brave-enabled') },
|
|
1339
1341
|
mojeek: { enabled: isChecked('mojeek-enabled') },
|
|
1340
1342
|
searxng:{ url: val('searxng-url'), enabled: isChecked('searxng-enabled') },
|
|
1343
|
+
yandex: { enabled: isChecked('yandex-enabled') },
|
|
1344
|
+
ahmia: { enabled: isChecked('ahmia-enabled') },
|
|
1345
|
+
marginalia: { enabled: isChecked('marginalia-enabled') },
|
|
1341
1346
|
};
|
|
1342
1347
|
if (aiKey) update.ai.api_key = aiKey;
|
|
1343
1348
|
if (braveKey) update.brave.api_key = braveKey;
|
|
@@ -1470,7 +1475,7 @@ async function renderSettings() {
|
|
|
1470
1475
|
el('label', { className: 'form-label', for: 'ai-base' }, 'API Endpoint'),
|
|
1471
1476
|
makeInput('ai-base', ai.api_base, 'http://localhost:11434/v1'),
|
|
1472
1477
|
el('div', { className: 'form-hint' },
|
|
1473
|
-
'Included presets: LocalHost (Ollama · LM Studio · llama.cpp) · Chutes.ai TEE · Anthropic · OpenAI
|
|
1478
|
+
'Included presets: LocalHost (Ollama · LM Studio · llama.cpp) · Chutes.ai TEE · Anthropic · OpenAI',
|
|
1474
1479
|
el('br', {}),
|
|
1475
1480
|
'You can also keep custom OpenAI-compatible endpoints.',
|
|
1476
1481
|
),
|
|
@@ -1563,7 +1568,7 @@ async function renderSettings() {
|
|
|
1563
1568
|
),
|
|
1564
1569
|
|
|
1565
1570
|
// SearXNG
|
|
1566
|
-
el('div', { style: 'padding:10px 0' },
|
|
1571
|
+
el('div', { style: 'padding:10px 0;border-bottom:1px solid var(--border2)' },
|
|
1567
1572
|
el('div', { className: 'toggle-row' },
|
|
1568
1573
|
el('span', { className: 'toggle-label' }, 'SearXNG (self-hosted)'),
|
|
1569
1574
|
el('label', { className: 'toggle' },
|
|
@@ -1578,6 +1583,33 @@ async function renderSettings() {
|
|
|
1578
1583
|
el('div', { id: 'provider-test-searxng', style: 'display:none' }),
|
|
1579
1584
|
),
|
|
1580
1585
|
|
|
1586
|
+
// Uncensored / Alternative
|
|
1587
|
+
el('div', { style: 'padding:10px 0' },
|
|
1588
|
+
el('div', { style: 'font-size:11px;color:var(--text2);margin-bottom:8px;letter-spacing:0.04em;text-transform:uppercase' }, 'Uncensored / Alternative'),
|
|
1589
|
+
el('div', { className: 'toggle-row' },
|
|
1590
|
+
el('span', { className: 'toggle-label' }, 'Yandex (HTML scraper, no key)'),
|
|
1591
|
+
el('label', { className: 'toggle' },
|
|
1592
|
+
el('input', { type: 'checkbox', id: 'yandex-enabled', ...(yandexCfg.enabled !== false ? { checked: '' } : {}) }),
|
|
1593
|
+
el('span', { className: 'toggle-slider' }),
|
|
1594
|
+
),
|
|
1595
|
+
),
|
|
1596
|
+
el('div', { className: 'toggle-row', style: 'margin-top:6px' },
|
|
1597
|
+
el('span', { className: 'toggle-label' }, 'Ahmia (Tor index, no key)'),
|
|
1598
|
+
el('label', { className: 'toggle' },
|
|
1599
|
+
el('input', { type: 'checkbox', id: 'ahmia-enabled', ...(ahmiaCfg.enabled !== false ? { checked: '' } : {}) }),
|
|
1600
|
+
el('span', { className: 'toggle-slider' }),
|
|
1601
|
+
),
|
|
1602
|
+
),
|
|
1603
|
+
el('div', { className: 'toggle-row', style: 'margin-top:6px' },
|
|
1604
|
+
el('span', { className: 'toggle-label' }, 'Marginalia (indie index, no key)'),
|
|
1605
|
+
el('label', { className: 'toggle' },
|
|
1606
|
+
el('input', { type: 'checkbox', id: 'marginalia-enabled', ...(marginaliaCfg.enabled !== false ? { checked: '' } : {}) }),
|
|
1607
|
+
el('span', { className: 'toggle-slider' }),
|
|
1608
|
+
),
|
|
1609
|
+
),
|
|
1610
|
+
el('div', { className: 'form-hint', style: 'margin-top:6px' }, 'Zero-config scraper engines. May be blocked by CAPTCHA under heavy use.'),
|
|
1611
|
+
),
|
|
1612
|
+
|
|
1581
1613
|
el('div', { style: 'margin-top:12px;display:flex;align-items:center;gap:8px' },
|
|
1582
1614
|
el('button', { className: 'btn btn-primary', onClick: saveSettings }, 'Save All'),
|
|
1583
1615
|
saveAlertEl,
|
package/frontend/dist/style.css
CHANGED
|
@@ -962,13 +962,13 @@ a:hover { color: var(--link-h); }
|
|
|
962
962
|
scrollbar-width: none;
|
|
963
963
|
}
|
|
964
964
|
.mobile-bar-tabs::-webkit-scrollbar { display: none; }
|
|
965
|
-
.mobile-bar-engine { padding: 0 12px 4px; }
|
|
966
965
|
.mobile-bar-row {
|
|
967
966
|
display: flex;
|
|
968
967
|
align-items: center;
|
|
969
968
|
gap: 6px;
|
|
970
969
|
padding: 4px 12px 2px;
|
|
971
970
|
}
|
|
971
|
+
.mobile-bar-row .engine-picker { flex-shrink: 0; }
|
|
972
972
|
.mobile-bar-row .lang-wrap { margin-left: auto; }
|
|
973
973
|
|
|
974
974
|
/* ─── Responsive ──────────────────────────────────────────────────────────── */
|
|
@@ -978,8 +978,7 @@ a:hover { color: var(--link-h); }
|
|
|
978
978
|
.main { padding-bottom: calc(20px + var(--mobile-bar-height, 0px) + env(safe-area-inset-bottom, 0px)); }
|
|
979
979
|
|
|
980
980
|
.cat-tab { font-size: 10px; padding: 4px 8px; }
|
|
981
|
-
.mobile-bar-
|
|
982
|
-
.mobile-bar-engine .engine-picker-summary { width: 100%; justify-content: space-between; }
|
|
981
|
+
.mobile-bar-row .engine-picker-summary { font-size: 11px; padding: 3px 6px; }
|
|
983
982
|
.engine-picker-body { width: calc(100vw - 24px); right: -6px; bottom: calc(100% + 8px); top: auto; }
|
|
984
983
|
.logo-text { font-size: 15px; }
|
|
985
984
|
.home-logo { font-size: 40px; }
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -17,9 +17,15 @@ function ok(msg) { console.log(` ${GREEN}✓${RESET} ${msg}`); }
|
|
|
17
17
|
function warn(msg) { console.log(` ${YELLOW}⚠${RESET} ${msg}`); }
|
|
18
18
|
function info(msg) { console.log(` ${CYAN}→${RESET} ${msg}`); }
|
|
19
19
|
|
|
20
|
+
let VERSION = '0.0.0';
|
|
21
|
+
try {
|
|
22
|
+
const pkgPath = new URL('../package.json', import.meta.url);
|
|
23
|
+
VERSION = JSON.parse(fs.readFileSync(pkgPath, 'utf8')).version || VERSION;
|
|
24
|
+
} catch { /* ignore */ }
|
|
25
|
+
|
|
20
26
|
try {
|
|
21
27
|
console.log('');
|
|
22
|
-
console.log(`${BOLD} TermSearch — post-install check
|
|
28
|
+
console.log(`${BOLD} TermSearch v${VERSION}${RESET} — post-install check`);
|
|
23
29
|
console.log('');
|
|
24
30
|
|
|
25
31
|
// ── Node.js version ──────────────────────────────────────────────────────
|
|
@@ -76,7 +82,7 @@ try {
|
|
|
76
82
|
}
|
|
77
83
|
|
|
78
84
|
console.log('');
|
|
79
|
-
info(`Run ${BOLD}termsearch${RESET}${CYAN}
|
|
85
|
+
info(`Run ${BOLD}termsearch${RESET}${CYAN} to start v${VERSION} → http://localhost:3000`);
|
|
80
86
|
console.log('');
|
|
81
87
|
|
|
82
88
|
} catch {
|