Skip to content

feat: add symbols tool — file symbol tree with line numbers#546

Merged
buger merged 3 commits intomainfrom
feat/find-symbols
Mar 21, 2026
Merged

feat: add symbols tool — file symbol tree with line numbers#546
buger merged 3 commits intomainfrom
feat/find-symbols

Conversation

@buger
Copy link
Copy Markdown
Collaborator

@buger buger commented Mar 21, 2026

Summary

  • Add new probe symbols CLI command that lists all symbols (functions, structs, classes, constants, enums, traits, impl blocks, type aliases, macros) in files as a table of contents with line numbers and nesting
  • Rust implementation uses tree-sitter AST parsing with a new is_symbol_node() trait method and recursive descent for nested symbols (methods inside impl/class blocks)
  • Full pipeline: CLI subcommand → Node.js wrapper → Vercel AI SDK tool → agent registration with schema, system prompt, and predefined prompt integration
  • Text and JSON output formats, --allow-tests flag, multi-file support

Changes

Rust (core engine):

  • src/language/language_trait.rs — new is_symbol_node() default trait method (broader than is_acceptable_parent)
  • src/language/rust.rs, typescript.rs, go.rs — language-specific overrides adding const/static/type/var nodes
  • src/extract/symbols.rsnew — core symbol tree extraction with SymbolNode/FileSymbols structs, recursive collection, text/JSON formatting, 11 unit tests
  • src/cli.rs, src/main.rsSymbols subcommand registration and dispatch

Node.js (SDK + agent):

  • npm/src/symbols.jsnew — Node.js wrapper spawning probe symbols --format json
  • npm/src/tools/common.jssymbolsSchema Zod schema
  • npm/src/tools/vercel.jssymbolsTool Vercel AI SDK wrapper
  • npm/src/tools/index.js, npm/src/index.js, npm/src/agent/tools.js — export chain
  • npm/src/agent/probeTool.jswrapToolWithEmitter integration
  • npm/src/agent/ProbeAgent.js — 4-point registration (toolImplementations, schema map, system prompt, valid tools)
  • npm/src/agent/shared/prompts.js — updated code-explorer, code-searcher, engineer prompts with symbols guidance
  • npm/src/tools/system-message.js — added to Tool Reference
  • npm/index.d.ts — TypeScript declarations

Documentation (everywhere extract is documented):

  • docs/probe-cli/symbols.mdnew — full CLI documentation
  • README.md, npm/README.md, docs/index.md — updated
  • docs/probe-agent/sdk/api-reference.md, tools-reference.md — SDK docs
  • docs/probe-agent/protocols/mcp.md, mcp-integration.md, mcp-server.md, acp.md — protocol docs

Testing

  • 11 new Rust unit tests covering: Rust/TypeScript/Python/Go symbol extraction, nesting, line numbers, JSON output, text formatting, allow-tests filtering, empty files, unsupported extensions
  • 7 new Node.js tests: schema validation (3), agent registration (2), export chain (2)
  • All 322 existing Rust tests pass (321 + 1 ignored)
  • All 11 integration tests pass
  • CLI tested end-to-end: probe symbols src/main.rs --format text and --format json

Add a new `symbols` command that lists all symbols (functions, structs,
classes, constants, enums, traits, impl blocks, type aliases, etc.) in
files as a table of contents with line numbers and nesting.

Rust implementation uses tree-sitter AST parsing with a new
`is_symbol_node()` trait method (broader than `is_acceptable_parent`)
and recursive descent for nested symbols (methods inside impl/class).

Full pipeline: CLI subcommand → Node.js wrapper → Vercel AI SDK tool →
agent registration (schema, system prompt, predefined prompts).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@probelabs
Copy link
Copy Markdown
Contributor

probelabs Bot commented Mar 21, 2026

PR Overview: Add Symbols Tool — File Symbol Tree with Line Numbers

Summary

This PR introduces a new symbols command that provides a table-of-contents view of source files, listing all symbols (functions, structs, classes, constants, enums, traits, impl blocks, type aliases, macros) with their line numbers and nesting hierarchy. The implementation spans Rust core engine, Node.js SDK wrapper, Vercel AI SDK tool integration, and comprehensive documentation updates.

Files Changed Analysis

30 files changed with 1,355 additions and 148 deletions:

Core Rust Implementation (5 files)

  • src/extract/symbols.rs (+638 lines) — NEW — Core symbol extraction engine with SymbolNode/FileSymbols structs, recursive AST traversal, text/JSON formatters, 11 unit tests
  • src/cli.rs (+19 lines) — New Symbols subcommand with --format and --allow-tests flags
  • src/main.rs — Command dispatch for symbols
  • src/extract/mod.rs (+1 line) — Module export
  • src/extract/processor.rs (+42/-136 lines) — Refactored extract_all_symbols_from_file() to delegate to new symbols module

Language Trait Extensions (4 files)

  • src/language/language_trait.rs (+7 lines) — New is_symbol_node() default trait method
  • src/language/rust.rs (+5 lines) — Override for const/static/type items
  • src/language/typescript.rs (+8 lines) — Override for variable declarations
  • src/language/go.rs (+8 lines) — Override for const/var declarations

Node.js SDK (8 files)

  • npm/src/symbols.js (+86 lines) — NEW — Spawns probe symbols --format json
  • npm/src/tools/vercel.js (+36/-1 lines) — symbolsTool Vercel AI SDK wrapper
  • npm/src/tools/common.js (+4 lines) — symbolsSchema Zod validation
  • npm/src/tools/index.js (+2/-1 lines) — Export chain update
  • npm/src/index.js (+6/-1 lines) — Export chain for symbols function and symbolsTool
  • npm/src/agent/tools.js (+6 lines) — Tool factory integration
  • npm/src/agent/ProbeAgent.js (+12/-2 lines) — 4-point registration (implementations, schema, system prompt, valid tools)
  • npm/src/agent/probeTool.js (+9 lines) — wrapToolWithEmitter integration

Documentation (9 files)

  • docs/probe-cli/symbols.md (+137 lines) — NEW — Full CLI documentation
  • README.md (+26/-1 lines) — Quick start examples
  • docs/index.md (+1 line) — Index update
  • npm/README.md (+25 lines) — SDK usage examples
  • npm/index.d.ts (+63 lines) — TypeScript declarations for SymbolsParams, SymbolNode, FileSymbols
  • Protocol docs: acp.md (+18/-1), mcp.md (+19), mcp-integration.md (+21/-1), mcp-server.md (+15) — Added symbols tool to all protocol specifications
  • SDK docs: api-reference.md (+19/-2), tools-reference.md (+34/-1) — API documentation and tool reference
  • npm/src/tools/system-message.js (+4 lines) — Tool reference in system message
  • npm/src/agent/shared/prompts.js (+4/-1 lines) — Updated prompts with symbols guidance

Tests (1 file)

  • npm/tests/unit/symbolsTool.test.js (+80 lines) — NEW — 7 tests covering schema validation, agent registration, export chain

Architecture & Impact Assessment

What This PR Accomplishes

  1. New CLI capability: probe symbols <files> [--format text|json] [--allow-tests] provides file structure overview
  2. AST-based extraction: Uses tree-sitter parsers for accurate symbol detection across languages
  3. Hierarchical output: Methods nested inside impl blocks/classes/traits with proper indentation
  4. Dual output formats: Human-readable text with line ranges, machine-readable JSON with full metadata
  5. Full SDK integration: Direct function call, Vercel AI SDK tool, and ProbeAgent tool registration

Key Technical Changes

Rust Core:

  • New is_symbol_node() trait method broader than existing is_acceptable_parent() — includes constants, type aliases, variables
  • Recursive descent with depth limiting (max 3 levels) for container nodes (impl, class, trait, module)
  • Signature extraction via language-specific get_symbol_signature() with fallback to first line
  • Name extraction handles impl blocks (impl Trait for Type), field-based lookups, and identifier traversal
  • Kind normalization maps tree-sitter node types to user-friendly labels (e.g., function_itemfunction)
  • Refactored extract_all_symbols_from_file() to delegate to new symbols::extract_symbols(), reducing code duplication

Node.js Integration:

  • Spawns binary with --format json for structured output
  • Path resolution via existing parseAndResolvePaths() utility
  • Error handling with formatErrorForAI() for AI-friendly responses
  • Zod schema validates single file parameter (string)

Agent Registration:

  • Added to toolImplementations map with conditional enablement
  • Schema and description in _getToolSchemaAndDescription()
  • System prompt updates in 3 personas (code-explorer, code-searcher, engineer)
  • Export chain: symbols.jsindex.jstools/index.jsagent/tools.js

Affected System Components

graph TD
    A[CLI: probe symbols] --> B[src/extract/symbols.rs]
    B --> C[Language Trait: is_symbol_node]
    C --> D[Rust/TS/Go Overrides]
    B --> E[Tree-sitter Parser Pool]
    E --> F[SymbolNode Extraction]
    F --> G[Text/JSON Formatter]
    
    H[Node.js SDK] --> I[npm/src/symbols.js]
    I --> J[Spawn: probe symbols --format json]
    J --> A
    
    K[Vercel AI SDK] --> L[npm/src/tools/vercel.js]
    L --> M[symbolsTool Wrapper]
    M --> I
    
    N[ProbeAgent] --> O[toolImplementations.symbols]
    O --> M
    N --> P[_getToolSchemaAndDescription]
    N --> Q[System Prompt Updates]
    
    R[Protocols] --> S[MCP Server]
    R --> T[ACP]
    S --> U[symbols_code Tool]
    T --> V[symbols Tool]
Loading

Scope Discovery & Context Expansion

Immediate Impact

  • CLI users: New command for file structure exploration
  • SDK users: New symbols() function and symbolsTool() for Vercel AI SDK
  • Agent users: Automatic tool availability in ProbeAgent instances
  • Protocol users: MCP and ACP servers expose symbols tool

Related Components

  • Existing extract command: src/extract/mod.rs already exports symbol_finder — symbols complements extract by providing TOC before extraction
  • Language implementations: All 4 language files (rust, typescript, go, python) updated with is_symbol_node() overrides
  • Test filtering: Reuses existing is_test_node() trait method for --allow-tests flag
  • Parser pooling: Uses existing get_pooled_parser()/return_pooled_parser() for efficiency
  • Code reuse: The PR refactors extract_all_symbols_from_file() in processor.rs to delegate to the new symbols::extract_symbols(), reducing duplication from ~135 lines to ~41 lines

Testing Coverage

  • 11 Rust unit tests: Rust/TypeScript/Python/Go extraction, nesting, line numbers, JSON output, text formatting, test filtering, empty files, unsupported extensions
  • 7 Node.js tests: Schema validation (3), agent registration (2), export chain (2)
  • All existing tests pass: 322 Rust tests (321 + 1 ignored), 11 integration tests

Documentation Completeness

  • CLI reference with examples
  • SDK API documentation
  • Tool reference for AI agents
  • Protocol specifications (MCP, ACP)
  • TypeScript declarations
  • System prompt integration

Review Focus Areas

  1. Rust core: src/extract/symbols.rs — recursive collection logic, container detection, name extraction edge cases
  2. Language overrides: Verify is_symbol_node() additions correctly capture language-specific symbol types
  3. Node.js wrapper: Error handling, path resolution, JSON parsing
  4. Agent integration: Tool registration completeness, system prompt clarity
  5. Test coverage: Edge cases for nesting, impl blocks, empty files

References

Core Implementation:

  • src/extract/symbols.rs:1-638 — Full implementation with tests
  • src/cli.rs:304-322 — CLI command definition
  • src/main.rs — Command dispatch

Language Trait:

  • src/language/language_trait.rs:33-39is_symbol_node() default method
  • src/language/rust.rs:328-332 — Rust override (const/static/type)
  • src/language/typescript.rs:458-465 — TypeScript override (variables)
  • src/language/go.rs:238-245 — Go override (const/var)

Node.js SDK:

  • npm/src/symbols.js:1-86 — Core wrapper function
  • npm/src/tools/vercel.js:1348-1381 — Vercel AI SDK tool
  • npm/src/tools/common.js:75-77 — Zod schema

Agent Integration:

  • npm/src/agent/ProbeAgent.js:949-951 — Tool implementation registration
  • npm/src/agent/ProbeAgent.js:2232-2235 — Schema and description
  • npm/src/agent/ProbeAgent.js:3030-3034,3089-3093 — System prompt updates
  • npm/src/agent/probeTool.js:268-274 — Emitter wrapper

Documentation:

  • docs/probe-cli/symbols.md:1-137 — CLI documentation
  • docs/probe-agent/sdk/tools-reference.md:205-237 — Tool reference
  • npm/index.d.ts:411-469 — TypeScript declarations
Metadata
  • Review Effort: 3 / 5
  • Primary Label: feature

Powered by Visor from Probelabs

Last updated: 2026-03-21T15:58:17.952Z | Triggered by: pr_updated | Commit: 4a7ec53

💡 TIP: You can chat with Visor using /visor ask <your question>

@probelabs
Copy link
Copy Markdown
Contributor

probelabs Bot commented Mar 21, 2026

Security Issues (8)

Severity Location Issue
🟠 Error npm/src/symbols.js:52
File paths from user input are passed directly to the CLI without validation. While validateCwdPath is called for the working directory, individual file paths in the files array are not validated for path traversal attacks (e.g., '../../../etc/passwd'). An attacker could potentially read files outside the intended directory.
💡 SuggestionAdd path validation for each file in the files array to ensure they are within the allowed working directory. Use the same path validation pattern as extract.js and search.js which validate paths against allowedFolders.
🟠 Error npm/src/tools/vercel.js:1358
The symbolsTool wrapper uses parseAndResolvePaths() but does not validate that the resolved file path is within allowed directories. Unlike other tools (edit, bash) that check isPathAllowed(), symbolsTool has no such validation, potentially allowing access to files outside allowedFolders.
💡 SuggestionAdd path validation similar to editTool's isPathAllowed() check to ensure the resolved file path is within allowedFolders before executing the symbols command.
🟠 Error src/extract/symbols.rs:43
The extract_symbols function only checks if the path exists (path.exists()) but does not validate that the path is within any allowed directory boundary. This could allow reading arbitrary files if the path is user-controlled.
💡 SuggestionAdd path validation to ensure the file path is within the current working directory or an explicitly allowed directory. Consider using the path_safety module or implementing similar checks.
🟢 Info src/extract/symbols.rs:23
MAX_SYMBOL_DEPTH is set to 3, which is reasonable, but there is no protection against files with an extremely large number of symbols at each level. A file with thousands of top-level symbols could consume excessive memory.
💡 SuggestionConsider adding a maximum symbol count limit in addition to depth limiting to prevent memory exhaustion.
🟢 Info npm/src/symbols.js:52
The files array is validated for non-emptiness but there is no validation that the file paths have valid extensions or are actually files (not directories, sockets, etc.). This could lead to unexpected behavior or errors.
💡 SuggestionAdd validation to ensure file paths have valid extensions and refer to regular files, not directories or special file types.
🟡 Warning npm/src/symbols.js:52
While escapeString() is used to escape file paths before passing to spawn(), the escapeString function has platform-specific behavior. On Windows, it only escapes double quotes but does not protect against all PowerShell command injection vectors. An attacker could potentially inject malicious commands if they can control file paths.
💡 SuggestionConsider using array arguments directly with spawn() instead of constructing command strings. The current implementation does use array arguments which is good, but ensure escapeString provides adequate protection for all shell metacharacters on all platforms.
🟡 Warning npm/src/symbols.js:75
Error messages from the symbols command (including stderr) are directly passed to rejection. This could potentially leak sensitive information about the system, file structure, or implementation details to unauthorized users.
💡 SuggestionSanitize error messages before returning them to users. Consider using formatErrorForAI() or similar error handling that strips sensitive system information.
🟡 Warning src/extract/symbols.rs:43
No file size limits or complexity limits are enforced when reading files. An attacker could provide a very large file or a file with deeply nested structures causing excessive memory consumption or CPU usage during AST parsing.
💡 SuggestionAdd file size limits and consider adding timeout or complexity limits for AST parsing to prevent denial-of-service attacks.

Security Issues (8)

Severity Location Issue
🟠 Error npm/src/symbols.js:52
File paths from user input are passed directly to the CLI without validation. While validateCwdPath is called for the working directory, individual file paths in the files array are not validated for path traversal attacks (e.g., '../../../etc/passwd'). An attacker could potentially read files outside the intended directory.
💡 SuggestionAdd path validation for each file in the files array to ensure they are within the allowed working directory. Use the same path validation pattern as extract.js and search.js which validate paths against allowedFolders.
🟠 Error npm/src/tools/vercel.js:1358
The symbolsTool wrapper uses parseAndResolvePaths() but does not validate that the resolved file path is within allowed directories. Unlike other tools (edit, bash) that check isPathAllowed(), symbolsTool has no such validation, potentially allowing access to files outside allowedFolders.
💡 SuggestionAdd path validation similar to editTool's isPathAllowed() check to ensure the resolved file path is within allowedFolders before executing the symbols command.
🟠 Error src/extract/symbols.rs:43
The extract_symbols function only checks if the path exists (path.exists()) but does not validate that the path is within any allowed directory boundary. This could allow reading arbitrary files if the path is user-controlled.
💡 SuggestionAdd path validation to ensure the file path is within the current working directory or an explicitly allowed directory. Consider using the path_safety module or implementing similar checks.
🟢 Info src/extract/symbols.rs:23
MAX_SYMBOL_DEPTH is set to 3, which is reasonable, but there is no protection against files with an extremely large number of symbols at each level. A file with thousands of top-level symbols could consume excessive memory.
💡 SuggestionConsider adding a maximum symbol count limit in addition to depth limiting to prevent memory exhaustion.
🟢 Info npm/src/symbols.js:52
The files array is validated for non-emptiness but there is no validation that the file paths have valid extensions or are actually files (not directories, sockets, etc.). This could lead to unexpected behavior or errors.
💡 SuggestionAdd validation to ensure file paths have valid extensions and refer to regular files, not directories or special file types.
🟡 Warning npm/src/symbols.js:52
While escapeString() is used to escape file paths before passing to spawn(), the escapeString function has platform-specific behavior. On Windows, it only escapes double quotes but does not protect against all PowerShell command injection vectors. An attacker could potentially inject malicious commands if they can control file paths.
💡 SuggestionConsider using array arguments directly with spawn() instead of constructing command strings. The current implementation does use array arguments which is good, but ensure escapeString provides adequate protection for all shell metacharacters on all platforms.
🟡 Warning npm/src/symbols.js:75
Error messages from the symbols command (including stderr) are directly passed to rejection. This could potentially leak sensitive information about the system, file structure, or implementation details to unauthorized users.
💡 SuggestionSanitize error messages before returning them to users. Consider using formatErrorForAI() or similar error handling that strips sensitive system information.
🟡 Warning src/extract/symbols.rs:43
No file size limits or complexity limits are enforced when reading files. An attacker could provide a very large file or a file with deeply nested structures causing excessive memory consumption or CPU usage during AST parsing.
💡 SuggestionAdd file size limits and consider adding timeout or complexity limits for AST parsing to prevent denial-of-service attacks.
\n\n ### Architecture Issues (11)
Severity Location Issue
🟠 Error src/extract/symbols.rs:233
The normalize_kind() function duplicates kind normalization logic that exists in multiple places: lsp-daemon/src/analyzer/tree_sitter_analyzer.rs (map_rust_node_to_symbol, map_typescript_node_to_symbol, etc.), lsp-daemon/src/lsp_database_adapter.rs (node_kind_to_symbol_kind), and lsp-daemon/src/indexing/ast_extractor.rs (determine_symbol_kind). This creates multiple sources of truth for the same mappings.
💡 SuggestionReuse existing kind normalization infrastructure. Either: (1) Move normalize_kind to a shared location in src/language/ and reuse it across all subsystems, or (2) Use the existing LSP daemon's node_kind_to_symbol_kind function if it covers all needed cases. The current approach creates maintenance burden and inconsistency risks.
🟠 Error src/language/language_trait.rs:33
The new is_symbol_node() trait method has overlapping responsibility with is_acceptable_parent(). The documentation says is_symbol_node is 'broader than is_acceptable_parent' but both determine if a node should be extracted. This creates confusion about when to use each method and leads to inconsistent implementations across languages.
💡 SuggestionClarify the distinction or consolidate the methods. Options: (1) Rename is_acceptable_parent to is_extractable_block and is_symbol_node to is_symbol_in_toc to make their purposes clear, or (2) Add a parameter to is_acceptable_parent like context: ExtractionContext (CodeBlock vs SymbolTOC) to handle both cases, or (3) Keep is_symbol_node but make is_acceptable_parent call it by default with language-specific overrides only when needed.
🟠 Error src/language/rust.rs:328
The is_symbol_node() override for Rust only adds const_item, static_item, type_item. However, the normalize_kind() function in symbols.rs handles many more Rust-specific kinds (macro_definition, use_declaration, etc.). This inconsistency means some symbol types will be detected by normalize_kind but not by is_symbol_node, leading to incomplete symbol extraction.
💡 SuggestionEnsure is_symbol_node() covers all symbol kinds that normalize_kind() can produce. Either add the missing kinds (macro_definition, use_declaration, etc.) to is_symbol_node() or refactor so that normalize_kind drives the symbol detection logic instead of having two separate classification systems.
🟠 Error src/language/typescript.rs:458
The is_symbol_node() override for TypeScript only adds variable_declarator, lexical_declaration, variable_declaration. But normalize_kind() handles many more TS kinds (decorated_definition, export_statement, declare_statement, constructor_declaration, field_declaration, etc.). This mismatch will cause inconsistent symbol detection.
💡 SuggestionAlign is_symbol_node() with normalize_kind() coverage. Either add all the missing kinds to is_symbol_node() or refactor the architecture so symbol kind normalization is the single source of truth for what constitutes a symbol, with is_symbol_node() using that information.
🟡 Warning src/extract/symbols.rs:18
Hardcoded MAX_SYMBOL_DEPTH constant (3) is arbitrary and not configurable. The codebase uses configurable depth limits elsewhere (e.g., RelationshipExtractionConfig with max_depth: 10, AnalyzerConfig with max_depth: 10). This hardcoded limit prevents users from adjusting nesting depth for their specific use cases.
💡 SuggestionMake MAX_SYMBOL_DEPTH configurable through a CLI flag or config parameter. Follow the pattern used in lsp-daemon/src/relationship/types.rs where depth is configurable via RelationshipExtractionConfig::max_depth.
🟡 Warning src/extract/symbols.rs:95
The is_container_node() function hardcodes a specific list of node kinds (impl_item, trait_item, class_body, etc.). This duplicates logic that exists elsewhere in the codebase with different implementations (e.g., creates_scope in lsp-daemon, can_contain_symbols in relationship analyzer). The hardcoded list will become stale as new languages are added.
💡 SuggestionMove container detection logic to the LanguageImpl trait as a new method like is_container_node() or can_contain_child_symbols(), allowing each language implementation to define its own container types. This follows the existing pattern of language-specific trait methods.
🟡 Warning src/extract/symbols.rs:165
Special-case handling for impl blocks (impl Trait for Type) in extract_symbol_name() is hardcoded and language-specific. This duplicates similar logic in src/language/rust.rs:194-224 and src/search/lsp_enrichment.rs:1200-1216. The function tries to handle multiple language-specific patterns instead of delegating to language implementations.
💡 SuggestionDelegate symbol name extraction to the LanguageImpl trait. Add a new trait method like extract_symbol_name(node, source) that each language implementation can override with its specific logic. This eliminates special-case handling and centralizes language-specific logic.
🟡 Warning src/extract/symbols.rs:119
The collect_symbols() function uses a depth parameter and MAX_SYMBOL_DEPTH constant to limit recursion, but this is unnecessary complexity. The existing codebase handles recursion depth through natural AST structure (containers contain their children) without explicit depth limits in most cases (see lsp-daemon/src/indexing/ast_extractor.rs extract_symbols_recursive).
💡 SuggestionRemove explicit depth limiting. Let the AST structure naturally determine recursion depth. Container nodes (impl, class, trait) will only recurse into their body children, which naturally limits depth. If depth limiting is truly needed, make it a configurable parameter rather than a hardcoded constant.
🟡 Warning src/extract/symbols.rs:145
The collect_children_symbols() function has multiple fallback strategies (child_by_field_name 'body', then 'members', then hardcoded node kind checks, then direct recursion). This complex fallback logic is difficult to maintain and duplicates similar logic in other parts of the codebase (e.g., lsp-daemon/src/indexing/ast_extractor.rs body field handling).
💡 SuggestionSimplify by delegating to a single, well-defined method in the LanguageImpl trait like get_container_body(node) that returns the node containing child symbols. Each language implementation can then handle its specific AST structure (body field, members field, etc.) in one place.
🟡 Warning src/extract/processor.rs:890
The refactored extract_all_symbols_from_file() now delegates to symbols::extract_symbols() then flattens the hierarchical SymbolNode tree into flat SearchResult objects. This is inefficient - it builds a hierarchical structure only to immediately flatten it, losing the nesting information that was just computed.
💡 SuggestionEither: (1) Keep the old implementation that directly extracts flat SearchResult objects if that's what's needed, or (2) Change the function to return FileSymbols and update all callers to use the hierarchical structure. The current approach of building hierarchy then flattening is wasteful and indicates the abstraction doesn't match the use case.
🟡 Warning npm/src/tools/vercel.js:1348
The symbolsTool wrapper returns JSON.stringify(result[0]) for a single file, but other tools (search, query, extract) return different formats. This inconsistency makes the tools harder to use programmatically. The schema accepts a single 'file' parameter but the underlying symbols() function accepts 'files' array.
💡 SuggestionMake the tool interface consistent with the underlying function. Either: (1) Change the schema to accept 'files' array and return the full array, or (2) Keep single-file interface but make it clear in the schema and documentation. The current mismatch between schema (single file) and implementation (array handling) is confusing.

✅ Quality Check Passed

No quality issues found – changes LGTM.


Powered by Visor from Probelabs

Last updated: 2026-03-21T15:57:38.325Z | Triggered by: pr_updated | Commit: 4a7ec53

💡 TIP: You can chat with Visor using /visor ask <your question>

buger and others added 2 commits March 21, 2026 08:54
- Refactor processor.rs extract_all_symbols_from_file to delegate to
  symbols::extract_symbols, eliminating duplicate AST traversal logic
- Fix Vercel tool to return full result array instead of only first element
- Add escapeString for file paths in symbols.js matching extract.js pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract depth limit to named constant MAX_SYMBOL_DEPTH with docs
- Pre-allocate Vec capacity in collect_symbols and format_symbols_text
- Simplify Vercel tool return: always result[0] (schema takes single file)
- Return consistent JSON for empty results instead of plain string
- Improve symbolsSchema description to mention hierarchical nesting
- Include stdout preview in JSON parse error messages
- Clarify processor.rs legacy wrapper documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@buger buger merged commit 5653a5c into main Mar 21, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant