| id | 174 | |||
|---|---|---|---|---|
| title | Expose rename and dependency-graph as CLI subcommands and feature docs | |||
| status | ✅ | |||
| model | opus | |||
| depends-on |
|
|||
| summary | Lift the heading / link-reference rename logic out of `internal/lsp` into a shared `internal/rename` core, relocate the LSP symbol index to `internal/index`, and expose rename plus the include/catalog/build/link dependency graph as the name-based `mdsmith rename` and `mdsmith deps` subcommands. Document every LSP capability as a feature. |
The rename capability (plan 151) ships only over the LSP
wire protocol. So does the call-hierarchy / dependency graph
(plan 131). An agent or script with no editor cannot reach
either. Neither appears in docs/features/.
This plan exposes both as CLI subcommands. It also documents the full LSP surface as features. Domain logic is not duplicated.
Today internal/lsp/rename.go computes slug remaps and
edits as methods on the LSP *Server. It speaks LSP wire
types (WorkspaceEdit, textEdit). The
layering map
makes cmd/mdsmith and internal/lsp sibling entry points.
So the CLI must not import internal/lsp.
Plan 153 made internal/linkgraph the canonical shared link
extractor. mdsmith list backlinks already consumes it with
no internal/lsp import. Plan 153 kept the symbol index
LSP-local on purpose.
This plan supersedes that one plan-153 non-goal. The symbol
index moves to a peer internal/index package. Both entry
points can then consult it. The
architecture audit log
records the supersession.
- File rename,
kind:rename, directive-name rename, front-matter-key rename — all out of scope per plan 151. - New CLI commands for the inherently interactive navigation
capabilities (definition, references, document-symbol,
workspace-symbol, implementation, completion). They get
feature-doc coverage only;
cross-system.mdwarns against manufacturing CLI surfaces for editor-only features. - Changing the LSP wire behavior. Plans 131 / 151 test suites are the regression gate for the delegation refactor.
- A persistent graph cache.
depsbuilds a transient index per invocation, likebacklinks.
internal/index— the relocated symbol / edge index (puregit mvofinternal/lsp/index; package name unchanged, import path only). Support layer; consumed byinternal/lsp,internal/rename, andcmd/mdsmith. Must not importinternal/lsp(SRP, DIP).internal/rename— NEW core. Answers one question: "given a workspace and a rename target, what file edits perform it, or what typed error?" Depends oninternal/linkgraph,internal/mdtext,internal/index. Returns plainEdit{File,Start,End,NewText}and typed errors; no LSP types. Must not importinternal/lsp(DIP — high-level surfaces depend on this, not the reverse).internal/lsp/rename.go— thin adapter: LSP params → core request → core edits →WorkspaceEdit; typed core error →InvalidParams{data.conflict}. Duplicated computation deleted (no half-formed duplicate, percross-system.md).- LSP call-hierarchy handlers — delegate to a shared
internal/indexdeps query so CLI and LSP share one walk. cmd/mdsmith/rename.go,cmd/mdsmith/deps.go— thin handlers (<50 lines each pergo.md), mirroringcmd/mdsmith/backlinks.go. Neither importsinternal/lsp.
mdsmith rename <file> --heading "Old Title" "New Title"
mdsmith rename <file> --link-ref oldlabel newlabelRewrites the heading / def plus every dependent edit across
the workspace in place. --format text|json summarizes the
files touched. Slug collision / label conflict / empty /
invalid-char fail with exit 2 and a message naming the
conflict (the CLI mirror of plan 151's data.conflict).
mdsmith deps <file> # outgoing: includes/catalogs/builds/links
mdsmith deps <file> --incoming # files that depend on <file>--format text|json. Builds a transient internal/index
over discovered files and queries OutgoingEdges /
IncomingEdges / BacklinksFor.
- New
docs/features/rename.md,docs/features/dependency-graph.md. - Expand
docs/features/live-diagnostics.mdso the remaining navigation suite is actually described (combined, per the scope decision). - Add cards to
docs/features/index.md; adddocs/reference/cli/rename.mdandcli/deps.md(catalog auto-regenerates).
- Create this plan;
mdsmith fix PLAN.md. - Relocate
internal/lsp/index→internal/index(git mv; rewrite import paths ininternal/lsp/*.go+ tests + every*.mdrepo-path reference). Layer move only;go build/test+ existing index/lsp tests are the regression gate. - Update architecture docs (
go.mdSRP list + DIP arrows,index.mdlayering map) and append the plan-153 supersession to the audit log. (cross-system.mdboundaries/versioning deferred to task 8 with the CLI surface.) - TDD
internal/renamecore. The link-reference engine and the heading engine are both lifted intointernal/rename(neutralEdit/Position/Range, typedErrEmptyLabel/InvalidLabelRuneError/LabelConflictError/InvalidHeadingRuneError/ErrEmptyHeadingSlug/HeadingCollisionError). The heading path takes aWorkspaceseam (incoming anchor edges, file list, path→bytes) so LSP can back it with the warm index + buffers and the CLI with a transient index + disk. Behavior-tested at 100% statement coverage with a real index-backed workspace (no mocks); every production function has a dedicated unit test. - Refactor
internal/lsp/rename.goto delegate tointernal/rename; duplicated computation deleted.handleRenameresolves the cursor and callsrename.Heading/rename.LinkRef; a thin adapter maps the neutralEditset toworkspaceEditand the typed errors toInvalidParams+renameCollisionData. The editor-only prepare-range / cursor-disambiguation code stays;isValidRefDefLinenow callsrename.ValidRefDefBodyLines. Plans 151/131 +cmd/mdsmith/lsp_rename_test.gostay green byte-for-byte. - TDD
cmd/mdsmith/rename.go(unit + e2e), registered inmain.godispatch +usageText. Name-based:--heading <old> <new>resolves the heading line viarename.FindHeadingLine;--link-refnormalizes the label viarename.NormalizeLabel. AcliRenameWorkspacebacks the engine'sWorkspaceover a transientinternal/index+ disk reads. Edits are spliced back by converting each UTF-16 range to bytes. Exit 0 rewritten, 1 no match, 2 conflict/error.rename.gois 100% covered (unit) with an e2e suite for the process boundary; therundispatch was split intodispatchto stay under the statement limit. - TDD
cmd/mdsmith/deps.go(unit + e2e); register inmain.go. The LSP call-hierarchy anddepsboth consultinternal/indexfor the edge graph, so the walk is already shared — no separate query-extraction refactor was needed. - Feature + reference docs;
mdsmith fix .to regenerate catalogs (CLAUDE.md, cli.md, README grid, CLAUDE.md include mirrors);mdsmith check ..cross-system.mdleft as-is: the CLI-surface row already covers subcommands generically, and "adding a flag/command is minor" is stated there. - Final gate + flip status to ✅; push. All slices
landed: the
internal/renamecore, the LSP delegation, and themdsmith renameCLI.go test ./...,golangci-lint, andmdsmith check .all clean.
-
internal/indexexists; no production file importsinternal/lsp/index;grep -r internal/lsp/indexfinds nothing (SRP / DIP — package answers one question, CLI no longer reaches the editor layer). -
internal/renamereturns plain edits and typed errors, imports neitherinternal/lspnor any LSP wire type (DIP — surfaces depend on the core). -
internal/lsp/rename.gocontains no slug / edit computation; it delegates tointernal/rename(no duplicated logic across surfaces —cross-system.md). - Plans 131/151 LSP test suites and
cmd/mdsmith/lsp_rename_test.gopass unchanged (Liskov — the relocation is behavior-preserving; the delegation refactor in task 5 must keep them green). -
mdsmith rename f.md --heading "A" "B"rewrites the heading and every workspace anchor link;--link-refrewrites def + uses; collisions exit 2 naming the conflict. -
mdsmith deps f.mdand--incomingemit the dependency edges in text and json. - CLI rename + deps contracts locked by e2e tests in
cmd/mdsmith/(cross-system contract test):e2e_deps_test.goande2e_rename_test.go. - Every new production function has a dedicated unit
test (
TestFoo/TestReceiver_Foo). Holds for the shippeddepscode; re-verify when the rename core lands. -
docs/features/documents rename, the dependency graph, and the full navigation suite;docs/features/index.mdand the CLI reference list the new commands. - All tests pass:
go test ./... -
go tool golangci-lint runreports no issues. -
mdsmith check .passes.
depscommand name.depschosen overgraph/list depsfor parity with the top-levelrenamesubcommand and the "what does this depend on" framing. Easy to rename before the contract test locks if a reviewer prefers otherwise.
All three slices landed as their own green commits:
internal/renameholds the link-reference engine (rename.go) and the heading engine (heading.go), both 100% covered behind aWorkspaceseam.internal/lsp/rename.gois a thin adapter; the duplicated engine is gone and the plan-131/151 suites stay green byte-for-byte.- cmd/mdsmith/rename.go is the name-based CLI, 100% unit-covered with an e2e suite, plus feature and reference docs.