diff --git a/catalog/Testing/Official-DotNet-Test/skills/grade-tests/SKILL.md b/catalog/Testing/Official-DotNet-Test/skills/grade-tests/SKILL.md index 1bf1b8c..d68eba5 100644 --- a/catalog/Testing/Official-DotNet-Test/skills/grade-tests/SKILL.md +++ b/catalog/Testing/Official-DotNet-Test/skills/grade-tests/SKILL.md @@ -1,15 +1,14 @@ --- name: grade-tests description: > - Grade a curated list of individual tests for readiness, A-F quality, and - concrete improvements. ALWAYS USE FOR: grade tests, review only a named test, - per-test readiness decisions, or quality bands for supplied methods, bodies, - file spans, or bounded PR diffs, including existing tests. Produce a PR-ready - Pass, Failed, Uncertain, or Not applicable table; unresolved or empty scopes - omit the grade. Compose read-only per-test mutation evidence when available. - Polyglot: .NET, Python, TS/JS, Java, Go, Ruby, Rust, Swift, Kotlin, - PowerShell, C++. DO NOT USE FOR: suite-wide audits (test-engineer or - test-anti-patterns), writing or fixing tests, or measuring coverage. + Grade curated individual tests for readiness, A-F quality and improvements. + ALWAYS USE FOR: grade tests, review only a named test, per-test readiness or + quality bands for supplied methods, bodies, file spans or bounded PR diffs, + including existing tests. Return Pass/Failed/Uncertain/Not applicable; + unresolved/empty scopes omit grades. Compose read-only per-test evidence. + Polyglot. DO NOT USE FOR: suite audits (test-engineer/test-anti-patterns), + concrete fix/feature detection proof (test-value-evidence), writing/fixing + tests, or coverage. license: MIT --- diff --git a/catalog/Testing/Official-DotNet-Test/skills/test-gap-analysis/SKILL.md b/catalog/Testing/Official-DotNet-Test/skills/test-gap-analysis/SKILL.md index 25de7f6..9893ffa 100644 --- a/catalog/Testing/Official-DotNet-Test/skills/test-gap-analysis/SKILL.md +++ b/catalog/Testing/Official-DotNet-Test/skills/test-gap-analysis/SKILL.md @@ -1,17 +1,14 @@ --- name: test-gap-analysis description: >- - Pseudo-mutation analysis ONLY: answer whether tests would catch a bug if - production code changed, which meaningful changes would still pass, or which - caller-visible mutations existing assertions would miss; verify candidates - when requested, then optionally close verified gaps. Includes explicit - read-only per-test composition for grading. Activate for behavioral blind - spots tied to production behavior. Polyglot. DO NOT USE FOR: suite taxonomy, - metadata, or distribution reports (test-tagging); .NET line-vs-branch or - Cobertura interpretation, arithmetic, plateaus, project-wide coverage gaps, - or coverage-backed test/CRAP priorities (coverage-analysis; use native - coverage tooling outside .NET); named-target CRAP (crap-score); new suites - (code-testing); assertion/smell audits; or mutation tools. + Find caller-visible production changes existing tests would miss through + pseudo-mutation analysis; verify candidates or close gaps only when requested. + Includes read-only per-test composition for grading. Polyglot. + USE FOR: would tests catch a bug, behavioral blind spots, surviving mutations. + DO NOT USE FOR: concrete fix/feature revision proof (test-value-evidence); + suite taxonomy (test-tagging); .NET coverage, Cobertura, plateaus or + coverage-backed priorities (coverage-analysis); named CRAP (crap-score); + new suites (code-testing); assertion/smell audits; mutation tools. license: MIT --- diff --git a/catalog/Testing/Official-DotNet-Test/skills/test-value-evidence/SKILL.md b/catalog/Testing/Official-DotNet-Test/skills/test-value-evidence/SKILL.md new file mode 100644 index 0000000..901ba4a --- /dev/null +++ b/catalog/Testing/Official-DotNet-Test/skills/test-value-evidence/SKILL.md @@ -0,0 +1,172 @@ +--- +name: test-value-evidence +description: >- + Assess tests for an identified code or test change, feature, PR or commit. USE FOR: review + changed behavior or regression tests, prove pre-fix/missing behavior is + detected, revision-bound red-green evidence. Polyglot. DO NOT USE without an + identified change: hypothetical mutations or general suite blind + spots (test-gap-analysis). Also exclude per-test readiness/A-F grades (grade-tests), + coverage (coverage-analysis), new suites (code-testing), or mutation engines. +license: MIT +--- + +# Test-value evidence + +A passing test proves little unless it detects the relevant wrong behavior. +Assess the changed contracts and their directly related tests, not the entire +repository. Discover and follow the repository's instructions, pinned toolchain, +test commands, assertion conventions, and execution permissions. This skill +does not authorize edits in a read-only review, execution of untrusted code, +workflow dispatch, publication, or access to another session's checkout. + +## Inputs and boundaries + +Discover the requested diff/revision, production entry points, tests, fixtures, +and available execution artifacts. If the change cannot be identified, report +the missing scope instead of grading the workspace. Existing unchanged tests +can suffice; a source-only diff is not automatically untested. + +Use `test-gap-analysis` for general existing-suite blind spots, `grade-tests` +for curated per-test readiness/quality, and existing repository mutation tooling +for mutation campaigns. Do not start a second mutation engine or require +full-suite mutation testing for every change. This skill is self-contained: +sibling skills are optional routing destinations, not required dependencies. + +## Workflow + +1. **Bind the contract to the tested revision.** For a PR, record its merge + base and exact head SHA. For a commit, record the selected parent and commit; + identify the parent explicitly for a merge commit. For uncommitted work, + record the base SHA plus a reproducible patch identity (saved patch/hash, + including relevant untracked files), not a fictitious committed revision. + Evidence expires after relevant source, tests, helpers, configuration, or + package changes unless revalidated. + + For each distinct behavior change, map: + `requirement -> input/sequence -> expected public outcome -> production + entry point -> named test/data case -> distinguishing assertion`. + Derive the expected outcome independently from requirements or supported + API/protocol semantics, not the implementation or the test's current value. + Check build/package/configuration behavior, deleted/renamed code, removed + tests, and shipping consumers as well as source. Include positive, negative, + boundary, compatibility, cancellation, cleanup, and multi-module cases only + where relevant to the changed contract. + + A mock of the changed component, self-comparison, or expected value computed + by the same production algorithm does not provide an independent oracle. + +2. **Choose the meaningful counterfactual.** + + | Change | Counterfactual | Required observation | + |---|---|---| + | Bug fix | Keep the regression test and restore the actual pre-fix defect. | The test fails for that defect, then passes with the fix. | + | New feature | Disable/remove or corrupt the behavior, retaining the API shape and setup needed to build. | An assertion detects absent/wrong behavior, then passes with the feature. | + | Stronger/test-only coverage | Introduce one plausible wrong public outcome. | The strengthened test detects it; the unmodified product passes. | + | Behavior-preserving refactor | Compare the preserved contract before and after; optionally probe a relevant fault. | Preservation tests pass on both revisions; passing before is expected. | + | Documentation/generated metadata only | Establish whether an executable contract changed. | Not applicable only with a concrete reason; generated or build metadata can change behavior. | + + For a fix, prefer the real pre-fix implementation with the same regression + test, setup, dependencies, and inputs. If new APIs prevent that combination + from compiling, restore only the defective behavior in the head version. + Call this a **targeted counterfactual**, not a run on the base revision. + Record its exact patch/hash. Never change assertions to manufacture red. + + For a feature, a missing-symbol compiler error is not behavioral proof. + Choose a buildable no-op, disabled registration, old branch, or wrong output. + A compiler/analyzer diagnostic can be valid behavior only when an executed + harness asserts that exact diagnostic or its absence. + + Prefer small plausible faults: restore the old boundary, drop a required + output, skip a callback, ignore an option, or return the wrong value. + An equivalent mutation is not a gap. A crash, timeout, or exception counts + only when it is the intended contract signal and diagnostics attribute it + to the fault, not setup, discovery, flakes, or infrastructure. + +3. **Execute paired runs only when authorized.** Implementation normally + requires execution; read-only/advisory review normally requires inspection. + A review request alone does not permit source edits or builds/tests. + Never run untrusted code with privileged credentials. + + In an authorized implementation/verification environment: + + - Use an owned isolated checkout or experiment directory. Preserve the + user's dirty files and other sessions/main checkout. Preflight concurrent + processes and shared outputs/resources; do not kill unrelated processes. + - Run the smallest relevant selection on the correct implementation. + Confirm the named tests and data cases actually execute and pass. + - Apply only the chosen defective behavior in the isolated experiment. + Rebuild and rerun the same tests, assertions, data, dependencies, and + applicable runtime configuration. Capture the named failure, assertion, + expected/actual observation, process exit, and diagnostics. + - Restore the correct implementation, rebuild, and rerun to confirm green + again. Verify protected source/test bytes, remove only owned temporary + resources, and never deliver the counterfactual patch in the product. + + Paired runs must not reuse stale build/test outputs or the other variant's + effective caches. Use separate outputs/caches or clean only owned outputs + and rebuild; do not rely on `--no-build` or a runner's success exit alone. + Record selected/executed/passed/failed/skipped counts for each run. If a + runner does not expose a count, say **unknown** rather than inventing it. + Zero selection/execution, skips, missing tools, authentication, setup/build, + unrelated failures, and unattributed timing flakes leave proof unverified. + + For cross-component/acceptance behavior, identify the producer-consumer + contract first: ownership, lifecycle, handshake/no-handshake, exit semantics, + fallback, compatibility, cancellation, and multi-module aggregation where + applicable. Record the exact shipping binaries/packages/extensions and + release branches. Rebuild/repack each variant, isolate effective package + caches, prove which variant the real shipping consumer loaded, and run a + representative composed command. Unit mocks or source-compatible compilation + alone do not replace shipping-layout validation. Exercise applicable normal, + suppressed, partial, legacy/incompatible, cancellation, nonzero-exit, + zero-result, fallback, and multi-module paths. Keep rollout/servicing ownership + explicit; a feature flag does not lower the evidence bar. + + In read-only/advisory mode, trace both revisions, setup/helpers, inputs, and + assertions without edits or execution unless separately permitted. Label + conclusions **static predictions**, never executed proof. Existing artifacts + count only when their revisions/patches, loaded variant, selection, counts, + and failure attribution match. Green CI or an author's claim alone is not + red-green evidence. Say what is inaccessible or missing. + +4. **Report only the evidence obtained.** Put a compact **Test-value evidence** + section in the handoff or authorized review/description. State base/parent + and head SHAs or tested patch identities. Use one row per changed contract, + group tests protecting the same contract, and identify unassessed groups. + + | Contract / test case | Counterfactual | Without behavior | Correct implementation | Evidence / gap | + |---|---|---|---|---| + | Boundary defect / named case | Restore old comparison; patch identity | Executed: assertion failed | Executed: passed | Commands, exits, expected/actual, counts, artifacts | + | New output / named case | Skip output write | Static: predicts failure | Not executed | Source/assertion locations; paired execution missing | + + Use **executed: detected**, **executed: survived**, **static: predicts + detection**, **static: predicts survival**, **unverified**, **equivalent**, + or **not applicable** accurately. Missing red/green or incomplete selection + leaves paired proof unverified. Report **executed: survived** only for an executed, + non-equivalent fault; do not count equivalent edits as gaps. Preservation + passes for a refactor are valid evidence, not missing-red defects. + + Include exact commands/exits, toolchain/framework/configuration, revision + and counterfactual patch identities, per-run counts, and relevant artifact + paths. Distinguish execution performed now from verified existing artifacts. + Never combine static predictions with measured mutation counts/scores. + Evidence for a final PR head does not prove every intermediate commit; + assess a requested commit against its parent separately. + + Missing evidence is not automatically a proven defect or an inline review + thread. Publication follows the caller's existing authorization gate; do + not create a new GitHub object just to store a report or claim instructions + enforce hooks, CI, or publication. + +## Validation + +- The evidence identifies the exact change, independent oracle, test/data case, + and meaningful buildable counterfactual. +- A claimed bug-fix proof fails for the actual old defect and passes with the + fix; a feature proof detects absent/wrong behavior rather than absent symbols. +- Executed claims have attributable outcomes, commands/exits, counts, and + matching artifacts/consumer provenance; unavailable details stay explicit. +- Static predictions, survival, equivalence, preservation, and missing evidence + remain distinct. Existing tests are credited without demanding redundant ones. +- Scope, read-only restrictions, clean variant outputs, parallel safety, and + owned-resource cleanup were preserved. diff --git a/catalog/Testing/Official-DotNet-Test/skills/test-value-evidence/manifest.json b/catalog/Testing/Official-DotNet-Test/skills/test-value-evidence/manifest.json new file mode 100644 index 0000000..01cb20a --- /dev/null +++ b/catalog/Testing/Official-DotNet-Test/skills/test-value-evidence/manifest.json @@ -0,0 +1,5 @@ +{ + "version": "1.0.0", + "category": "Testing", + "compatibility": "Requires a .NET test project or solution." +} diff --git a/catalog/Tools/Roslynk/manifest.json b/catalog/Tools/Roslynk/manifest.json index c6d5377..67c2455 100644 --- a/catalog/Tools/Roslynk/manifest.json +++ b/catalog/Tools/Roslynk/manifest.json @@ -1,7 +1,7 @@ { "name": "roslynk", "title": "Roslynk", - "description": "How to use the Roslynk MCP tools (mcp__roslynk__*) effectively for .NET work. Use this whenever a Roslynk server is connected and the task touches *.cs, *.cshtml or *.razor files in a solution — checking for compile errors or warnings, finding a symbol's definition, references, callers, or implementations, renaming symbols, applying code fixes or refactorings, finding dead code, or editing those files — even if the user never says \"Roslynk\". Consult it before reaching for grep, file reads, hand-written edits, or `dotnet build` on such files: Roslynk's semantic tools are faster and more correct for all of those jobs.", + "description": "Use Roslynk for semantic inspection and edits of *.cs, *.razor and *.cshtml solution files.", "links": { "repository": "https://github.com/mrpmorris/Roslynk", "docs": "https://github.com/mrpmorris/Roslynk/tree/master/skills/roslynk" diff --git a/catalog/Tools/Roslynk/skills/roslynk/SKILL.md b/catalog/Tools/Roslynk/skills/roslynk/SKILL.md index b568982..95dd456 100644 --- a/catalog/Tools/Roslynk/skills/roslynk/SKILL.md +++ b/catalog/Tools/Roslynk/skills/roslynk/SKILL.md @@ -1,77 +1,6 @@ --- name: roslynk -description: How to use the Roslynk MCP tools (mcp__roslynk__*) effectively for .NET work. Use this whenever a Roslynk server is connected and the task touches *.cs, *.cshtml or *.razor files in a solution — checking for compile errors or warnings, finding a symbol's definition, references, callers, or implementations, renaming symbols, applying code fixes or refactorings, finding dead code, or editing those files — even if the user never says "Roslynk". Consult it before reaching for grep, file reads, hand-written edits, or `dotnet build` on such files: Roslynk's semantic tools are faster and more correct for all of those jobs. +description: Use Roslynk for semantic inspection and edits of *.cs, *.razor and *.cshtml solution files. --- -# Using Roslynk - -Roslynk is an MCP server holding a live Roslyn compilation of a .NET solution. The questions you'd normally answer with grep, file reads, or `dotnet build` — "where is this used?", "does it compile?", "rename this safely" — it answers from the compiler's symbol model instead. Text search lies: it hits comments, strings and unrelated same-named members, and misses partial classes, generated code and `#if` branches. Roslynk doesn't. - -**Default to Roslynk for all semantic work on `*.cs`, `*.cshtml` and `*.razor` files in the loaded solution.** Plain file tools remain only for what Roslynk doesn't cover: files outside the solution folder, file creation/deletion, and non-compiled files (`.csproj`, `.json`, `.md` — still editable safely via `apply_patch`). - -Tools that take a `documentPath` accept `.razor` and `.cshtml` files as well as `.cs`: give positions in the Razor file itself, inside its C# (`@code`/`@functions`, `@{ }`, expressions). Edits are written back to the Razor source in the file's own indentation; renames and other edits that reach a `@bind-X="Expr"` attribute's generated lambdas update the Razor source once at the attribute itself. Analyzer (`IDE*`/`CA*`) fixes are not available in Razor files, and `_Imports.razor`/`_ViewImports.cshtml` usings are never removed. `get_diagnostics` also reports the Razor compiler's own `RZ*` errors against the Razor file. In a `.cshtml` view where a new method cannot be added, `extract_method` suggests `asLocalFunction=true`. - -Each tool's exact contract — parameters, output format, limits, error codes — lives in that tool's own MCP description. This skill covers *when* to use the tools and *how* to combine them; [references/tools.md](references/tools.md) holds the deeper reference (exact output envelopes, `#if` projection mechanics) for when a tool's behavior surprises you. - -## Solution setup - -1. Call `open_solution` with the absolute path to the `.sln`/`.slnx`. It returns immediately and loads in the background; the returned `solutionId` is the handle every other tool needs. -2. While loading, other tools return `error=Indexing` — retry the call shortly, or poll `get_solution_status` (~1s) and report progress. Do **not** fall back to reading or editing files directly; loading finishes within seconds to a minute. If `open_solution` reports `loadDiagnostics` above 0, call `get_solution_status` to read the messages (skipped analyzers, failed project loads): they often explain confusing compiler errors. A missing generator DLL names the project to build: once built (in the configuration its path names, normally Debug), the next call compiles with its generated code, no reload needed. -3. `open_solution` is idempotent and the daemon keeps solutions warm across sessions — calling it again is cheap and safe. -4. Never call `reload_solution` on your own initiative: the file watcher picks up all changes, including your own edits, and a generator project built or rebuilt after load is picked up on the next call. If results look stale (branch switch, `dotnet restore`, SDK/props change, a rebuilt analyzer from a NuGet package or outside the solution), *suggest* it to the user. - -## Choose semantic tools over text search - -| You want to... | Use | Why not grep / reading files | -|---|---|---| -| Check it compiles / see warnings | `get_diagnostics`, once after the task's edits; narrow a broad failure with `summaryOnly=true` or `ids`/`filePath`/`projectName` and cap it with `maxResults` | far faster than `dotnet build`, but still costly per call | -| Find where a symbol is used, or who calls it | `find_references` / `get_callers` | text search finds false hits and misses partial classes, generated code, `#if` branches | -| See what a member calls (its callees) | `get_callees` | reading the body and tracing each call by eye misses overloads and extension-method bindings | -| Find where a field, property or parameter is read or written (assign, `+=`, `++`, `ref`/`out`, initialisers) | `find_reads` / `find_writes` | text search cannot tell a read from a write; `compound`/`increment`/`ref` appear in both results, so do not add the counts | -| Jump from a usage to its declaration | `find_definition` | compiler binding; correct through overloads and shadowing | -| Know what an expression means before editing it (type, overload chosen, nullability, constant, conversion) | `get_expression_info` | `var`, overloads, implicit conversions and nullable flow are invisible in the text | -| Find implementations of an interface/abstract member | `find_implementations` | compiler's type graph | -| See a type's members (and their local functions) / what a name refers to | `get_members` / `get_symbol` | compiler's view; correct across partial classes | -| Read a member's implementation (incl. a partial method's implementation part, and members only a generator declares) | `get_symbol_body` | returns the declaration verbatim, paged when long (`truncated=Y` → re-call with `startItem=`; a partial type's `omitted=Y` part is fetched with `part=`); a path marked `generated=Y` is virtual - read it with this tool, not from disk | -| Explore base/derived types | `get_type_hierarchy` | includes referenced-assembly base types | -| Find a symbol by partial name | `search_symbols` | compiler-declared symbols, generated code included | -| Rename a symbol everywhere (incl. `.razor`/`.cshtml`) | `rename_symbol` | find-and-replace misses markup and same-named text; a symbol only a source generator declares is refused (`error=NotSupported`) - change the generator's input instead | -| Rename one parameter of a method/constructor/indexer | `rename_parameter` | also fixes named arguments, `` docs and the override/interface family | -| Fix a diagnostic `get_diagnostics` reported (incl. `.razor`/`.cshtml`) | `apply_code_fix` with that entry's id, `line` and `column`; on `error=Conflict`, ask the user which candidate, unless the request names one, then `apply_code_action` with its actionId | hand-editing | -| Apply a refactoring, or choose among fixes at a position | `get_code_actions` + `apply_code_action` | hand-editing | -| Add a parameter to a method and its callers (incl. `.razor`/`.cshtml`) | `change_signature` | hand-editing misses call sites in markup | -| Extract statements or an expression into a new method (incl. `@code`/`@functions`) | `extract_method` | hand-cutting code misses parameters, `ref`/`out` and return values | -| Edit source or text files | `apply_patch` | keeps the in-memory model in sync; stale-guarded | -| Remove unused usings / find dead code | `remove_unused_usings`, `find_dead_code`, `find_dead_conditionals` | eyeballing | - -A fix must keep the code's declared intent: never hand-edit or `apply_patch` to make a diagnostic go away, and don't remove an interface, base type, member, attribute or other declaration to silence an error unless the user asks for that. - -All name arguments are fully-qualified (`Namespace.Type` or `Namespace.Type.Member`, with an optional parameter-type list to target one overload). A generic type may be written without its type parameters (`Namespace.Box`, `Namespace.Box.Get`) when only one arity exists — with several arities the response is `error=Ambiguous` with one candidate per arity, and a non-generic of the same name wins; any spelling with the right arity is accepted (`Box`, `Box`, ``Box`1``, `Box<>`, ``Namespace.Box`1``, ``Namespace.Outer`1+Inner``). A local function is a member of the method declaring it: `Namespace.Type.Method.local`, or `Namespace.Type.Method.outer.inner` when nested; put a parameter list on any segment to pick an overload (`Namespace.Type.Method(int).local`). On `error=Ambiguous` or `error=NotFound` the response lists `candidate=` lines that are exact names the same tool accepts — copy one back verbatim rather than guessing. - -## Combine tools, don't chain calls - -When you need several facts before making a change, send them as **one `multi_query`** call instead of sequential calls: every operation runs against a single snapshot, so the facts can never disagree with each other. `multi_query` accepts only the read-only query tools, and each operation uses exactly that tool's own parameter names — a wrong key is `error=Invalid` naming the key, never silently ignored. Every operation runs; results are then delivered whole, smallest first, until the response budget (about 80,000 characters) is filled, and operations whose result did not fit are named once in the header as `retry=:` (size = that result's cost as a ratio of the budget, rounded up to 0.1). Plan the continuation from the ratios: size ≥ 1.0 → re-send that operation alone (it pages with `nextStartItem=`); sizes summing to ≤ 1.0 → one continuation batch together; pass the response's `snapshot=` value as `expectSnapshot` so a continuation that would straddle a solution change is refused with `error=Stale` instead of mixing states. Delivered slots are always complete, so their own headers can be trusted. The envelope format is in the multi_query section of [references/tools.md](references/tools.md). - -**Impact analysis** — before renaming a symbol or changing a signature, and whenever someone asks "what uses X", "who calls X", "what breaks if I change X": batch `get_symbol` + `find_references` + `get_callers` + `get_callees` + `find_implementations` + `get_type_hierarchy` in one call, pointing each at the member or type you're changing (`get_callers` takes `methodName`, `get_callees` takes `memberName`, `get_type_hierarchy` takes `typeName`, the others `symbolName`). `get_callers` and `get_callees` are inverses — who calls this member, what does this member call — so alternating them walks a call chain one hop per query, including calls the compiler inserts (`foreach`/`await` plumbing, `using` disposal, operators and conversions); a caller inside an accessor is reported as its property, while `get_callees` names the accessor (`get_X`), so pass the property name back. Then follow each reference with `get_symbol_body` to read the calling convention before editing. Answer with Roslynk, never with grep over `*.cs`/`*.cshtml`/`*.razor` — text search both misses real usages and wrongly matches identically-named symbols. - -**Understand before editing** — when an edit depends on what an expression *is* (the type behind `var`, which overload a call picks, whether a value can be null at that point, whether a conversion is implicit or user-defined), call `get_expression_info` on its position instead of inferring from text; on a declared name (e.g. the `x` of `var x = ...`) it reports the declared symbol and its type, like an editor hover. It distinguishes the expression's `type` from the `symbol` it binds to — both can matter — and reports a missing fact as `none` rather than guessing; `symbol=none` with `candidateReason`/`candidates` means the call does not resolve. Batch several positions in one `multi_query`. - -Results are **snapshots** of a solution that is edited live: re-query after any write rather than reusing an earlier response. - -## Preview broad edits before writing - -Every write tool takes `checkOnly=true`, which returns the changed-file list without writing anything. Use it whenever a change might be broad — a rename of a widely-used symbol, a whole-solution cleanup — and confirm the scope before applying. Write tools are atomic and stale-guarded: if a target file changed on disk since Roslynk read it, the whole operation is rejected with `error=Stale` and nothing is written — recompute from current state and retry. Writes go straight to disk and advance the in-memory model immediately, so no reload or rebuild is ever needed afterwards. - -## Rename parameters with Roslyn - -To rename a parameter, call `rename_parameter` with the declaring member's `methodId` (add the parameter-type list when overloaded; a constructor is `Namespace.Type.Type(int)`), the current `parameterName` and `newName`. It updates named arguments at call sites and `` docs, and renames the same parameter across overrides, interface members and implementations that use the same old name - check `renamedMembers` and `unchangedRelated` in the response to see what was and wasn't cascaded. On `error=Conflict` pick a name not already used inside the member. Prefer it over `rename_symbol` for parameters, which cannot target a parameter by name. - -## Extract methods with Roslyn - -To pull code into its own method, call `extract_method` with the selection (1-based; end column exclusive - `endLine+1`, column `1` takes whole lines) and a `methodName`; add `asLocalFunction=true` for a local function. Preview with `checkOnly=true` to see the `signature` and `call` Roslyn chose. It writes nothing when the selection cannot be extracted safely or the result would not compile - read the `NotSupported` reason and adjust the selection (whole statements from one block, or one complete expression) rather than extracting by hand. - -## Check diagnostics once a task's edits are done - -The core edit cycle: make all the changes the task needs (any write tools) → `get_diagnostics` once at the end (bare call; the header always reports error/warning/info/hidden counts; each call compiles and analyzes everything the edits affect, so do not run it after every edit) → if counts are non-zero, re-call with `includeErrors=true` to see the details → fix each entry via `apply_code_fix` with its id, `line` and `column` → if that returns `error=Conflict` with `candidate=` lines, the diagnostic has several fixes: pick the one whose title matches your intent and pass its actionId (the text before the first comma) to `apply_code_action`; do not retry `apply_code_fix` → repeat until clean. This replaces `dotnet build` during development. Pass `includeAnalyzers=false` for a faster compiler-only pass when style rules don't matter yet. When the detail body is huge (one root cause, hundreds of entries), do not re-read it all: re-call with `summaryOnly=true` for one line per id, or narrow with `ids=[...]`, `filePath` or `projectName`, and cap with `maxResults` - a filtered call reuses the compiled result instead of recompiling. - -`find_dead_code` and `find_dead_conditionals` never delete anything — treat the results as candidates (public or reflection-used API can be a false positive), confirm intent with the user before bulk-removing, and hand each reported `loc` span to `apply_patch`. +Follow server instructions and tool schemas. diff --git a/catalog/Tools/Roslynk/skills/roslynk/manifest.json b/catalog/Tools/Roslynk/skills/roslynk/manifest.json index e5654dd..cad7e6a 100644 --- a/catalog/Tools/Roslynk/skills/roslynk/manifest.json +++ b/catalog/Tools/Roslynk/skills/roslynk/manifest.json @@ -1,5 +1,5 @@ { - "version": "1.0.0+source.28965e29d20f3192", + "version": "1.0.0+source.a136391a8f27e43b", "category": "Quality", "compatibility": "Requires a connected Roslynk MCP server and a .NET solution. Follow repository build and approval requirements.", "packages": [ diff --git a/catalog/Tools/Roslynk/skills/roslynk/references/tools.md b/catalog/Tools/Roslynk/skills/roslynk/references/tools.md index 687ab44..e69de29 100644 --- a/catalog/Tools/Roslynk/skills/roslynk/references/tools.md +++ b/catalog/Tools/Roslynk/skills/roslynk/references/tools.md @@ -1,344 +0,0 @@ -# Roslynk tool reference - -Deep per-tool reference: the operation-specific contract (exact envelopes, mechanics, edge cases) behind -what each tool's published MCP description summarizes. Read the section you need; SKILL.md carries the -workflows and the tool descriptions carry the concise contract for discovery. - -## Contents - -- [Shared conventions](#shared-conventions) -- [Lifecycle: open_solution, get_solution_status, reload_solution](#lifecycle) -- [Navigation: find_definition, get_expression_info, get_symbol, get_symbol_body, get_members, search_symbols](#navigation) -- [Relationships: find_references, find_reads, find_writes, get_callers, get_callees, find_implementations, get_type_hierarchy](#relationships) -- [Diagnostics: get_diagnostics](#diagnostics) -- [Razor and CSHTML: how path-based and write tools handle .razor/.cshtml](#razor-and-cshtml) -- [Code actions: get_code_actions, apply_code_action, apply_code_fix](#code-actions) -- [Editing: apply_patch, rename_symbol, rename_parameter, change_signature, extract_method, remove_unused_usings](#editing) -- [Dead code: find_dead_code, find_dead_conditionals](#dead-code) -- [Batching: multi_query](#batching) - -## Shared conventions - -**Output format.** Compact text outline: `key=value` header lines, a blank line, then a tab-indented body. No blank line means the response is all headers (typically an error). Booleans render `Y`/`N`. Newlines inside a field are literal `\n`. A `status=` header (`Building`|`Faulted`) appears only when the solution is not Ready. - -**Body nesting** (multi-symbol tools): project → one line per folder segment → file → namespace → `typeKind,typeName,loc` → `memberKind,memberName,loc`. `kind` ∈ `method|property|field|event|class|struct|interface|enum|delegate`. `loc` is `line:col` or `startLine:startCol-endLine:endCol`, 1-based; multiple locations on one line are pipe-delimited. Names containing commas (e.g. `Dictionary`) are single-quoted. - -**Error shape** (header-only): - -``` -error= -errorMessage= -candidate= (0+ lines: NotFound suggestions / Ambiguous matches) -stale= (0+ lines, Stale only) -``` - -**Symbol names.** A name is a fully-qualified name, optionally carrying a parameter-type list for a -method or indexer: `N.T.M`, `N.T.M(int, string)`, `N.T.this[int]`, `N.T.M(T)`. Parameter names, -default values, nullable annotations and `global::` are ignored on input, and fully-qualified parameter -types are accepted, so `M(System.Int32)` and `M(int value = 0)` both resolve `M(int)`. A `ref`/`out`/`in` -modifier is optional but honoured when written. Without a parameter list the name matches every overload -→ `error=Ambiguous`, one `candidate=` per match; every candidate is accepted verbatim by the tool that -emitted it, and the `resolvedSymbol`/`resolvedType`/`resolvedMethod`/`#fullName` a tool echoes is in the -same re-queryable form. When a declaration compiles in several target frameworks or `#if` projections and -a type in its signature binds in only some of them, the echoed name, candidates and outline parameter -types are taken from a copy where it binds (`M(int)`, not the unresolved `M(Int32)`); any spelling of the -declaration's signature still reaches its copies in every framework. - -**Generic names.** A generic type may be written without its type parameters (`N.Box`, `N.Box.Get`) -when only one arity exists; with several arities sharing the name the response is `error=Ambiguous` -with one `candidate=` per arity, and a non-generic of the same name wins over a generic one. Any -spelling with the right arity on a segment is accepted — `N.Box`, `N.Box`, `N.Box<>`, and the -reflection/metadata form ``N.Box`1`` (doc-id style ``N.T.M``2`` for generic methods) — while a wrong arity -(``N.Box`2``) is `NotFound`. A metadata `+`-nested name (``N.Outer`1+Inner``) also resolves. Every -name-based tool accepts these, including `get_symbol_body`, which returns the source body when the -metadata-spelled type is declared in the solution. - -**Local functions** are named as members of the member that declares them, through any nesting of types or -of local functions: `N.Parent.Widget.Method1.localMethod`, and `N.Parent.Widget.Method1.localMethod.inner` for -one declared inside another. The container is the enclosing method, constructor, operator, property or event -(or outer local function); a local function inside a lambda belongs to the member around the lambda. Any -segment may carry its own parameter list, so overloads of the container are told apart: -`N.T.Method2(int).helper` vs `N.T.Method2(string).helper`. Tools emit the fully signed form, with every -container's parameter list, e.g. `N.Parent.Widget.Method1(int).localMethod(string, int).inner(string)`, and -that form is what an `Ambiguous` candidate looks like. A bare name such as `inner` also resolves. Outlines -report a local function's kind as `localfunction` and nest it under its containing member. - -**Paging and truncation.** Tools whose result can be too large page by item: an oversized result carries `count=`, `truncated=Y` and `nextStartItem=` — call again with `startItem=` and the same other arguments for the next page. An item is one leaf record (a reference, caller, callee, implementor, diagnostic, member, candidate, search hit; for get_symbol_body one source line). Every page repeats the container lines open above its first item, so it reads standalone; the preamble counts against `maxSize` but not against `count=`. `maxSize` (characters; default the response budget, about 80,000 — set with `Roslynk:MaxResponseChars` or the `Roslynk__MaxResponseChars` environment variable, read once at daemon start) bounds a page; an item longer than a whole page is delivered as far as it fits and named `partialItem=` — the rest of that item is not retrievable. `startItem` past the end, or a `maxSize` too small to carry one item beside its container lines, is `error=Invalid`. `maxResults` bounds the result SET (a scan halts at the cap); paging walks that capped set and `count=` names its size — omit `maxResults` and page when you want everything. A result that fits whole carries no paging headers at all. The tools that cannot page (get_symbol, find_definition, get_expression_info, get_solution_status) cut an oversized result after its last whole line, starting with `outputTruncated=Y` and `fullOutputChars=`. - -**Defaults.** Don't pass a value for a defaulted parameter unless you need the non-default behavior. - -**Generated locations.** A location declared by a source generator has a virtual path that does not exist on disk (unless `EmitCompilerGeneratedFiles` is set). `get_symbol`, `get_symbol_body` and `find_definition` add `generated=Y` and `generator=` headers after `loc`; in nested bodies (`get_members`, `find_references`, `find_reads`, `find_writes`, `get_callers`, `get_callees`, `find_implementations`, `search_symbols`) the file-name line ends `,generated=Y`. Read such code with `get_symbol_body`, not from disk. Razor's generated `.g.cs` documents are not marked. `search_symbols` includes declarations a source generator emits (types, members, namespaces and local functions inside generated members), marked like any generated location, whether or not a hand-written declaration in the same project also matches the query. - -**Generated declarations resolve by name.** Every name-based tool (get_symbol_body, find_references, get_callers, get_callees, find_implementations, get_type_hierarchy, find_reads, find_writes, search_symbols, rename_symbol, rename_parameter, change_signature) resolves a generator's declarations — members, nested types, local functions — whether or not hand-written code mentions them. `rename_symbol`, `rename_parameter` and `change_signature` refuse a symbol declared only by a generator (`error=NotSupported` naming the generator): the generated declaration is never written to disk and would be regenerated unchanged, so change the generator or the code that drives it instead. A partial member or type with a hand-written declaration (e.g. `[GeneratedRegex]`, a `JsonSerializerContext`) can still be renamed — the generator follows the hand-written name. - -**`#if` projections.** Symbol tools (find_definition, find_implementations, get_members, get_symbol, get_symbol_body, get_type_hierarchy, find_references, find_reads, find_writes, get_callers, get_callees, rename_symbol, search_symbols) also cover inactive `#if`/`#else` branches: Roslynk builds derived compilations toggling each uniformly-defined preprocessor symbol, and unions/dedupes results. - -## Lifecycle - -### open_solution -`solutionPath` (required): absolute path to `.sln`/`.slnx`. -Returns `solutionId` (= the path you passed), `status`, `projects`, `loadDiagnostics` (a count; `get_solution_status` lists the messages), then one `,` line per project. Loads in the background; idempotent; missing file → `NotFound`, failed load → `Faulted`. While loading, other tools return `error=Indexing` — retry them shortly; never fall back to raw file edits. - -### get_solution_status -`allLoadDiagnostics` (optional, default false). Lists every solution loaded by the daemon (daemon-wide, not session-scoped): `,,/` per line. `total` is `?` until the first load completes. Status values: `Building`, `Updating`, `Ready`, `Faulted`. - -When the load reported messages (the count `open_solution` shows as `loadDiagnostics`: a skipped or unloadable analyzer/generator such as an unbuilt generator DLL, a project that failed to evaluate, an SDK that was not found), each is a tab-indented `loadDiagnostic=` line under its solution line, shown only once that solution is `Ready` (never while `Building`, `Updating` or `Faulted`); a solution with none stays one line. These often explain a batch of confusing compiler errors. Messages are sorted, and without `solutionId` only the first 20 per solution are listed, followed by `\tloadDiagnosticsTruncated=` for the rest. With `solutionId` only that solution is listed, with every message. A `solutionId` that is not loaded → `error=NotFound`. Not batchable in `multi_query`. - -``` -C:\repo\GeneratorSolution.slnx,Ready,2/2 - loadDiagnostic=Skipped unresolved analyzer in project 'ConsumerLib': 'C:\repo\GeneratorLib\bin\Debug\netstandard2.0\GeneratorLib.dll' does not exist, so the generated code of project 'GeneratorLib' is unavailable. Build project 'GeneratorLib' in the configuration this path names; the next call picks it up without a reload. -``` - -A missing generator DLL (typically a generator project referenced as an analyzer and built only in Release, while Roslynk loads Debug) is reported with the project that builds it. Every data tool call compares the file stamps of such DLLs, and of every analyzer DLL a project of the solution builds, with the ones loaded: a DLL built or rebuilt since is attached before the call reads, so that call already sees the new generated code, wherever the DLL lives (`bin`, an artifacts directory, outside the solution). No reload is needed. The message goes away once the DLL exists; a DLL that then fails to load is reported as `Analyzer load failed for '': ...` until a later build loads. - -### reload_solution -`solutionId` (required). Forces a from-disk MSBuild re-evaluation; the old snapshot keeps serving as `Building` until the fresh one is ready. Manual backstop for missed watcher events (network/WSL filesystems), `dotnet restore`, SDK/`global.json`/`Directory.Build.props` changes, branch switches, or retrying a `Faulted` load. **Never call it unless the user explicitly instructs you to** — suggest it instead. - -## Navigation - -### find_definition -`solutionId`, `filePath` (absolute or solution-relative), `line`, `column` (1-based). Position-based go-to-definition. Returns `#fullName`, `#kind`, plus `#project`/`#path`/`#loc` for source symbols or `#assembly=` for metadata-only. (Note the `#`-prefixed header style, unique to this tool family.) A file compiled into several projects or `#if` projections is resolved in each, and the answer whose types bind is reported. - -### get_expression_info -`solutionId`, `filePath` (`.cs`, `.razor` or `.cshtml`; absolute or solution-relative), `line`, `column` (1-based, anywhere inside the expression; the position just after a token counts as that token). Returns compiler facts about the expression at the position. Batchable in `multi_query`. - -The expression is the innermost one containing the token, widened to what an edit means: a member name reports its whole member access (`a.B`), a called name its invocation (`a.B(c)`, so `type` is the return type and `symbol` the selected overload), and a created type its object creation (`new T(...)`, symbol = constructor). A position on the name a declaration introduces (local, parameter, field, property, event, method, type, foreach/catch/pattern variable) reports the declared symbol instead, like an editor hover: `declaration=Y`, `expr` is the name, `exprKind` the declaring syntax kind (e.g. `VariableDeclarator`, `MethodDeclaration`), `type` the declared type (a method's return type; `none` for a type declaration), `nullability` the declared annotation with the initializer's flow state (`None` without an initializer), `constant` for a `const`, then the usual symbol keys; no `convertedType`/`conversion`. A position on a keyword, punctuation, comment or whitespace is `error=NotFound`; a line/column outside the file or a file not compiled in the solution is `error=NotFound`; a loading solution is `error=Indexing`. Positions inside an inactive `#if` branch are tried in each projection. - -Output is header only, in this order (optional keys only when applicable): - -| Key | Meaning | -|---|---| -| `expr` | Expression text, whitespace collapsed, cut at 200 chars with `...` | -| `exprKind` | Roslyn `SyntaxKind` (e.g. `InvocationExpression`, `IdentifierName`) | -| `declaration` | `Y` only when the position is on a declared name (see above) | -| `path`, `loc` | Solution-relative file and `startLine:startCol-endLine:endCol` (Razor source positions for `.razor`/`.cshtml`) | -| `type` | Expression's natural type, fully qualified with C# keywords and `?` for annotated references; `none` for a method group, namespace or typeless expression (`null`, lambda) | -| `convertedType` | Only when the target type differs (implicit conversion, target typing) | -| `nullability` | `/`: annotation `None|NotAnnotated|Annotated`, flow state `None|NotNull|MaybeNull`; `None/None` when nullable analysis is off. Flow state reflects prior null checks | -| `conversion` | Only when converted type is known and not a plain identity: `implicit`/`explicit` followed by kinds (`numeric`, `nullable`, `reference`, `boxing`, `constant`, `user-defined `, `target-typed-new`, `collection-expression`, ...), `identity`, or `none` when no conversion exists | -| `constant` | Compile-time constant as a C# literal (`40`, `"x"`, `null`), else `none` | -| `symbol` | Bound symbol: generic definition / static extension form, re-queryable with name-based tools (`get_symbol`, `find_references`, ...); locals, parameters and range variables report their bare name; `none` when nothing binds | -| `candidateReason`, `candidates` | With `symbol=none`: Roslyn's reason (e.g. `OverloadResolutionFailure`) and pipe-delimited candidate names | -| `symbolKind` | Same kind words as other tools (`method`, `property`, `field`, `local`, `parameter`, `class`, ...) | -| `instantiation` | Constructed generic or reduced extension form, e.g. `Formatter.Echo(string)` | -| `origin` | `source` with `symbolPath`/`symbolLoc` (`line:col`), or `metadata` with `assembly` | -| `doc` | XML-doc `` as plain text (cref short names), cut at 400 chars; absent when none is available | - -### get_symbol -`solutionId`, `symbolName` (FQN, any symbol kind including members). Unambiguous source match → `#project`/`#path`/`#loc` headers + body containing the verbatim declaration text cut before the body (brace/`=>` excluded). Metadata symbol → `#source=metadata`, `#kind`, `#signature`, `#assembly`. Ambiguous → `error=Ambiguous` with one `candidate=` per match. Preferred over reading a file to identify a symbol. - -### get_symbol_body -`solutionId`, `symbolName` (FQN, any declared symbol kind), `includeLeadingTrivia` (default false), `startItem` (default 1), `maxSize` (characters; default the response budget), `part` (default 0). Returns the symbol's source text including its body, verbatim — original indentation, line endings and spacing, never reformatted. Headers `project`/`path`/`loc`, a blank line, then the text. `includeLeadingTrivia=true` extends the text (and the `loc`) back over the declaration's comments, XML docs and directives. A partial type, or a partial method/property/event, returns `parts=` and one `part=,project=...,path=...,loc=...,lines=` line per block; a partial member's parts are its defining declaration then its implementation, including one supplied by a source generator (`[GeneratedRegex]`, `[LoggerMessage]`, `[LibraryImport]`), whose part line ends `,generated=Y,generator=`. - -Long text is paged, never cut silently: a call returns at most `maxSize` characters and stays within the response budget. Items are the text's lines, counted from 1 at the first line of the returned text (its first comment line with `includeLeadingTrivia`), not in the file; for a Razor member that text is the generated C#, while `loc` stays the `#line`-mapped display span — the two coordinates are deliberately unrelated. A page that is not the whole text adds `truncated=Y`, `count=` and `nextStartItem=`: re-call with `startItem=`, keeping `includeLeadingTrivia` and `part` unchanged; a `startItem` past the end is `error=Invalid` naming `count`. There is no unlimited mode (the budget is the ceiling). A single line longer than a whole page's budget is delivered as far as it fits and named `partialItem=` — the rest of that line is not retrievable by paging. When a partial type's parts do not all fit, the result is the whole-or-omitted overview: `parts=`, `truncated=Y`, `omittedParts=`, each part that fits shown whole, the rest listed with their `lines=` count and `,omitted=Y` — fetch one with `part=`, which returns that part alone, paged as above with `parts=`/`part=` headers. `startItem` pages one part; combining it with several parts and no `part=` is `error=Invalid`. - -Overloads (or any name matching several distinct symbols) — `error=Ambiguous`, resolved by retrying with a candidate's parameter-type list; a metadata/referenced-assembly symbol — `error=NotSupported` (use `get_symbol` for its signature), but a metadata spelling (``Ns.Box`1``, `N.Outer+Inner`) of a type the solution declares in source returns that source. Prefer this over reading or grepping the file to see what a member does. - -### get_members -`solutionId`, `typeName` (FQN), `includeInherited` (default false), `nameFilter` (default null; trailing `*` = prefix match, otherwise case-insensitive substring), `includeMethods`/`includeFields`/`includeProperties`/`includeEvents`/`includeNestedTypes` (all default true). Lists all members including private, grouped by declaring file (`` bucket for referenced-assembly types). Member lines: `kind,name,loc[,paramType|paramType|...]` (param list only for methods with parameters). Returns declarations + spans, not bodies — use `get_symbol_body` for a member's body. Each member's local functions are listed beneath it in declaration order, one level deeper (`localfunction,,,`), a local function declared inside another one level further. - -### search_symbols -`solutionId`, `query` (case-insensitive substring), `maxResults` (omit for every match - the result then pages with startItem/maxSize). Source-declared symbols only (no metadata), local functions included. Declarations a source generator emits are included and marked `,generated=Y` — a generated-only type, member, nested type, namespace or local function is found even when nothing hand-written matches; a partial type with a generated part is still one leaf at its first location (the hand-written part), with the generated part visible through its own members. Matched members nest under their type, and a local function under its containing member (`localfunction` kind); a type's `loc` appears only if the type itself matched. - -## Relationships - -### find_references -`solutionId`, `symbolName` (FQN), `maxResults` (omit for every reference - the result then pages with startItem/maxSize). Compiler-accurate: skips comments, strings, unrelated same-named members. References grouped file→namespace→type→member; pipe-delimited `loc`s on one line for multiple hits. Deduped across `#if` projections. `count=`/`truncated=Y` when capped. Prefer this over text search for usages in `*.cs`, `*.cshtml` and `*.razor`; combine with get_callers/find_implementations via multi_query for impact analysis. - -### find_reads / find_writes -`solutionId`, `symbolName`, `maxResults` (omit for every location - the result then pages with startItem/maxSize). Target a field or property by FQN (`N.T.Field`), or a parameter as its containing method, constructor, indexer or local function's FQN + `:` + parameter name (`N.T.Method:value`, `N.T.Method(int):value`; the member part follows the usual overload grammar). Local variables are not supported. Same body as find_references, but one location per leaf with the access kind appended: `,,,`. - -`accessKind`: `read`, `assign` (`=`, including deconstruction targets), `compound` (`+=`, `??=`, ...), `increment` (`++`/`--`), `ref` (`ref x` argument, `ref x` expression, `&x`), `out`, `init` (field/property declaration initialiser, object or `with` initialiser, attribute named argument, or an assignment to the constructor's own field/property inside its constructor; a lambda inside the constructor is `assign`). find_reads returns `read`, `compound`, `increment`, `ref`; find_writes returns everything except `read`. **`compound`, `increment` and `ref` appear in both tools with the same kind** — do not add the two counts. `nameof(...)`, doc crefs and named arguments (`M(value: 1)`) are omitted from both. - -`count=`/`truncated=Y` when capped, as find_references. Errors: `NotFound` (for an unknown parameter, candidates list the member's real parameters), `Ambiguous` with candidates, `NotSupported` (method, type, event, local variable), `Indexing`. Coverage: all loaded target frameworks plus derived compilations that each toggle one uniformly-defined/undefined preprocessor symbol; a branch reachable only with several symbols toggled together, or guarded by a symbol defined in only some projects, is not analysed. Both are available in `multi_query`. - -### get_callers -`solutionId`, `methodName` (FQN; a method, constructor (`N.T.T(...)`), operator (`N.T.op_Addition(T, T)`) or conversion (`N.T.op_Implicit(T)`)). Callers grouped file→namespace→containing type→calling member with the caller's declaration `loc`. Target one overload by writing its parameter-type list. - -A caller is the declaration containing the call: a method, constructor, operator or local function; a property, indexer or event when the call is in one of its accessors; a field — or an auto-property, named as the property — when it is in its initializer. Lambdas belong to the member around them. A call through an interface or base member that the target implements or overrides is included. - -Calls the compiler inserts count: `foreach` (`GetEnumerator`, `MoveNext`, `Current`, the enumerator's `Dispose`, and the `await foreach` equivalents), `await` (`GetAwaiter`, `IsCompleted`, `GetResult`), the `Dispose`/`DisposeAsync` a `using`/`await using` runs, deconstruction and positional patterns, collection-initializer `Add`, user-defined operators and conversions (including `+=`, `++`, implicit conversions and `true`/`false` in a condition), query-expression methods, interpolated-string handler members, implicit `base()` calls, and the `Length`/`Count` behind `^`/`..`. `nameof(...)` and doc-comment references are not calls. Conversion-operator queries compile every project that can see the type and are slower. Not reported (by either tool): the `op_True`/`op_False` hidden inside `&&`/`||`, collection-expression `Add`, `dynamic` dispatch, and an implicitly declared constructor's own callers. - -### get_callees -`solutionId`, `memberName` (FQN), `excludeExternal` (default false). The inverse of get_callers: every method, constructor, property/event accessor and user-defined operator or conversion the member's code calls. Resolved from the compiler's operation model, so each call names the exact overload: a property read reports `get_X`, an assignment `set_X`, a compound assignment or increment both; `new T()` reports T's constructor; `e += h` reports `add_E` (`remove_E` for `-=`). Also reported: user-defined operators and conversions (including `+=` and `++`), the `Dispose`/`DisposeAsync` a `using` runs, and a method group passed as a delegate (`xs.Select(Helper)`). Only calls the source spells out are listed: the plumbing the compiler inserts for `foreach` (`GetEnumerator`, `MoveNext`, `get_Current`) and `await` (`GetAwaiter`, `get_IsCompleted`, `GetResult`) is not, though an explicit `.GetAwaiter()` call is. Also not reported: calls inside deconstruction assignments and interpolated-string handlers. - -The member may be a method, constructor, operator, property, indexer, event or field. What counts as its code: a property or indexer is its accessor bodies or expression body (plus an auto-property initializer), a field is its initializer, and a constructor also includes the field and property initializers it runs (instance ones, or static ones for a static constructor; none when it chains to `this(...)`). Lambdas and local functions declared inside the member are part of it. A member with no code in the solution (an abstract or interface declaration, an auto-property without initializer, or one in referenced metadata) calls nothing. Target one overload by writing its parameter-type list. - -Output: callees in the solution use the get_callers outline (project → folder → file → namespace → type → `kind,name,loc`). Callees declared in a referenced assembly (BCL, NuGet) sit under one top-level `` line per assembly (`` if the assembly is unknown), then namespace → type → leaf, with the leaf's `loc` field present but empty. `excludeExternal=true` leaves them out. A leaf gets a fourth field only when the callee's own type declares more than one method of that name (inherited overloads do not count): its declared parameter types, pipe-delimited, minimally qualified with nullable annotations and without `ref`/`out`/`in`, a type containing a comma single-quoted; `()` for the parameterless overload. Every callee is reported as declared: generic instantiations (`List.Add`, `To`) collapse to their definition, a classic extension method lists its `this` parameter, and a C# 14 `extension(...)` block member lists only the parameters declared on it. - -``` -resolvedSymbol=MyApp.Report.Save(string, int) - - - System - class,Console - method,WriteLine,,int - method,WriteLine,,string? - - System - class,String - method,get_Length, - struct,Int32 - method,ToString,,() -MyApp - MyApp - Audit.cs - MyApp - class,Audit - method,Log,5:21 - Tally.cs - MyApp - class,Tally - method,Add,5:14,int - method,Reset,7:14,() -``` - -### find_implementations -`solutionId`, `symbolName` (FQN of interface, abstract member, or virtual member). Implementors/overrides across all projections, deduped. - -### get_type_hierarchy -`solutionId`, `typeName` (FQN). Up to three sections — `base`, `interfaces`, `derived` (omitted when empty) — entries `typeKind,FQN`. - -## Diagnostics - -### get_diagnostics -`solutionId`, `includeErrors`/`includeWarnings`/`includeInfo`/`includeHidden` (**all default false**), `includeAnalyzers` (default true; `false` = faster compiler-only pass), and five optional filters: `projectName`, `filePath`, `ids` (a JSON array of strings - the tool surface's only array parameter), `maxResults` and `summaryOnly`. - -**Costly:** it compiles and analyzes every project the edits since the last call affect (seconds on a large solution), so make all of a task's edits first and call it once at the end rather than after every edit. Header always carries `errors=`, `warnings=`, `infos=`, `hidden=` counts regardless of include flags, so filtering is never silent. Body (per included severity) nests file→severity→`,,`. Ids that exist only to trigger a code fix (they carry no message and accompany a public rule, as IDE0005's does) are not listed; fix the public id instead. Multi-targeted projects report diagnostics across their loaded target frameworks. The Razor compiler's own diagnostics (`RZ*`, e.g. `RZ1006` for an unclosed `@code` block) are reported against the `.razor`/`.cshtml` file with Razor-source positions, once even for a multi-targeted project (not when the Razor compiler cannot be loaded and the last build's generated output is used instead). Results are cached per `includeAnalyzers`: a repeat call with no change in between is near-instant, and after a change only the edited projects and the projects depending on them are recomputed. This replaces `dotnet build` for correctness checking. - -**Filters** narrow the result after compilation, so a filtered call still reuses the cached result and recompiles nothing; they combine (AND): - -- `projectName`: only that project's diagnostics - exactly the name the outline prints (the project file name with the `.csproj` extension omitted; other extensions such as `.vbproj` are kept, and a trailing `.csproj` you pass is stripped). Case-insensitive, and it matches every loaded target framework of a multi-targeted project. -- `filePath`: only diagnostics located in that file - absolute or relative to the solution folder (the same spellings `find_definition` accepts), case-insensitive. A `.razor`/`.cshtml` path also matches the C# diagnostics `#line`-mapped into it and the `RZ*` diagnostics reported against it. -- `ids`: only those diagnostic ids, e.g. `["CS0246","CS0103"]`, case-insensitive. Omit, or pass an empty list, for every id. -- `maxResults`: caps the result set (the body lists id rows in summary mode). When the cap drops something, `count=` and `truncated=Y` precede the body; both are absent otherwise. The per-severity header counts always stay complete. Omit maxResults to page through everything with startItem/maxSize. -- `summaryOnly`: `true` replaces the body with one line per id - `,,,,,` - ordered by count descending then id, carrying each id's count, one example location (its first diagnostic in body order) and that example's message. It covers every severity unless an include flag is set. `maxResults` caps the id rows, with `count=` counting rows. - -Every active filter is echoed as a `filter=:` header before the counts, and the counts describe the **filtered** set - `errors=3` under a `filter=` line means 3 errors in that filtered scope, not 3 in the solution. An empty body with a `filter=` header means the filter matched nothing, NOT that the solution is clean. A `projectName` or `filePath` that is not in the solution is `error=NotFound` with `candidate=` values (one of which the tool would accept); one that exists but has no diagnostics returns zero counts, not an error. An `ids` entry that matches nothing is zero counts too - ids are open-ended and never validated. - -## Razor and CSHTML - -Every tool that takes a `documentPath` (`get_code_actions`, `apply_code_fix`, `extract_method`, `remove_unused_usings`) accepts `.cs`, `.razor` and `.cshtml` files, and every write tool edits `.razor`/`.cshtml` sources, including `apply_code_action`, `change_signature`, `rename_symbol`, `rename_parameter` and `apply_patch`. Roslyn only analyses C#, so for a Razor file the tools work on the C# the Razor compiler generates from it and write the result back to the Razor file. The generated `.g.cs` is never written. - -- **Positions** (`line`/`column`, selections) are given in the `.razor`/`.cshtml` file. They must fall inside C# the compiler copied from the file: an `@code`/`@functions` block, an `@{ }` block, an inline expression or a directive. Markup is `error=NotSupported`. -- **Mapping back.** An edit is written to the Razor file only when it lies inside those C# regions; code Roslyn formats is re-indented to the file's own indentation, and lines it did not touch are kept verbatim. Edits to a `@bind-X="Expr"` expansion's hidden scaffolding (the setter lambdas and `ValueExpression` lambda the compiler derives from the one source span) are copies of the edit already made at the mapped attribute-value span (`@bind-X`, `:get`/`:set`/`:after`, `@bind`), so renames of bound members update the `.razor` source once at the user-written span. An edit to generated scaffolding with no attributable Razor source (for example a `using` or member added to the generated class) is `error=NotSupported`. Razor text that no longer matches the generated code is `error=Conflict`. Nothing is written in either case. -- **Analyzers do not run on Razor-generated code**, so a Razor file offers compiler-diagnostic fixes (e.g. `CS0219`) and refactorings, but no `IDE*`/`CA*` fixes. The exception is unnecessary usings: see `remove_unused_usings` and `apply_code_fix`. -- **Imports files** (`_Imports.razor`, `_ViewImports.cshtml`) apply to every component or view beneath them. Using removal never edits them. -- **Freshness.** An edit to an existing `.razor`/`.cshtml` file (yours or the user's) is applied in place: the Razor compiler reruns incrementally for that project and the projects using it, with no solution reload. A C# edit that changes declarations (not just method bodies) reruns it too, so generated code follows a code-behind change such as a renamed `[Parameter]`; this holds for every write tool, `apply_patch` included. Adding or deleting a Razor file reloads the solution on the next call. Multi-targeted projects get generated code for every target framework. -- **Some `.cshtml` views cannot take a new method.** Roslyn will not add a member where the generated view class hides the insertion point. `extract_method` then returns `error=NotSupported` and suggests `asLocalFunction=true`, which still works. - -## Code actions - -### get_code_actions -`solutionId`, `documentPath` (.cs, .razor or .cshtml, absolute or solution-relative), `line`, `column` (1-based), `endLine`/`endColumn` (optional, for a selection span). Returns lines `,, `; a grouped action (such as the choices under "Generate type") is listed as its individual actions; `kind` ∈ `Fix|Refactoring`; `diagnosticId` is `-` for refactorings. Fixes cover analyzer diagnostics as well as compiler ones, so `IDE*` and `CA*` ids appear here when the project references the analyzer that reports them. Capped at 50. `actionId` is opaque — pass it back verbatim. In a `.razor`/`.cshtml` file the position must be inside C# (see [Razor and CSHTML](#razor-and-cshtml)); a position in markup → `NotSupported`. Actions are listed before their edits are computed, so an action whose edits cannot be mapped back to the Razor file is only refused when applied. - -### apply_code_action -`solutionId`, `actionId` (from get_code_actions), `checkOnly` (default false). The action is re-resolved at apply time, not cached — if the code changed since discovery, `error=Conflict`: re-run `get_code_actions`. Malformed id → `error=Invalid`. Returns `applied`, `action`, changed files. For an action discovered in a `.razor`/`.cshtml` file the edits are written to the Razor source; an unmappable edit → `NotSupported`, mismatched Razor text → `Conflict`, nothing written. External edit since load → `Stale`. - -### apply_code_fix -`solutionId`, `documentPath` (.cs, .razor or .cshtml), `diagnosticId` (a compiler id such as `CS0219`, or an analyzer id such as `IDE0005`), `line`, `column` (**required**, 1-based), `checkOnly` (default false). Quick path from `get_diagnostics`: pass an entry's id and its `line:col` unchanged, and the diagnostic with that id whose span contains the position (start and end included) is fixed, without an actionId round-trip. Other occurrences of the same id are left alone. - -- No diagnostic with that id at the position → `NotFound`; `line` or `column` below 1 → `Invalid`; no registered fix → `NotSupported`; fix produced no changes → `Conflict` (no candidates); external edit since load → `Stale`. -- **Several fixes → hand off to `apply_code_action`.** When the diagnostic has more than one distinct fix (e.g. `CS0535`: implement interface / implement all members explicitly; `CS0246`: add a `using` / fully qualify / generate the type), nothing is written and the result is `error=Conflict` with one `candidate=<actionId>,Fix,<diagnosticId> <title>` header per fix. Show the user the candidate titles and ask which to apply, unless their request clearly names one, then call `apply_code_action` with its actionId (the text before the first comma). Do not call `apply_code_fix` again for it: it will return the same Conflict. `checkOnly` returns the same Conflict. - - ``` - error=Conflict - errorMessage=CS0535 at 9:22 has 2 fixes; apply the chosen candidate's actionId with apply_code_action. - candidate=eyJEb2N1...,Fix,CS0535 Implement interface - candidate=eyJEb2N1...,Fix,CS0535 Implement all members explicitly - ``` - -In a `.razor`/`.cshtml` file the position is in the Razor file, only diagnostics located in that file count, and the fix is written to the Razor source (unmappable → `NotSupported`, mismatched text → `Conflict`). `CS8019`/`IDE0005` remove the unnecessary `@using` on that line, the same analysis as `remove_unused_usings`; a used `@using` there → `NotFound`. - -Analyzer ids are only reported — and so only fixable — when the project actually references the analyzer. `IDE*` rules come from the CodeStyle analyzers, which a project pulls in with `EnforceCodeStyleInBuild` or an explicit `Microsoft.CodeAnalysis.CSharp.CodeStyle` package reference; an SDK copy built against a newer compiler than Roslynk's is skipped. - -## Editing - -All write tools: `checkOnly=true` previews changed files without writing; writes are atomic (all-or-nothing) and stale-guarded (on-disk content re-hashed against the loaded snapshot; mismatch → `error=Stale`, nothing written). Successful writes advance the in-memory model immediately. Response shape: `applied=Y|N` + tool-specific headers + changed-file list grouped by project. - -### apply_patch -`solutionId`, `patch` (git unified diff: `---`/`+++`/`@@` hunks, one or more file sections), `baseVersions` (optional list of `{path, version}` from a prior read, for explicit optimistic concurrency), `checkOnly`. - -- Hunks are **content-anchored**; line numbers in `@@` headers are untrusted and may be omitted (`@@`). Each hunk must match exactly one place — include enough context. Ambiguous or unmatched → `error=Conflict` naming the file and reason. -- Edits any existing text file inside the solution folder. Compiled `.cs` and `.razor`/`.cshtml` documents (regular and additional) are folded into the in-memory model; other files (`.csproj`, `.json`, `.md`, ...) are written to disk only. Creation, deletion, binary files, `obj`/`bin` paths, and paths outside the solution folder are rejected before any hunk is attempted: `error=NotSupported` with `rejected=<path>` lines. A path naming no file → `error=NotFound` (the message names the solution folder that paths are relative to); a suffix matching several distinct files → `error=Ambiguous` with `candidate=<solution-relative path>` lines. Mixed reasons give one error (NotFound, else Ambiguous, else NotSupported) whose message explains each, with every path in `rejected=`. Encoding (UTF-8/UTF-16 BOM) is preserved. -- Path resolution: absolute → solution-relative → unique suffix match across solution documents (regular and additional; a multi-targeted file counts once, so a repo-root-relative path such as `src/Multi/Api.cs` resolves); a path not in the model falls back to solution-folder-relative. -- The stale-write guard runs even without `baseVersions`. - -### rename_symbol -`solutionId`, `symbolName` (FQN), `newName` (must be a valid C# identifier), `checkOnly`. Renames across partial classes, all `#if` projections, all TFMs, and Razor: edits computed against generated `.g.cs` are mapped back through `#line` directives and written to the real `.razor`/`.cshtml` (covering `@code` blocks, markup expressions, component attributes in other components, and `@bind-X="Expr"` bindings — the compiler's hidden setter/`ValueExpression` expansions collapse into the one attribute-value edit). Unverifiable mapping aborts the whole rename before writing. Ambiguous → `error=Ambiguous` with candidates; retry with one verbatim to rename a single overload. A symbol declared only by a source generator → `error=NotSupported` naming the generator (change the generator or the code that drives it instead); a partial member/type with a hand-written declaration is renamable. A file the rename changes that was edited on disk, or in the loaded model after the rename was computed → `error=Stale` with a `stale=` path; nothing is written. Edits to other files made meanwhile are kept. - -### rename_parameter -`solutionId`, `methodId` (FQN of the method, local function — see [Symbol names](#shared-conventions) — constructor — written `Namespace.Type.Type(...)` — or indexer; add a parameter-type list to pick one overload), `parameterName` (existing name), `newName` (valid C# identifier, different from `parameterName`), `checkOnly`. Uses Roslyn's semantic rename on the parameter: declaration, body uses, named arguments at call sites and `<paramref>`/`<param>` doc references; strings and comments untouched. Covers all `#if` projections, TFMs and Razor like `rename_symbol`. Cascades across the override/interface group (overridden/overriding members, interface members and implementations, both partial-method parts) when the related declaration is in source and its parameter at the same position has the same old name; related members with a different name, or in metadata, or declared only by a generator (listed in `unchangedRelated`), are left alone. Headers: `applied`, `resolvedMethod` (before the rename), `parameter` (old name), `renamedMembers` (declarations renamed, including the target), `unchangedRelated` (`; `-separated, omitted when empty), then changed files. Errors: invalid/unchanged `newName` → `error=Invalid`; overloads → `error=Ambiguous` with candidates; unknown member → `error=NotFound` with suggestions; unknown `parameterName` → `error=NotFound` listing the member's parameters; `newName` already declared in a renamed member (parameter, local, local function, lambda/query variable, type parameter) → `error=Conflict` naming the member; not a method/constructor/indexer, positional record constructor, metadata-only member, or a member declared only by a source generator → `error=NotSupported` (naming the generator in the last case); changed on disk → `error=Stale`. Nothing written on any error. Not available in `multi_query`. - -### change_signature -`solutionId`, `methodId` (FQN), `parameterType` (e.g. `System.Threading.CancellationToken`), `parameterName` (valid identifier), `defaultValue` (**required** — keeps the parameter optional, e.g. `default`, `null`, `0`), `callSiteArgument` (optional; when given, threaded into every call site as a named argument), `checkOnly`. - -v1 scope: appends one optional parameter to one ordinary method or local function. `NotSupported` for virtual/override/abstract methods, interface members and implementations, partial methods, `params` methods, constructors/operators/accessors, and a method declared only by a source generator (naming the generator). An overloaded method is targeted by its parameter-type list; a bare name → `Ambiguous`. Only true invocation call sites are updated — method groups, `nameof`, and `cref` are left alone (still valid because the parameter is optional). Returns `updatedCallSites` count. Razor: a method declared in a `.razor`/`.cshtml` `@code` block, and call sites in `@code` or markup expressions, are mapped back through `#line` directives and written to the Razor source; an unmappable edit → `NotSupported`, mismatched Razor text → `Conflict`, nothing written. External edit since load → `Stale`. - -### extract_method -`solutionId`, `documentPath` (.cs, .razor or .cshtml, absolute or solution-relative), `startLine`, `startColumn`, `endLine`, `endColumn` (1-based, in that file; the end column is exclusive, so `endLine+1`, column `1` selects through the end of `endLine`), `methodName` (optional; defaults to Roslyn's own name, e.g. `NewMethod` or one derived from the code), `asLocalFunction` (default false), `checkOnly` (default false). - -Runs Roslyn's Extract Method refactoring (the same provider behind get_code_actions' "Extract method"/"Extract local function"), so parameters, `ref`/`out`, the return value, `static`/`async` modifiers and the call-site replacement all come from Roslyn's data-flow analysis - never text splicing. Whitespace at either end of the selection is ignored, so whole-line selections work. Roslyn may widen a partial expression to the enclosing complete expression. When `methodName` is given, the extracted symbol is renamed semantically before anything is written. Roslyn formats the new method and the edited call site with the project's formatting options (`.editorconfig`); the rest of the file is untouched. - -Returns `applied`, `method` (final name), `symbolName` (the new method's full name, ready for the name-based tools — for a local function it carries its containers, e.g. `N.T.M(int).NewMethod(string)`), `kind` (`Method`|`LocalFunction`), `signature` (the declaration header on one line, e.g. `private static int Total(int a, int b)`), `call` (the statement now containing the call), then the changed files. `checkOnly=true` returns the same preview without writing. - -Nothing is written on any failure: -- Selection Roslyn cannot extract (spans members, partial statements, jumps out of the selection, `yield`, ...) → `NotSupported` with the constraints. -- Roslyn flags the extraction as possibly changing behavior → `NotSupported` with Roslyn's warning. -- The result would add compile errors to an edited file (e.g. a `methodName` equal to the type name, CS0542) → `NotSupported` listing up to five `id: message (line n)` entries. Errors already present are not counted. -- The call would bind to another member, or the rename produced no declaration of that name → `Conflict`. -- An edited file changed since the extraction was computed (in memory or on disk) → `Stale` with `stale=<path>`. -- Unknown document → `NotFound`; generated `.g.cs` (incl. Razor output; pass the `.razor`/`.cshtml` source instead) or non-C# → `NotSupported`; out-of-range, empty or reversed selection, or an invalid/keyword `methodName` → `Invalid`. -- `.razor`/`.cshtml`: a selection outside C# (in markup) → `NotSupported`; an edit that cannot be mapped back to the Razor file → `NotSupported`, mismatched Razor text → `Conflict`. Where Roslyn cannot add a new method to a `.cshtml` view (the generated class hides the insertion point), the error suggests `asLocalFunction=true`, which extracts into the containing member instead. The new code is written in the file's own indentation. - -Prefer this over get_code_actions + apply_code_action for extraction: it is deterministic (no action-id round trip, no title matching), names the method in one step, and checks the result compiles. Not available in multi_query (it is a write tool). - -### remove_unused_usings -`solutionId`, `documentPath` (optional .cs, .razor or .cshtml; omit to clean the whole solution, Razor files included), `checkOnly`. CS8019 finds the files to touch; each one is then rewritten by Roslyn's own IDE0005 fix, which preserves the surrounding trivia, falling back to a syntactic removal when the IDE0005 analyzer is not referenced. Nothing to remove → `applied=N`, `removedCount=0` (not an error). Safe to re-run (idempotent). External edit since load → `Stale`. - -Razor: the compiler never reports CS8019 in generated code, so each `.razor`/`.cshtml` file's generated C# is checked as ordinary code, and every unnecessary `@using` line written in the file itself is deleted. Directives in imports files (`_Imports.razor`, `_ViewImports.cshtml`) are shared by other components and views, so they are never removed, even when unused by the file being cleaned. - -## Dead code - -### find_dead_code -`solutionId`, `scope` (optional FQN prefix, e.g. `MyApp.Services` — use it on large solutions; the scan runs find-references per symbol), `includePublic` (default false — public/protected API excluded unless set), `maxResults` (bounds the expensive scan; omit it to scan everything - the result then pages with startItem/maxSize). - -Leaf lines: `memberKind,memberName,loc,confidence,reason` with confidence `High|Medium`. Automatically excludes interface implementations, virtual/override/abstract chains, test-attributed members (xUnit/NUnit/MSTest), generated code, and DI/reflection-attributed members (`[Export]`, `[ImportingConstructor]`). The `loc` is the full declaration span, ready to pass to `apply_patch` for removal — this tool never deletes anything itself. Treat results as candidates, not verdicts. - -### find_dead_conditionals -`solutionId` only. Header `#deadConditionals=<n>`; body per file: `<line:col>,<directive>,<condition>` with directive ∈ `if|elif|else` (condition `(else)` for `#else`). Flags branches never compiled under any configuration Roslynk actually loaded (each project's defined symbols, and that set minus DEBUG, across TFMs). A branch used only by a configuration not loaded (CI-injected define, missing workload) is a false positive — treat as "possibly dead". - -## Batching - -### multi_query -`solutionId`, `operations` (1+ items; the limit is the framing itself — a batch whose retry line cannot fit the budget is refused with `error=Invalid` before anything runs), optional `expectSnapshot`. - -Each operation is `{ "tool": <name>, "arguments": { ... } }` where `tool` is one of the 15 read-only query tools (get_symbol, get_symbol_body, get_members, find_definition, find_implementations, find_references, find_reads, find_writes, get_callers, get_callees, search_symbols, get_type_hierarchy, find_dead_code, find_dead_conditionals, get_expression_info) and `arguments` uses exactly that tool's single-call parameter names - unknown or misspelled keys are rejected (`error=Invalid` naming the key), never ignored; omitted parameters take the tool's declared defaults. The schema's `tool` enum lists the legal names, so a write tool, get_diagnostics or get_solution_status is unrepresentable and fails the whole call at binding (`error=Invalid` naming the offending value and the permitted set). - -**Impact analysis.** To answer "what uses X / who calls X / what breaks if I change X", batch find_references (`symbolName`), get_callers (`methodName`), get_callees (`memberName`), find_implementations (`symbolName`) and get_type_hierarchy (`typeName`) in one call instead of grepping - parameter names are each tool's own and a wrong key is an `Invalid` slot. get_callers and get_callees are inverses: who calls this member, and what does this member call - together they trace a call chain one hop per query. - -Everything runs against ONE snapshot of the solution, so results inside one response can never disagree with each other. The response is one envelope, not JSON: - -``` -operations=<n> -snapshot=<32-hex id of the snapshot every slot was computed against> -boundary=<32-hex, fresh per request> -budget=<n, the per-operation character allowance, net of the envelope's own framing> -retry=1:3.0,7:0.2 (present only when operations were dropped) - ---<boundary> -slot=2 tool=get_type_hierarchy - -<that tool's own output format, verbatim - headers, blank line, tab-indented body> - ---<boundary> -slot=3 tool=get_callees - -<that tool's output> - ---<boundary>-- -``` - -Every operation runs (in parallel); each result is then delivered WHOLE, smallest first, until the budget is filled, and delivered slots are emitted in request order. A slot is complete or absent - never cut - so only a delivered slot's own body headers may drive tool-level paging (`nextStartItem=`). Operations whose result did not fit are listed once in the `retry=` header, in request order, as `<index>:<size>` where size is that result's cost (frame + body) as a ratio of `budget=`, rounded up to 0.1 (0.1 is the smallest value reported, never 0.0). Plan the continuation from the ratios: size ≥ 1.0 can never fit beside anything - re-send that operation alone (it pages); sizes summing to at most 1.0 fit one continuation batch together; `ceil(size)` is roughly a solo call's page count. Ratios smaller than 0.1 of the budget are indistinguishable, so about ten such operations per continuation batch is the safe number. Ratios describe one snapshot: pass the response's `snapshot=` as `expectSnapshot` on the continuation, or a re-run against a moved solution re-measures and re-decides. Re-send exactly the listed operations with their original arguments from your own copy of the request - slot frames carry the index and tool name only, never the arguments. A failing operation is delivered as its normal `error=` block and can itself be dropped like any oversized result. - -**Truncation and continuation.** Pass the first response's `snapshot=` value as `expectSnapshot` when you continue: if the solution changed between the calls (another client, or the user saving a file) the continuation is refused with `error=Stale` naming both ids plus a `snapshot=<current id>` header - re-run the whole batch instead of stitching two generations. Consistency is guaranteed within one response, never across two. `get_diagnostics` and `get_solution_status` are deliberately not multi-queryable - call them directly. diff --git a/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/README.md b/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/README.md index b068f7c..59a8dad 100644 --- a/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/README.md +++ b/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/README.md @@ -17,6 +17,7 @@ PowerShell (Pester), and C++ (GoogleTest/Catch2/doctest/Boost.Test). - **Generate tests** *(polyglot)* — scaffold comprehensive unit tests for any language via a multi-agent pipeline - **Migrate tests** *(.NET only)* — see the separate [`dotnet-test-migration`](../dotnet-test-migration/) plugin (MSTest v1/v2 → v3 → v4, xUnit v2 → v3, xUnit → MSTest, VSTest → Microsoft.Testing.Platform) - **Audit test quality** *(polyglot)* — detect anti-patterns, test smells, assertion gaps, and (for .NET) coverage risks +- **Validate changed behavior** *(polyglot)* — bind regression/feature detection evidence to exact revisions, without mistaking static predictions or build failures for proof - **Improve testability** *(.NET only)* — find static dependencies, generate wrappers, and migrate call sites to injectable abstractions - **Measure coverage** *(.NET only)* — collect code coverage, compute CRAP scores, and surface risk hotspots @@ -43,7 +44,7 @@ Moved to the [`dotnet-test-migration`](../dotnet-test-migration/) plugin (`migra ### Test quality & analysis *(polyglot)* -These six skills are all polyglot. They work across all supported languages by loading a per-language reference file from `test-analysis-extensions`. `grade-tests` additionally embeds its own decision and scoring rubric so per-test Pass / Failed / Uncertain outcomes and supporting A-F quality grades stay consistent across calls. +These seven skills are all polyglot. The suite-analysis skills use per-language reference files from `test-analysis-extensions`. `grade-tests` additionally embeds its own decision and scoring rubric so per-test Pass / Failed / Uncertain outcomes and supporting A-F quality grades stay consistent across calls. `test-value-evidence` is self-contained and assesses changed contracts rather than grading tests or auditing the suite. | Skill | Description | |---|---| @@ -51,6 +52,7 @@ These six skills are all polyglot. They work across all supported languages by l | **test-smell-detection** | Deep formal audit using academic test smell taxonomy (19 smell types, any language) | | **assertion-quality** | Measure assertion variety and depth — find shallow tests that barely verify anything (any language) | | **test-gap-analysis** | Analyze test blind spots through pseudo-mutations, expose read-only per-test evidence for grading, and verify or close gaps only when requested (any language) | +| **test-value-evidence** | Prove tests detect the actual pre-fix defect or buildable missing/wrong feature behavior; distinguish paired execution, static predictions, survival, equivalence, and missing evidence (any language) | | **test-tagging** | Tag tests with standardized traits (smoke, regression, boundary, critical-path, etc.); auto-edits where the framework has canonical syntax, report-only otherwise | | **grade-tests** | Assess curated tests with Pass, Failed, or Uncertain decisions, A-F quality detail, notes, and concrete improvement actions; unresolved or empty scopes omit the grade, and a valid empty scope returns Not applicable (any language) | @@ -85,6 +87,44 @@ requested assertions reject wrong costs/flags while production stays byte-for-byte unchanged. The CLI integration needs Copilot access via an existing token or authenticated GitHub CLI; it does not change user settings. +`test-value-evidence` separates change-specific detection proof from this +grading contract and from general suite blind spots. Its canonical +[`SKILL.md`](skills/test-value-evidence/SKILL.md) has no bundled dependencies; +single-file consumers can vendor exact upstream bytes, record the producer +commit/blob and SHA-256, and keep repository-specific adapters outside the +canonical file. It does not enforce CI or authorize publication. + +Focused offline calibration: + +```powershell +python -B tests\dotnet-test\test-value-evidence\test_regressions.py -v +``` + +This replays ten evidence-report goldens and three routing goldens, rejects misleading alternatives, +checks complete workspace scope and native discovery, and runs the same three boundary +tests against the actual defective and fixed bytes in fresh owned experiment +directories. The production command grader starts Python in isolated mode +before authenticating its staged helper, preventing workspace module shadowing, and +replays exit codes, the named assertion, and all test counts without trusting +narrated or stale red results. Its captured replay proves behavioral detection, +not what the model executor itself ran. Recorder conformance is tested separately +from the model-facing prompts, with authenticated calls in original-to-fixed order. Each call +checks the source and unchanged-test digests before executing captured bytes in +an isolated child; records include those digests, the named assertion, counts, +and actual exits. Temporary test edits cannot manufacture accepted red evidence. +The model-facing patch case asks for a minimal correction and a static assessment +without command execution; it does not prescribe this evaluator's recorder API. +Calibration also rejects unrelated edits, extra files, altered +helpers, and skipped or misattributed results. +Only the allowed changed production file may omit its terminal LF; preserved +test bytes and all other product content remain exact. It is not a measured +model-vs-baseline verdict. The +Vally eval adds static-edit and advisory cases plus three sibling-routing +dormancy guards; run it through the repository's normal evaluation entry point. +The current model-facing matrix does not certify authorized paired execution; +that path is calibrated offline and still needs trusted host instrumentation +before it can be graded without directing the model to evaluator-specific APIs. + ### Coverage & risk *(.NET only)* | Skill | Description | @@ -193,12 +233,18 @@ work that benefits from separate context. ### For polyglot skills and agents The `test-engineer` agent, `code-testing` skill, generation workers, internal -quality auditor, and six test-analysis skills (`test-anti-patterns`, +quality auditor, and seven test-analysis skills (`test-anti-patterns`, `test-smell-detection`, `assertion-quality`, `test-gap-analysis`, -`test-tagging`, `grade-tests`) work with any supported language above. You just -need a working test runtime for the target language (for example `pytest`, +`test-tagging`, `grade-tests`, `test-value-evidence`) work with any supported +language above. Execution requires a working test runtime for the target +language (for example `pytest`, `npm test`, `mvn`, `go`, `cargo test`, Pester, or CMake plus a C++ test runner). +`test-value-evidence` can also assess a change statically in read-only mode when +execution is unavailable or unauthorized. This does not require a working +runtime; the result must distinguish static predictions and missing evidence +from executed proof. + ### For .NET-only skills and agents - .NET SDK installed (`dotnet` on PATH) diff --git a/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/grade-tests/SKILL.md b/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/grade-tests/SKILL.md index 1bf1b8c..d68eba5 100644 --- a/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/grade-tests/SKILL.md +++ b/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/grade-tests/SKILL.md @@ -1,15 +1,14 @@ --- name: grade-tests description: > - Grade a curated list of individual tests for readiness, A-F quality, and - concrete improvements. ALWAYS USE FOR: grade tests, review only a named test, - per-test readiness decisions, or quality bands for supplied methods, bodies, - file spans, or bounded PR diffs, including existing tests. Produce a PR-ready - Pass, Failed, Uncertain, or Not applicable table; unresolved or empty scopes - omit the grade. Compose read-only per-test mutation evidence when available. - Polyglot: .NET, Python, TS/JS, Java, Go, Ruby, Rust, Swift, Kotlin, - PowerShell, C++. DO NOT USE FOR: suite-wide audits (test-engineer or - test-anti-patterns), writing or fixing tests, or measuring coverage. + Grade curated individual tests for readiness, A-F quality and improvements. + ALWAYS USE FOR: grade tests, review only a named test, per-test readiness or + quality bands for supplied methods, bodies, file spans or bounded PR diffs, + including existing tests. Return Pass/Failed/Uncertain/Not applicable; + unresolved/empty scopes omit grades. Compose read-only per-test evidence. + Polyglot. DO NOT USE FOR: suite audits (test-engineer/test-anti-patterns), + concrete fix/feature detection proof (test-value-evidence), writing/fixing + tests, or coverage. license: MIT --- diff --git a/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/test-gap-analysis/SKILL.md b/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/test-gap-analysis/SKILL.md index 25de7f6..9893ffa 100644 --- a/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/test-gap-analysis/SKILL.md +++ b/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/test-gap-analysis/SKILL.md @@ -1,17 +1,14 @@ --- name: test-gap-analysis description: >- - Pseudo-mutation analysis ONLY: answer whether tests would catch a bug if - production code changed, which meaningful changes would still pass, or which - caller-visible mutations existing assertions would miss; verify candidates - when requested, then optionally close verified gaps. Includes explicit - read-only per-test composition for grading. Activate for behavioral blind - spots tied to production behavior. Polyglot. DO NOT USE FOR: suite taxonomy, - metadata, or distribution reports (test-tagging); .NET line-vs-branch or - Cobertura interpretation, arithmetic, plateaus, project-wide coverage gaps, - or coverage-backed test/CRAP priorities (coverage-analysis; use native - coverage tooling outside .NET); named-target CRAP (crap-score); new suites - (code-testing); assertion/smell audits; or mutation tools. + Find caller-visible production changes existing tests would miss through + pseudo-mutation analysis; verify candidates or close gaps only when requested. + Includes read-only per-test composition for grading. Polyglot. + USE FOR: would tests catch a bug, behavioral blind spots, surviving mutations. + DO NOT USE FOR: concrete fix/feature revision proof (test-value-evidence); + suite taxonomy (test-tagging); .NET coverage, Cobertura, plateaus or + coverage-backed priorities (coverage-analysis); named CRAP (crap-score); + new suites (code-testing); assertion/smell audits; mutation tools. license: MIT --- diff --git a/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/test-value-evidence/SKILL.md b/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/test-value-evidence/SKILL.md new file mode 100644 index 0000000..901ba4a --- /dev/null +++ b/external-sources/upstreams/dotnet-skills/plugins/dotnet-test/skills/test-value-evidence/SKILL.md @@ -0,0 +1,172 @@ +--- +name: test-value-evidence +description: >- + Assess tests for an identified code or test change, feature, PR or commit. USE FOR: review + changed behavior or regression tests, prove pre-fix/missing behavior is + detected, revision-bound red-green evidence. Polyglot. DO NOT USE without an + identified change: hypothetical mutations or general suite blind + spots (test-gap-analysis). Also exclude per-test readiness/A-F grades (grade-tests), + coverage (coverage-analysis), new suites (code-testing), or mutation engines. +license: MIT +--- + +# Test-value evidence + +A passing test proves little unless it detects the relevant wrong behavior. +Assess the changed contracts and their directly related tests, not the entire +repository. Discover and follow the repository's instructions, pinned toolchain, +test commands, assertion conventions, and execution permissions. This skill +does not authorize edits in a read-only review, execution of untrusted code, +workflow dispatch, publication, or access to another session's checkout. + +## Inputs and boundaries + +Discover the requested diff/revision, production entry points, tests, fixtures, +and available execution artifacts. If the change cannot be identified, report +the missing scope instead of grading the workspace. Existing unchanged tests +can suffice; a source-only diff is not automatically untested. + +Use `test-gap-analysis` for general existing-suite blind spots, `grade-tests` +for curated per-test readiness/quality, and existing repository mutation tooling +for mutation campaigns. Do not start a second mutation engine or require +full-suite mutation testing for every change. This skill is self-contained: +sibling skills are optional routing destinations, not required dependencies. + +## Workflow + +1. **Bind the contract to the tested revision.** For a PR, record its merge + base and exact head SHA. For a commit, record the selected parent and commit; + identify the parent explicitly for a merge commit. For uncommitted work, + record the base SHA plus a reproducible patch identity (saved patch/hash, + including relevant untracked files), not a fictitious committed revision. + Evidence expires after relevant source, tests, helpers, configuration, or + package changes unless revalidated. + + For each distinct behavior change, map: + `requirement -> input/sequence -> expected public outcome -> production + entry point -> named test/data case -> distinguishing assertion`. + Derive the expected outcome independently from requirements or supported + API/protocol semantics, not the implementation or the test's current value. + Check build/package/configuration behavior, deleted/renamed code, removed + tests, and shipping consumers as well as source. Include positive, negative, + boundary, compatibility, cancellation, cleanup, and multi-module cases only + where relevant to the changed contract. + + A mock of the changed component, self-comparison, or expected value computed + by the same production algorithm does not provide an independent oracle. + +2. **Choose the meaningful counterfactual.** + + | Change | Counterfactual | Required observation | + |---|---|---| + | Bug fix | Keep the regression test and restore the actual pre-fix defect. | The test fails for that defect, then passes with the fix. | + | New feature | Disable/remove or corrupt the behavior, retaining the API shape and setup needed to build. | An assertion detects absent/wrong behavior, then passes with the feature. | + | Stronger/test-only coverage | Introduce one plausible wrong public outcome. | The strengthened test detects it; the unmodified product passes. | + | Behavior-preserving refactor | Compare the preserved contract before and after; optionally probe a relevant fault. | Preservation tests pass on both revisions; passing before is expected. | + | Documentation/generated metadata only | Establish whether an executable contract changed. | Not applicable only with a concrete reason; generated or build metadata can change behavior. | + + For a fix, prefer the real pre-fix implementation with the same regression + test, setup, dependencies, and inputs. If new APIs prevent that combination + from compiling, restore only the defective behavior in the head version. + Call this a **targeted counterfactual**, not a run on the base revision. + Record its exact patch/hash. Never change assertions to manufacture red. + + For a feature, a missing-symbol compiler error is not behavioral proof. + Choose a buildable no-op, disabled registration, old branch, or wrong output. + A compiler/analyzer diagnostic can be valid behavior only when an executed + harness asserts that exact diagnostic or its absence. + + Prefer small plausible faults: restore the old boundary, drop a required + output, skip a callback, ignore an option, or return the wrong value. + An equivalent mutation is not a gap. A crash, timeout, or exception counts + only when it is the intended contract signal and diagnostics attribute it + to the fault, not setup, discovery, flakes, or infrastructure. + +3. **Execute paired runs only when authorized.** Implementation normally + requires execution; read-only/advisory review normally requires inspection. + A review request alone does not permit source edits or builds/tests. + Never run untrusted code with privileged credentials. + + In an authorized implementation/verification environment: + + - Use an owned isolated checkout or experiment directory. Preserve the + user's dirty files and other sessions/main checkout. Preflight concurrent + processes and shared outputs/resources; do not kill unrelated processes. + - Run the smallest relevant selection on the correct implementation. + Confirm the named tests and data cases actually execute and pass. + - Apply only the chosen defective behavior in the isolated experiment. + Rebuild and rerun the same tests, assertions, data, dependencies, and + applicable runtime configuration. Capture the named failure, assertion, + expected/actual observation, process exit, and diagnostics. + - Restore the correct implementation, rebuild, and rerun to confirm green + again. Verify protected source/test bytes, remove only owned temporary + resources, and never deliver the counterfactual patch in the product. + + Paired runs must not reuse stale build/test outputs or the other variant's + effective caches. Use separate outputs/caches or clean only owned outputs + and rebuild; do not rely on `--no-build` or a runner's success exit alone. + Record selected/executed/passed/failed/skipped counts for each run. If a + runner does not expose a count, say **unknown** rather than inventing it. + Zero selection/execution, skips, missing tools, authentication, setup/build, + unrelated failures, and unattributed timing flakes leave proof unverified. + + For cross-component/acceptance behavior, identify the producer-consumer + contract first: ownership, lifecycle, handshake/no-handshake, exit semantics, + fallback, compatibility, cancellation, and multi-module aggregation where + applicable. Record the exact shipping binaries/packages/extensions and + release branches. Rebuild/repack each variant, isolate effective package + caches, prove which variant the real shipping consumer loaded, and run a + representative composed command. Unit mocks or source-compatible compilation + alone do not replace shipping-layout validation. Exercise applicable normal, + suppressed, partial, legacy/incompatible, cancellation, nonzero-exit, + zero-result, fallback, and multi-module paths. Keep rollout/servicing ownership + explicit; a feature flag does not lower the evidence bar. + + In read-only/advisory mode, trace both revisions, setup/helpers, inputs, and + assertions without edits or execution unless separately permitted. Label + conclusions **static predictions**, never executed proof. Existing artifacts + count only when their revisions/patches, loaded variant, selection, counts, + and failure attribution match. Green CI or an author's claim alone is not + red-green evidence. Say what is inaccessible or missing. + +4. **Report only the evidence obtained.** Put a compact **Test-value evidence** + section in the handoff or authorized review/description. State base/parent + and head SHAs or tested patch identities. Use one row per changed contract, + group tests protecting the same contract, and identify unassessed groups. + + | Contract / test case | Counterfactual | Without behavior | Correct implementation | Evidence / gap | + |---|---|---|---|---| + | Boundary defect / named case | Restore old comparison; patch identity | Executed: assertion failed | Executed: passed | Commands, exits, expected/actual, counts, artifacts | + | New output / named case | Skip output write | Static: predicts failure | Not executed | Source/assertion locations; paired execution missing | + + Use **executed: detected**, **executed: survived**, **static: predicts + detection**, **static: predicts survival**, **unverified**, **equivalent**, + or **not applicable** accurately. Missing red/green or incomplete selection + leaves paired proof unverified. Report **executed: survived** only for an executed, + non-equivalent fault; do not count equivalent edits as gaps. Preservation + passes for a refactor are valid evidence, not missing-red defects. + + Include exact commands/exits, toolchain/framework/configuration, revision + and counterfactual patch identities, per-run counts, and relevant artifact + paths. Distinguish execution performed now from verified existing artifacts. + Never combine static predictions with measured mutation counts/scores. + Evidence for a final PR head does not prove every intermediate commit; + assess a requested commit against its parent separately. + + Missing evidence is not automatically a proven defect or an inline review + thread. Publication follows the caller's existing authorization gate; do + not create a new GitHub object just to store a report or claim instructions + enforce hooks, CI, or publication. + +## Validation + +- The evidence identifies the exact change, independent oracle, test/data case, + and meaningful buildable counterfactual. +- A claimed bug-fix proof fails for the actual old defect and passes with the + fix; a feature proof detects absent/wrong behavior rather than absent symbols. +- Executed claims have attributable outcomes, commands/exits, counts, and + matching artifacts/consumer provenance; unavailable details stay explicit. +- Static predictions, survival, equivalence, preservation, and missing evidence + remain distinct. Existing tests are credited without demanding redundant ones. +- Scope, read-only restrictions, clean variant outputs, parallel safety, and + owned-resource cleanup were preserved. diff --git a/external-sources/upstreams/roslynk/skills/roslynk/SKILL.md b/external-sources/upstreams/roslynk/skills/roslynk/SKILL.md index b568982..95dd456 100644 --- a/external-sources/upstreams/roslynk/skills/roslynk/SKILL.md +++ b/external-sources/upstreams/roslynk/skills/roslynk/SKILL.md @@ -1,77 +1,6 @@ --- name: roslynk -description: How to use the Roslynk MCP tools (mcp__roslynk__*) effectively for .NET work. Use this whenever a Roslynk server is connected and the task touches *.cs, *.cshtml or *.razor files in a solution — checking for compile errors or warnings, finding a symbol's definition, references, callers, or implementations, renaming symbols, applying code fixes or refactorings, finding dead code, or editing those files — even if the user never says "Roslynk". Consult it before reaching for grep, file reads, hand-written edits, or `dotnet build` on such files: Roslynk's semantic tools are faster and more correct for all of those jobs. +description: Use Roslynk for semantic inspection and edits of *.cs, *.razor and *.cshtml solution files. --- -# Using Roslynk - -Roslynk is an MCP server holding a live Roslyn compilation of a .NET solution. The questions you'd normally answer with grep, file reads, or `dotnet build` — "where is this used?", "does it compile?", "rename this safely" — it answers from the compiler's symbol model instead. Text search lies: it hits comments, strings and unrelated same-named members, and misses partial classes, generated code and `#if` branches. Roslynk doesn't. - -**Default to Roslynk for all semantic work on `*.cs`, `*.cshtml` and `*.razor` files in the loaded solution.** Plain file tools remain only for what Roslynk doesn't cover: files outside the solution folder, file creation/deletion, and non-compiled files (`.csproj`, `.json`, `.md` — still editable safely via `apply_patch`). - -Tools that take a `documentPath` accept `.razor` and `.cshtml` files as well as `.cs`: give positions in the Razor file itself, inside its C# (`@code`/`@functions`, `@{ }`, expressions). Edits are written back to the Razor source in the file's own indentation; renames and other edits that reach a `@bind-X="Expr"` attribute's generated lambdas update the Razor source once at the attribute itself. Analyzer (`IDE*`/`CA*`) fixes are not available in Razor files, and `_Imports.razor`/`_ViewImports.cshtml` usings are never removed. `get_diagnostics` also reports the Razor compiler's own `RZ*` errors against the Razor file. In a `.cshtml` view where a new method cannot be added, `extract_method` suggests `asLocalFunction=true`. - -Each tool's exact contract — parameters, output format, limits, error codes — lives in that tool's own MCP description. This skill covers *when* to use the tools and *how* to combine them; [references/tools.md](references/tools.md) holds the deeper reference (exact output envelopes, `#if` projection mechanics) for when a tool's behavior surprises you. - -## Solution setup - -1. Call `open_solution` with the absolute path to the `.sln`/`.slnx`. It returns immediately and loads in the background; the returned `solutionId` is the handle every other tool needs. -2. While loading, other tools return `error=Indexing` — retry the call shortly, or poll `get_solution_status` (~1s) and report progress. Do **not** fall back to reading or editing files directly; loading finishes within seconds to a minute. If `open_solution` reports `loadDiagnostics` above 0, call `get_solution_status` to read the messages (skipped analyzers, failed project loads): they often explain confusing compiler errors. A missing generator DLL names the project to build: once built (in the configuration its path names, normally Debug), the next call compiles with its generated code, no reload needed. -3. `open_solution` is idempotent and the daemon keeps solutions warm across sessions — calling it again is cheap and safe. -4. Never call `reload_solution` on your own initiative: the file watcher picks up all changes, including your own edits, and a generator project built or rebuilt after load is picked up on the next call. If results look stale (branch switch, `dotnet restore`, SDK/props change, a rebuilt analyzer from a NuGet package or outside the solution), *suggest* it to the user. - -## Choose semantic tools over text search - -| You want to... | Use | Why not grep / reading files | -|---|---|---| -| Check it compiles / see warnings | `get_diagnostics`, once after the task's edits; narrow a broad failure with `summaryOnly=true` or `ids`/`filePath`/`projectName` and cap it with `maxResults` | far faster than `dotnet build`, but still costly per call | -| Find where a symbol is used, or who calls it | `find_references` / `get_callers` | text search finds false hits and misses partial classes, generated code, `#if` branches | -| See what a member calls (its callees) | `get_callees` | reading the body and tracing each call by eye misses overloads and extension-method bindings | -| Find where a field, property or parameter is read or written (assign, `+=`, `++`, `ref`/`out`, initialisers) | `find_reads` / `find_writes` | text search cannot tell a read from a write; `compound`/`increment`/`ref` appear in both results, so do not add the counts | -| Jump from a usage to its declaration | `find_definition` | compiler binding; correct through overloads and shadowing | -| Know what an expression means before editing it (type, overload chosen, nullability, constant, conversion) | `get_expression_info` | `var`, overloads, implicit conversions and nullable flow are invisible in the text | -| Find implementations of an interface/abstract member | `find_implementations` | compiler's type graph | -| See a type's members (and their local functions) / what a name refers to | `get_members` / `get_symbol` | compiler's view; correct across partial classes | -| Read a member's implementation (incl. a partial method's implementation part, and members only a generator declares) | `get_symbol_body` | returns the declaration verbatim, paged when long (`truncated=Y` → re-call with `startItem=<nextStartItem>`; a partial type's `omitted=Y` part is fetched with `part=<n>`); a path marked `generated=Y` is virtual - read it with this tool, not from disk | -| Explore base/derived types | `get_type_hierarchy` | includes referenced-assembly base types | -| Find a symbol by partial name | `search_symbols` | compiler-declared symbols, generated code included | -| Rename a symbol everywhere (incl. `.razor`/`.cshtml`) | `rename_symbol` | find-and-replace misses markup and same-named text; a symbol only a source generator declares is refused (`error=NotSupported`) - change the generator's input instead | -| Rename one parameter of a method/constructor/indexer | `rename_parameter` | also fixes named arguments, `<paramref>` docs and the override/interface family | -| Fix a diagnostic `get_diagnostics` reported (incl. `.razor`/`.cshtml`) | `apply_code_fix` with that entry's id, `line` and `column`; on `error=Conflict`, ask the user which candidate, unless the request names one, then `apply_code_action` with its actionId | hand-editing | -| Apply a refactoring, or choose among fixes at a position | `get_code_actions` + `apply_code_action` | hand-editing | -| Add a parameter to a method and its callers (incl. `.razor`/`.cshtml`) | `change_signature` | hand-editing misses call sites in markup | -| Extract statements or an expression into a new method (incl. `@code`/`@functions`) | `extract_method` | hand-cutting code misses parameters, `ref`/`out` and return values | -| Edit source or text files | `apply_patch` | keeps the in-memory model in sync; stale-guarded | -| Remove unused usings / find dead code | `remove_unused_usings`, `find_dead_code`, `find_dead_conditionals` | eyeballing | - -A fix must keep the code's declared intent: never hand-edit or `apply_patch` to make a diagnostic go away, and don't remove an interface, base type, member, attribute or other declaration to silence an error unless the user asks for that. - -All name arguments are fully-qualified (`Namespace.Type` or `Namespace.Type.Member`, with an optional parameter-type list to target one overload). A generic type may be written without its type parameters (`Namespace.Box`, `Namespace.Box.Get`) when only one arity exists — with several arities the response is `error=Ambiguous` with one candidate per arity, and a non-generic of the same name wins; any spelling with the right arity is accepted (`Box<T>`, `Box<int>`, ``Box`1``, `Box<>`, ``Namespace.Box`1``, ``Namespace.Outer`1+Inner``). A local function is a member of the method declaring it: `Namespace.Type.Method.local`, or `Namespace.Type.Method.outer.inner` when nested; put a parameter list on any segment to pick an overload (`Namespace.Type.Method(int).local`). On `error=Ambiguous` or `error=NotFound` the response lists `candidate=` lines that are exact names the same tool accepts — copy one back verbatim rather than guessing. - -## Combine tools, don't chain calls - -When you need several facts before making a change, send them as **one `multi_query`** call instead of sequential calls: every operation runs against a single snapshot, so the facts can never disagree with each other. `multi_query` accepts only the read-only query tools, and each operation uses exactly that tool's own parameter names — a wrong key is `error=Invalid` naming the key, never silently ignored. Every operation runs; results are then delivered whole, smallest first, until the response budget (about 80,000 characters) is filled, and operations whose result did not fit are named once in the header as `retry=<index>:<size>` (size = that result's cost as a ratio of the budget, rounded up to 0.1). Plan the continuation from the ratios: size ≥ 1.0 → re-send that operation alone (it pages with `nextStartItem=`); sizes summing to ≤ 1.0 → one continuation batch together; pass the response's `snapshot=` value as `expectSnapshot` so a continuation that would straddle a solution change is refused with `error=Stale` instead of mixing states. Delivered slots are always complete, so their own headers can be trusted. The envelope format is in the multi_query section of [references/tools.md](references/tools.md). - -**Impact analysis** — before renaming a symbol or changing a signature, and whenever someone asks "what uses X", "who calls X", "what breaks if I change X": batch `get_symbol` + `find_references` + `get_callers` + `get_callees` + `find_implementations` + `get_type_hierarchy` in one call, pointing each at the member or type you're changing (`get_callers` takes `methodName`, `get_callees` takes `memberName`, `get_type_hierarchy` takes `typeName`, the others `symbolName`). `get_callers` and `get_callees` are inverses — who calls this member, what does this member call — so alternating them walks a call chain one hop per query, including calls the compiler inserts (`foreach`/`await` plumbing, `using` disposal, operators and conversions); a caller inside an accessor is reported as its property, while `get_callees` names the accessor (`get_X`), so pass the property name back. Then follow each reference with `get_symbol_body` to read the calling convention before editing. Answer with Roslynk, never with grep over `*.cs`/`*.cshtml`/`*.razor` — text search both misses real usages and wrongly matches identically-named symbols. - -**Understand before editing** — when an edit depends on what an expression *is* (the type behind `var`, which overload a call picks, whether a value can be null at that point, whether a conversion is implicit or user-defined), call `get_expression_info` on its position instead of inferring from text; on a declared name (e.g. the `x` of `var x = ...`) it reports the declared symbol and its type, like an editor hover. It distinguishes the expression's `type` from the `symbol` it binds to — both can matter — and reports a missing fact as `none` rather than guessing; `symbol=none` with `candidateReason`/`candidates` means the call does not resolve. Batch several positions in one `multi_query`. - -Results are **snapshots** of a solution that is edited live: re-query after any write rather than reusing an earlier response. - -## Preview broad edits before writing - -Every write tool takes `checkOnly=true`, which returns the changed-file list without writing anything. Use it whenever a change might be broad — a rename of a widely-used symbol, a whole-solution cleanup — and confirm the scope before applying. Write tools are atomic and stale-guarded: if a target file changed on disk since Roslynk read it, the whole operation is rejected with `error=Stale` and nothing is written — recompute from current state and retry. Writes go straight to disk and advance the in-memory model immediately, so no reload or rebuild is ever needed afterwards. - -## Rename parameters with Roslyn - -To rename a parameter, call `rename_parameter` with the declaring member's `methodId` (add the parameter-type list when overloaded; a constructor is `Namespace.Type.Type(int)`), the current `parameterName` and `newName`. It updates named arguments at call sites and `<paramref>` docs, and renames the same parameter across overrides, interface members and implementations that use the same old name - check `renamedMembers` and `unchangedRelated` in the response to see what was and wasn't cascaded. On `error=Conflict` pick a name not already used inside the member. Prefer it over `rename_symbol` for parameters, which cannot target a parameter by name. - -## Extract methods with Roslyn - -To pull code into its own method, call `extract_method` with the selection (1-based; end column exclusive - `endLine+1`, column `1` takes whole lines) and a `methodName`; add `asLocalFunction=true` for a local function. Preview with `checkOnly=true` to see the `signature` and `call` Roslyn chose. It writes nothing when the selection cannot be extracted safely or the result would not compile - read the `NotSupported` reason and adjust the selection (whole statements from one block, or one complete expression) rather than extracting by hand. - -## Check diagnostics once a task's edits are done - -The core edit cycle: make all the changes the task needs (any write tools) → `get_diagnostics` once at the end (bare call; the header always reports error/warning/info/hidden counts; each call compiles and analyzes everything the edits affect, so do not run it after every edit) → if counts are non-zero, re-call with `includeErrors=true` to see the details → fix each entry via `apply_code_fix` with its id, `line` and `column` → if that returns `error=Conflict` with `candidate=` lines, the diagnostic has several fixes: pick the one whose title matches your intent and pass its actionId (the text before the first comma) to `apply_code_action`; do not retry `apply_code_fix` → repeat until clean. This replaces `dotnet build` during development. Pass `includeAnalyzers=false` for a faster compiler-only pass when style rules don't matter yet. When the detail body is huge (one root cause, hundreds of entries), do not re-read it all: re-call with `summaryOnly=true` for one line per id, or narrow with `ids=[...]`, `filePath` or `projectName`, and cap with `maxResults` - a filtered call reuses the compiled result instead of recompiling. - -`find_dead_code` and `find_dead_conditionals` never delete anything — treat the results as candidates (public or reflection-used API can be a false positive), confirm intent with the user before bulk-removing, and hand each reported `loc` span to `apply_patch`. +Follow server instructions and tool schemas. diff --git a/external-sources/upstreams/roslynk/skills/roslynk/references/tools.md b/external-sources/upstreams/roslynk/skills/roslynk/references/tools.md index 687ab44..e69de29 100644 --- a/external-sources/upstreams/roslynk/skills/roslynk/references/tools.md +++ b/external-sources/upstreams/roslynk/skills/roslynk/references/tools.md @@ -1,344 +0,0 @@ -# Roslynk tool reference - -Deep per-tool reference: the operation-specific contract (exact envelopes, mechanics, edge cases) behind -what each tool's published MCP description summarizes. Read the section you need; SKILL.md carries the -workflows and the tool descriptions carry the concise contract for discovery. - -## Contents - -- [Shared conventions](#shared-conventions) -- [Lifecycle: open_solution, get_solution_status, reload_solution](#lifecycle) -- [Navigation: find_definition, get_expression_info, get_symbol, get_symbol_body, get_members, search_symbols](#navigation) -- [Relationships: find_references, find_reads, find_writes, get_callers, get_callees, find_implementations, get_type_hierarchy](#relationships) -- [Diagnostics: get_diagnostics](#diagnostics) -- [Razor and CSHTML: how path-based and write tools handle .razor/.cshtml](#razor-and-cshtml) -- [Code actions: get_code_actions, apply_code_action, apply_code_fix](#code-actions) -- [Editing: apply_patch, rename_symbol, rename_parameter, change_signature, extract_method, remove_unused_usings](#editing) -- [Dead code: find_dead_code, find_dead_conditionals](#dead-code) -- [Batching: multi_query](#batching) - -## Shared conventions - -**Output format.** Compact text outline: `key=value` header lines, a blank line, then a tab-indented body. No blank line means the response is all headers (typically an error). Booleans render `Y`/`N`. Newlines inside a field are literal `\n`. A `status=` header (`Building`|`Faulted`) appears only when the solution is not Ready. - -**Body nesting** (multi-symbol tools): project → one line per folder segment → file → namespace → `typeKind,typeName,loc` → `memberKind,memberName,loc`. `kind` ∈ `method|property|field|event|class|struct|interface|enum|delegate`. `loc` is `line:col` or `startLine:startCol-endLine:endCol`, 1-based; multiple locations on one line are pipe-delimited. Names containing commas (e.g. `Dictionary<string, int>`) are single-quoted. - -**Error shape** (header-only): - -``` -error=<Indexing|Faulted|NotFound|Ambiguous|NotSupported|Stale|Invalid|Conflict|Truncated> -errorMessage=<text> -candidate=<name> (0+ lines: NotFound suggestions / Ambiguous matches) -stale=<path> (0+ lines, Stale only) -``` - -**Symbol names.** A name is a fully-qualified name, optionally carrying a parameter-type list for a -method or indexer: `N.T.M`, `N.T.M(int, string)`, `N.T.this[int]`, `N.T.M<T>(T)`. Parameter names, -default values, nullable annotations and `global::` are ignored on input, and fully-qualified parameter -types are accepted, so `M(System.Int32)` and `M(int value = 0)` both resolve `M(int)`. A `ref`/`out`/`in` -modifier is optional but honoured when written. Without a parameter list the name matches every overload -→ `error=Ambiguous`, one `candidate=` per match; every candidate is accepted verbatim by the tool that -emitted it, and the `resolvedSymbol`/`resolvedType`/`resolvedMethod`/`#fullName` a tool echoes is in the -same re-queryable form. When a declaration compiles in several target frameworks or `#if` projections and -a type in its signature binds in only some of them, the echoed name, candidates and outline parameter -types are taken from a copy where it binds (`M(int)`, not the unresolved `M(Int32)`); any spelling of the -declaration's signature still reaches its copies in every framework. - -**Generic names.** A generic type may be written without its type parameters (`N.Box`, `N.Box.Get`) -when only one arity exists; with several arities sharing the name the response is `error=Ambiguous` -with one `candidate=` per arity, and a non-generic of the same name wins over a generic one. Any -spelling with the right arity on a segment is accepted — `N.Box<T>`, `N.Box<int>`, `N.Box<>`, and the -reflection/metadata form ``N.Box`1`` (doc-id style ``N.T.M``2`` for generic methods) — while a wrong arity -(``N.Box`2``) is `NotFound`. A metadata `+`-nested name (``N.Outer`1+Inner``) also resolves. Every -name-based tool accepts these, including `get_symbol_body`, which returns the source body when the -metadata-spelled type is declared in the solution. - -**Local functions** are named as members of the member that declares them, through any nesting of types or -of local functions: `N.Parent.Widget.Method1.localMethod`, and `N.Parent.Widget.Method1.localMethod.inner` for -one declared inside another. The container is the enclosing method, constructor, operator, property or event -(or outer local function); a local function inside a lambda belongs to the member around the lambda. Any -segment may carry its own parameter list, so overloads of the container are told apart: -`N.T.Method2(int).helper` vs `N.T.Method2(string).helper`. Tools emit the fully signed form, with every -container's parameter list, e.g. `N.Parent.Widget.Method1(int).localMethod(string, int).inner(string)`, and -that form is what an `Ambiguous` candidate looks like. A bare name such as `inner` also resolves. Outlines -report a local function's kind as `localfunction` and nest it under its containing member. - -**Paging and truncation.** Tools whose result can be too large page by item: an oversized result carries `count=<items in the result set>`, `truncated=Y` and `nextStartItem=<k>` — call again with `startItem=<k>` and the same other arguments for the next page. An item is one leaf record (a reference, caller, callee, implementor, diagnostic, member, candidate, search hit; for get_symbol_body one source line). Every page repeats the container lines open above its first item, so it reads standalone; the preamble counts against `maxSize` but not against `count=`. `maxSize` (characters; default the response budget, about 80,000 — set with `Roslynk:MaxResponseChars` or the `Roslynk__MaxResponseChars` environment variable, read once at daemon start) bounds a page; an item longer than a whole page is delivered as far as it fits and named `partialItem=<n>` — the rest of that item is not retrievable. `startItem` past the end, or a `maxSize` too small to carry one item beside its container lines, is `error=Invalid`. `maxResults` bounds the result SET (a scan halts at the cap); paging walks that capped set and `count=` names its size — omit `maxResults` and page when you want everything. A result that fits whole carries no paging headers at all. The tools that cannot page (get_symbol, find_definition, get_expression_info, get_solution_status) cut an oversized result after its last whole line, starting with `outputTruncated=Y` and `fullOutputChars=<n>`. - -**Defaults.** Don't pass a value for a defaulted parameter unless you need the non-default behavior. - -**Generated locations.** A location declared by a source generator has a virtual path that does not exist on disk (unless `EmitCompilerGeneratedFiles` is set). `get_symbol`, `get_symbol_body` and `find_definition` add `generated=Y` and `generator=<generator type>` headers after `loc`; in nested bodies (`get_members`, `find_references`, `find_reads`, `find_writes`, `get_callers`, `get_callees`, `find_implementations`, `search_symbols`) the file-name line ends `,generated=Y`. Read such code with `get_symbol_body`, not from disk. Razor's generated `.g.cs` documents are not marked. `search_symbols` includes declarations a source generator emits (types, members, namespaces and local functions inside generated members), marked like any generated location, whether or not a hand-written declaration in the same project also matches the query. - -**Generated declarations resolve by name.** Every name-based tool (get_symbol_body, find_references, get_callers, get_callees, find_implementations, get_type_hierarchy, find_reads, find_writes, search_symbols, rename_symbol, rename_parameter, change_signature) resolves a generator's declarations — members, nested types, local functions — whether or not hand-written code mentions them. `rename_symbol`, `rename_parameter` and `change_signature` refuse a symbol declared only by a generator (`error=NotSupported` naming the generator): the generated declaration is never written to disk and would be regenerated unchanged, so change the generator or the code that drives it instead. A partial member or type with a hand-written declaration (e.g. `[GeneratedRegex]`, a `JsonSerializerContext`) can still be renamed — the generator follows the hand-written name. - -**`#if` projections.** Symbol tools (find_definition, find_implementations, get_members, get_symbol, get_symbol_body, get_type_hierarchy, find_references, find_reads, find_writes, get_callers, get_callees, rename_symbol, search_symbols) also cover inactive `#if`/`#else` branches: Roslynk builds derived compilations toggling each uniformly-defined preprocessor symbol, and unions/dedupes results. - -## Lifecycle - -### open_solution -`solutionPath` (required): absolute path to `.sln`/`.slnx`. -Returns `solutionId` (= the path you passed), `status`, `projects`, `loadDiagnostics` (a count; `get_solution_status` lists the messages), then one `<projectPath>,<documentCount>` line per project. Loads in the background; idempotent; missing file → `NotFound`, failed load → `Faulted`. While loading, other tools return `error=Indexing` — retry them shortly; never fall back to raw file edits. - -### get_solution_status -`allLoadDiagnostics` (optional, default false). Lists every solution loaded by the daemon (daemon-wide, not session-scoped): `<solutionId>,<status>,<loaded>/<total>` per line. `total` is `?` until the first load completes. Status values: `Building`, `Updating`, `Ready`, `Faulted`. - -When the load reported messages (the count `open_solution` shows as `loadDiagnostics`: a skipped or unloadable analyzer/generator such as an unbuilt generator DLL, a project that failed to evaluate, an SDK that was not found), each is a tab-indented `loadDiagnostic=<message>` line under its solution line, shown only once that solution is `Ready` (never while `Building`, `Updating` or `Faulted`); a solution with none stays one line. These often explain a batch of confusing compiler errors. Messages are sorted, and without `solutionId` only the first 20 per solution are listed, followed by `\tloadDiagnosticsTruncated=<n>` for the rest. With `solutionId` only that solution is listed, with every message. A `solutionId` that is not loaded → `error=NotFound`. Not batchable in `multi_query`. - -``` -C:\repo\GeneratorSolution.slnx,Ready,2/2 - loadDiagnostic=Skipped unresolved analyzer in project 'ConsumerLib': 'C:\repo\GeneratorLib\bin\Debug\netstandard2.0\GeneratorLib.dll' does not exist, so the generated code of project 'GeneratorLib' is unavailable. Build project 'GeneratorLib' in the configuration this path names; the next call picks it up without a reload. -``` - -A missing generator DLL (typically a generator project referenced as an analyzer and built only in Release, while Roslynk loads Debug) is reported with the project that builds it. Every data tool call compares the file stamps of such DLLs, and of every analyzer DLL a project of the solution builds, with the ones loaded: a DLL built or rebuilt since is attached before the call reads, so that call already sees the new generated code, wherever the DLL lives (`bin`, an artifacts directory, outside the solution). No reload is needed. The message goes away once the DLL exists; a DLL that then fails to load is reported as `Analyzer load failed for '<path>': ...` until a later build loads. - -### reload_solution -`solutionId` (required). Forces a from-disk MSBuild re-evaluation; the old snapshot keeps serving as `Building` until the fresh one is ready. Manual backstop for missed watcher events (network/WSL filesystems), `dotnet restore`, SDK/`global.json`/`Directory.Build.props` changes, branch switches, or retrying a `Faulted` load. **Never call it unless the user explicitly instructs you to** — suggest it instead. - -## Navigation - -### find_definition -`solutionId`, `filePath` (absolute or solution-relative), `line`, `column` (1-based). Position-based go-to-definition. Returns `#fullName`, `#kind`, plus `#project`/`#path`/`#loc` for source symbols or `#assembly=` for metadata-only. (Note the `#`-prefixed header style, unique to this tool family.) A file compiled into several projects or `#if` projections is resolved in each, and the answer whose types bind is reported. - -### get_expression_info -`solutionId`, `filePath` (`.cs`, `.razor` or `.cshtml`; absolute or solution-relative), `line`, `column` (1-based, anywhere inside the expression; the position just after a token counts as that token). Returns compiler facts about the expression at the position. Batchable in `multi_query`. - -The expression is the innermost one containing the token, widened to what an edit means: a member name reports its whole member access (`a.B`), a called name its invocation (`a.B(c)`, so `type` is the return type and `symbol` the selected overload), and a created type its object creation (`new T(...)`, symbol = constructor). A position on the name a declaration introduces (local, parameter, field, property, event, method, type, foreach/catch/pattern variable) reports the declared symbol instead, like an editor hover: `declaration=Y`, `expr` is the name, `exprKind` the declaring syntax kind (e.g. `VariableDeclarator`, `MethodDeclaration`), `type` the declared type (a method's return type; `none` for a type declaration), `nullability` the declared annotation with the initializer's flow state (`None` without an initializer), `constant` for a `const`, then the usual symbol keys; no `convertedType`/`conversion`. A position on a keyword, punctuation, comment or whitespace is `error=NotFound`; a line/column outside the file or a file not compiled in the solution is `error=NotFound`; a loading solution is `error=Indexing`. Positions inside an inactive `#if` branch are tried in each projection. - -Output is header only, in this order (optional keys only when applicable): - -| Key | Meaning | -|---|---| -| `expr` | Expression text, whitespace collapsed, cut at 200 chars with `...` | -| `exprKind` | Roslyn `SyntaxKind` (e.g. `InvocationExpression`, `IdentifierName`) | -| `declaration` | `Y` only when the position is on a declared name (see above) | -| `path`, `loc` | Solution-relative file and `startLine:startCol-endLine:endCol` (Razor source positions for `.razor`/`.cshtml`) | -| `type` | Expression's natural type, fully qualified with C# keywords and `?` for annotated references; `none` for a method group, namespace or typeless expression (`null`, lambda) | -| `convertedType` | Only when the target type differs (implicit conversion, target typing) | -| `nullability` | `<annotation>/<flowState>`: annotation `None|NotAnnotated|Annotated`, flow state `None|NotNull|MaybeNull`; `None/None` when nullable analysis is off. Flow state reflects prior null checks | -| `conversion` | Only when converted type is known and not a plain identity: `implicit`/`explicit` followed by kinds (`numeric`, `nullable`, `reference`, `boxing`, `constant`, `user-defined <operator>`, `target-typed-new`, `collection-expression`, ...), `identity`, or `none` when no conversion exists | -| `constant` | Compile-time constant as a C# literal (`40`, `"x"`, `null`), else `none` | -| `symbol` | Bound symbol: generic definition / static extension form, re-queryable with name-based tools (`get_symbol`, `find_references`, ...); locals, parameters and range variables report their bare name; `none` when nothing binds | -| `candidateReason`, `candidates` | With `symbol=none`: Roslyn's reason (e.g. `OverloadResolutionFailure`) and pipe-delimited candidate names | -| `symbolKind` | Same kind words as other tools (`method`, `property`, `field`, `local`, `parameter`, `class`, ...) | -| `instantiation` | Constructed generic or reduced extension form, e.g. `Formatter.Echo<string>(string)` | -| `origin` | `source` with `symbolPath`/`symbolLoc` (`line:col`), or `metadata` with `assembly` | -| `doc` | XML-doc `<summary>` as plain text (cref short names), cut at 400 chars; absent when none is available | - -### get_symbol -`solutionId`, `symbolName` (FQN, any symbol kind including members). Unambiguous source match → `#project`/`#path`/`#loc` headers + body containing the verbatim declaration text cut before the body (brace/`=>` excluded). Metadata symbol → `#source=metadata`, `#kind`, `#signature`, `#assembly`. Ambiguous → `error=Ambiguous` with one `candidate=` per match. Preferred over reading a file to identify a symbol. - -### get_symbol_body -`solutionId`, `symbolName` (FQN, any declared symbol kind), `includeLeadingTrivia` (default false), `startItem` (default 1), `maxSize` (characters; default the response budget), `part` (default 0). Returns the symbol's source text including its body, verbatim — original indentation, line endings and spacing, never reformatted. Headers `project`/`path`/`loc`, a blank line, then the text. `includeLeadingTrivia=true` extends the text (and the `loc`) back over the declaration's comments, XML docs and directives. A partial type, or a partial method/property/event, returns `parts=<n>` and one `part=<n>,project=...,path=...,loc=...,lines=<count>` line per block; a partial member's parts are its defining declaration then its implementation, including one supplied by a source generator (`[GeneratedRegex]`, `[LoggerMessage]`, `[LibraryImport]`), whose part line ends `,generated=Y,generator=<type>`. - -Long text is paged, never cut silently: a call returns at most `maxSize` characters and stays within the response budget. Items are the text's lines, counted from 1 at the first line of the returned text (its first comment line with `includeLeadingTrivia`), not in the file; for a Razor member that text is the generated C#, while `loc` stays the `#line`-mapped display span — the two coordinates are deliberately unrelated. A page that is not the whole text adds `truncated=Y`, `count=<total lines>` and `nextStartItem=<k>`: re-call with `startItem=<k>`, keeping `includeLeadingTrivia` and `part` unchanged; a `startItem` past the end is `error=Invalid` naming `count`. There is no unlimited mode (the budget is the ceiling). A single line longer than a whole page's budget is delivered as far as it fits and named `partialItem=<n>` — the rest of that line is not retrievable by paging. When a partial type's parts do not all fit, the result is the whole-or-omitted overview: `parts=<n>`, `truncated=Y`, `omittedParts=<k>`, each part that fits shown whole, the rest listed with their `lines=` count and `,omitted=Y` — fetch one with `part=<n>`, which returns that part alone, paged as above with `parts=`/`part=` headers. `startItem` pages one part; combining it with several parts and no `part=` is `error=Invalid`. - -Overloads (or any name matching several distinct symbols) — `error=Ambiguous`, resolved by retrying with a candidate's parameter-type list; a metadata/referenced-assembly symbol — `error=NotSupported` (use `get_symbol` for its signature), but a metadata spelling (``Ns.Box`1``, `N.Outer+Inner`) of a type the solution declares in source returns that source. Prefer this over reading or grepping the file to see what a member does. - -### get_members -`solutionId`, `typeName` (FQN), `includeInherited` (default false), `nameFilter` (default null; trailing `*` = prefix match, otherwise case-insensitive substring), `includeMethods`/`includeFields`/`includeProperties`/`includeEvents`/`includeNestedTypes` (all default true). Lists all members including private, grouped by declaring file (`<metadata>` bucket for referenced-assembly types). Member lines: `kind,name,loc[,paramType|paramType|...]` (param list only for methods with parameters). Returns declarations + spans, not bodies — use `get_symbol_body` for a member's body. Each member's local functions are listed beneath it in declaration order, one level deeper (`localfunction,<name>,<loc>,<paramTypes>`), a local function declared inside another one level further. - -### search_symbols -`solutionId`, `query` (case-insensitive substring), `maxResults` (omit for every match - the result then pages with startItem/maxSize). Source-declared symbols only (no metadata), local functions included. Declarations a source generator emits are included and marked `,generated=Y` — a generated-only type, member, nested type, namespace or local function is found even when nothing hand-written matches; a partial type with a generated part is still one leaf at its first location (the hand-written part), with the generated part visible through its own members. Matched members nest under their type, and a local function under its containing member (`localfunction` kind); a type's `loc` appears only if the type itself matched. - -## Relationships - -### find_references -`solutionId`, `symbolName` (FQN), `maxResults` (omit for every reference - the result then pages with startItem/maxSize). Compiler-accurate: skips comments, strings, unrelated same-named members. References grouped file→namespace→type→member; pipe-delimited `loc`s on one line for multiple hits. Deduped across `#if` projections. `count=`/`truncated=Y` when capped. Prefer this over text search for usages in `*.cs`, `*.cshtml` and `*.razor`; combine with get_callers/find_implementations via multi_query for impact analysis. - -### find_reads / find_writes -`solutionId`, `symbolName`, `maxResults` (omit for every location - the result then pages with startItem/maxSize). Target a field or property by FQN (`N.T.Field`), or a parameter as its containing method, constructor, indexer or local function's FQN + `:` + parameter name (`N.T.Method:value`, `N.T.Method(int):value`; the member part follows the usual overload grammar). Local variables are not supported. Same body as find_references, but one location per leaf with the access kind appended: `<memberKind>,<memberName>,<loc>,<accessKind>`. - -`accessKind`: `read`, `assign` (`=`, including deconstruction targets), `compound` (`+=`, `??=`, ...), `increment` (`++`/`--`), `ref` (`ref x` argument, `ref x` expression, `&x`), `out`, `init` (field/property declaration initialiser, object or `with` initialiser, attribute named argument, or an assignment to the constructor's own field/property inside its constructor; a lambda inside the constructor is `assign`). find_reads returns `read`, `compound`, `increment`, `ref`; find_writes returns everything except `read`. **`compound`, `increment` and `ref` appear in both tools with the same kind** — do not add the two counts. `nameof(...)`, doc crefs and named arguments (`M(value: 1)`) are omitted from both. - -`count=`/`truncated=Y` when capped, as find_references. Errors: `NotFound` (for an unknown parameter, candidates list the member's real parameters), `Ambiguous` with candidates, `NotSupported` (method, type, event, local variable), `Indexing`. Coverage: all loaded target frameworks plus derived compilations that each toggle one uniformly-defined/undefined preprocessor symbol; a branch reachable only with several symbols toggled together, or guarded by a symbol defined in only some projects, is not analysed. Both are available in `multi_query`. - -### get_callers -`solutionId`, `methodName` (FQN; a method, constructor (`N.T.T(...)`), operator (`N.T.op_Addition(T, T)`) or conversion (`N.T.op_Implicit(T)`)). Callers grouped file→namespace→containing type→calling member with the caller's declaration `loc`. Target one overload by writing its parameter-type list. - -A caller is the declaration containing the call: a method, constructor, operator or local function; a property, indexer or event when the call is in one of its accessors; a field — or an auto-property, named as the property — when it is in its initializer. Lambdas belong to the member around them. A call through an interface or base member that the target implements or overrides is included. - -Calls the compiler inserts count: `foreach` (`GetEnumerator`, `MoveNext`, `Current`, the enumerator's `Dispose`, and the `await foreach` equivalents), `await` (`GetAwaiter`, `IsCompleted`, `GetResult`), the `Dispose`/`DisposeAsync` a `using`/`await using` runs, deconstruction and positional patterns, collection-initializer `Add`, user-defined operators and conversions (including `+=`, `++`, implicit conversions and `true`/`false` in a condition), query-expression methods, interpolated-string handler members, implicit `base()` calls, and the `Length`/`Count` behind `^`/`..`. `nameof(...)` and doc-comment references are not calls. Conversion-operator queries compile every project that can see the type and are slower. Not reported (by either tool): the `op_True`/`op_False` hidden inside `&&`/`||`, collection-expression `Add`, `dynamic` dispatch, and an implicitly declared constructor's own callers. - -### get_callees -`solutionId`, `memberName` (FQN), `excludeExternal` (default false). The inverse of get_callers: every method, constructor, property/event accessor and user-defined operator or conversion the member's code calls. Resolved from the compiler's operation model, so each call names the exact overload: a property read reports `get_X`, an assignment `set_X`, a compound assignment or increment both; `new T()` reports T's constructor; `e += h` reports `add_E` (`remove_E` for `-=`). Also reported: user-defined operators and conversions (including `+=` and `++`), the `Dispose`/`DisposeAsync` a `using` runs, and a method group passed as a delegate (`xs.Select(Helper)`). Only calls the source spells out are listed: the plumbing the compiler inserts for `foreach` (`GetEnumerator`, `MoveNext`, `get_Current`) and `await` (`GetAwaiter`, `get_IsCompleted`, `GetResult`) is not, though an explicit `.GetAwaiter()` call is. Also not reported: calls inside deconstruction assignments and interpolated-string handlers. - -The member may be a method, constructor, operator, property, indexer, event or field. What counts as its code: a property or indexer is its accessor bodies or expression body (plus an auto-property initializer), a field is its initializer, and a constructor also includes the field and property initializers it runs (instance ones, or static ones for a static constructor; none when it chains to `this(...)`). Lambdas and local functions declared inside the member are part of it. A member with no code in the solution (an abstract or interface declaration, an auto-property without initializer, or one in referenced metadata) calls nothing. Target one overload by writing its parameter-type list. - -Output: callees in the solution use the get_callers outline (project → folder → file → namespace → type → `kind,name,loc`). Callees declared in a referenced assembly (BCL, NuGet) sit under one top-level `<external:AssemblySimpleName>` line per assembly (`<external>` if the assembly is unknown), then namespace → type → leaf, with the leaf's `loc` field present but empty. `excludeExternal=true` leaves them out. A leaf gets a fourth field only when the callee's own type declares more than one method of that name (inherited overloads do not count): its declared parameter types, pipe-delimited, minimally qualified with nullable annotations and without `ref`/`out`/`in`, a type containing a comma single-quoted; `()` for the parameterless overload. Every callee is reported as declared: generic instantiations (`List<int>.Add`, `To<string>`) collapse to their definition, a classic extension method lists its `this` parameter, and a C# 14 `extension(...)` block member lists only the parameters declared on it. - -``` -resolvedSymbol=MyApp.Report.Save(string, int) - -<external:System.Console> - System - class,Console - method,WriteLine,,int - method,WriteLine,,string? -<external:System.Runtime> - System - class,String - method,get_Length, - struct,Int32 - method,ToString,,() -MyApp - MyApp - Audit.cs - MyApp - class,Audit - method,Log,5:21 - Tally.cs - MyApp - class,Tally - method,Add,5:14,int - method,Reset,7:14,() -``` - -### find_implementations -`solutionId`, `symbolName` (FQN of interface, abstract member, or virtual member). Implementors/overrides across all projections, deduped. - -### get_type_hierarchy -`solutionId`, `typeName` (FQN). Up to three sections — `base`, `interfaces`, `derived` (omitted when empty) — entries `typeKind,FQN`. - -## Diagnostics - -### get_diagnostics -`solutionId`, `includeErrors`/`includeWarnings`/`includeInfo`/`includeHidden` (**all default false**), `includeAnalyzers` (default true; `false` = faster compiler-only pass), and five optional filters: `projectName`, `filePath`, `ids` (a JSON array of strings - the tool surface's only array parameter), `maxResults` and `summaryOnly`. - -**Costly:** it compiles and analyzes every project the edits since the last call affect (seconds on a large solution), so make all of a task's edits first and call it once at the end rather than after every edit. Header always carries `errors=`, `warnings=`, `infos=`, `hidden=` counts regardless of include flags, so filtering is never silent. Body (per included severity) nests file→severity→`<id>,<line:col>,<message>`. Ids that exist only to trigger a code fix (they carry no message and accompany a public rule, as IDE0005's does) are not listed; fix the public id instead. Multi-targeted projects report diagnostics across their loaded target frameworks. The Razor compiler's own diagnostics (`RZ*`, e.g. `RZ1006` for an unclosed `@code` block) are reported against the `.razor`/`.cshtml` file with Razor-source positions, once even for a multi-targeted project (not when the Razor compiler cannot be loaded and the last build's generated output is used instead). Results are cached per `includeAnalyzers`: a repeat call with no change in between is near-instant, and after a change only the edited projects and the projects depending on them are recomputed. This replaces `dotnet build` for correctness checking. - -**Filters** narrow the result after compilation, so a filtered call still reuses the cached result and recompiles nothing; they combine (AND): - -- `projectName`: only that project's diagnostics - exactly the name the outline prints (the project file name with the `.csproj` extension omitted; other extensions such as `.vbproj` are kept, and a trailing `.csproj` you pass is stripped). Case-insensitive, and it matches every loaded target framework of a multi-targeted project. -- `filePath`: only diagnostics located in that file - absolute or relative to the solution folder (the same spellings `find_definition` accepts), case-insensitive. A `.razor`/`.cshtml` path also matches the C# diagnostics `#line`-mapped into it and the `RZ*` diagnostics reported against it. -- `ids`: only those diagnostic ids, e.g. `["CS0246","CS0103"]`, case-insensitive. Omit, or pass an empty list, for every id. -- `maxResults`: caps the result set (the body lists id rows in summary mode). When the cap drops something, `count=<items in the capped set>` and `truncated=Y` precede the body; both are absent otherwise. The per-severity header counts always stay complete. Omit maxResults to page through everything with startItem/maxSize. -- `summaryOnly`: `true` replaces the body with one line per id - `<id>,<count>,<project>,<path>,<line:col>,<message>` - ordered by count descending then id, carrying each id's count, one example location (its first diagnostic in body order) and that example's message. It covers every severity unless an include flag is set. `maxResults` caps the id rows, with `count=` counting rows. - -Every active filter is echoed as a `filter=<parameter>:<value>` header before the counts, and the counts describe the **filtered** set - `errors=3` under a `filter=` line means 3 errors in that filtered scope, not 3 in the solution. An empty body with a `filter=` header means the filter matched nothing, NOT that the solution is clean. A `projectName` or `filePath` that is not in the solution is `error=NotFound` with `candidate=` values (one of which the tool would accept); one that exists but has no diagnostics returns zero counts, not an error. An `ids` entry that matches nothing is zero counts too - ids are open-ended and never validated. - -## Razor and CSHTML - -Every tool that takes a `documentPath` (`get_code_actions`, `apply_code_fix`, `extract_method`, `remove_unused_usings`) accepts `.cs`, `.razor` and `.cshtml` files, and every write tool edits `.razor`/`.cshtml` sources, including `apply_code_action`, `change_signature`, `rename_symbol`, `rename_parameter` and `apply_patch`. Roslyn only analyses C#, so for a Razor file the tools work on the C# the Razor compiler generates from it and write the result back to the Razor file. The generated `.g.cs` is never written. - -- **Positions** (`line`/`column`, selections) are given in the `.razor`/`.cshtml` file. They must fall inside C# the compiler copied from the file: an `@code`/`@functions` block, an `@{ }` block, an inline expression or a directive. Markup is `error=NotSupported`. -- **Mapping back.** An edit is written to the Razor file only when it lies inside those C# regions; code Roslyn formats is re-indented to the file's own indentation, and lines it did not touch are kept verbatim. Edits to a `@bind-X="Expr"` expansion's hidden scaffolding (the setter lambdas and `ValueExpression` lambda the compiler derives from the one source span) are copies of the edit already made at the mapped attribute-value span (`@bind-X`, `:get`/`:set`/`:after`, `@bind`), so renames of bound members update the `.razor` source once at the user-written span. An edit to generated scaffolding with no attributable Razor source (for example a `using` or member added to the generated class) is `error=NotSupported`. Razor text that no longer matches the generated code is `error=Conflict`. Nothing is written in either case. -- **Analyzers do not run on Razor-generated code**, so a Razor file offers compiler-diagnostic fixes (e.g. `CS0219`) and refactorings, but no `IDE*`/`CA*` fixes. The exception is unnecessary usings: see `remove_unused_usings` and `apply_code_fix`. -- **Imports files** (`_Imports.razor`, `_ViewImports.cshtml`) apply to every component or view beneath them. Using removal never edits them. -- **Freshness.** An edit to an existing `.razor`/`.cshtml` file (yours or the user's) is applied in place: the Razor compiler reruns incrementally for that project and the projects using it, with no solution reload. A C# edit that changes declarations (not just method bodies) reruns it too, so generated code follows a code-behind change such as a renamed `[Parameter]`; this holds for every write tool, `apply_patch` included. Adding or deleting a Razor file reloads the solution on the next call. Multi-targeted projects get generated code for every target framework. -- **Some `.cshtml` views cannot take a new method.** Roslyn will not add a member where the generated view class hides the insertion point. `extract_method` then returns `error=NotSupported` and suggests `asLocalFunction=true`, which still works. - -## Code actions - -### get_code_actions -`solutionId`, `documentPath` (.cs, .razor or .cshtml, absolute or solution-relative), `line`, `column` (1-based), `endLine`/`endColumn` (optional, for a selection span). Returns lines `<actionId>,<kind>,<diagnosticId> <title>`; a grouped action (such as the choices under "Generate type") is listed as its individual actions; `kind` ∈ `Fix|Refactoring`; `diagnosticId` is `-` for refactorings. Fixes cover analyzer diagnostics as well as compiler ones, so `IDE*` and `CA*` ids appear here when the project references the analyzer that reports them. Capped at 50. `actionId` is opaque — pass it back verbatim. In a `.razor`/`.cshtml` file the position must be inside C# (see [Razor and CSHTML](#razor-and-cshtml)); a position in markup → `NotSupported`. Actions are listed before their edits are computed, so an action whose edits cannot be mapped back to the Razor file is only refused when applied. - -### apply_code_action -`solutionId`, `actionId` (from get_code_actions), `checkOnly` (default false). The action is re-resolved at apply time, not cached — if the code changed since discovery, `error=Conflict`: re-run `get_code_actions`. Malformed id → `error=Invalid`. Returns `applied`, `action`, changed files. For an action discovered in a `.razor`/`.cshtml` file the edits are written to the Razor source; an unmappable edit → `NotSupported`, mismatched Razor text → `Conflict`, nothing written. External edit since load → `Stale`. - -### apply_code_fix -`solutionId`, `documentPath` (.cs, .razor or .cshtml), `diagnosticId` (a compiler id such as `CS0219`, or an analyzer id such as `IDE0005`), `line`, `column` (**required**, 1-based), `checkOnly` (default false). Quick path from `get_diagnostics`: pass an entry's id and its `line:col` unchanged, and the diagnostic with that id whose span contains the position (start and end included) is fixed, without an actionId round-trip. Other occurrences of the same id are left alone. - -- No diagnostic with that id at the position → `NotFound`; `line` or `column` below 1 → `Invalid`; no registered fix → `NotSupported`; fix produced no changes → `Conflict` (no candidates); external edit since load → `Stale`. -- **Several fixes → hand off to `apply_code_action`.** When the diagnostic has more than one distinct fix (e.g. `CS0535`: implement interface / implement all members explicitly; `CS0246`: add a `using` / fully qualify / generate the type), nothing is written and the result is `error=Conflict` with one `candidate=<actionId>,Fix,<diagnosticId> <title>` header per fix. Show the user the candidate titles and ask which to apply, unless their request clearly names one, then call `apply_code_action` with its actionId (the text before the first comma). Do not call `apply_code_fix` again for it: it will return the same Conflict. `checkOnly` returns the same Conflict. - - ``` - error=Conflict - errorMessage=CS0535 at 9:22 has 2 fixes; apply the chosen candidate's actionId with apply_code_action. - candidate=eyJEb2N1...,Fix,CS0535 Implement interface - candidate=eyJEb2N1...,Fix,CS0535 Implement all members explicitly - ``` - -In a `.razor`/`.cshtml` file the position is in the Razor file, only diagnostics located in that file count, and the fix is written to the Razor source (unmappable → `NotSupported`, mismatched text → `Conflict`). `CS8019`/`IDE0005` remove the unnecessary `@using` on that line, the same analysis as `remove_unused_usings`; a used `@using` there → `NotFound`. - -Analyzer ids are only reported — and so only fixable — when the project actually references the analyzer. `IDE*` rules come from the CodeStyle analyzers, which a project pulls in with `EnforceCodeStyleInBuild` or an explicit `Microsoft.CodeAnalysis.CSharp.CodeStyle` package reference; an SDK copy built against a newer compiler than Roslynk's is skipped. - -## Editing - -All write tools: `checkOnly=true` previews changed files without writing; writes are atomic (all-or-nothing) and stale-guarded (on-disk content re-hashed against the loaded snapshot; mismatch → `error=Stale`, nothing written). Successful writes advance the in-memory model immediately. Response shape: `applied=Y|N` + tool-specific headers + changed-file list grouped by project. - -### apply_patch -`solutionId`, `patch` (git unified diff: `---`/`+++`/`@@` hunks, one or more file sections), `baseVersions` (optional list of `{path, version}` from a prior read, for explicit optimistic concurrency), `checkOnly`. - -- Hunks are **content-anchored**; line numbers in `@@` headers are untrusted and may be omitted (`@@`). Each hunk must match exactly one place — include enough context. Ambiguous or unmatched → `error=Conflict` naming the file and reason. -- Edits any existing text file inside the solution folder. Compiled `.cs` and `.razor`/`.cshtml` documents (regular and additional) are folded into the in-memory model; other files (`.csproj`, `.json`, `.md`, ...) are written to disk only. Creation, deletion, binary files, `obj`/`bin` paths, and paths outside the solution folder are rejected before any hunk is attempted: `error=NotSupported` with `rejected=<path>` lines. A path naming no file → `error=NotFound` (the message names the solution folder that paths are relative to); a suffix matching several distinct files → `error=Ambiguous` with `candidate=<solution-relative path>` lines. Mixed reasons give one error (NotFound, else Ambiguous, else NotSupported) whose message explains each, with every path in `rejected=`. Encoding (UTF-8/UTF-16 BOM) is preserved. -- Path resolution: absolute → solution-relative → unique suffix match across solution documents (regular and additional; a multi-targeted file counts once, so a repo-root-relative path such as `src/Multi/Api.cs` resolves); a path not in the model falls back to solution-folder-relative. -- The stale-write guard runs even without `baseVersions`. - -### rename_symbol -`solutionId`, `symbolName` (FQN), `newName` (must be a valid C# identifier), `checkOnly`. Renames across partial classes, all `#if` projections, all TFMs, and Razor: edits computed against generated `.g.cs` are mapped back through `#line` directives and written to the real `.razor`/`.cshtml` (covering `@code` blocks, markup expressions, component attributes in other components, and `@bind-X="Expr"` bindings — the compiler's hidden setter/`ValueExpression` expansions collapse into the one attribute-value edit). Unverifiable mapping aborts the whole rename before writing. Ambiguous → `error=Ambiguous` with candidates; retry with one verbatim to rename a single overload. A symbol declared only by a source generator → `error=NotSupported` naming the generator (change the generator or the code that drives it instead); a partial member/type with a hand-written declaration is renamable. A file the rename changes that was edited on disk, or in the loaded model after the rename was computed → `error=Stale` with a `stale=` path; nothing is written. Edits to other files made meanwhile are kept. - -### rename_parameter -`solutionId`, `methodId` (FQN of the method, local function — see [Symbol names](#shared-conventions) — constructor — written `Namespace.Type.Type(...)` — or indexer; add a parameter-type list to pick one overload), `parameterName` (existing name), `newName` (valid C# identifier, different from `parameterName`), `checkOnly`. Uses Roslyn's semantic rename on the parameter: declaration, body uses, named arguments at call sites and `<paramref>`/`<param>` doc references; strings and comments untouched. Covers all `#if` projections, TFMs and Razor like `rename_symbol`. Cascades across the override/interface group (overridden/overriding members, interface members and implementations, both partial-method parts) when the related declaration is in source and its parameter at the same position has the same old name; related members with a different name, or in metadata, or declared only by a generator (listed in `unchangedRelated`), are left alone. Headers: `applied`, `resolvedMethod` (before the rename), `parameter` (old name), `renamedMembers` (declarations renamed, including the target), `unchangedRelated` (`; `-separated, omitted when empty), then changed files. Errors: invalid/unchanged `newName` → `error=Invalid`; overloads → `error=Ambiguous` with candidates; unknown member → `error=NotFound` with suggestions; unknown `parameterName` → `error=NotFound` listing the member's parameters; `newName` already declared in a renamed member (parameter, local, local function, lambda/query variable, type parameter) → `error=Conflict` naming the member; not a method/constructor/indexer, positional record constructor, metadata-only member, or a member declared only by a source generator → `error=NotSupported` (naming the generator in the last case); changed on disk → `error=Stale`. Nothing written on any error. Not available in `multi_query`. - -### change_signature -`solutionId`, `methodId` (FQN), `parameterType` (e.g. `System.Threading.CancellationToken`), `parameterName` (valid identifier), `defaultValue` (**required** — keeps the parameter optional, e.g. `default`, `null`, `0`), `callSiteArgument` (optional; when given, threaded into every call site as a named argument), `checkOnly`. - -v1 scope: appends one optional parameter to one ordinary method or local function. `NotSupported` for virtual/override/abstract methods, interface members and implementations, partial methods, `params` methods, constructors/operators/accessors, and a method declared only by a source generator (naming the generator). An overloaded method is targeted by its parameter-type list; a bare name → `Ambiguous`. Only true invocation call sites are updated — method groups, `nameof`, and `cref` are left alone (still valid because the parameter is optional). Returns `updatedCallSites` count. Razor: a method declared in a `.razor`/`.cshtml` `@code` block, and call sites in `@code` or markup expressions, are mapped back through `#line` directives and written to the Razor source; an unmappable edit → `NotSupported`, mismatched Razor text → `Conflict`, nothing written. External edit since load → `Stale`. - -### extract_method -`solutionId`, `documentPath` (.cs, .razor or .cshtml, absolute or solution-relative), `startLine`, `startColumn`, `endLine`, `endColumn` (1-based, in that file; the end column is exclusive, so `endLine+1`, column `1` selects through the end of `endLine`), `methodName` (optional; defaults to Roslyn's own name, e.g. `NewMethod` or one derived from the code), `asLocalFunction` (default false), `checkOnly` (default false). - -Runs Roslyn's Extract Method refactoring (the same provider behind get_code_actions' "Extract method"/"Extract local function"), so parameters, `ref`/`out`, the return value, `static`/`async` modifiers and the call-site replacement all come from Roslyn's data-flow analysis - never text splicing. Whitespace at either end of the selection is ignored, so whole-line selections work. Roslyn may widen a partial expression to the enclosing complete expression. When `methodName` is given, the extracted symbol is renamed semantically before anything is written. Roslyn formats the new method and the edited call site with the project's formatting options (`.editorconfig`); the rest of the file is untouched. - -Returns `applied`, `method` (final name), `symbolName` (the new method's full name, ready for the name-based tools — for a local function it carries its containers, e.g. `N.T.M(int).NewMethod(string)`), `kind` (`Method`|`LocalFunction`), `signature` (the declaration header on one line, e.g. `private static int Total(int a, int b)`), `call` (the statement now containing the call), then the changed files. `checkOnly=true` returns the same preview without writing. - -Nothing is written on any failure: -- Selection Roslyn cannot extract (spans members, partial statements, jumps out of the selection, `yield`, ...) → `NotSupported` with the constraints. -- Roslyn flags the extraction as possibly changing behavior → `NotSupported` with Roslyn's warning. -- The result would add compile errors to an edited file (e.g. a `methodName` equal to the type name, CS0542) → `NotSupported` listing up to five `id: message (line n)` entries. Errors already present are not counted. -- The call would bind to another member, or the rename produced no declaration of that name → `Conflict`. -- An edited file changed since the extraction was computed (in memory or on disk) → `Stale` with `stale=<path>`. -- Unknown document → `NotFound`; generated `.g.cs` (incl. Razor output; pass the `.razor`/`.cshtml` source instead) or non-C# → `NotSupported`; out-of-range, empty or reversed selection, or an invalid/keyword `methodName` → `Invalid`. -- `.razor`/`.cshtml`: a selection outside C# (in markup) → `NotSupported`; an edit that cannot be mapped back to the Razor file → `NotSupported`, mismatched Razor text → `Conflict`. Where Roslyn cannot add a new method to a `.cshtml` view (the generated class hides the insertion point), the error suggests `asLocalFunction=true`, which extracts into the containing member instead. The new code is written in the file's own indentation. - -Prefer this over get_code_actions + apply_code_action for extraction: it is deterministic (no action-id round trip, no title matching), names the method in one step, and checks the result compiles. Not available in multi_query (it is a write tool). - -### remove_unused_usings -`solutionId`, `documentPath` (optional .cs, .razor or .cshtml; omit to clean the whole solution, Razor files included), `checkOnly`. CS8019 finds the files to touch; each one is then rewritten by Roslyn's own IDE0005 fix, which preserves the surrounding trivia, falling back to a syntactic removal when the IDE0005 analyzer is not referenced. Nothing to remove → `applied=N`, `removedCount=0` (not an error). Safe to re-run (idempotent). External edit since load → `Stale`. - -Razor: the compiler never reports CS8019 in generated code, so each `.razor`/`.cshtml` file's generated C# is checked as ordinary code, and every unnecessary `@using` line written in the file itself is deleted. Directives in imports files (`_Imports.razor`, `_ViewImports.cshtml`) are shared by other components and views, so they are never removed, even when unused by the file being cleaned. - -## Dead code - -### find_dead_code -`solutionId`, `scope` (optional FQN prefix, e.g. `MyApp.Services` — use it on large solutions; the scan runs find-references per symbol), `includePublic` (default false — public/protected API excluded unless set), `maxResults` (bounds the expensive scan; omit it to scan everything - the result then pages with startItem/maxSize). - -Leaf lines: `memberKind,memberName,loc,confidence,reason` with confidence `High|Medium`. Automatically excludes interface implementations, virtual/override/abstract chains, test-attributed members (xUnit/NUnit/MSTest), generated code, and DI/reflection-attributed members (`[Export]`, `[ImportingConstructor]`). The `loc` is the full declaration span, ready to pass to `apply_patch` for removal — this tool never deletes anything itself. Treat results as candidates, not verdicts. - -### find_dead_conditionals -`solutionId` only. Header `#deadConditionals=<n>`; body per file: `<line:col>,<directive>,<condition>` with directive ∈ `if|elif|else` (condition `(else)` for `#else`). Flags branches never compiled under any configuration Roslynk actually loaded (each project's defined symbols, and that set minus DEBUG, across TFMs). A branch used only by a configuration not loaded (CI-injected define, missing workload) is a false positive — treat as "possibly dead". - -## Batching - -### multi_query -`solutionId`, `operations` (1+ items; the limit is the framing itself — a batch whose retry line cannot fit the budget is refused with `error=Invalid` before anything runs), optional `expectSnapshot`. - -Each operation is `{ "tool": <name>, "arguments": { ... } }` where `tool` is one of the 15 read-only query tools (get_symbol, get_symbol_body, get_members, find_definition, find_implementations, find_references, find_reads, find_writes, get_callers, get_callees, search_symbols, get_type_hierarchy, find_dead_code, find_dead_conditionals, get_expression_info) and `arguments` uses exactly that tool's single-call parameter names - unknown or misspelled keys are rejected (`error=Invalid` naming the key), never ignored; omitted parameters take the tool's declared defaults. The schema's `tool` enum lists the legal names, so a write tool, get_diagnostics or get_solution_status is unrepresentable and fails the whole call at binding (`error=Invalid` naming the offending value and the permitted set). - -**Impact analysis.** To answer "what uses X / who calls X / what breaks if I change X", batch find_references (`symbolName`), get_callers (`methodName`), get_callees (`memberName`), find_implementations (`symbolName`) and get_type_hierarchy (`typeName`) in one call instead of grepping - parameter names are each tool's own and a wrong key is an `Invalid` slot. get_callers and get_callees are inverses: who calls this member, and what does this member call - together they trace a call chain one hop per query. - -Everything runs against ONE snapshot of the solution, so results inside one response can never disagree with each other. The response is one envelope, not JSON: - -``` -operations=<n> -snapshot=<32-hex id of the snapshot every slot was computed against> -boundary=<32-hex, fresh per request> -budget=<n, the per-operation character allowance, net of the envelope's own framing> -retry=1:3.0,7:0.2 (present only when operations were dropped) - ---<boundary> -slot=2 tool=get_type_hierarchy - -<that tool's own output format, verbatim - headers, blank line, tab-indented body> - ---<boundary> -slot=3 tool=get_callees - -<that tool's output> - ---<boundary>-- -``` - -Every operation runs (in parallel); each result is then delivered WHOLE, smallest first, until the budget is filled, and delivered slots are emitted in request order. A slot is complete or absent - never cut - so only a delivered slot's own body headers may drive tool-level paging (`nextStartItem=`). Operations whose result did not fit are listed once in the `retry=` header, in request order, as `<index>:<size>` where size is that result's cost (frame + body) as a ratio of `budget=`, rounded up to 0.1 (0.1 is the smallest value reported, never 0.0). Plan the continuation from the ratios: size ≥ 1.0 can never fit beside anything - re-send that operation alone (it pages); sizes summing to at most 1.0 fit one continuation batch together; `ceil(size)` is roughly a solo call's page count. Ratios smaller than 0.1 of the budget are indistinguishable, so about ten such operations per continuation batch is the safe number. Ratios describe one snapshot: pass the response's `snapshot=` as `expectSnapshot` on the continuation, or a re-run against a moved solution re-measures and re-decides. Re-send exactly the listed operations with their original arguments from your own copy of the request - slot frames carry the index and tool name only, never the arguments. A failing operation is delivered as its normal `error=` block and can itself be dropped like any oversized result. - -**Truncation and continuation.** Pass the first response's `snapshot=` value as `expectSnapshot` when you continue: if the solution changed between the calls (another client, or the user saving a file) the continuation is refused with `error=Stale` naming both ids plus a `snapshot=<current id>` header - re-run the whole batch instead of stitching two generations. Consistency is guaranteed within one response, never across two. `get_diagnostics` and `get_solution_status` are deliberately not multi-queryable - call them directly. diff --git a/external-sources/vendir.lock.yml b/external-sources/vendir.lock.yml index a6fc744..387c475 100644 --- a/external-sources/vendir.lock.yml +++ b/external-sources/vendir.lock.yml @@ -2,27 +2,27 @@ apiVersion: vendir.k14s.io/v1alpha1 directories: - contents: - git: - commitTitle: 'chore: refresh gh-aw pins and recompile workflows (#1303)...' - sha: b0bf1730479858941ae22bdf0b45e88cfa31bcc5 + commitTitle: 'Merge pull request #1305 from dotnet/abhitejjohn-ef-eval-safeguards...' + sha: 9de888b8ce55da34e76a113bd7b2d463d6b3e1e6 tags: - - skill-validator-nightly + - skill-validator-nightly-8-g9de888b8 path: dotnet-skills - git: commitTitle: Add Cursor rules that reference the existing skill docs... sha: af2319bd01bb7cc881267a9ef42cafdaf5e9029d path: webgpu-claude-skill - git: - commitTitle: Fail the build when a prerender error is swallowed by a custom - fetch handler (#18355) - sha: 59b9cc00726495bb45f5c4b000dbbb7b5a19d662 + commitTitle: 'fix(content): propagate glob() loader rendering errors instead + of swallowing them (#18353)...' + sha: af54bfaebff9180cb96822c0da11737b4b26e65a tags: - - '@astrojs/vercel@11.0.14-11-g59b9cc0072' + - '@astrojs/vercel@11.0.14-17-gaf54bfaebf' path: astro - git: - commitTitle: 'multi_query improved paging (Fixes #96) (#98)' - sha: d59c7ba3d485da1202dc977f15d36a142d892db9 + commitTitle: 'Skills update (Fixes #99) (Fixes #100) (#102)' + sha: ff5e73400f66b0ea18199cc698f2ba5179c98cde tags: - - 2.1.0-18-gd59c7ba + - 2.1.0-20-gff5e734 path: roslynk path: upstreams kind: LockConfig