Skip to content

[FEATURE] Symbol operations & refactoring — LSP-based rename, symbolic editing, dynamic dispatch synthesizers #62

Description

@Wolfvin

Summary

Add symbol-level operations modeled on Serena (symbolic editing, LSP-based rename) and CodeGraph (dynamic-dispatch synthesizers, framework-aware routes, affected test tracing). Transforms CodeLens from read-only analysis to active refactoring tool.

Worker consensus (2 reports — Serena for LSP ops, CodeGraph for synthesis)

Worker Source Contribution
Serena update!/CodeLens_vs_Serena_Upgrade_Analysis.md S3 Symbolic editing tools — replace-symbol, insert-after-symbol, insert-before-symbol. Atomic body replacement, auto-detect indentation, --dry-run, backup to .codelens/backup/.
Serena same file S4 LSP-based rename refactoring — codelens rename <old> <new> using LSP textDocument/rename. codelens rename-file <old> <new> using workspace/willRenameFiles + didRenameFiles to update imports. --dry-run, --force.
CodeGraph update!/CodeLens_CodeGraph_Upgrade_Analysis.md #10 affected command — transitive import dependency from changed source files to identify test files to run. codelens affected [files...] or --stdin from git diff --name-only. -d/--depth, -f/--filter, -j/--json, -q/--quiet.
CodeGraph same file #13 Framework-aware routes (17 frameworks) — Django, Flask, FastAPI, Express, NestJS, Laravel, Rails, Spring, etc. Emit route nodes linked by references edges to handlers.
CodeGraph same file #8 Dynamic-dispatch synthesizer (21 patterns) — callback edge, C function pointer, Celery/Sidekiq dispatch, Spring event, Pinia store, Redux thunk, etc. Synthesized edges tagged provenance: 'heuristic'.
CodeGraph same file #9 Dynamic-boundary detection (9 forms) — computed-call, dynamic-import, ruby-send, php-dynamic, reflection, proxy-reflect, typed-bus, var-key-dispatch, selector. Honest announcement when flow cannot be followed statically.
CodeGraph same file #29 Multi-repo workspace — projectPath parameter to MCP tools.
CodeGraph same file #30 Overload resolution — return all definitions for ambiguous name.

Proposed phased scope

Phase 1 — affected command (P1, 1 week, quick win, independent)

  • New codelens affected [files...] command
  • Accepts files as args or via --stdin (pipe from git diff --name-only)
  • Options: -d/--depth (default 5), -f/--filter <glob> (default auto-detect *test*/*spec*), -j/--json, -q/--quiet
  • Extend dependents_engine.py to transitive (depth-controlled BFS)
  • is_test_file(path) heuristic
  • Cache dependency graph in-memory, invalidate on registry update
  • CI/hook pattern: AFFECTED=$(git diff --name-only HEAD | codelens affected --stdin --quiet); pytest $AFFECTED

Phase 2 — Symbolic editing tools (P2, 2 weeks, depends on native LSP server issue)

  • codelens replace-symbol <symbol> <new-body> — atomic body replacement
  • codelens insert-after-symbol <symbol> <new-code> — append at symbol end
  • codelens insert-before-symbol <symbol> <new-code> — prepend
  • Symbol identified by name path (foo/bar)
  • Auto-detect indentation
  • --dry-run for preview
  • Backup original to .codelens/backup/ before edit
  • Integrate with guard --pre for pre-write safety check

Phase 3 — LSP-based rename (P2, 2-3 weeks, depends on native LSP server issue)

  • codelens rename <old-name> <new-name> using LSP textDocument/rename
  • Returns preview of all changes (file, line, old text, new text)
  • --dry-run for preview-only
  • codelens rename-file <old-path> <new-path> using workspace/willRenameFiles + didRenameFiles to update all imports
  • Safety: backup before apply, --force to skip confirmation
  • Integrate with refactor-safe pre-check

Phase 4 — Overload resolution (P2, 3 days, quick win)

  • Modify query command to return list of all matching definitions (not just first match)
  • Surface disambiguation info (file path, language, kind) for each
  • When name is ambiguous, MCP codelens_query returns array

Phase 5 — Framework-aware routes (P2, 3-4 weeks)

  • 17 framework resolvers: Django, Flask, FastAPI, Express, NestJS, Laravel, Drupal, Rails, Spring, Play, Gin/chi/gorilla/mux, Axum/actix/Rocket, ASP.NET, Vapor, React Router/SvelteKit, Vue Router/Nuxt, Astro
  • Emit route nodes linked by references edges to handler classes/functions
  • Integrate with api-map command, callers command, codelens_explore

Phase 6 — Dynamic-dispatch synthesizers (P3, 4-6 weeks, optional)

  • 21 synthesizers for dynamic-dispatch patterns static parsing cannot follow
  • Each runs as whole-graph pass after base resolution
  • Synthesized edges tagged provenance: 'heuristic' with metadata.synthesized_by: '<channel-name>'
  • Per-synthesizer YAML config in scripts/plugins/synthesizers/<name>.yaml

Phase 7 — Dynamic-boundary detection (P3, 2-3 weeks, optional)

  • 9 forms: computed-call, dynamic-import, ruby-send, php-dynamic, reflection, proxy-reflect, typed-bus, var-key-dispatch, selector
  • Run at QUERY TIME only (graph never mutated)
  • Per match: form, label, snippet, line, key?, keyIsType?, moreSites?

Acceptance criteria

  • codelens affected correctly identifies test files affected by source change
  • codelens replace-symbol produces valid code (no syntax errors)
  • codelens rename updates all references across files
  • codelens query returns multiple definitions for ambiguous names
  • Framework-aware routes correctly map URL patterns to handlers

Related

  • Phases 2, 3 depend on native LSP server issue
  • Phase 5 (framework routes) overlaps with api-map command — should integrate, not duplicate

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions