Commit Graph

98 Commits

Author SHA1 Message Date
Giancarlo Erra ea69a72145 fix(graph): tighten C# namespace regex; capture nested declarations
The previous regex `^namespace\s+([\w.]+)` was anchored at column 0, so
nested namespace declarations (the `namespace Inner` block inside
`namespace Outer { ... }`) were silently missed. The capture group also
accepted invalid identifiers like `1Foo` and matched on stray
occurrences of the word `namespace` not followed by `;` or `{`.

The new regex `^\s*namespace\s+([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\s*(?=[;{])`:

- `^\s*` allows leading whitespace, so indented (nested) declarations
  are captured.
- The dotted-identifier capture requires each segment to start with a
  letter or underscore, matching C# identifier rules.
- `(?=[;{])` requires a real terminator, filtering out spurious matches.

Adds three regression tests: nested-namespace capture, rejection of
digit-leading identifiers, and the terminator-lookahead behaviour.

Found by CodeRabbit on PR #34 (nitpick).
2026-04-28 00:30:36 +01:00
Giancarlo Erra fc249fdfcf fix(graph): make C# namespace resolution deterministic
`buildCsNamespaceMap` previously iterated `fileSet` in fs.readdir()
traversal order, which POSIX does not guarantee. Combined with the
`candidates[0]` selection in `resolveImport`, this meant a `using`
directive could resolve to different files on different machines or
runs.

Sort the `.cs` paths lexically before scanning so candidate lists are
stable. Adds a regression test that builds the map twice from sets
populated in different orders and asserts both produce the same
candidate sequence and the same first candidate.

Found by CodeRabbit on PR #34.
2026-04-28 00:20:45 +01:00
Giancarlo Erra 0aaf3f1d75 fix(graph): resolve C# using directives via namespace scan (closes #33)
C# imports previously always returned null because there is no direct
filename mapping for `using X.Y.Z;`. As a result `codebase_graph_query`
reported zero edges for C# projects, and the symbol-level tools
(impact, flow, symbol) silently lost cross-file resolution because they
walk the file-import graph for Tier 2/3 candidates.

Build a namespace-to-files map once per graph build by regex-scanning
every `.cs` file for `^namespace X.Y.Z` (covers both block-scoped and
file-scoped C# 10+ syntax) and consult it from the csharp branch of
resolveImport. When a namespace spans multiple files the first
candidate is returned; multi-file fan-out is tracked as a follow-up.
External namespaces (System.*, Microsoft.*) are still filtered upstream
by isExternalModule, so the map is only consulted for project-internal
names.

Cost is O(n) reads at graph-build time, gated by a `hasCs` precheck so
non-C# projects pay nothing.

Adds 12 unit tests covering block-scoped, file-scoped, multi-file,
multi-namespace-per-file, commented-out lines, non-.cs files, empty
projects, unknown namespaces, and external (System.*) filtering.
2026-04-28 00:04:01 +01:00
Giancarlo Erra 0e86cd0731 chore: release v1.7.0 v1.7.0 2026-04-27 23:46:19 +01:00
Giancarlo Erra b0356a517f chore: add release-it as dev dependency 2026-04-27 22:32:06 +01:00
Giancarlo Erra 7814ac7d60 Merge pull request #32 from giancarloerra/feat/impact-analysis
feat: Impact Analysis (symbol-level call graph) + Interactive HTML graph explorer
2026-04-27 22:14:36 +01:00
Giancarlo Erra e4da76979e feat(visualize): symbol view as focus graph; UX polish & stats consistency
Symbol view (full rebuild)
──────────────────────────
Replaces the unusable "show all symbols at once" mode with a focus
graph (SourceTrail / IntelliJ pattern):

- Landing state shows the alphabetical list of all symbols in the
  sidebar; canvas shows a "pick a symbol" overlay constrained to the
  canvas area (right: 340px) so the list stays visible.
- Three entry paths to seed: list click, search bar, or symbol click
  from a file's sidebar in Files view.
- Once seeded, canvas shows the symbol + its 2-hop callers/callees
  neighbourhood (auto-falls back to depth 1 if > 60 nodes).
- Clicking any neighbour re-centres on it. Seed has a distinctive
  orange ring + always-visible label so the anchor is obvious.
- "← Back to symbol list" link in the sidebar restores the empty
  state — explicit way out instead of relying on accidental
  empty-canvas clicks.
- Light file-grouping: each symbol's border colour is a stable hash
  of its file path; symbols from the same file share a colour.

Layout dropdown clean-up
────────────────────────
Removed Force-directed (cose). Force-directed is the wrong algorithm
for code dependency graphs — hub clusters collapse, orphans fly off,
labels overlap, no tuning fixes the underlying shape mismatch. Tried
fcose as a substitute; same fundamental problem on dense code graphs.
Default is now Dagre TB; remaining options are Concentric, Breadth-
first, Grid, Circle — all deterministic.

UX polish
─────────
- autoungrabify: true — disables single-click drag, fixes "node jumps
  on click" (trackpad clicks always have some motion which Cytoscape's
  default interprets as a node grab).
- Tap-to-highlight neighbourhood — clicking any node highlights its
  direct neighbours and fades the rest. Less aggressive than the
  transitive blast-radius / call-flow buttons in the sidebar.
- Zoom-bound label visibility — labels hidden below zoom 0.55 so 100+
  node graphs aren't a soup of overlapping text. Selected / highlighted
  nodes always show their label.
- Layout-position persistence — switching Files ↔ Symbols and back
  preserves Files-view positions instead of re-running the layout.

TDZ regression test
───────────────────
New tests/unit/viewer-app.test.ts runs the bundled viewer-app.js in a
sandboxed node:vm context with mocked DOM + Cytoscape, triggering
every function-typed style closure on a fake element. Catches TDZ
("Cannot access X before initialization") and other reference errors
at unit-test time. Would have caught both the prior `cy` and
`LABEL_ZOOM_THRESHOLD` ordering bugs before they reached the browser.

Stats-line consistency
──────────────────────
graph-visualize-html.ts — top bar now displays embedded counts
(sym.symbols.length / sym.symbolEdges.length) instead of meta counts.
Previously the top bar said "630 symbols" while the sidebar's "All
symbols" said "722" because meta excludes synthetic <module>
placeholders. Capped mode keeps meta counts with a "(capped)"
qualifier since the embedded set is empty there.

Quality gates
─────────────
- Biome lint: clean
- TypeScript (tsc): clean
- Unit tests: 687/687 (incl. the new viewer-app.js evaluation test)
2026-04-27 17:46:51 +01:00
Giancarlo Erra 9d113975dc docs(readme): surface impact analysis & portability; fix Claude Code install
- Add "Portable, AI- and host-agnostic" paragraph in the intro that
  bundles two claims: the codebase context lives with the code (works
  with any assistant / IDE / CLI, any combination), and pre-computed
  reasoning (blast radius, call-flow, dependency traversal) lets
  smaller / cheaper models hold their own on architectural questions.
- Add three rows to the "Built-in Code Search vs SocratiCode"
  comparison table: symbol-level impact / blast radius, call-flow
  tracing, interactive visual graph explorer.
- Plugins section: chain Claude Code's two install commands with &&
  so the row is a single copy-paste — the install step was missing.
2026-04-27 17:44:43 +01:00
Giancarlo Erra 081606f9e2 fix(visualize): use function replacers so vendored assets containing $& survive intact
String.prototype.replace with a string replacement argument interprets
`$&`, `$'`, `` $` ``, and `$$` as special tokens (match, post-match,
pre-match, literal-$). The vendored bundles contain the classic
regex-escape idiom `"\\$&"` (`cytoscape.min.js` and `dagre.min.js` each
have one), which the asset-injection pipeline was corrupting into e.g.
`"\\{{CYTOSCAPE}}"` in the generated HTML. The visible symptom was a
broken Cytoscape search-box escape path whenever a user typed a regex
metacharacter into the live-search input.

Fix: convert the six asset/data replacements in buildInteractiveGraphHtml
to function-replacer form (`() => assets.cytoscape`), which uses the
returned string literally with no `$`-token interpretation. Same class
of bug would have affected embedded JSON had a file path or symbol name
contained `$&` — now neutralised for the whole chain.

Regression test added: asserts the `\\$&` idiom survives verbatim in the
rendered HTML and that neither `\\{{CYTOSCAPE}}` nor `\\{{DAGRE}}`
appears. A single `expect(html).toContain('"\\\\$&"')` catches the bug.

Quality gates (all green):
- Biome lint: clean
- TypeScript (tsc --noEmit): clean
- Unit tests: 686/686 (was 685; +1 regression test)
- CodeRabbit: No findings
- Snyk: 0 issues

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:48:58 +01:00
Giancarlo Erra 50d8853ea6 feat(visualize): add interactive HTML graph explorer; British-English doc sweep
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>
2026-04-23 16:04:41 +01:00
Giancarlo Erra 4e41b4604e feat(impact): wire Phase F into watcher; fix prototype-key crash; add real scale test
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.
2026-04-21 15:59:55 +01:00
Giancarlo Erra 2d686a2688 feat(impact): close gaps from review — Phase F API, scale + integration tests, language coverage
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.
2026-04-21 15:27:16 +01:00
Giancarlo Erra 59f630e1ca test+docs(impact): add symbol pipeline tests and Phase G docs
- 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).
2026-04-21 13:54:01 +01:00
Giancarlo Erra c356c42f4f feat(impact): add symbol-level call graph and Impact Analysis tools
Implements Phases A-E of the Impact Analysis plan:

Phase A — Foundations:
- New types: SymbolNode, SymbolEdge, SymbolGraphMeta, SymbolGraphFilePayload, EntryPoint
- Constants: MAX_IMPACT_DEPTH, MAX_FLOW_DEPTH, SYMBOL_NAME_SHARDS=27, SYMBOL_REVERSE_SHARDS=256
- Sharded Qdrant store (symbol-graph-store.ts): meta/file/index collections,
  27 name shards, 256 reverse-call shards, all dummy-vector pattern
- LRU cache (symbol-graph-cache.ts): per-project lazy shard loading, 500-file LRU

Phase B — Symbol & call extraction (graph-symbols.ts):
- Per-language extractors: TS/JS/TSX, Python, Go, Rust, JVM (Java/Kotlin/Scala),
  C#, C/C++, Ruby, PHP, Swift, Bash, regex fallback for Dart/Lua/Svelte/Vue
- Synthetic <module> symbol per file as fallback caller
- Scope tracking via ScopeFrame[] for accurate caller attribution

Phase C — Resolution (graph-symbol-resolution.ts):
- Three-tier strategy: local match → walk caller deps → one transitive hop
- Confidence levels: unresolved | unique | multiple-candidates
- computeUnresolvedPct for meta stats

Phase D — Analysis primitives:
- detectEntryPoints: orphans + conventional names + framework patterns + tests
- getImpactRadius: BFS via reverseFileIndex, polymorphic file/symbol target
- getCallFlow: DFS via lazy outgoing edges, cycle-safe, depth-limited
- getSymbolContext: 360° view (definition + callers + callees)
- listSymbols: file-mode or query-mode

Phase E — MCP tools:
- codebase_impact: blast radius for file/symbol
- codebase_flow: entry-point discovery + forward call tree
- codebase_symbol: symbol context (callers + callees)
- codebase_symbols: file/query symbol listing

Integration:
- buildCodeGraph now extracts symbols inline alongside imports
- doRebuildGraph persists both file-import graph and symbol graph
- removeGraph cleans up symbol collections + drops cache
- getGraphStatus surfaces symbol stats (files/symbols/edges/unresolved%)

All 621 existing tests still pass. TypeScript compiles cleanly. Biome lint clean.
2026-04-21 13:26:10 +01:00
Giancarlo Erra 2ad7b3db5d docs: add workflow examples to Context Artifacts section 2026-04-17 12:37:54 +01:00
Giancarlo Erra deaf82981b chore: release v1.6.1 v1.6.1 2026-04-17 11:19:30 +01:00
Giancarlo Erra a21cf01516 Merge pull request #29 from giancarloerra:docs/agent-instructions-zed-graph-triggers
docs: add Zed support, per-IDE instruction paths, and strengthen graph triggers
2026-04-17 11:18:05 +01:00
Giancarlo Erra 270d402f48 docs: add Zed support, per-IDE instruction paths, and strengthen graph triggers 2026-04-17 11:17:08 +01:00
Giancarlo Erra 486bf7622b chore: release v1.6.0 v1.6.0 2026-04-16 19:03:58 +01:00
Giancarlo Erra a8b069a900 docs: add Discord community, Cloud section, and tool portability to README 2026-04-16 19:02:09 +01:00
Giancarlo Erra 2fdbaf8ba4 chore: fix Biome lint warnings (non-null assertions, unused param) 2026-04-16 18:31:44 +01:00
Giancarlo Erra af7d1d4d45 Merge pull request #25 from sb-giithub/feat/global-config-and-batch-size-env
feat: support global config fallback and configurable embedding batch size
2026-04-14 17:43:43 +01:00
jason.ma 49b5b35bff fix: resolve relative paths for global config fallback and strict batch size validation
1. Global config fallback: relative artifact paths are now resolved against
   the global config directory (not the project root) when loading from fallback.
   Absolute paths are left unchanged. Project-level config behavior is unaffected.

2. EMBEDDING_BATCH_SIZE: replaced Number.parseInt with Number() + Number.isInteger()
   so that inputs like "64abc", "1.5", and "" are correctly rejected instead of
   silently accepted.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 19:12:44 +08:00
Giancarlo Erra 2eb74ae620 chore: add .private/ to .gitignore for internal planning docs 2026-04-13 23:27:12 +01:00
Giancarlo Erra afd2da2771 docs: add CodeRabbit review expectations to PR template and contributing guide 2026-04-13 22:55:03 +01:00
Giancarlo Erra 68f4b36794 chore: release v1.5.0 v1.5.0 2026-04-13 22:46:53 +01:00
Giancarlo Erra 648d04e24d Merge pull request #26 from giancarloerra:feat/multi-platform-plugins
feat: multi-platform plugin support (Cursor, Codex, Gemini CLI, VS Code)
2026-04-13 22:21:43 +01:00
Giancarlo Erra b2333b574c fix: correct spelling of "visualize" in GEMINI.md and update Codex installation instructions in README.md 2026-04-13 22:15:04 +01:00
Giancarlo Erra 529d1b2a64 feat: multi-platform plugin support (Cursor, Codex, Gemini CLI, VS Code) 2026-04-13 22:06:30 +01:00
Giancarlo Erra 61060d5153 docs: consolidate README 2026-04-13 16:45:10 +01:00
jason.ma 9d04c4443a feat: support global config fallback and configurable batch size
- loadConfig: fall back to ~/.claude/arch (or SOCRATICODE_GLOBAL_CONFIG_DIR
  env var) when project root has no .socraticodecontextartifacts.json
- BATCH_SIZE: configurable via EMBEDDING_BATCH_SIZE env var, default 32
  (validates positive integer, throws on invalid input)
2026-04-13 20:38:29 +08:00
Giancarlo Erra efec8dd29a docs: consolidate README — add feature comparison table and streamline sections 2026-04-13 10:55:59 +01:00
Giancarlo Erra af0c397b8c chore: release v1.4.1 v1.4.1 2026-04-12 21:37:52 +01:00
Giancarlo Erra 81a4422b63 Merge pull request #24 from giancarloerra:fix/coderabbit-review-findings
fix: address CodeRabbit review findings
2026-04-12 21:34:33 +01:00
Giancarlo Erra 00f7be169c fix: address CodeRabbit PR review feedback
- 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()
2026-04-12 21:31:45 +01:00
Giancarlo Erra bb5e6c3e19 fix: address CodeRabbit review findings 2026-04-12 20:21:36 +01:00
Giancarlo Erra f10a45d619 chore: add AGENTS.md and update .gitignore 2026-04-12 19:49:19 +01:00
Giancarlo Erra 5c84a9ad66 chore: release v1.4.0 v1.4.0 2026-04-12 19:30:53 +01:00
Giancarlo Erra 9eea98079e Merge pull request #23 from giancarloerra:feat/multi-collection-search
feat: cross-project search and branch-aware indexing
2026-04-12 19:15:08 +01:00
Giancarlo Erra f745d59ddd fix: address remaining CodeRabbit production code issues
- Scope dedupe key to label::relativePath in mergeMultiCollectionResults
  so same file in different projects is not collapsed
- Compute embedding once in searchMultipleCollections via internal
  searchChunksWithVector helper (avoids N redundant API calls)
- Compare base project hashes (not branch-suffixed names) when skipping
  duplicate linked projects in resolveLinkedCollections
- Use path.resolve() for platform-neutral assertion in query-tools tests
- Update multi-collection-search tests for new cross-project dedup semantics
2026-04-11 17:53:59 +01:00
Giancarlo Erra f09f417c6e fix: address CodeRabbit review feedback on tests
- Refactor git temp repos into initTempRepo() helper using git config
  instead of env vars (resolves Critical finding)
- Restore SOCRATICODE_LINKED_PROJECTS and SOCRATICODE_PROJECT_ID to
  original values in resolveLinkedCollections afterEach
- Fix TypeScript 'never' type errors in query-tools mocks by adding
  explicit SearchResult[] return types
2026-04-11 17:53:59 +01:00
Giancarlo Erra ad2e3b9ea1 fix: provide git identity for temp repo commits in CI
CI runners have no git user.name/email configured, causing
'git commit --allow-empty' to fail with 'Author identity unknown'.
Pass GIT_AUTHOR_NAME/EMAIL and GIT_COMMITTER_NAME/EMAIL env vars.
2026-04-11 17:53:59 +01:00
Giancarlo Erra ffa8e95bdf fix: use self-contained temp git repos in branch-aware tests
CI checks out in detached HEAD state, causing detectGitBranch(process.cwd())
to return null. Replace process.cwd() with temporary git repos that have a
known branch and initial commit, making tests deterministic everywhere.
2026-04-11 17:53:59 +01:00
Giancarlo Erra 24faa1075b docs: add cross-project and branch-aware highlights to intro and Why SocratiCode 2026-04-11 17:53:59 +01:00
Giancarlo Erra bf93e4a992 test: add includeLinked and searchMultipleCollections tests
- query-tools.test.ts: 6 new tests for includeLinked parameter:
  - omitted/false → calls searchChunks (not searchMultipleCollections)
  - true → calls searchMultipleCollections via resolveLinkedCollections
  - passes collections and args correctly
  - project label appears in output
  - no project tag when field absent

- multi-collection-search.test.ts: 1 new test for searchMultipleCollections
  empty-input short-circuit (internal searchChunks calls cannot be mocked
  from the same module — integration covered by query-tools tests)
2026-04-11 17:53:59 +01:00
Giancarlo Erra fc3c2988fa fix: linked projects use base hash without branch suffix
resolveLinkedCollections() was calling projectIdFromPath() for linked
projects, which with SOCRATICODE_BRANCH_AWARE=true appended the linked
project's git branch to its ID. Linked projects indexed without
branch-aware mode don't have __branch collections, so lookups failed.

Extract coreProjectId() helper (hash-only, no branch suffix) and use
it for linked projects. Also fix dedup to compare collection names
instead of raw IDs to handle the branch suffix mismatch.

Adds unit test verifying linked collection names are branch-agnostic.
2026-04-11 17:53:59 +01:00
Giancarlo Erra 096f59da13 fix: update path handling and type imports in indexer and query tools 2026-04-11 17:53:59 +01:00
Giancarlo Erra 76e3ff5f59 docs: add cross-project search and branch-aware indexing documentation
- 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
2026-04-11 17:53:59 +01:00
Giancarlo Erra 3a4139d714 feat: branch-aware collection naming via SOCRATICODE_BRANCH_AWARE
- detectGitBranch() detects current git branch via git rev-parse
- sanitizeBranchName() converts branch names to Qdrant-safe suffixes
- When SOCRATICODE_BRANCH_AWARE=true, projectIdFromPath appends __branch
  to create separate indexes per branch
- Explicit SOCRATICODE_PROJECT_ID takes precedence (no branch suffix)
- 14 unit tests for sanitization, detection, and integration

Relates to #19
2026-04-11 17:53:59 +01:00
Giancarlo Erra 61e868cf9e feat: linked projects support via .socraticode.json and SOCRATICODE_LINKED_PROJECTS
- loadLinkedProjects() reads .socraticode.json config and env var
- resolveLinkedCollections() maps linked projects to collection names
- codebase_search gains includeLinked parameter for cross-project queries
- Results tagged with [project-label] when searching across projects
- 10 unit tests for config loading and collection resolution

Relates to #20
2026-04-11 17:53:59 +01:00