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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions