Agent Skills › gnomeria/usbtree

gnomeria/usbtree

GitHub

系统化根因调试技能。通过复现、缩小范围、定位根因、最小化修复及验证证明,解决报错、崩溃或测试失败等问题,强调先找原因再改代码。

3 skills 108

Install All Skills

npx skills add gnomeria/usbtree --all -g -y
More Options

List skills in collection

npx skills add gnomeria/usbtree --list

Skills in Collection (3)

系统化根因调试技能。通过复现、缩小范围、定位根因、最小化修复及验证证明,解决报错、崩溃或测试失败等问题,强调先找原因再改代码。
用户报告bug、错误或崩溃 出现不稳定行为或功能失效 询问'为什么失败' 粘贴堆栈跟踪或失败的测试输出
.agents/skills/debug/SKILL.md
npx skills add gnomeria/usbtree --skill debug -g -y
SKILL.md
Frontmatter
{
    "name": "debug",
    "description": "Systematic root-cause debugging — reproduce, isolate, fix at the source, prove the fix. Use when the user reports a bug, an error, a crash, flaky behavior, \"this doesn't work\", \"why is this failing\", or pastes a stack trace or failing test output."
}

Debug

Find the root cause before touching code. A fix without a understood cause is a guess wearing a fix's clothes.

Step 1 — Reproduce

  • Get a deterministic reproduction before anything else: failing test, curl command, or exact click path. If you can't trigger it, you can't prove you fixed it.
  • Read the actual error verbatim — full message, full stack trace, not a paraphrase. The answer is often in the line the eye skips.
  • Capture the reproduction as a failing automated test now when feasible. It becomes the regression test in Step 5 for free.
  • Flaky bugs: run the repro in a loop (go test -run X -count=100, vitest --retry=0 repeated) to establish a failure rate before changing anything.

Step 2 — Shrink the search space

Cheapest checks first:

  1. Recent changes: git log --oneline -15 and git diff HEAD~5 on the touched area. Most bugs are days old, not years. git bisect when a known-good commit exists and the repro is scriptable.
  2. Boundaries: is the bad value born here or delivered here? Log/inspect at the boundary (request in, DB out, API response) to decide which side owns the bug.
  3. Binary search: cut the path in half — instrument the midpoint, determine which half is wrong, repeat. Never shotgun ten print statements at once; each probe should answer one question.
  4. Question one assumption per probe: "this config is loaded", "this branch runs", "this is the version deployed". Verify, don't assume — the bug lives in a false assumption.

Step 3 — Identify root cause

  • Keep asking "why" past the first plausible answer. Symptom: nil deref. Cause: field unset. Root cause: constructor allows partial init. Fix the constructor.
  • Before fixing a shared function, grep its callers. If the bug can bite them too, the fix belongs in the shared code path, not in the one caller from the bug report.
  • State the root cause in one sentence. If you can't, you haven't found it — return to Step 2.

Step 4 — Fix

  • Smallest change that removes the root cause. No drive-by refactors, no "while I'm here" — separate commits for that (see refactor skill).
  • If the real fix is large and something is bleeding in prod, a guard + TODO is acceptable — but say explicitly it's a mitigation, name the real fix, and don't call the bug closed.

Step 5 — Prove it

  • The Step 1 reproduction now passes. The rest of the test suite still passes.
  • Remove every temporary probe/print you added.
  • Report: root cause (one sentence), the fix, how it's verified. If tests still fail, say so — never declare victory on partial evidence.

Per-stack probes

Read references/tools.md when you need stack-specific instrumentation: delve / go test -race, Node --inspect and vitest filtering, browser devtools for frontend state/hydration issues, SQL logging for query bugs.

安全地重构代码结构而不改变行为。通过先建立测试网、执行小步验证、严格禁止行为变更和范围蔓延,确保重构过程可逆且可靠。适用于清理、提取、重命名或拆分代码等场景。
用户要求重构、清理、重组代码 用户请求提取函数、重命名、拆分文件或功能 用户希望减少代码重复或提高可测试性
.agents/skills/refactor/SKILL.md
npx skills add gnomeria/usbtree --skill refactor -g -y
SKILL.md
Frontmatter
{
    "name": "refactor",
    "description": "Behavior-preserving restructuring done safely — test net first, small verified steps, no mixed-in feature changes. Use when the user says \"refactor\", \"clean up\", \"restructure\", \"extract\", \"rename\", \"split this file\/function\", \"reduce duplication\", or \"make this testable\"."
}

Refactor

Refactoring changes structure, never behavior. If behavior changes, it's a feature or a bug fix — do that separately.

Step 0 — Decide it's worth it

  • Refactor with a purpose: enabling a concrete upcoming change, killing duplication that actually bit someone, or making untestable code testable. "Could be cleaner" alone is not a purpose — say so and stop.
  • Scope it: name the target shape in one or two sentences before touching code. No target = wandering diff.

Step 1 — Safety net

  • Run the existing tests covering the code; note the passing baseline. Typecheck/lint too (go vet, tsc --noEmit).
  • Uncovered code: write characterization tests first — pin down what it does now (including odd behavior), not what it should do. A refactor without a net is just editing and hoping.
  • Working tree must be clean before starting; the ability to git checkout . at any point is the escape hatch.

Step 2 — Small steps, verify each

  • One named refactoring at a time: extract function, inline, rename, move, split module, introduce parameter. Finish it, verify, then the next.
  • Verify after every step: tests + typecheck. Green → keep going or commit-point; red → the last step broke it, undo just that step. Never push forward on red planning to "fix at the end".
  • Use mechanical tools for mechanical work: gopls rename, TS language-server rename, IDE move-symbol. A tool rename can't miss a call site; a regex can.
  • Keep steps commit-sized. On long refactors, stop at green checkpoints so the user can commit — a 40-file big-bang diff that "should work" is failure, not progress.

Step 3 — Hard rules

  • No behavior changes. Spot a bug mid-refactor? Note it, finish or checkpoint the refactor, fix the bug as a separate change (see debug skill). Never fold it in silently.
  • No API breaks without saying so. Changing an exported/public signature? Grep all call sites first; update every one in the same change, and flag it to the user if the surface is shared beyond this repo.
  • No test rewrites to fit the refactor. Tests failing after a "behavior-preserving" change means the change wasn't behavior-preserving. The exception is tests coupled to structure (mocks of a now-gone internal); update those minimally and say why.
  • No scope creep. The target shape from Step 0 is the boundary. New improvement ideas get listed at the end, not done.

Step 4 — Finish

  • Full test suite + typecheck + lint green. Dead code left behind by the restructure gets deleted, not commented out.
  • Report: target shape achieved, steps taken, anything discovered but deliberately not done (bugs found, further refactorings), and any API changes.

Direction

For which structures to prefer per stack, follow the stack guides (go-service, node-backend, react-next, sveltekit, solidjs, astro). Common calls:

  • Prefer extracting functions over introducing classes/interfaces; add an interface only at a genuine seam (Go: define it where it's consumed).
  • Duplication rule of three: two similar blocks may stand; the third occurrence earns the abstraction — with the right shape now visible.
  • Don't abstract for testability when injecting a plain function/value would do.
根据仓库技术栈和现有风格编写测试,以最低成本捕获回归。支持Go、JS/TS等框架,自动检测配置并匹配现有规范。按逻辑层级(单元、集成、E2E)选择测试级别,确保测试独立、行为导向且无冗余。
用户说“write tests for” 用户说“add test coverage” 用户说“test this function/handler/component” 用户说“this needs tests” 实现缺乏测试的功能后
.agents/skills/write-tests/SKILL.md
npx skills add gnomeria/usbtree --skill write-tests -g -y
SKILL.md
Frontmatter
{
    "name": "write-tests",
    "description": "Author tests that match the repo's stack and existing test style, at the cheapest level that catches the regression. Use when the user says \"write tests for\", \"add test coverage\", \"test this function\/handler\/component\", \"this needs tests\", or after implementing a feature that lacks tests."
}

Write Tests

Write tests that fail when the behavior breaks and pass when it doesn't — nothing more. Always run them at the end and report results honestly.

Step 1: Detect stack and existing setup

  • go.mod → Go stdlib testing. Check whether the repo uses testify or plain assertions and match it.
  • package.json → look for vitest (default assumption, v2+), jest, @testing-library/react / @testing-library/svelte / @solidjs/testing-library, @playwright/test. Check vitest.config.* / vite.config.* for environment (node vs jsdom/happy-dom) and setup files.
  • Find 2–3 existing test files near the code under test and read them. Mirror their location convention (foo_test.go beside source; foo.test.ts beside source vs __tests__/ vs tests/), naming, imports, and helper usage. If the repo has test utilities (factories, fixtures, a test app builder), use them — do not build parallel ones.

If there is no test setup at all, install the minimal standard for the stack (Go needs nothing; TS: vitest + config matching the framework's docs) and say so in your report.

Step 2: Choose the level

Pick the cheapest level that would catch the regression you care about:

  • Unit — pure logic, parsing, calculations, branching. Default choice. No I/O, no framework.
  • Integration — handler + routing + validation together, DB queries against a real (local/test) database, service with its real store. Choose this when the risk is in the wiring, not the logic.
  • E2E — full user flows through a browser. Only for critical paths (signup, checkout) that unit/integration can't verify. Defer to the repo's e2e skill if it has one, else e2e-playwright from this catalog; don't write ad-hoc Playwright here.

Testing a pure function through a browser test, or a routing bug with a unit test that bypasses the router, are both wrong — match the level to where the bug would live.

Step 3: Write the tests

Rules (all stacks)

  • Test behavior, not implementation. Assert on outputs, state changes, and responses — not on "method X was called with Y" unless the call is the contract (e.g., "sends an email").
  • Name tests by behavior: TestParseAmount_RejectsNegative, it("returns 404 when the user does not exist") — not test1 or testHandleUser.
  • Each test independent: own setup, own data, no reliance on execution order or state left by another test. Parallel-safe where the framework supports it.
  • No snapshot tests for logic. Snapshots are acceptable only for genuinely serialized output (a generated config file); for behavior, assert specific fields.
  • Cover the happy path, the interesting failure paths (validation, not-found, permission), and boundary values. Skip permutations that exercise the same branch.
  • Don't test the framework or the library — test your code's use of it.

Go

Table-driven tests with named cases and t.Run subtests — follow the go-service skill's conventions (test struct, t.Fatalf for preconditions, t.Errorf for assertions, t.Parallel() where safe). For handlers, use httptest.NewRequest + httptest.NewRecorder against the handler or router. Hand-write small fakes against consumer-side interfaces; no mock frameworks. Use t.Cleanup for teardown and t.TempDir for filesystem tests.

TypeScript (vitest)

describe per unit, it per behavior. Prefer dependency injection over vi.mock: if a function takes its collaborators as arguments, pass fakes; reach for vi.mock only for module boundaries you can't inject (and reset with vi.restoreAllMocks in afterEach). Use vi.useFakeTimers() for time-dependent code, expect(...).rejects.toThrow for async failures. Async tests must await — a floating promise makes the test pass vacuously.

React / Solid components (testing-library)

Render, interact via userEvent, assert on what the user sees:

  • Query by role/label/text (getByRole('button', { name: /save/i })), never by class name or test-id unless there's no accessible handle.
  • await user.click(...) then assert with findBy*/waitFor for async updates.
  • Test the component's contract: given props/state, the right thing renders; on interaction, the right callback fires or the right UI appears. Do not assert on internal state or hook internals.
  • Solid: same API via @solidjs/testing-library; remember effects are synchronous but resource-driven UI still needs findBy*.

E2E

Pointer only: identify the 1–3 critical flows worth E2E and defer to the repo's e2e skill (or e2e-playwright from this catalog) for authoring (Playwright 1.4x, web-first assertions, no fixed sleeps).

Step 4: Run and report

Run exactly what you wrote first (go test ./pkg/... -run TestX -v; bunx vitest run path/to/file.test.ts — match the repo's package runner: bunx/pnpm/npx), then the broader suite if it's cheap. Then report:

  • What passed, what failed, and why — verbatim failure output for anything red.
  • If a test fails because it caught a real bug in the code under test, say so and fix the code (or flag it), not the test.
  • Never weaken an assertion, add a skip, or loosen a matcher just to get green. Never report green without having run the tests.

Home - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-13 22:11
浙ICP备14020137号-1 $Map of visitor$