sweet-search 0.0.1 → 2.3.0
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/LICENSE +190 -0
- package/NOTICE +23 -0
- package/core/cli.js +51 -0
- package/core/config.js +27 -0
- package/core/embedding/embedding-cache.js +467 -0
- package/core/embedding/embedding-local-model.js +845 -0
- package/core/embedding/embedding-remote.js +492 -0
- package/core/embedding/embedding-service.js +712 -0
- package/core/embedding/embedding-telemetry.js +219 -0
- package/core/embedding/index.js +40 -0
- package/core/graph/community-detector.js +294 -0
- package/core/graph/graph-expansion.js +839 -0
- package/core/graph/graph-extractor.js +2304 -0
- package/core/graph/graph-search.js +2148 -0
- package/core/graph/hcgs-generator.js +666 -0
- package/core/graph/index.js +16 -0
- package/core/graph/leiden-algorithm.js +547 -0
- package/core/graph/relationship-resolver.js +366 -0
- package/core/graph/repo-map.js +408 -0
- package/core/graph/summary-manager.js +549 -0
- package/core/indexing/artifact-builder.js +1054 -0
- package/core/indexing/ast-chunker.js +709 -0
- package/core/indexing/chunking/chunk-builder.js +170 -0
- package/core/indexing/chunking/markdown-chunker.js +503 -0
- package/core/indexing/chunking/plaintext-chunker.js +104 -0
- package/core/indexing/dedup/dedup-phase.js +159 -0
- package/core/indexing/dedup/exemplar-selector.js +65 -0
- package/core/indexing/document-chunker.js +56 -0
- package/core/indexing/incremental-parser.js +390 -0
- package/core/indexing/incremental-tracker.js +761 -0
- package/core/indexing/index-codebase-v21.js +472 -0
- package/core/indexing/index-maintainer.mjs +1674 -0
- package/core/indexing/index.js +90 -0
- package/core/indexing/indexer-ann.js +1077 -0
- package/core/indexing/indexer-build.js +742 -0
- package/core/indexing/indexer-phases.js +800 -0
- package/core/indexing/indexer-pool.js +764 -0
- package/core/indexing/indexer-sparse-gram.js +98 -0
- package/core/indexing/indexer-utils.js +536 -0
- package/core/indexing/indexer-worker.js +148 -0
- package/core/indexing/li-skip-policy.js +225 -0
- package/core/indexing/merkle-tracker.js +244 -0
- package/core/indexing/model-pool.js +166 -0
- package/core/infrastructure/code-graph-repository.js +120 -0
- package/core/infrastructure/codebase-repository.js +131 -0
- package/core/infrastructure/config/dedup.js +54 -0
- package/core/infrastructure/config/embedding.js +298 -0
- package/core/infrastructure/config/graph.js +80 -0
- package/core/infrastructure/config/index.js +82 -0
- package/core/infrastructure/config/indexing.js +8 -0
- package/core/infrastructure/config/platform.js +254 -0
- package/core/infrastructure/config/ranking.js +221 -0
- package/core/infrastructure/config/search.js +396 -0
- package/core/infrastructure/config/translation.js +89 -0
- package/core/infrastructure/config/vector-store.js +114 -0
- package/core/infrastructure/constants.js +86 -0
- package/core/infrastructure/coreml-cascade.js +909 -0
- package/core/infrastructure/coreml-cascade.json +46 -0
- package/core/infrastructure/coreml-provider.js +81 -0
- package/core/infrastructure/db-utils.js +69 -0
- package/core/infrastructure/dedup-hashing.js +83 -0
- package/core/infrastructure/hardware-capability.js +332 -0
- package/core/infrastructure/index.js +104 -0
- package/core/infrastructure/language-patterns/maps.js +121 -0
- package/core/infrastructure/language-patterns/registry-core.js +323 -0
- package/core/infrastructure/language-patterns/registry-data-query.js +155 -0
- package/core/infrastructure/language-patterns/registry-object-oriented.js +285 -0
- package/core/infrastructure/language-patterns/registry-tooling.js +240 -0
- package/core/infrastructure/language-patterns/registry-web-style.js +143 -0
- package/core/infrastructure/language-patterns/registry.js +19 -0
- package/core/infrastructure/language-patterns.js +141 -0
- package/core/infrastructure/llm-provider.js +733 -0
- package/core/infrastructure/manifest.json +46 -0
- package/core/infrastructure/maxsim.wasm +0 -0
- package/core/infrastructure/model-fetcher.js +423 -0
- package/core/infrastructure/model-registry.js +214 -0
- package/core/infrastructure/native-inference.js +587 -0
- package/core/infrastructure/native-resolver.js +187 -0
- package/core/infrastructure/native-sparse-gram.js +257 -0
- package/core/infrastructure/native-tokenizer.js +160 -0
- package/core/infrastructure/onnx-mutex.js +45 -0
- package/core/infrastructure/onnx-session-utils.js +261 -0
- package/core/infrastructure/ort-pipeline.js +111 -0
- package/core/infrastructure/project-detector.js +102 -0
- package/core/infrastructure/quantization.js +410 -0
- package/core/infrastructure/simd-distance.js +502 -0
- package/core/infrastructure/simd-distance.wasm +0 -0
- package/core/infrastructure/tree-sitter-provider.js +665 -0
- package/core/infrastructure/webgpu-maxsim.js +222 -0
- package/core/query/index.js +35 -0
- package/core/query/intent-detector.js +201 -0
- package/core/query/intent-router.js +156 -0
- package/core/query/query-router-catboost.js +222 -0
- package/core/query/query-router-ml.js +266 -0
- package/core/query/query-router.js +213 -0
- package/core/ranking/cascaded-scorer.js +379 -0
- package/core/ranking/flashrank.js +810 -0
- package/core/ranking/index.js +49 -0
- package/core/ranking/late-interaction-index.js +2383 -0
- package/core/ranking/late-interaction-model.js +812 -0
- package/core/ranking/local-reranker.js +374 -0
- package/core/ranking/mmr.js +379 -0
- package/core/ranking/quality-scorer.js +363 -0
- package/core/search/context-expander.js +1167 -0
- package/core/search/dedup/sibling-expander.js +327 -0
- package/core/search/index.js +16 -0
- package/core/search/search-boost.js +259 -0
- package/core/search/search-cli.js +544 -0
- package/core/search/search-format.js +282 -0
- package/core/search/search-fusion.js +327 -0
- package/core/search/search-hybrid.js +204 -0
- package/core/search/search-pattern-chunks.js +337 -0
- package/core/search/search-pattern-planner.js +439 -0
- package/core/search/search-pattern-prefilter.js +412 -0
- package/core/search/search-pattern-ripgrep.js +663 -0
- package/core/search/search-pattern.js +463 -0
- package/core/search/search-postprocess.js +452 -0
- package/core/search/search-semantic.js +706 -0
- package/core/search/search-server.js +554 -0
- package/core/search/session-daemon-prewarm.mjs +164 -0
- package/core/search/session-warmup.js +595 -0
- package/core/search/sweet-search.js +632 -0
- package/core/search/warmup-metrics.js +532 -0
- package/core/start-server.js +6 -0
- package/core/training/query-router/features/extractor.js +762 -0
- package/core/training/query-router/features/multilingual-patterns.js +431 -0
- package/core/training/query-router/features/text-segmenter.js +303 -0
- package/core/training/query-router/features/unicode-utils.js +383 -0
- package/core/training/query-router/output/v45_router_d4.js +11521 -0
- package/core/training/query-router/output/v46_router_d4.js +11498 -0
- package/core/vector-store/binary-heap.js +227 -0
- package/core/vector-store/binary-hnsw-index.js +1004 -0
- package/core/vector-store/float-vector-store.js +234 -0
- package/core/vector-store/hnsw-index.js +580 -0
- package/core/vector-store/index.js +39 -0
- package/core/vector-store/seismic-index.js +498 -0
- package/core/vocabulary/index.js +84 -0
- package/core/vocabulary/vocab-constants.js +20 -0
- package/core/vocabulary/vocab-miner-extractors.js +375 -0
- package/core/vocabulary/vocab-miner-nl.js +404 -0
- package/core/vocabulary/vocab-miner-utils.js +146 -0
- package/core/vocabulary/vocab-miner.js +574 -0
- package/core/vocabulary/vocab-prewarm-cli.js +110 -0
- package/core/vocabulary/vocab-ranker.js +492 -0
- package/core/vocabulary/vocab-warmer.js +523 -0
- package/core/vocabulary/vocab-warmup-orchestrator.js +425 -0
- package/core/vocabulary/vocabulary-utils.js +704 -0
- package/crates/wasm-router/pkg/package.json +13 -0
- package/crates/wasm-router/pkg/query_router_wasm.d.ts +36 -0
- package/crates/wasm-router/pkg/query_router_wasm.js +271 -0
- package/crates/wasm-router/pkg/query_router_wasm_bg.wasm +0 -0
- package/crates/wasm-router/pkg/query_router_wasm_bg.wasm.d.ts +19 -0
- package/mcp/config-gen.js +121 -0
- package/mcp/server.js +335 -0
- package/mcp/tool-handlers.js +476 -0
- package/package.json +131 -9
- package/scripts/benchmark-harness.js +794 -0
- package/scripts/init.js +1058 -0
- package/scripts/smoke-test.js +435 -0
- package/scripts/uninstall.js +478 -0
- package/scripts/verify-runtime.js +176 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code SessionStart hook: detached daemon prewarm.
|
|
4
|
+
*
|
|
5
|
+
* Spawns the sweet-search search server in a fully-detached child so this
|
|
6
|
+
* hook exits immediately and the daemon loads its models + indexes in the
|
|
7
|
+
* background while the user reads Claude's first response. By the time the
|
|
8
|
+
* user issues their first `sweet-search <query>`, the daemon is already up
|
|
9
|
+
* and the query hits the warm path (~80ms instead of ~2.5s cold start).
|
|
10
|
+
*
|
|
11
|
+
* Safety properties:
|
|
12
|
+
* - Socket-probed liveness: PID-alive alone is not enough, because a
|
|
13
|
+
* daemon stuck mid-init has a live PID but an unresponsive socket.
|
|
14
|
+
* We only skip spawning when the socket actually accepts a connection.
|
|
15
|
+
* - Concurrent SessionStart lock: two Claude Code windows opening at the
|
|
16
|
+
* same time both fire this hook; a tmp lockfile ensures only one spawns.
|
|
17
|
+
* - Env overrides (SWEET_SEARCH_*_PATH / SWEET_SEARCH_SERVER_ENTRY) make
|
|
18
|
+
* the hook testable against fake fixtures.
|
|
19
|
+
*
|
|
20
|
+
* Always exits 0 and fast — a failed prewarm must not block Claude Code
|
|
21
|
+
* session start.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { spawn } from 'node:child_process';
|
|
25
|
+
import { existsSync, readFileSync, openSync, writeSync, closeSync, unlinkSync } from 'node:fs';
|
|
26
|
+
import { connect } from 'node:net';
|
|
27
|
+
import { dirname, join } from 'node:path';
|
|
28
|
+
import { fileURLToPath } from 'node:url';
|
|
29
|
+
|
|
30
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
31
|
+
|
|
32
|
+
const SERVER_ENTRY = process.env.SWEET_SEARCH_SERVER_ENTRY || join(__dirname, '..', 'start-server.js');
|
|
33
|
+
const SOCKET_PATH = process.env.SWEET_SEARCH_SOCKET_PATH || '/tmp/sweet-search.sock';
|
|
34
|
+
const PID_FILE = process.env.SWEET_SEARCH_PID_FILE || '/tmp/sweet-search-server.pid';
|
|
35
|
+
const LOCK_PATH = process.env.SWEET_SEARCH_PREWARM_LOCK || '/tmp/sweet-search-prewarm.lock';
|
|
36
|
+
const SOCKET_PROBE_TIMEOUT_MS = Number(process.env.SWEET_SEARCH_PREWARM_PROBE_MS ?? 300);
|
|
37
|
+
|
|
38
|
+
const verbose = !!process.env.SWEET_SEARCH_PREWARM_VERBOSE;
|
|
39
|
+
const log = (msg) => {
|
|
40
|
+
if (verbose) process.stderr.write(`[sweet-search prewarm] ${msg}\n`);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Does a process with this PID exist right now? Handles EPERM (alien user) as "alive". */
|
|
44
|
+
function pidAlive(pid) {
|
|
45
|
+
if (!pid || !Number.isFinite(pid)) return false;
|
|
46
|
+
try {
|
|
47
|
+
process.kill(pid, 0);
|
|
48
|
+
return true;
|
|
49
|
+
} catch (err) {
|
|
50
|
+
return err.code === 'EPERM';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Try to connect to the unix socket. Resolves true if connect succeeds quickly. */
|
|
55
|
+
function socketResponsive(socketPath, timeoutMs) {
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
if (!existsSync(socketPath)) {
|
|
58
|
+
resolve(false);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const c = connect(socketPath);
|
|
62
|
+
const timer = setTimeout(() => {
|
|
63
|
+
try { c.destroy(); } catch { /* ignore */ }
|
|
64
|
+
resolve(false);
|
|
65
|
+
}, timeoutMs);
|
|
66
|
+
c.once('connect', () => {
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
try { c.destroy(); } catch { /* ignore */ }
|
|
69
|
+
resolve(true);
|
|
70
|
+
});
|
|
71
|
+
c.once('error', () => {
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
resolve(false);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Daemon counts as healthy only if its PID is alive AND its socket accepts a connection. */
|
|
79
|
+
async function daemonHealthy() {
|
|
80
|
+
let pid = null;
|
|
81
|
+
if (existsSync(PID_FILE)) {
|
|
82
|
+
try { pid = Number(readFileSync(PID_FILE, 'utf-8').trim()); }
|
|
83
|
+
catch { pid = null; }
|
|
84
|
+
}
|
|
85
|
+
if (!pidAlive(pid)) return false;
|
|
86
|
+
return socketResponsive(SOCKET_PATH, SOCKET_PROBE_TIMEOUT_MS);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Acquire an exclusive lock so only one concurrent SessionStart spawns a
|
|
91
|
+
* daemon. Returns the file descriptor on success, null on failure. Handles
|
|
92
|
+
* stale locks whose holder is dead.
|
|
93
|
+
*/
|
|
94
|
+
function acquireLock() {
|
|
95
|
+
try {
|
|
96
|
+
const fd = openSync(LOCK_PATH, 'wx');
|
|
97
|
+
writeSync(fd, String(process.pid));
|
|
98
|
+
return fd;
|
|
99
|
+
} catch (err) {
|
|
100
|
+
if (err.code !== 'EEXIST') return null;
|
|
101
|
+
// Another process holds the lock. Read it to see if they're still alive.
|
|
102
|
+
let holderRaw = '';
|
|
103
|
+
try { holderRaw = readFileSync(LOCK_PATH, 'utf-8').trim(); } catch { /* unreadable */ }
|
|
104
|
+
// Empty or unparseable: another process is mid-write between its
|
|
105
|
+
// openSync('wx') success and its writeSync(pid) — do NOT try to steal
|
|
106
|
+
// the lock. Let them finish; we back off.
|
|
107
|
+
if (!holderRaw) return null;
|
|
108
|
+
const holder = Number(holderRaw);
|
|
109
|
+
if (!Number.isFinite(holder)) return null;
|
|
110
|
+
if (pidAlive(holder) && holder !== process.pid) {
|
|
111
|
+
return null; // legitimate live holder
|
|
112
|
+
}
|
|
113
|
+
// Verifiably dead holder — unlink + retry once.
|
|
114
|
+
try { unlinkSync(LOCK_PATH); } catch { /* ignore */ }
|
|
115
|
+
try {
|
|
116
|
+
const fd = openSync(LOCK_PATH, 'wx');
|
|
117
|
+
writeSync(fd, String(process.pid));
|
|
118
|
+
return fd;
|
|
119
|
+
} catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function releaseLock(fd) {
|
|
126
|
+
try { closeSync(fd); } catch { /* ignore */ }
|
|
127
|
+
try { unlinkSync(LOCK_PATH); } catch { /* ignore */ }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
if (await daemonHealthy()) {
|
|
132
|
+
log('daemon already responsive on socket');
|
|
133
|
+
process.exit(0);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!existsSync(SERVER_ENTRY)) {
|
|
137
|
+
log(`server entry missing: ${SERVER_ENTRY}`);
|
|
138
|
+
process.exit(0);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const lockFd = acquireLock();
|
|
142
|
+
if (lockFd === null) {
|
|
143
|
+
log('another prewarm hook already holds the lock; skipping');
|
|
144
|
+
process.exit(0);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
// Fully detach: new session, no stdio, parent can exit while daemon loads.
|
|
149
|
+
const child = spawn(process.execPath, [SERVER_ENTRY, '--serve'], {
|
|
150
|
+
detached: true,
|
|
151
|
+
stdio: 'ignore',
|
|
152
|
+
cwd: process.cwd(),
|
|
153
|
+
env: process.env,
|
|
154
|
+
});
|
|
155
|
+
child.unref();
|
|
156
|
+
log(`daemon spawned (pid ${child.pid}, detached)`);
|
|
157
|
+
} finally {
|
|
158
|
+
releaseLock(lockFd);
|
|
159
|
+
}
|
|
160
|
+
} catch (err) {
|
|
161
|
+
log(`non-fatal: ${err?.message || err}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
process.exit(0);
|