sweet-search 2.5.2 → 2.5.4
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/cli.js +24 -3
- package/core/graph/graph-expansion.js +215 -36
- package/core/graph/graph-extractor.js +196 -11
- package/core/graph/graph-search.js +395 -92
- package/core/graph/hcgs-generator.js +2 -1
- package/core/graph/index.js +2 -0
- package/core/graph/repo-map.js +28 -6
- package/core/graph/structural-answer-cues.js +168 -0
- package/core/graph/structural-callsite-hints.js +40 -0
- package/core/graph/structural-context-format.js +40 -0
- package/core/graph/structural-context.js +450 -0
- package/core/graph/structural-forward-push.js +156 -0
- package/core/graph/structural-header-context.js +19 -0
- package/core/graph/structural-importance.js +148 -0
- package/core/graph/structural-pagerank.js +197 -0
- package/core/graph/summary-manager.js +13 -9
- package/core/incremental-indexing/application/dirty-scan.mjs +236 -0
- package/core/incremental-indexing/application/file-watcher.mjs +197 -0
- package/core/incremental-indexing/application/maintenance-handlers.mjs +519 -0
- package/core/incremental-indexing/application/maintenance-worker.mjs +380 -0
- package/core/incremental-indexing/application/operator-cli.mjs +554 -0
- package/core/incremental-indexing/application/production-li-delta.mjs +192 -0
- package/core/incremental-indexing/application/production-reconciler-helpers.mjs +107 -0
- package/core/incremental-indexing/application/production-reconciler.mjs +583 -0
- package/core/incremental-indexing/application/reconciler.mjs +477 -0
- package/core/incremental-indexing/application/tombstone-injector.mjs +148 -0
- package/core/incremental-indexing/domain/chunk-identity.mjs +260 -0
- package/core/incremental-indexing/domain/encoder-deps.mjs +193 -0
- package/core/incremental-indexing/domain/encoder-input.mjs +225 -0
- package/core/incremental-indexing/domain/interval-autotune.mjs +255 -0
- package/core/incremental-indexing/domain/reconcile-counters.mjs +149 -0
- package/core/incremental-indexing/domain/watermark-scheduler.mjs +239 -0
- package/core/incremental-indexing/infrastructure/artifact-temp-sweep.mjs +163 -0
- package/core/incremental-indexing/infrastructure/baseline-readiness.mjs +121 -0
- package/core/incremental-indexing/infrastructure/dirty-set.mjs +233 -0
- package/core/incremental-indexing/infrastructure/graph-gc.mjs +314 -0
- package/core/incremental-indexing/infrastructure/hashing.mjs +298 -0
- package/core/incremental-indexing/infrastructure/hcgs-invalidation.mjs +182 -0
- package/core/incremental-indexing/infrastructure/li-segment-merge.mjs +278 -0
- package/core/incremental-indexing/infrastructure/li-segment-state.mjs +173 -0
- package/core/incremental-indexing/infrastructure/lockfile.mjs +119 -0
- package/core/incremental-indexing/infrastructure/maintenance-state-reader.mjs +283 -0
- package/core/incremental-indexing/infrastructure/manifest.mjs +194 -0
- package/core/incremental-indexing/infrastructure/path-filter.mjs +190 -0
- package/core/incremental-indexing/infrastructure/reader-heartbeat.mjs +201 -0
- package/core/incremental-indexing/infrastructure/schema-migrations.mjs +257 -0
- package/core/incremental-indexing/infrastructure/sparse-gram-delta.mjs +335 -0
- package/core/incremental-indexing/infrastructure/sqlite-fts5.mjs +176 -0
- package/core/incremental-indexing/infrastructure/staleness-display.mjs +105 -0
- package/core/incremental-indexing/infrastructure/tombstone-bitmap.mjs +234 -0
- package/core/incremental-indexing/infrastructure/vector-delta-writer.mjs +359 -0
- package/core/incremental-indexing/infrastructure/vector-gc.mjs +133 -0
- package/core/incremental-indexing/infrastructure/worktree-stamp.mjs +155 -0
- package/core/incremental-indexing/infrastructure/wsl2-detect.mjs +115 -0
- package/core/indexing/admission-policy.js +139 -0
- package/core/indexing/artifact-builder.js +29 -12
- package/core/indexing/ast-chunker.js +107 -30
- package/core/indexing/dedup/exemplar-selector.js +19 -1
- package/core/indexing/gitignore-filter.js +223 -0
- package/core/indexing/incremental-tracker.js +99 -30
- package/core/indexing/index-codebase-v21.js +6 -5
- package/core/indexing/index-maintainer.mjs +698 -6
- package/core/indexing/indexer-ann.js +99 -15
- package/core/indexing/indexer-build.js +158 -45
- package/core/indexing/indexer-empty-baseline.js +80 -0
- package/core/indexing/indexer-manifest.js +66 -0
- package/core/indexing/indexer-phases.js +56 -23
- package/core/indexing/indexer-sparse-gram.js +54 -13
- package/core/indexing/indexer-utils.js +26 -208
- package/core/indexing/indexing-file-policy.js +32 -7
- package/core/indexing/maintainer-launcher.mjs +137 -0
- package/core/indexing/merkle-tracker.js +251 -244
- package/core/indexing/model-pool.js +46 -5
- package/core/infrastructure/code-graph-repository.js +758 -6
- package/core/infrastructure/code-graph-visibility.js +157 -0
- package/core/infrastructure/codebase-repository.js +100 -13
- package/core/infrastructure/config/search.js +1 -1
- package/core/infrastructure/db-utils.js +118 -0
- package/core/infrastructure/dedup-hashing.js +10 -13
- package/core/infrastructure/hardware-capability.js +17 -7
- package/core/infrastructure/index.js +8 -2
- package/core/infrastructure/language-patterns/maps.js +4 -1
- package/core/infrastructure/language-patterns/registry-core.js +56 -17
- package/core/infrastructure/language-patterns/registry-object-oriented.js +12 -5
- package/core/infrastructure/language-patterns.js +69 -0
- package/core/infrastructure/model-registry.js +20 -0
- package/core/infrastructure/native-inference.js +7 -12
- package/core/infrastructure/native-resolver.js +52 -37
- package/core/infrastructure/native-sparse-gram.js +261 -20
- package/core/infrastructure/native-tokenizer.js +6 -15
- package/core/infrastructure/simd-distance.js +10 -16
- package/core/infrastructure/sparse-gram-delta-reader.js +76 -0
- package/core/infrastructure/structural-alias-resolver.js +122 -0
- package/core/infrastructure/structural-candidate-ranker.js +34 -0
- package/core/infrastructure/structural-context-repository.js +472 -0
- package/core/infrastructure/structural-context-utils.js +51 -0
- package/core/infrastructure/structural-graph-signals.js +121 -0
- package/core/infrastructure/structural-qualified-resolution.js +15 -0
- package/core/infrastructure/structural-source-definitions.js +100 -0
- package/core/infrastructure/tombstone-bitmap-reader.js +139 -0
- package/core/infrastructure/tree-sitter-provider.js +811 -37
- package/core/prompt-optimization/data/p7-final/sweet-search-system-prompt.md +50 -0
- package/core/query/query-router.js +55 -5
- package/core/ranking/file-kind-ranking.js +2192 -15
- package/core/ranking/late-interaction-index.js +87 -12
- package/core/search/cli-decoration.js +290 -0
- package/core/search/context-expander.js +988 -78
- package/core/search/index.js +1 -0
- package/core/search/output-policy.js +275 -0
- package/core/search/search-anchor.js +499 -0
- package/core/search/search-boost.js +93 -1
- package/core/search/search-cli.js +61 -204
- package/core/search/search-hybrid.js +250 -10
- package/core/search/search-pattern-chunks.js +57 -8
- package/core/search/search-pattern-planner.js +68 -9
- package/core/search/search-pattern-prefilter.js +30 -10
- package/core/search/search-pattern-ripgrep.js +40 -4
- package/core/search/search-pattern-sparse-overlay.js +256 -0
- package/core/search/search-pattern.js +117 -29
- package/core/search/search-postprocess.js +479 -5
- package/core/search/search-read-semantic.js +260 -23
- package/core/search/search-read.js +82 -64
- package/core/search/search-reader-pin.js +71 -0
- package/core/search/search-rrf.js +279 -0
- package/core/search/search-semantic.js +110 -5
- package/core/search/search-server.js +130 -57
- package/core/search/search-trace.js +107 -0
- package/core/search/server-identity.js +93 -0
- package/core/search/session-daemon-prewarm.mjs +33 -10
- package/core/search/sweet-search.js +399 -7
- package/core/skills/sweet-index/SKILL.md +8 -6
- package/core/vector-store/binary-hnsw-index.js +194 -30
- package/core/vector-store/float-vector-store.js +96 -6
- package/core/vector-store/hnsw-index.js +220 -49
- package/eval/agent-read-workflows/bin/_ss-helpers.mjs +471 -0
- package/eval/agent-read-workflows/bin/ss-find +15 -0
- package/eval/agent-read-workflows/bin/ss-grep +12 -0
- package/eval/agent-read-workflows/bin/ss-read +14 -0
- package/eval/agent-read-workflows/bin/ss-search +18 -0
- package/eval/agent-read-workflows/bin/ss-semantic +12 -0
- package/eval/agent-read-workflows/bin/ss-trace +11 -0
- package/mcp/read-tool.js +109 -0
- package/mcp/server.js +55 -15
- package/mcp/tool-handlers.js +14 -124
- package/mcp/trace-tool.js +81 -0
- package/package.json +25 -10
- package/scripts/hooks/intercept-read.mjs +55 -0
- package/scripts/hooks/remind-tools.mjs +40 -0
- package/scripts/init.js +698 -54
- package/scripts/inject-agent-instructions.js +431 -0
- package/scripts/install-prompt-reminders.js +188 -0
- package/scripts/install-tool-enforcement.js +220 -0
- package/scripts/smoke-test.js +12 -9
- package/scripts/uninstall.js +276 -18
- package/scripts/write-claude-rules.js +110 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-scoped warm-server identity (release-gate C3).
|
|
3
|
+
*
|
|
4
|
+
* The warm search server was discovered via a single GLOBAL Unix socket
|
|
5
|
+
* (`/tmp/sweet-search.sock`) + a global legacy symlink (`/tmp/search.sock`) and
|
|
6
|
+
* an unconditional TCP port (9876). With more than one project on a machine
|
|
7
|
+
* this silently routed project B's queries to project A's server, and a second
|
|
8
|
+
* project's server crashed on `EADDRINUSE`.
|
|
9
|
+
*
|
|
10
|
+
* The fix derives a per-project socket/pidfile from the canonical project root,
|
|
11
|
+
* so each project gets its own server and can never answer another project's
|
|
12
|
+
* queries. The native Rust CLI re-implements the SAME derivation (FNV-1a/64 of
|
|
13
|
+
* the canonical root → `/tmp/sweet-search-<hash16>.sock`) so both sides agree.
|
|
14
|
+
*
|
|
15
|
+
* Why a hashed `/tmp` path and not `<root>/.sweet-search/search.sock`:
|
|
16
|
+
* `sockaddr_un.sun_path` is capped (~104 bytes on macOS); a deep project path
|
|
17
|
+
* would overflow it. The hashed `/tmp` path is always short and collision-safe.
|
|
18
|
+
*
|
|
19
|
+
* Overrides:
|
|
20
|
+
* - `SWEET_SEARCH_SOCKET_PATH` — explicit socket; when set, NO legacy fallback.
|
|
21
|
+
* - `SWEET_SEARCH_PID_FILE` — explicit pidfile.
|
|
22
|
+
* - `SWEET_SEARCH_TCP_PORT` — opt-in TCP (off by default; see search-server).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { realpathSync, existsSync } from 'node:fs';
|
|
26
|
+
import path from 'node:path';
|
|
27
|
+
|
|
28
|
+
const FNV_OFFSET = 14695981039346656037n; // 0xcbf29ce484222325
|
|
29
|
+
const FNV_PRIME = 1099511628211n; // 0x100000001b3
|
|
30
|
+
const U64_MASK = (1n << 64n) - 1n;
|
|
31
|
+
|
|
32
|
+
/** FNV-1a 64-bit of a string's UTF-8 bytes → 16 lowercase hex chars. */
|
|
33
|
+
export function fnv1a64Hex(str) {
|
|
34
|
+
let hash = FNV_OFFSET;
|
|
35
|
+
const bytes = Buffer.from(String(str), 'utf8');
|
|
36
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
37
|
+
hash ^= BigInt(bytes[i]);
|
|
38
|
+
hash = (hash * FNV_PRIME) & U64_MASK;
|
|
39
|
+
}
|
|
40
|
+
return hash.toString(16).padStart(16, '0');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Canonicalise a path (resolve symlinks, e.g. macOS /tmp → /private/tmp). */
|
|
44
|
+
function canonicalize(p) {
|
|
45
|
+
const abs = path.resolve(p);
|
|
46
|
+
try {
|
|
47
|
+
return realpathSync.native(abs);
|
|
48
|
+
} catch {
|
|
49
|
+
return abs; // path may not exist yet (pre-index cold start) — use lexical.
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Resolve the canonical project root for socket derivation. Honors an explicit
|
|
55
|
+
* `SWEET_SEARCH_PROJECT_ROOT`; otherwise walks up from `cwd` to the nearest
|
|
56
|
+
* ancestor containing a `.sweet-search/` state dir (so queries from a
|
|
57
|
+
* subdirectory map to the same server), falling back to the canonical `cwd`.
|
|
58
|
+
*/
|
|
59
|
+
export function resolveProjectRoot(env = process.env, cwd = process.cwd()) {
|
|
60
|
+
const base = canonicalize(env.SWEET_SEARCH_PROJECT_ROOT || cwd);
|
|
61
|
+
let dir = base;
|
|
62
|
+
while (true) {
|
|
63
|
+
if (existsSync(path.join(dir, '.sweet-search'))) return dir;
|
|
64
|
+
const parent = path.dirname(dir);
|
|
65
|
+
if (parent === dir) break;
|
|
66
|
+
dir = parent;
|
|
67
|
+
}
|
|
68
|
+
return base;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Project-scoped socket path (or the explicit override). */
|
|
72
|
+
export function projectSocketPath(env = process.env, cwd = process.cwd()) {
|
|
73
|
+
if (env.SWEET_SEARCH_SOCKET_PATH) return env.SWEET_SEARCH_SOCKET_PATH;
|
|
74
|
+
return `/tmp/sweet-search-${fnv1a64Hex(resolveProjectRoot(env, cwd))}.sock`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Project-scoped server pidfile (or the explicit override). */
|
|
78
|
+
export function projectPidFile(env = process.env, cwd = process.cwd()) {
|
|
79
|
+
if (env.SWEET_SEARCH_PID_FILE) return env.SWEET_SEARCH_PID_FILE;
|
|
80
|
+
return `/tmp/sweet-search-${fnv1a64Hex(resolveProjectRoot(env, cwd))}.pid`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Opt-in TCP port. Off by default — TCP on a single global port is the
|
|
85
|
+
* multi-project collision source (EADDRINUSE) and a cross-project leak vector.
|
|
86
|
+
* Returns a finite port number, or null when TCP should not be bound.
|
|
87
|
+
*/
|
|
88
|
+
export function tcpPort(env = process.env) {
|
|
89
|
+
const raw = env.SWEET_SEARCH_TCP_PORT;
|
|
90
|
+
if (raw == null || raw === '') return null;
|
|
91
|
+
const n = Number.parseInt(String(raw), 10);
|
|
92
|
+
return Number.isInteger(n) && n > 0 && n < 65536 ? n : null;
|
|
93
|
+
}
|
|
@@ -26,12 +26,16 @@ import { existsSync, readFileSync, openSync, writeSync, closeSync, unlinkSync }
|
|
|
26
26
|
import { connect } from 'node:net';
|
|
27
27
|
import { dirname, join } from 'node:path';
|
|
28
28
|
import { fileURLToPath } from 'node:url';
|
|
29
|
+
import { launchMaintainer } from '../indexing/maintainer-launcher.mjs';
|
|
30
|
+
import { projectSocketPath, projectPidFile } from './server-identity.js';
|
|
29
31
|
|
|
30
32
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
31
33
|
|
|
32
34
|
const SERVER_ENTRY = process.env.SWEET_SEARCH_SERVER_ENTRY || join(__dirname, '..', 'start-server.js');
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
// Per-project socket/pidfile (C3) — honors SWEET_SEARCH_SOCKET_PATH /
|
|
36
|
+
// SWEET_SEARCH_PID_FILE overrides, otherwise derives from the canonical root.
|
|
37
|
+
const SOCKET_PATH = projectSocketPath();
|
|
38
|
+
const PID_FILE = projectPidFile();
|
|
35
39
|
const LOCK_PATH = process.env.SWEET_SEARCH_PREWARM_LOCK || '/tmp/sweet-search-prewarm.lock';
|
|
36
40
|
const SOCKET_PROBE_TIMEOUT_MS = Number(process.env.SWEET_SEARCH_PREWARM_PROBE_MS ?? 300);
|
|
37
41
|
|
|
@@ -127,23 +131,25 @@ function releaseLock(fd) {
|
|
|
127
131
|
try { unlinkSync(LOCK_PATH); } catch { /* ignore */ }
|
|
128
132
|
}
|
|
129
133
|
|
|
130
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Spawn the detached search server unless it is already responsive or another
|
|
136
|
+
* concurrent prewarm hook is mid-spawn. Returns (does not exit) so the
|
|
137
|
+
* maintainer launch below always runs.
|
|
138
|
+
*/
|
|
139
|
+
async function prewarmServer() {
|
|
131
140
|
if (await daemonHealthy()) {
|
|
132
141
|
log('daemon already responsive on socket');
|
|
133
|
-
|
|
142
|
+
return;
|
|
134
143
|
}
|
|
135
|
-
|
|
136
144
|
if (!existsSync(SERVER_ENTRY)) {
|
|
137
145
|
log(`server entry missing: ${SERVER_ENTRY}`);
|
|
138
|
-
|
|
146
|
+
return;
|
|
139
147
|
}
|
|
140
|
-
|
|
141
148
|
const lockFd = acquireLock();
|
|
142
149
|
if (lockFd === null) {
|
|
143
150
|
log('another prewarm hook already holds the lock; skipping');
|
|
144
|
-
|
|
151
|
+
return;
|
|
145
152
|
}
|
|
146
|
-
|
|
147
153
|
try {
|
|
148
154
|
// Fully detach: new session, no stdio, parent can exit while daemon loads.
|
|
149
155
|
const child = spawn(process.execPath, [SERVER_ENTRY, '--serve'], {
|
|
@@ -157,8 +163,25 @@ try {
|
|
|
157
163
|
} finally {
|
|
158
164
|
releaseLock(lockFd);
|
|
159
165
|
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// The search server and the index maintainer are independent: a stuck/already
|
|
169
|
+
// running server must not stop the maintainer from starting, and vice versa.
|
|
170
|
+
// Each is isolated in its own try so one failing never blocks the other.
|
|
171
|
+
try {
|
|
172
|
+
await prewarmServer();
|
|
173
|
+
} catch (err) {
|
|
174
|
+
log(`server prewarm non-fatal: ${err?.message || err}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
// Delegate to the shared launcher (core/indexing/maintainer-launcher.mjs).
|
|
179
|
+
// The hook is a best-effort convenience layer; the durable guarantee lives in
|
|
180
|
+
// the warm search-server startup, which calls this same launcher. Pass our
|
|
181
|
+
// verbose-gated logger so output keeps the prewarm prefix + stays stderr-only.
|
|
182
|
+
launchMaintainer({ log });
|
|
160
183
|
} catch (err) {
|
|
161
|
-
log(`non-fatal: ${err?.message || err}`);
|
|
184
|
+
log(`maintainer prewarm non-fatal: ${err?.message || err}`);
|
|
162
185
|
}
|
|
163
186
|
|
|
164
187
|
process.exit(0);
|