Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >-
errors, verifying project builds successfully.
name: code-testing-builder
user-invocable: false
tools: ["skill", "read", "search", "edit", "execute"]
tools: ["skill", "read", "search", "edit", "execute", "Skill", "Read", "Glob", "Grep", "Edit", "Write", "Bash", "read_file", "replace", "write_file", "glob", "grep_search", "run_shell_command"]
license: MIT
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >-
imports, correcting type mismatches, fixing compilation failures.
name: code-testing-fixer
user-invocable: false
tools: ["skill", "read", "search", "edit", "execute"]
tools: ["skill", "read", "search", "edit", "execute", "Skill", "Read", "Glob", "Grep", "Edit", "Write", "Bash", "read_file", "replace", "write_file", "glob", "grep_search", "run_shell_command"]
license: MIT
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >-
coverage plateaus or project-wide coverage/CRAP analysis without writing tests
(use coverage-analysis); targeted method/class CRAP scores (use crap-score).
name: code-testing-generator
tools: ["agent", "skill", "read", "search", "edit", "execute"]
tools: ["agent", "skill", "read", "search", "edit", "execute", "Task", "Skill", "Read", "Glob", "Grep", "Edit", "Write", "Bash", "read_file", "replace", "write_file", "glob", "grep_search", "run_shell_command"]
agents:
- code-testing-researcher
- code-testing-planner
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: >-
running build-test-fix cycle for generated tests.
name: code-testing-implementer
user-invocable: false
tools: ["agent", "skill", "read", "search", "edit", "execute"]
tools: ["agent", "skill", "read", "search", "edit", "execute", "Task", "Skill", "Read", "Glob", "Grep", "Edit", "Write", "Bash", "read_file", "replace", "write_file", "glob", "grep_search", "run_shell_command"]
agents:
- code-testing-builder
- code-testing-tester
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >-
applying lint fixes.
name: code-testing-linter
user-invocable: false
tools: ["skill", "read", "search", "edit", "execute"]
tools: ["skill", "read", "search", "edit", "execute", "Skill", "Read", "Glob", "Grep", "Edit", "Write", "Bash", "read_file", "replace", "write_file", "glob", "grep_search", "run_shell_command"]
license: MIT
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >-
creating .testagent/plan.md from research.
name: code-testing-planner
user-invocable: false
tools: ["skill", "read", "search", "edit", "execute"]
tools: ["skill", "read", "search", "edit", "execute", "Skill", "Read", "Glob", "Grep", "Edit", "Write", "Bash", "read_file", "replace", "write_file", "glob", "grep_search", "run_shell_command"]
license: MIT
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >-
discovering test frameworks and build commands, producing .testagent/research.md.
name: code-testing-researcher
user-invocable: false
tools: ["skill", "read", "search", "edit", "execute"]
tools: ["skill", "read", "search", "edit", "execute", "Skill", "Read", "Glob", "Grep", "Edit", "Write", "Bash", "read_file", "replace", "write_file", "glob", "grep_search", "run_shell_command"]
license: MIT
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >-
checking test results and failures.
name: code-testing-tester
user-invocable: false
tools: ["skill", "read", "search", "edit", "execute"]
tools: ["skill", "read", "search", "edit", "execute", "Skill", "Read", "Glob", "Grep", "Edit", "Write", "Bash", "read_file", "replace", "write_file", "glob", "grep_search", "run_shell_command"]
license: MIT
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ Before reporting, calibrate findings:

### Step 6: Report findings

**Scale the report depth to the size and complexity of the suite.** The structure below is the full template for a substantial suite (roughly 15+ tests or a multi-file project). For a small or simple input (a single file with only a handful of tests), do not emit every section — a padded multi-section dashboard on a trivial input reads as noise and buries the answer. Instead, answer the user's question directly and concisely: which tests are assertion-free or trivial-only, the overall assertion-quality verdict, and concrete recommendations (still distinguishing intentional smoke tests from tests masquerading as real verification). Use only the sections that carry real signal for the input at hand; a short metric summary plus the assertion-free list and recommendations is often enough. Never omit the rubric-relevant substance (assertion-free/trivial identification, the quality verdict, and concrete recommendations) — only trim structural overhead that adds no information.

Present the analysis in this structure:

1. **Summary Dashboard** — A quick-reference table of key metrics:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
---
name: generate-testability-wrappers
description: >
Generate wrapper interfaces and DI registration for hard-to-test static dependencies in C#.
Produces IFileSystem, IEnvironmentProvider, IConsole, IProcessRunner wrappers, or guides adoption
of TimeProvider and IHttpClientFactory.
Generate wrapper interfaces and DI registration for hard-to-test static dependencies in C#,
when the abstraction does NOT exist yet. Produces IFileSystem, IEnvironmentProvider, IConsole,
IProcessRunner wrappers, or guides first-time adoption of TimeProvider and IHttpClientFactory
and registering them in DI.
USE FOR: generate wrapper for static, create IFileSystem wrapper, wrap DateTime.Now,
make static testable, make class testable, create abstraction for File.*, generate
DI registration, TimeProvider adoption, IHttpClientFactory setup, testability wrapper,
mock-friendly interface, mock time in tests, create the right abstraction to mock,
how to mock DateTime, test code using File.ReadAllText, what abstraction for Environment,
how to make statics injectable, adopt System.IO.Abstractions, make file calls testable.
DO NOT USE FOR: detecting statics (use detect-static-dependencies), migrating call
sites (use migrate-static-to-wrapper), general interface design not about testability.
DI registration, set up/adopt TimeProvider when it is not registered yet, IHttpClientFactory
setup, testability wrapper, create the right abstraction to mock, what abstraction for
Environment, how to make statics injectable, adopt System.IO.Abstractions.
DO NOT USE FOR: detecting statics (use detect-static-dependencies), migrating
call sites or replacing existing DateTime.*/File.* usages once the wrapper is created
or already registered in DI (use migrate-static-to-wrapper), general interface design.
license: MIT
---

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
---
name: migrate-static-to-wrapper
description: >
Mechanically replace static dependency call sites with wrapper or built-in
abstraction calls across a bounded scope (file, project, or namespace).
Performs codemod-style bulk replacement of DateTime.UtcNow to TimeProvider.GetUtcNow(),
File.ReadAllText to IFileSystem, and similar transformations. Adds constructor
injection parameters and updates DI registration.
USE FOR: replace DateTime.Now/UtcNow with TimeProvider, migrate static calls
to wrapper, bulk replace File.* with IFileSystem, codemod static to
injectable, add constructor injection for a dependency, mechanical or scoped
migration of statics, convert static calls to use an abstraction, update call
sites.
DO NOT USE FOR: detecting statics (use detect-static-dependencies), generating
wrappers (use generate-testability-wrappers), migrating between test frameworks.
Replace existing static dependency call sites with wrapper or built-in
abstraction calls when the abstraction already exists or is already registered
in DI. Codemod-style bulk replacement of DateTime.Now/UtcNow to TimeProvider,
File.ReadAllText to IFileSystem, and similar, across a bounded scope (file,
project, or namespace). Adds the constructor injection parameter to affected classes.
USE FOR: replace all DateTime.UtcNow/DateTime.Now calls with TimeProvider and add
the constructor parameter, TimeProvider already registered in DI so migrate the call
sites, migrate static calls to wrapper, bulk replace File.* with IFileSystem, codemod
static to injectable, add constructor injection for an existing dependency, scoped
migration of statics, migrate statics in only certain scoped files.
DO NOT USE FOR: detecting statics (use detect-static-dependencies), creating the
wrapper or registering it when it does not exist yet (use
generate-testability-wrappers), migrating between test frameworks.
license: MIT
---

Expand Down Expand Up @@ -89,6 +90,39 @@ Add the new dependency following the class's existing pattern:
- **Primary constructor** (C# 12+): Add parameter to primary constructor: `public class OrderProcessor(ILogger<OrderProcessor> logger, TimeProvider timeProvider)`
- **Traditional constructor**: Add `private readonly` field + constructor parameter, matching the existing field naming convention (`_camelCase` or `m_camelCase`)

#### Static classes: use ambient context (no constructor injection)

A `static` class with only static members **cannot** receive constructor injection — adding an instance constructor or instance field would break it. Do **not** convert it to a non-static class just to inject the dependency; that changes its design and every call site. Instead, apply the **ambient context** pattern: expose a static, settable seam that defaults to the real implementation and is overridden once at composition/test setup.

```csharp
public static class TimestampFormatter
{
// Ambient seam — defaults to the real clock, swap in tests.
public static TimeProvider Clock { get; set; } = TimeProvider.System;

public static string Now() => Clock.GetUtcNow().ToString("O");
}
```

- Production: leave `Clock` at its `TimeProvider.System` default, or assign the DI-resolved `TimeProvider` once at startup (`TimestampFormatter.Clock = app.Services.GetRequiredService<TimeProvider>();`).
- Tests: override `Clock` with a `FakeTimeProvider` and **always restore it in a `finally`** so a failing assertion can't leak the fake into other tests:

```csharp
var original = TimestampFormatter.Clock;
TimestampFormatter.Clock = new FakeTimeProvider(instant);
try
{
// exercise code under test
}
finally
{
TimestampFormatter.Clock = original;
}
```

- **Parallelism caveat**: a mutable static seam is process-global. Tests that mutate it must **not** run in parallel with each other (or with code that reads it) — put them in a non-parallel collection/class (e.g. xUnit `[Collection]` with parallelization disabled, or MSTest `[DoNotParallelize]`). If tests must run in parallel, prefer constructor injection (convert the caller) over an ambient static.
- The same seam works for other statics (`IFileSystem`, custom wrappers): a `public static <Abstraction> X { get; set; }` defaulting to the real implementation, with the same restore-in-`finally` and non-parallel discipline.

### Step 4: Replace call sites

Perform each replacement mechanically. For each call site:
Expand Down Expand Up @@ -171,7 +205,7 @@ Summarize what was done:
| Pitfall | Solution |
|---------|----------|
| Replacing statics in test code | Only replace in production code; tests should use fakes/mocks |
| Breaking static classes | Static classes can't have constructors — use ambient context for these |
| Breaking static classes | Static classes can't have constructors — use the ambient context seam (Step 3) instead of converting them to non-static |
| Missing `FakeTimeProvider` NuGet | Add `Microsoft.Extensions.TimeProvider.Testing` to test project |
| Replacing in expression-bodied members without updating return type | `DateTime` → `DateTimeOffset` when using `TimeProvider.GetUtcNow()` — verify type compatibility |
| Migrating too much at once | Stick to the defined scope — one project or namespace per run |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Detect the test platform and framework, run tests, and apply filters using `dotn

| Input | Required | Description |
|-------|----------|-------------|
| Project or solution path | No | Path to the test project (.csproj) or solution (.sln). Defaults to current directory. |
| Project or solution path | No | Path to the test project (.csproj) or solution (.sln, .slnf, .slnx). Defaults to current directory. |
| Filter expression | No | Filter expression to select specific tests |
| Target framework | No | Target framework moniker to run against (e.g., `net8.0`) |

Expand Down Expand Up @@ -154,6 +154,8 @@ dotnet test --project path/to/

# Run all tests in a solution (sln, slnf, slnx)
dotnet test --solution path/to/MySolution.sln
dotnet test --solution path/to/MySolution.slnf
dotnet test --solution path/to/MySolution.slnx

# Run all tests in a directory containing a solution
dotnet test --solution path/to/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
name: writing-mstest-tests
description: >
Write, create, modernize, or fix comprehensive MSTest unit tests with MSTest 3.x/4.x APIs.
USE FOR: write or create MSTest unit tests, fix/modernize MSTest assertions,
better MSTest assertion than Assert.IsTrue, replace hard cast with type check (IsInstanceOfType),
USE FOR: write, create, review, or modernize MSTest tests and assertions,
better MSTest assertion than Assert.IsTrue, replace hard cast with IsInstanceOfType,
MSTest assertion APIs (Contains, ContainsSingle, HasCount, IsEmpty, IsNotEmpty, DoesNotContain,
AreSame, IsNull, StartsWith, EndsWith, MatchesRegex, IsGreaterThan, IsLessThan, IsInRange),
swapped Assert.AreEqual args, replace ExpectedException with Assert.Throws,
swapped/reversed Assert.AreEqual args (Expected/Actual backwards),
replace ExpectedException with Assert.Throws,
data-driven (DataRow, DynamicData, ValueTuples),
lifecycle (TestInitialize, TestCleanup, TestContext),
async tests and cancellation tokens, conditional execution/retry/cleanup (OSCondition, Retry),
async and cancellation tests, conditional execution/retry/cleanup (OSCondition, Retry),
parallelization (Parallelize/DoNotParallelize), MSTest.Sdk setup, MSTESTxxxx analyzer fixes.
DO NOT USE FOR: test quality audits (use test-anti-patterns),
running tests (use run-tests), MSTest version migration (use the migrate-mstest skills),
running tests (use run-tests), MSTest version migration (use migrate-mstest skills),
xUnit/NUnit/TUnit, or non-.NET languages.
license: MIT
---
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "Analyzes .NET code for performance bottlenecks, recommends concrete optimizations, and guides benchmarking. Scans for ~50 anti-patterns across async, memory, strings, collections, LINQ, regex, serialization, and I/O. Use when reviewing .NET code performance, optimizing hot paths, reducing allocations, or tuning async/concurrency patterns."
name: optimizing-dotnet-performance
tools: ['read', 'search', 'edit', 'task', 'skill', 'web_search', 'web_fetch', 'ask_user']
tools: ['read', 'search', 'edit', 'task', 'skill', 'web_search', 'web_fetch', 'ask_user', 'Read', 'Glob', 'Grep', 'Edit', 'Write', 'Skill', 'read_file', 'replace', 'write_file', 'glob', 'grep_search']
license: MIT
---

Expand Down
2 changes: 1 addition & 1 deletion cli/ManagedCode.Agents/ManagedCode.Agents.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<PackageReference Include="Microsoft.ML.Tokenizers" Version="1.0.1" />
<PackageReference Include="Microsoft.ML.Tokenizers.Data.O200kBase" Version="1.0.1" />
<PackageReference Include="NuGet.Versioning" Version="7.3.0" />
<PackageReference Include="SharpConsoleUI" Version="2.5.0" />
<PackageReference Include="SharpConsoleUI" Version="2.5.10" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<PackageReference Include="Microsoft.ML.Tokenizers" Version="1.0.1" />
<PackageReference Include="Microsoft.ML.Tokenizers.Data.O200kBase" Version="1.0.1" />
<PackageReference Include="NuGet.Versioning" Version="7.3.0" />
<PackageReference Include="SharpConsoleUI" Version="2.5.0" />
<PackageReference Include="SharpConsoleUI" Version="2.5.10" />
</ItemGroup>

<ItemGroup>
Expand Down
12 changes: 8 additions & 4 deletions cli/ManagedCode.DotnetSkills/InteractiveConsoleApp.Catalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ private void BuildSkillBrowserPage(ConsoleWindowSystem ws, ScrollablePanelContro

private void ShowSkillDetailModal(ConsoleWindowSystem ws, ScrollablePanelControl owner, SkillEntry skill)
{
// Fold the one-line summary into the top of the scrolling markdown document so the modal
// reads as one cohesive skill page (summary lead-in, then the full SKILL.md) rather than
// three stacked blocks. The identity strip stays pinned above.
var body = ComposeSkillMarkdown(skill.Description, LoadSkillPreview(skill));

var detail = new IWindowControl[]
{
BuildPropertyPanel(ToAlias(skill.Name), AccentTurquoise,
Expand All @@ -101,8 +106,7 @@ private void ShowSkillDetailModal(ConsoleWindowSystem ws, ScrollablePanelControl
("lane", Escape(skill.Lane)),
("version", Escape(skill.Version)),
("tokens", FormatTokenCount(skill.TokenCount))),
BuildModalBlock("summary", Escape(skill.Description)),
BuildModalBlock("preview", Escape(LoadSkillPreview(skill))),
BuildScrollingMarkdownBlock("preview", body),
};

ShowModalNative(ws, $"Skill · {ToAlias(skill.Name)}", detail,
Expand Down Expand Up @@ -489,7 +493,7 @@ private void ShowBundleModal(ConsoleWindowSystem ws, ScrollablePanelControl owne
("title", Escape(package.Title)),
("skills", package.Skills.Count.ToString()),
("includes", Escape(string.Join(", ", package.Skills.Take(10).Select(ToAlias))))),
BuildModalBlock("summary", Escape(package.Description)),
BuildMarkdownBlock("summary", package.Description),
};

ShowModalNative(ws, $"Bundle · {package.Name}", detail,
Expand Down Expand Up @@ -672,7 +676,7 @@ private void ShowAgentModal(ConsoleWindowSystem ws, ScrollablePanelControl owner
("agent", Escape(agent.Name)),
("skills", agent.Skills.Count == 0 ? "[grey50]-[/]" : Escape(string.Join(", ", agent.Skills.Select(ToAlias)))),
("platform", Escape(Session.Agent.ToString()))),
BuildModalBlock("summary", Escape(agent.Description)),
BuildMarkdownBlock("summary", agent.Description),
};

var buttons = new List<(string, Action)>();
Expand Down
Loading
Loading