@esankhan3/code-search-mcp 0.1.0 → 0.2.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/README.md +174 -19
- package/dist/__tests__/config-resolver.test.js +153 -0
- package/dist/__tests__/daemon-rpc.test.js +100 -0
- package/dist/__tests__/observability.test.js +69 -0
- package/dist/__tests__/projects.test.js +141 -0
- package/dist/backends/daemon-client.js +87 -0
- package/dist/backends/in-process.js +104 -0
- package/dist/backends/index.js +29 -0
- package/dist/backends/types.js +0 -0
- package/dist/cli/index.js +231 -0
- package/dist/core/config.js +372 -0
- package/dist/core/env-config.js +45 -43
- package/dist/daemon/index.js +119 -0
- package/dist/daemon/rpc-server.js +99 -0
- package/dist/daemon/watcher.js +105 -0
- package/dist/index.js +7 -0
- package/dist/observability/logger.js +66 -0
- package/dist/observability/metrics.js +138 -0
- package/dist/projects/registry.js +146 -0
- package/dist/server.js +4 -0
- package/dist/transports/http-transport.js +38 -0
- package/package.json +18 -6
- package/scripts/smoke/run-smoke.sh +167 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# code-search-mcp end-to-end smoke (T1–T8 from the standalone product plan).
|
|
3
|
+
#
|
|
4
|
+
# Runs the same eight checks we used while landing the P0–P8 work. Requires:
|
|
5
|
+
# - Ollama running on $OLLAMA_HOST (default http://localhost:11434) with
|
|
6
|
+
# `bge-m3` and `qwen2.5-coder:7b` pulled (re-rank step).
|
|
7
|
+
# - The bundle built (`npm -w @esankhan3/code-search-mcp run build`).
|
|
8
|
+
#
|
|
9
|
+
# Optional envs picked up by individual cases:
|
|
10
|
+
# - OPENAI_API_KEY → T5 OpenAI embedding path
|
|
11
|
+
# - GEMINI_OAUTH_CREDS=~/.gemini/oauth_creds.json → T5b Gemini path
|
|
12
|
+
#
|
|
13
|
+
# Exit non-zero on the first failure. The script is idempotent: every case
|
|
14
|
+
# writes under $TMP/ and cleans up its own state at the start.
|
|
15
|
+
|
|
16
|
+
set -u
|
|
17
|
+
cd "$(dirname "$0")/../.." # → packages/code-search-mcp
|
|
18
|
+
|
|
19
|
+
TMP="${TMP:-/tmp/cs-smoke}"
|
|
20
|
+
DIST_CLI="$PWD/dist/cli/index.js"
|
|
21
|
+
DIST_MCP="$PWD/dist/index.js"
|
|
22
|
+
DIST_DAEMON="$PWD/dist/daemon/index.js"
|
|
23
|
+
|
|
24
|
+
if [[ ! -f "$DIST_CLI" || ! -f "$DIST_MCP" || ! -f "$DIST_DAEMON" ]]; then
|
|
25
|
+
echo "FATAL: dist/ missing — run \`npm -w @esankhan3/code-search-mcp run build\` first" >&2
|
|
26
|
+
exit 64
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
PASS=0
|
|
30
|
+
FAIL=0
|
|
31
|
+
SKIP=0
|
|
32
|
+
|
|
33
|
+
pass() { echo " ✓ $*"; PASS=$((PASS+1)); }
|
|
34
|
+
fail() { echo " ✗ $*" >&2; FAIL=$((FAIL+1)); }
|
|
35
|
+
skip() { echo " - $* (skipped)"; SKIP=$((SKIP+1)); }
|
|
36
|
+
hdr() { echo; echo "── $* ──"; }
|
|
37
|
+
|
|
38
|
+
# ── Setup: minimal pet-shop repo ─────────────────────────────────────────────
|
|
39
|
+
hdr "Setup"
|
|
40
|
+
rm -rf "$TMP"
|
|
41
|
+
mkdir -p "$TMP/pet-shop/src" "$TMP/index"
|
|
42
|
+
cat > "$TMP/pet-shop/src/auth.ts" <<'EOF'
|
|
43
|
+
export function verifyToken(token: string, secret: string): boolean { return token.length > 0 && secret.length > 0; }
|
|
44
|
+
export function requireScope(scope: string, scopes: string[]): void { if (!scopes.includes(scope)) throw new Error('forbidden'); }
|
|
45
|
+
EOF
|
|
46
|
+
cat > "$TMP/pet-shop/src/pets.ts" <<'EOF'
|
|
47
|
+
export interface Pet { id: string; name: string; available: boolean }
|
|
48
|
+
const pets = new Map<string, Pet>();
|
|
49
|
+
export function listAvailablePets(): Pet[] { return [...pets.values()].filter((p) => p.available); }
|
|
50
|
+
export function adoptPet(id: string): Pet { const p = pets.get(id); if (!p) throw new Error('not found'); p.available = false; return p; }
|
|
51
|
+
EOF
|
|
52
|
+
( cd "$TMP/pet-shop" && git init -q && git config user.email t@t.t && git config user.name t && git add -A && git commit -q -m initial ) || { fail "git init"; exit 1; }
|
|
53
|
+
pass "pet-shop fixture committed"
|
|
54
|
+
|
|
55
|
+
# Common envs for the rest of the smoke.
|
|
56
|
+
export CODE_SEARCH_DATA_DIR="$TMP/index"
|
|
57
|
+
export CODE_SEARCH_EMBEDDING_PROVIDER=ollama
|
|
58
|
+
export CODE_SEARCH_EMBEDDING_MODEL=bge-m3
|
|
59
|
+
export CODE_SEARCH_EMBEDDING_DIMENSIONS=1024
|
|
60
|
+
export CODE_SEARCH_RERANKER_PROVIDER=none
|
|
61
|
+
export CODE_SEARCH_LLM_MODE=none
|
|
62
|
+
export CODE_SEARCH_DAEMON_DISABLED=1
|
|
63
|
+
|
|
64
|
+
# ── T1: --print-config ───────────────────────────────────────────────────────
|
|
65
|
+
hdr "T1: --print-config"
|
|
66
|
+
OUT="$(CODE_SEARCH_EMBEDDING_PROVIDER=ollama node "$DIST_CLI" --print-config --retrieval.max-chunks 12 2>&1)" || { fail "exited non-zero"; }
|
|
67
|
+
echo "$OUT" | grep -q '"provider": "ollama"' && pass "env layer applied" || fail "embedding.provider != ollama"
|
|
68
|
+
echo "$OUT" | grep -q '"maxChunks": 12' && pass "CLI flag applied" || fail "retrieval.maxChunks != 12 (CLI flag override)"
|
|
69
|
+
|
|
70
|
+
# ── T2: code-search index against real Ollama ───────────────────────────────
|
|
71
|
+
hdr "T2: index pet-shop (Ollama bge-m3)"
|
|
72
|
+
OUT="$(node "$DIST_CLI" index "$TMP/pet-shop" --project petshop 2>&1)" || { fail "indexer exited non-zero"; echo "$OUT" >&2; }
|
|
73
|
+
echo "$OUT" | grep -q '"chunks":' && pass "indexer printed chunks summary" || fail "indexer summary missing"
|
|
74
|
+
echo "$OUT" | grep -q 'DEPRECATED: CODE_SEARCH_LLM_MODE' && fail "F1 regression — stale ANVIL_LLM_MODE warning fired" || pass "F1: no stale legacy-env warning"
|
|
75
|
+
|
|
76
|
+
# ── T3: query (vector + bm25 baseline; reranker disabled) ───────────────────
|
|
77
|
+
hdr "T3: code-search query"
|
|
78
|
+
OUT="$(node "$DIST_CLI" query "adopt pet" --project petshop --mode vector --top-k 1 --format json 2>&1)" || { fail "vector query failed"; }
|
|
79
|
+
echo "$OUT" | grep -q '"filePath": "src/pets.ts"' && pass "vector query surfaced pets.ts" || fail "vector query did not surface pets.ts"
|
|
80
|
+
OUT="$(node "$DIST_CLI" query "adoptPet" --project petshop --mode bm25 --top-k 1 --format json 2>&1)" || { fail "bm25 query failed"; }
|
|
81
|
+
echo "$OUT" | grep -q '"filePath": "src/pets.ts"' && pass "bm25 query surfaced pets.ts" || fail "bm25 query did not surface pets.ts"
|
|
82
|
+
|
|
83
|
+
# ── T4: status reports the index ────────────────────────────────────────────
|
|
84
|
+
hdr "T4: status"
|
|
85
|
+
OUT="$(node "$DIST_CLI" status --project petshop 2>&1)"
|
|
86
|
+
echo "$OUT" | grep -q '"embeddingProvider": "ollama"' && pass "embeddingProvider=ollama" || fail "status embeddingProvider mismatch"
|
|
87
|
+
echo "$OUT" | grep -q '"totalChunks":' && pass "totalChunks reported" || fail "totalChunks missing"
|
|
88
|
+
|
|
89
|
+
# ── T5: issue #6 — env vars reach the embedder (provider switch) ────────────
|
|
90
|
+
hdr "T5: env-vars-reach-embedder (issue #6 reproduction)"
|
|
91
|
+
if [[ -n "${OPENAI_API_KEY:-}" ]]; then
|
|
92
|
+
OUT="$(CODE_SEARCH_DATA_DIR="$TMP/index-openai" CODE_SEARCH_EMBEDDING_PROVIDER=openai CODE_SEARCH_EMBEDDING_MODEL=text-embedding-3-small CODE_SEARCH_EMBEDDING_DIMENSIONS=512 CODE_SEARCH_EMBEDDING_API_KEY="$OPENAI_API_KEY" node "$DIST_CLI" index "$TMP/pet-shop" --project petshop-openai 2>&1)"
|
|
93
|
+
# Either embedding succeeds (real key) OR we get OpenAI's auth error
|
|
94
|
+
# (placeholder key). Both prove the env var reached the embedder.
|
|
95
|
+
if echo "$OUT" | grep -qE '("chunks":|api.openai.com|OpenAI embedding request)'; then
|
|
96
|
+
pass "OpenAI embedder constructed + called (env vars threaded through)"
|
|
97
|
+
else
|
|
98
|
+
fail "OpenAI embedder didn't run"; echo "$OUT" | tail -5 >&2
|
|
99
|
+
fi
|
|
100
|
+
else
|
|
101
|
+
skip "T5 OpenAI path — set OPENAI_API_KEY to verify"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# ── T6: vector-space mismatch guard ─────────────────────────────────────────
|
|
105
|
+
hdr "T6: vector-space mismatch guard"
|
|
106
|
+
OUT="$(CODE_SEARCH_EMBEDDING_PROVIDER=openai CODE_SEARCH_EMBEDDING_API_KEY=stub-key node "$DIST_CLI" query "adopt pet" --project petshop --mode vector --top-k 1 --format json 2>&1)" || true
|
|
107
|
+
echo "$OUT" | grep -q 'Vector-space mismatch' && pass "guard refused the cross-provider query" || fail "guard did not fire on provider mismatch"
|
|
108
|
+
|
|
109
|
+
# ── T7: daemon round-trip ───────────────────────────────────────────────────
|
|
110
|
+
hdr "T7: daemon round-trip"
|
|
111
|
+
unset CODE_SEARCH_DAEMON_DISABLED
|
|
112
|
+
DAEMON_LOG="$TMP/daemon.log"
|
|
113
|
+
node "$DIST_DAEMON" --workspace "$TMP/pet-shop" > "$DAEMON_LOG" 2>&1 &
|
|
114
|
+
DAEMON_PID=$!
|
|
115
|
+
sleep 6
|
|
116
|
+
if kill -0 "$DAEMON_PID" 2>/dev/null; then
|
|
117
|
+
pass "daemon process alive (pid $DAEMON_PID)"
|
|
118
|
+
SOCKET="$TMP/index/daemon/pet-shop.sock"
|
|
119
|
+
test -S "$SOCKET" && pass "UDS socket present" || fail "socket missing at $SOCKET"
|
|
120
|
+
OUT="$(node "$DIST_CLI" query "adopt pet" --project pet-shop --mode vector --top-k 1 --format json 2>&1)"
|
|
121
|
+
echo "$OUT" | grep -q '"filePath": "src/pets.ts"' && pass "query through daemon succeeded" || fail "daemon-backed query failed"
|
|
122
|
+
echo "// touched $(date)" >> "$TMP/pet-shop/src/pets.ts"
|
|
123
|
+
sleep 3
|
|
124
|
+
grep -q 'reindex queued' "$DAEMON_LOG" && pass "watcher debounce-reindexed on file touch" || fail "watcher didn't fire"
|
|
125
|
+
kill "$DAEMON_PID" 2>/dev/null
|
|
126
|
+
for _ in 1 2 3 4 5; do
|
|
127
|
+
kill -0 "$DAEMON_PID" 2>/dev/null || break
|
|
128
|
+
sleep 1
|
|
129
|
+
done
|
|
130
|
+
kill -9 "$DAEMON_PID" 2>/dev/null || true
|
|
131
|
+
wait "$DAEMON_PID" 2>/dev/null || true
|
|
132
|
+
else
|
|
133
|
+
fail "daemon exited prematurely"; tail -10 "$DAEMON_LOG" >&2
|
|
134
|
+
fi
|
|
135
|
+
export CODE_SEARCH_DAEMON_DISABLED=1
|
|
136
|
+
|
|
137
|
+
# ── T8: HTTP server endpoints ───────────────────────────────────────────────
|
|
138
|
+
hdr "T8: HTTP serve"
|
|
139
|
+
PORT=$(( ( RANDOM % 1000 ) + 4100 ))
|
|
140
|
+
HTTP_LOG="$TMP/http.log"
|
|
141
|
+
CODE_SEARCH_PORT="$PORT" CODE_SEARCH_HOST=127.0.0.1 CODE_SEARCH_TRANSPORT=streamable-http node "$DIST_MCP" --serve --project petshop > "$HTTP_LOG" 2>&1 &
|
|
142
|
+
HTTP_PID=$!
|
|
143
|
+
sleep 5
|
|
144
|
+
if kill -0 "$HTTP_PID" 2>/dev/null; then
|
|
145
|
+
for ep in health ready version metrics admin/api/status; do
|
|
146
|
+
code="$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:${PORT}/${ep}")"
|
|
147
|
+
if [[ "$code" == "200" ]]; then pass "GET /$ep → 200"; else fail "GET /$ep → $code"; fi
|
|
148
|
+
done
|
|
149
|
+
curl -s "http://127.0.0.1:${PORT}/metrics" | grep -q '^# HELP code_search_queries_total' \
|
|
150
|
+
&& pass "/metrics emits Prom text format" || fail "/metrics missing prelude"
|
|
151
|
+
kill "$HTTP_PID" 2>/dev/null
|
|
152
|
+
for _ in 1 2 3 4 5; do
|
|
153
|
+
kill -0 "$HTTP_PID" 2>/dev/null || break
|
|
154
|
+
sleep 1
|
|
155
|
+
done
|
|
156
|
+
kill -9 "$HTTP_PID" 2>/dev/null || true
|
|
157
|
+
wait "$HTTP_PID" 2>/dev/null || true
|
|
158
|
+
else
|
|
159
|
+
fail "HTTP server failed to start"; tail -10 "$HTTP_LOG" >&2
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# ── Summary ─────────────────────────────────────────────────────────────────
|
|
163
|
+
echo
|
|
164
|
+
echo "──────────────────────────────────────────"
|
|
165
|
+
echo "PASS: $PASS FAIL: $FAIL SKIP: $SKIP"
|
|
166
|
+
echo "──────────────────────────────────────────"
|
|
167
|
+
exit $(( FAIL == 0 ? 0 : 1 ))
|