Add proxy support for fetch indexing#345
Conversation
ReviewThe proxy logic in Before we can merge1. Remove bundle files from the diff. 2. Target the 3. SOCKS5 validation.
Question: real-world demandI want to understand the actual need before committing to maintaining proxy infrastructure:
This adds ~200 lines of source + Thanks for the thorough implementation — the code quality is solid. Just need clarity on demand before we merge. |
- Bug report: 12 → 14 platforms, PR target main → next - Feature request: add JetBrains Copilot, Qwen Code, Pi to dropdown - PR template: add JetBrains Copilot, Qwen Code, Pi to checklist - CONTRIBUTING.md: feature branch from main → next Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
d9e0744 to
76b86dc
Compare
|
Thanks for the review. I pushed an update addressing the merge blockers:
On demand: this came from a real failure I hit while using I do not know of additional user reports, so I would frame this as one concrete reproducible environment rather than broad demand. README documentation alone would not have fixed this case because the generated fetch script needed an explicit cross-runtime proxy path: Bun needs I kept Validation after the update:
All passed locally. |
|
Thanks for the quick turnaround — all three items addressed cleanly. I haven't seen this need come up before, so I'd like to wait for a bit of community signal before merging. If others need proxy support too, they can 👍 this PR. Once we see demand, we'll merge it in. Appreciate the contribution and the detailed repro. |
|
I think everyone in mainland China needs it; you should understand. |
…stats Shows all events across all sessions with visual bars — visible in both fresh and active session states. Replaces old single-line continuity summary. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…laude-code#46915) Claude Code auto-update can leave installed_plugins.json pointing to a non-existent directory, breaking all hooks. This adds 4 defense layers: 1. start.mjs startup: reverse heal — symlink from broken registry path to our dir 2. server.ts first tool call: mid-session heal — catches auto-update during session 3. postinstall.mjs: backward symlink on new install for stale registry 4. start.mjs auto-deploy: global SessionStart hook at ~/.claude/hooks/ that survives total plugin cache breakage 9 TDD tests verify heal behavior with real filesystem fixtures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…th pure Node.js - postinstall.mjs: removed duplicate self-heal block (was copy-pasted twice) - Global heal hook: replaced #!/usr/bin/env bash with #!/usr/bin/env node Bash dependency caused issues on Windows (no bash) and macOS with SIP/MDM security policies that restrict shell execution. Pure Node.js works everywhere. - Auto-cleans old .sh hook if present, deploys .mjs version - Windows: uses junction type for symlinks (no admin required) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Agent review found critical issues in the initial cache self-heal: 1. CRITICAL: Layer 4 global hook was dead code — now registers in ~/.claude/settings.json SessionStart (Claude Code doesn't auto-discover hooks) 2. HIGH: Path traversal — installPath now validated inside plugin cache root via resolve(rp).startsWith(cacheRoot + sep) in all 4 code paths 3. HIGH: server.ts bundle mode — symlink target used wrong dir, now uses pluginRoot pattern (package.json existence check) 4. HIGH: Dangling symlink — lstatSync + unlinkSync before symlinkSync prevents EEXIST when broken symlink already exists 5. MEDIUM: Tests asserted .sh but code deploys .mjs — fixed 6. LOW: Dead lstatSync import removed, unlinkSync in static imports 7. LOW: Exact key match (=== "context-mode@context-mode") instead of includes() 13 TDD tests now cover: dangling symlink, path traversal, exact match, settings.json registration, and all previous behaviors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ss (mksglu#347) Claude Code spawns hooks via `bash -c "node ..."` on WSL2/Linux. The intermediate shell makes process.ppid point to a transient bash PID, not Claude Code. The PPID-keyed sentinel is never found, causing all MCP redirects to be bypassed — context window floods. Fix: hooks now scan /tmp for `context-mode-mcp-ready-*` files and probe each PID with kill(pid,0). Server writes sentinel with process.pid (not ppid). Hardcoded /tmp on Unix avoids TMPDIR mismatch. Changes: - hooks/core/mcp-ready.mjs: glob scan + PID liveness + stale cleanup - src/server.ts: sentinel uses process.pid, /tmp on Unix - 11 test files: updated sentinel path pattern Closes mksglu#347 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The existing minSpan proximity formula `1/(1 + minSpan/contentLen)` rewards
longer documents — a long doc with one tight occurrence outranks a short doc
with multiple tight occurrences at the same span. Add a saturating phrase-
frequency reward layered on top: count ordered adjacent-pair occurrences of
consecutive query terms within 30 chars, contribute `0.5 * min(1, pairs/4)`
to the boost so frequency breaks the tie without unbounded keyword-stuffing
wins.
Pure additive signal — minSpan formula and length-norm intent are unchanged.
Cap (0.5) sits below max proximity (≈1.0) and in title-boost range (0.3-0.6).
Saturation at 4 hits keeps stuffed docs from unbeatably dominating.
Bench (1000-doc corpus, 500 iters, p95 us/call):
baseline with-boost
cache invalidation 403 325
database connection 398 390
auth token 285 264
rate limiter 320 299
circuit breaker retry 517 453
→ latency neutral (within noise)
Ranking quality (3 controlled cases of long-1-hit vs short-N-hits):
baseline correct: 0/3
with-boost correct: 3/3
Co-authored-by: Mert Köseoğlu <bm.ksglu@gmail.com>
…#350) (mksglu#351) ContentStore.index() used `content ?? readFileSync(path)`, so an empty string `""` won out over `path` and 0 sections were indexed. Some MCP clients materialize optional string fields as `""`, which masked the file path. Treat empty content as missing so a valid `path` falls back to reading the file. Adds regression test covering the empty-content + path code path. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
After reading the diff carefully I want to flag three concrete points before merge — not blockers per se, but the kind of things that bite later. 1. Duplication of all NO_PROXY logic between TS and runtime template
Two sources of truth for identical logic, with no compile-time link between them. The unit tests exercise the TS version (CIDR / suffix / wildcard / port edge cases), but the string-injected runtime version is only exercised by a smoke test that checks "Bun gets Cleaner alternative: ship a vendored plain-JS file (e.g. This is the change I'd push back on hardest before merging — once it lands as-is, the two copies will drift the first time someone fixes a NO_PROXY edge case. 2.
|
Summary
ctx_fetch_and_indexcurrently generates a subprocess script that calls barefetch(url). In environments where direct DNS/network access is blocked or polluted, this makes fetch indexing fail even when users have standard proxy variables configured.This PR adds proxy-aware fetch support for both JavaScript runtimes used by context-mode:
fetch(targetUrl, { proxy }).fetch(targetUrl, { dispatcher: new ProxyAgent(proxy) })throughundici.Details
src/fetch-proxy.tsto select proxy URLs fromHTTPS_PROXY,https_proxy,HTTP_PROXY,http_proxy,ALL_PROXY, andall_proxy.NO_PROXY/no_proxybypass support for exact hosts, suffix hosts, wildcard, host:port, and IPv4 CIDR entries.ctx_fetch_and_indexgenerated fetch code to callfetchWithProxy(url)instead of barefetch(url).undici@^6.25.0as a runtime dependency so Node 18+ can use a stableProxyAgentpath.Validation
bunx vitest run tests/core/fetch-proxy.test.tsnpm run typechecknpm test -- tests/core/fetch-proxy.test.ts tests/core/server.test.ts tests/core/search.test.tsnpm run buildAlso ran
npm test; unrelated existing ABI-cache assertions intests/core/cli.test.tsfail locally under Node 25 becauseensureNativeCompat()returns early whenhasModernSqlite()is true:cache hit: copies cached ABI binary to active pathcache hit does not trigger rebuild