A pass over the extension surface to address review feedback:
Safety / hardening:
- `graphPanel.ts`: validate `m.path` from the webview before opening
files. Reject absolute paths and any path that escapes the workspace
root (`..`, `/foo`, `C:/...`). Validate the line number is a positive
integer before constructing a `Range`. Surface failures via the output
channel rather than letting the rejection bubble up.
- `mcpProvider.ts`: defensively check that
`vscode.lm.registerMcpServerDefinitionProvider` exists before calling
it. The `engines.vscode: ^1.99.0` field already enforces this on
install, but some VS Code-derived editors mis-report their engine
version. The extension now degrades gracefully (sidebar, commands,
status bar still work) instead of failing activation.
- `commands.ts` and `graphPanel.ts`: wrap `workbench.action.chat.open`
in try/catch. Not every VS Code-compatible editor exposes that
command; falling back to the output channel avoids unhandled
rejections after the user clicked "Open chat".
- `extension.ts`: persist the first-run walkthrough flag only after the
walkthrough command resolves successfully, so a transient failure
doesn't silently skip the onboarding forever.
CI gates:
- `extension-ci.yml` and `extension-release.yml`: run `npm test` between
typecheck and build, so manifest-level smoke regressions can't slip
through to either the PR artefact or the marketplace publishes.
Settings copy:
- `socraticode.env` description: explicitly call out that the setting
is for non-secret config only. Recommend OS environment variables /
local `.env` files for API keys, since workspace settings can sync
via Settings Sync and end up in committed `.vscode/settings.json`.
Quality of life:
- `sidebar.ts` `formatRelative`: clamp the computed seconds to zero so
a file mtime slightly ahead of the local clock doesn't render
"-5s ago".
- `walkthroughs/first-index.md`: corrected the embedding model name
(`nomic-embed-text`, not `mxbai-embed-large`) to match the engine
default in `src/constants.ts`.
Lint / docs:
- `extension/README.md`: hyphenate "Eclipse Theia-based editors".
- `DEVELOPER.md`: add `text` language hint to the directory-tree code
fence (markdownlint MD040). Updated the inline comment for
`settings.ts` to reflect its current shape.
- `README.md`: reflow the "extension vs plugin" callout into a single
blockquote (markdownlint MD028).
Lint, typecheck, manifest tests and build all clean. Engine unit tests
unaffected (706/706 still pass).
README updates:
- Plugins table now includes a row for the VS Code / Open VSX extension,
with a list of every editor that pulls from one of the two registries
(Cursor, VSCodium, Gitpod, code-server, Theia, Antigravity, Particle
Workbench).
- Cursor Marketplace listing mentioned alongside the existing
`/add-plugin` URL install.
- A short "extension vs plugin" callout explaining when to install
which: the extension auto-registers MCP and adds native UI, the
plugin formats add skills + agent rules. Both can coexist.
DEVELOPER.md updates:
- New "VS Code / Open VSX Extension" section covering layout, local
development (F5 to launch an Extension Development Host), build /
lint / test / package commands, publishing flow, and versioning
policy (extension tracks the engine version via the bump script).
- Explicit list of what the extension is NOT (no re-implementation of
search, no shipped engine, no language-server features). Keeps scope
honest and prevents future feature creep.
- Added the new section to the table of contents.
Interactive Viewer (primary)
────────────────────────────
codebase_graph_visualize now accepts mode="mermaid" (default, existing
behaviour — text Mermaid diagram) or mode="interactive". Interactive
mode generates a self-contained HTML page and opens it in the user's
default browser via the `open` npm package (cross-platform: macOS,
Linux, Windows). Cytoscape.js 3.30.2 + Dagre 0.8.5 + cytoscape-dagre
2.5.0 are vendored under src/assets/ — no CDN, works offline.
Features:
- File view — every source file as a node, imports as edges, language
colour-coded, circular deps highlighted in red.
- Symbol view toggle — functions/classes/methods as nodes with call
edges (confidence-styled). Embedded when the symbol graph fits under
20k symbols / 60k call edges; above that threshold the file view
remains usable and a banner directs users to codebase_impact /
codebase_symbols for symbol-level queries.
- Sidebar on node click — imports, dependents, per-file symbol list
(first 30 + link to codebase_symbols), action buttons for blast
radius and call flow.
- Right-click any node → blast radius overlay (reverse-transitive
closure). Call-flow button on the sidebar for forward traversal.
- Live search across files and symbols, six Cytoscape layouts
(Dagre / force / concentric / breadth-first / grid / circle),
PNG export (filename sanitised for cross-platform safety).
- `open: false` parameter skips auto-launch and just returns the file
path — useful in headless environments.
Viewer is XSS-safe by construction: all DOM built with createElement
+ textContent (no innerHTML anywhere); embedded JSON escapes every
"<" as \u003c so a stray </script> in a file path or symbol name
cannot break out of the script-type="application/json" container.
New files:
- src/assets/{cytoscape.min.js,dagre.min.js,cytoscape-dagre.js,
viewer-template.html,viewer-styles.css,viewer-app.js}
- scripts/copy-assets.mjs — postbuild copier (tsc does not handle
non-TS files); wired into npm run build and prepublishOnly
- src/services/graph-visualize-html.ts — HTML builder with scale-cap
logic (MAX_SYMBOLS / MAX_EDGES / MAX_SYMS_PER_FILE) and parallel
per-file Qdrant payload loading
- src/services/graph-visualize-browser.ts — temp-file write +
cross-platform open wrapper
- tests/unit/graph-visualize-html.test.ts — 5 tests (self-contained,
escape-safety, symbolMode omitted/capped, cycle marking)
- tests/unit/graph-visualize-browser.test.ts — 4 tests (deterministic
path, overwrite, success + failure paths)
New runtime dependency: open@^10.2.0 (Sindre Sorhus, zero transitive
deps, cross-platform).
British-English doc sweep (secondary)
─────────────────────────────────────
Switched all project docs to British English spelling:
behavior → behaviour organized → organised
color-coded → colour-coded initialization → initialisation
visualization → visualisation customization → customisation
recognized → recognised optimized → optimised
acknowledgment → acknowledgement finalize → finalise
analyzing → analysing apologizing → apologising
sexualized → sexualised
Affected files: README, DEVELOPER, AGENTS, CLAUDE, GEMINI, SECURITY,
CONTRIBUTING, CODE_OF_CONDUCT, agents/codebase-explorer.md,
skills/codebase-exploration/{SKILL.md,references/tool-reference.md},
skills/codebase-management/references/tool-reference.md.
Also surfaced Impact Analysis in the top-level README paragraph.
Docs
────
- README: "Interactive graph explorer" subsection under Impact Analysis,
tool-table row updated.
- DEVELOPER.md: architecture section under codebase_graph_visualize
covering asset layout, data flow, cap logic, XSS-safety invariants.
- AGENTS.md / CLAUDE.md / GEMINI.md: new "User asks for a visual /
interactive / shareable graph" row in the tool-routing table.
- skills/codebase-exploration/: SKILL.md bullet + tool-reference.md
full mode description.
- CHANGELOG.md: "Interactive Graph Explorer" section under Unreleased.
Quality gates (all green)
─────────────────────────
- Biome lint: clean
- TypeScript (tsc): clean
- Unit tests: 685/685
- Integration tests: 154/154 (real Qdrant + Ollama)
- CodeRabbit: No findings (1 fix applied — filename sanitisation)
- Snyk code test: 0 issues
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the four reviewer-flagged gaps from the previous round:
1. **Phase F wired into the watcher / `codebase_update`.**
`rebuildGraph(path, { skipSymbolGraph: true })` now exposes a
file-import-only build mode. `services/indexer.ts` calls it +
`updateChangedFilesSymbolGraph(...)` when meta exists AND ≤ 50 files
changed (`INCREMENTAL_SYMBOL_THRESHOLD`); falls back to full rebuild
above that. Measured speedup on a 1000-file synthetic repo: full
rebuild 6.55 s → Phase F single-file update 197 ms (~33×).
2. **Real end-to-end scale test.**
New `tests/integration/symbol-graph-scale.test.ts` generates 1000
synthetic Python files × 20 symbols/file (20k symbols) against a real
Qdrant, asserts (a) full rebuild within budget, (b) cold listSymbols /
getImpactRadius queries within budget, (c) Phase F update ≥ 4× faster
than full rebuild. `SCALE_LARGE=1` pushes to 10k files / 200k symbols.
3. **Smoke benchmark numbers captured.**
New `scripts/benchmark-graph.ts` runs `rebuildGraph` against any
target dir and emits JSON + a Markdown row. Numbers for SocratiCode
itself (82 files / 571 symbols / 9914 call edges / 0.90 s / 167 MB
RSS) and the synthetic 1000-file repo are now in DEVELOPER.md
§ "Real-world benchmark numbers".
4. **Logger test flake fixed.**
`services/logger.ts` exposes `setLogLevel` / `getLogLevel`;
`tests/unit/logger.test.ts` pins the level in beforeEach and restores
in afterEach. Verified deterministic with `SOCRATICODE_LOG_LEVEL=debug`
set in the shell environment.
### Bug discovered + fixed by the new benchmark
Running `scripts/benchmark-graph.ts` against SocratiCode itself crashed
the symbol graph build with `TypeError: existing.push is not a function`.
Root cause: shard maps used `shard[name]` bracket access on a plain
`{}`, which returned `Object.prototype.constructor` (a function) for
common method names like `constructor`, `toString`, `hasOwnProperty`.
Fixed by guarding all reads with `Object.hasOwn` in
`services/code-graph.ts` and `services/symbol-graph-incremental.ts`.
Added a regression test in
`tests/integration/symbol-graph-incremental.test.ts`.
### QA
- Biome lint: clean (auto-fixed 1 file).
- VS Code Problems panel: clean.
- Unit tests: 676/676 pass (29 files); reproducible.
- Integration tests touched: 45/45 pass (incremental, scale,
indexer, code-graph).
- CodeRabbit review: no findings.
- Snyk Code: 0 issues.
### Doc updates
- DEVELOPER.md: removed "watcher still triggers full rebuild" wording,
added "Real-world benchmark numbers" subsection with measured table.
- CHANGELOG.md: removed "Known Limitations" block; added new
Bug Fixes entries (prototype keys, logger flake) and a Performance
entry for the wired Phase F path with measured numbers.
Addresses six gaps in the prior Impact Analysis work:
1. **Scale benchmarks** (was missing): tests/unit/symbol-graph-scale.test.ts
exercises sharding/hashing at 10k–100k symbol volumes with loose
regression thresholds (>10× slowdown to fail).
2. **Per-language symbol-extraction tests** (was ~15% of plan):
tests/unit/graph-symbols.test.ts now covers Rust, Java/Kotlin/Scala (JVM),
C#, C/C++, Ruby, PHP, Swift, Bash, and the regex fallback path.
3. **Phase F (per-file incremental updates)** — implemented as
src/services/symbol-graph-incremental.ts with
updateChangedFilesSymbolGraph(). Re-extracts changed files, diffs against
persisted payloads via contentHash, patches only affected name (≤27) and
reverse-call (≤256) shards, and updates meta counts incrementally.
Integration tests in tests/integration/symbol-graph-incremental.test.ts.
Watcher wiring is documented as a follow-up in CHANGELOG (still does
full rebuild on save).
4. **Integration tests for the four new MCP tools**: codebase_impact,
codebase_flow, codebase_symbol, codebase_symbols added to
tests/integration/tools.test.ts.
5. **Symbol-graph store unit tests**: tests/unit/symbol-graph-store.test.ts
covers nameShardKey, allNameShardKeys, reverseShardKey, reverseShardHex,
contentHashOf — 14 tests.
6. **Bug fix**: Java/Kotlin/Swift/Scala silently failed because ast-grep
throws 'Invalid Kind' when a queried node-kind doesn't exist for that
grammar (e.g. object_declaration is Kotlin-only). The outer try/catch in
extractSymbolsAndCalls swallowed the error and returned only <module>.
Fixed via safeFindAll wrapper applied to all 36 call sites in
src/services/graph-symbols.ts.
Also fixes a CodeRabbit-flagged comment/code mismatch in
src/services/graph-entrypoints.ts (now actually checks for it/describe
test names as the comment claimed).
Tests: 676 unit pass. Lint clean. CodeRabbit clean. Snyk clean.
- 4 new unit test files (22 tests) for graph-symbols, graph-symbol-resolution,
graph-entrypoints, symbol-graph-cache. All 799 tests pass.
- README/AGENTS/CLAUDE/GEMINI: document codebase_impact, codebase_flow,
codebase_symbol, codebase_symbols and updated workflow guidance.
- DEVELOPER.md: new architectural section for symbol-level call graph,
including sharded storage layout and resolution confidence levels.
- CHANGELOG: Unreleased section for the impact-analysis feature.
- Apply CodeRabbit fixes: dedupe in-flight cache loads, set ImpactResult.truncated
when frontier extends beyond depth limit, drop redundant String() around Lang enum.
- Switch reverse-shard hash from SHA1 to SHA256 (Snyk hardening; non-cryptographic use).
- Use Object.hasOwn() instead of `in` for log level validation
- Normalize relativePath in shouldIgnore() for Windows compatibility
- Reject zero/negative/decimal values in embedding config (Number() instead of parseInt())
- Update aggregate test count to 765
- Harden code-graph test assertion with explicit toBeDefined()
- README: new Features entries, full sections with config examples
- README: new env vars SOCRATICODE_BRANCH_AWARE, SOCRATICODE_LINKED_PROJECTS
- README: updated codebase_search tool description for includeLinked
- DEVELOPER.md: updated config.ts description, branch-aware and linked projects sections
- Move Svelte/Vue from "Indexing Only" to "Full Support" in README
- Move SASS/LESS to "Code Graph via Regex" in README
- Add graph-aliases.ts to DEVELOPER.md service file listing
- Update DEVELOPER.md data flow with CSS @import, path alias, and SCSS
partial resolution steps