geneseed 4.10.0 → 4.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +106 -0
- package/README.md +5 -4
- package/SHIPPED.md +1 -1
- package/adapters/opencode/plugins/geneseed-guard.js +16 -1
- package/adapters/opencode/plugins/geneseed-learn.js +28 -12
- package/adapters/opencode/plugins/geneseed-workflow.js +19 -2
- package/docs/concepts/kits.md +14 -2
- package/docs/concepts/skills.md +1 -1
- package/docs/extending.md +3 -4
- package/docs/guides/install-bob.md +3 -1
- package/docs/guides/run-anywhere.md +2 -2
- package/docs/guides/upgrade.md +2 -2
- package/docs/reference/troubleshoot-install.md +1 -1
- package/docs/web-ui.md +6 -1
- package/harness.config.json +1 -1
- package/js/build/emit-claude.mjs +4 -2
- package/js/build/stubs.mjs +13 -0
- package/js/hosts/link.mjs +88 -1
- package/js/inspect/checks-build.mjs +8 -2
- package/js/inspect/cost.mjs +1 -1
- package/js/inspect/diff.mjs +53 -7
- package/js/inspect/inventory.mjs +1 -0
- package/js/lib/prompt.mjs +19 -2
- package/js/maintain/setup.mjs +92 -28
- package/js/maintain/update.mjs +2 -2
- package/js/web/actions.mjs +8 -0
- package/js/web/api.mjs +39 -17
- package/js/web/catalog.mjs +17 -2
- package/js/web/handler.mjs +1 -0
- package/js/web/server.mjs +11 -5
- package/js/web/state.mjs +38 -3
- package/package.json +1 -1
- package/registry.json +28 -0
- package/src/AGENT.md.tmpl +5 -5
- package/src/agents/_self-improvement.md +11 -0
- package/src/agents/_template.md +1 -8
- package/src/agents/advocate.md +1 -8
- package/src/agents/architect.md +1 -8
- package/src/agents/developer.md +1 -8
- package/src/agents/devops-engineer.md +1 -9
- package/src/agents/docker-expert.md +1 -9
- package/src/agents/docs.md +1 -8
- package/src/agents/empiricist.md +1 -8
- package/src/agents/explorer.md +1 -8
- package/src/agents/framer.md +1 -8
- package/src/agents/historian.md +1 -8
- package/src/agents/kubernetes-specialist.md +1 -9
- package/src/agents/memory-curator.md +1 -8
- package/src/agents/operator.md +1 -8
- package/src/agents/performance.md +1 -8
- package/src/agents/pragmatist.md +1 -8
- package/src/agents/react-engineer.md +38 -0
- package/src/agents/react-reviewer.md +42 -0
- package/src/agents/researcher.md +5 -10
- package/src/agents/reviewer.md +1 -8
- package/src/agents/security.md +1 -8
- package/src/agents/skeptic.md +1 -8
- package/src/agents/spring-boot-engineer.md +1 -9
- package/src/agents/spring-reviewer.md +1 -9
- package/src/agents/spring-security.md +1 -9
- package/src/agents/steward.md +1 -8
- package/src/agents/tester.md +1 -8
- package/src/agents/user-advocate.md +1 -8
- package/src/agents/visionary.md +1 -8
- package/src/doctrines/comms.md +21 -0
- package/src/kits/react/rules.md +13 -0
- package/src/kits/react.json +18 -0
- package/src/licenses/everything-claude-code.txt +21 -0
- package/src/skills/_self-improvement.md +22 -5
- package/src/skills/brainstorm.md +7 -2
- package/src/skills/codebase-design.md +6 -2
- package/src/skills/debug.md +1 -1
- package/src/skills/develop.md +4 -2
- package/src/skills/handoff.md +1 -1
- package/src/skills/parallel-agents.md +3 -1
- package/src/skills/plan.md +5 -2
- package/src/skills/prototype.md +4 -2
- package/src/skills/react/a11y.md +33 -0
- package/src/skills/react/vite.md +35 -0
- package/src/skills/react/webpack.md +40 -0
- package/src/skills/react-testing.md +68 -0
- package/src/skills/react.md +63 -0
- package/src/skills/research.md +4 -2
- package/src/skills/rule.md +4 -2
- package/src/skills/ship.md +6 -4
- package/src/skills/skill-forge.md +10 -5
- package/src/skills/wayfinder.md +6 -2
- package/src/skills/wiki.md +18 -5
- package/src/upstreams.json +7 -0
- package/themes/_TEMPLATE.json +5 -0
- package/themes/biker.json +5 -0
- package/themes/commentator.json +5 -0
- package/themes/cyberpunk.json +5 -0
- package/themes/gamer.json +5 -0
- package/themes/imperial.json +5 -0
- package/themes/joker.json +5 -0
- package/themes/marvin.json +5 -0
- package/themes/mean.json +5 -0
- package/themes/military.json +5 -0
- package/themes/neutral.json +5 -0
- package/themes/pirate.json +5 -0
- package/themes/sports.json +5 -0
- package/themes/verstappen.json +5 -0
- package/themes/wizard.json +5 -0
- package/web/dist/assets/Activity-M5qj6CxJ.js +1 -0
- package/web/dist/assets/ActivityDetail-DVCdNy73.js +1 -0
- package/web/dist/assets/Dashboard-B1rpgTz-.js +2 -0
- package/web/dist/assets/{Docs-DLVckkew.js → Docs-D-EixVuX.js} +3 -3
- package/web/dist/assets/FilterInput-CZREvrjX.js +1 -0
- package/web/dist/assets/GreenhouseView-BvA4t12P.js +2 -0
- package/web/dist/assets/Installs-DP4WjTpD.js +3 -0
- package/web/dist/assets/JournalView-hf2eO133.js +1 -0
- package/web/dist/assets/KitApply-aORiqjFC.js +1 -0
- package/web/dist/assets/Kits-DpIEozdv.js +1 -0
- package/web/dist/assets/{Laws-BkKnZOBI.js → Laws-cM_4CG9i.js} +2 -2
- package/web/dist/assets/Library-I1zEH3UW.js +1 -0
- package/web/dist/assets/Loops-CDa_mxP9.js +2 -0
- package/web/dist/assets/{Markdown-iHvBrpRN.js → Markdown-zaXXXHz9.js} +13 -13
- package/web/dist/assets/OperatorHudView-CMf1DQMB.js +2 -0
- package/web/dist/assets/Personal-BqU9Pzt1.js +1 -0
- package/web/dist/assets/Tabs-JZ2FQBcz.js +1 -0
- package/web/dist/assets/activity-Jw8XcPiP.js +1 -0
- package/web/dist/assets/{drawable-CgYi0Dtg.js → drawable-svc6-2Gp.js} +1 -1
- package/web/dist/assets/index-CZFrNe4N.js +2 -0
- package/web/dist/assets/{index-BCJz4_8C.css → index-jYlWihN-.css} +1 -1
- package/web/dist/assets/{react-BOF6yL40.js → react-DlYQp10C.js} +1 -1
- package/web/dist/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/web/dist/assets/sections-ChwaobfW.js +1 -0
- package/web/dist/assets/usePoll-bDFN-Hr6.js +1 -0
- package/web/dist/index.html +5 -4
- package/web/src/pages/Laws.jsx +5 -0
- package/web/dist/assets/Activity-BjyJaf8e.js +0 -1
- package/web/dist/assets/ActivityDetail-Bo9nRDNV.js +0 -1
- package/web/dist/assets/Dashboard-BQJGU7vE.js +0 -2
- package/web/dist/assets/FilterInput-zLFXoSt6.js +0 -1
- package/web/dist/assets/GreenhouseView--DML7CW3.js +0 -2
- package/web/dist/assets/Installs-CxCiln1F.js +0 -3
- package/web/dist/assets/JournalView-ymgZleHi.js +0 -1
- package/web/dist/assets/Library-C8ercIZv.js +0 -1
- package/web/dist/assets/Loops-C95zhbFl.js +0 -2
- package/web/dist/assets/OperatorHudView-B9qwc3w3.js +0 -2
- package/web/dist/assets/Personal-DyR72AF-.js +0 -1
- package/web/dist/assets/Tabs-ChCr_HqV.js +0 -1
- package/web/dist/assets/activity-DvPxoS4Y.js +0 -1
- package/web/dist/assets/index-B32EvfDT.js +0 -2
- package/web/dist/assets/sections-BET3c1WT.js +0 -1
- package/web/dist/assets/usePoll-NSTzLOF4.js +0 -1
package/src/agents/skeptic.md
CHANGED
|
@@ -39,11 +39,4 @@ independently.)*
|
|
|
39
39
|
contract above. Never mechanical proof — this seat runs no commands, so the
|
|
40
40
|
suite and lint results come from the reviewer or tester, not from here.
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
If this spec misled you — an input you needed but were not given, a boundary
|
|
45
|
-
that proved wrong, a step you could not execute — end your report with one line:
|
|
46
|
-
`spec-feedback: <what failed — the one-line fix>`. Omit it when there is no
|
|
47
|
-
friction. The caller weighs the feedback, folds a real flaw back into this file
|
|
48
|
-
with the user's assent, and records it to {{MEMORY}} only if it clears
|
|
49
|
-
{{DOCTRINE:persist-insight}}'s bar — most reports carry no feedback at all.
|
|
42
|
+
<!-- INCLUDE: agents/_self-improvement.md -->
|
|
@@ -37,12 +37,4 @@ Implements Spring Boot 4 / Java 21+ features, following the spring-boot, spring-
|
|
|
37
37
|
- Files changed, a one-line summary, and the test command with its result.
|
|
38
38
|
- If the task cannot be done as given, report the blocker instead of guessing.
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
If this spec misled you — an input you needed but were not given, a boundary
|
|
43
|
-
that proved wrong, a step you could not execute — end your report with one line:
|
|
44
|
-
`spec-feedback: <what failed — the one-line fix>`. Omit it when there is no
|
|
45
|
-
friction. The caller weighs the feedback, folds a real flaw back into this file
|
|
46
|
-
with the user's assent, and records it to {{MEMORY}} only if it clears
|
|
47
|
-
{{DOCTRINE:persist-insight}}'s bar — most reports carry no feedback at all.
|
|
48
|
-
|
|
40
|
+
<!-- INCLUDE: agents/_self-improvement.md -->
|
|
@@ -38,12 +38,4 @@ Spring-specific review only. Generic correctness, naming and structure belong to
|
|
|
38
38
|
- Findings as Conventional Comments, `label (decoration): file:line — problem — suggested fix`, most serious first; then a **Set aside:** list (or `none`) and a one-line verdict: any blocking → block, any if-minor and nothing blocking → fix-then-ship, otherwise ship.
|
|
39
39
|
- Name any check that was impossible instead of issuing a verdict on partial evidence.
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
If this spec misled you — an input you needed but were not given, a boundary
|
|
44
|
-
that proved wrong, a step you could not execute — end your report with one line:
|
|
45
|
-
`spec-feedback: <what failed — the one-line fix>`. Omit it when there is no
|
|
46
|
-
friction. The caller weighs the feedback, folds a real flaw back into this file
|
|
47
|
-
with the user's assent, and records it to {{MEMORY}} only if it clears
|
|
48
|
-
{{DOCTRINE:persist-insight}}'s bar — most reports carry no feedback at all.
|
|
49
|
-
|
|
41
|
+
<!-- INCLUDE: agents/_self-improvement.md -->
|
|
@@ -39,12 +39,4 @@ Spring Security 7 audit only. The generic audit (injection, secrets, dependencie
|
|
|
39
39
|
- Findings by severity (critical, high, medium, low), each with `file:line`, the risk and a fix; then a one-line verdict.
|
|
40
40
|
- Name any check that was impossible instead of issuing a verdict on partial evidence.
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
If this spec misled you — an input you needed but were not given, a boundary
|
|
45
|
-
that proved wrong, a step you could not execute — end your report with one line:
|
|
46
|
-
`spec-feedback: <what failed — the one-line fix>`. Omit it when there is no
|
|
47
|
-
friction. The caller weighs the feedback, folds a real flaw back into this file
|
|
48
|
-
with the user's assent, and records it to {{MEMORY}} only if it clears
|
|
49
|
-
{{DOCTRINE:persist-insight}}'s bar — most reports carry no feedback at all.
|
|
50
|
-
|
|
42
|
+
<!-- INCLUDE: agents/_self-improvement.md -->
|
package/src/agents/steward.md
CHANGED
|
@@ -26,11 +26,4 @@
|
|
|
26
26
|
- A long-term verdict: the structural benefits and risks, the debt this incurs or retires, how reversible it is, and a one-line keep-it-healthy recommendation with the trade-off it accepts.
|
|
27
27
|
- If the change is too small or too reversible to carry long-term stakes, say so and stand down — inflating stakes to justify the seat is its own kind of debt.
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
If this spec misled you — an input you needed but were not given, a boundary
|
|
32
|
-
that proved wrong, a step you could not execute — end your report with one line:
|
|
33
|
-
`spec-feedback: <what failed — the one-line fix>`. Omit it when there is no
|
|
34
|
-
friction. The caller weighs the feedback, folds a real flaw back into this file
|
|
35
|
-
with the user's assent, and records it to {{MEMORY}} only if it clears
|
|
36
|
-
{{DOCTRINE:persist-insight}}'s bar — most reports carry no feedback at all.
|
|
29
|
+
<!-- INCLUDE: agents/_self-improvement.md -->
|
package/src/agents/tester.md
CHANGED
|
@@ -48,11 +48,4 @@ independently.)*
|
|
|
48
48
|
On failure, findings go back to the developer seat; when the fresh
|
|
49
49
|
developer fails too, the pipeline stops and reports instead of looping again.
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
If this spec misled you — an input you needed but were not given, a boundary
|
|
54
|
-
that proved wrong, a step you could not execute — end your report with one line:
|
|
55
|
-
`spec-feedback: <what failed — the one-line fix>`. Omit it when there is no
|
|
56
|
-
friction. The caller weighs the feedback, folds a real flaw back into this file
|
|
57
|
-
with the user's assent, and records it to {{MEMORY}} only if it clears
|
|
58
|
-
{{DOCTRINE:persist-insight}}'s bar — most reports carry no feedback at all.
|
|
51
|
+
<!-- INCLUDE: agents/_self-improvement.md -->
|
|
@@ -39,11 +39,4 @@ independently.)*
|
|
|
39
39
|
- **Delivers:** the consumer's verdict, same shape as its own output contract
|
|
40
40
|
above.
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
If this spec misled you — an input you needed but were not given, a boundary
|
|
45
|
-
that proved wrong, a step you could not execute — end your report with one line:
|
|
46
|
-
`spec-feedback: <what failed — the one-line fix>`. Omit it when there is no
|
|
47
|
-
friction. The caller weighs the feedback, folds a real flaw back into this file
|
|
48
|
-
with the user's assent, and records it to {{MEMORY}} only if it clears
|
|
49
|
-
{{DOCTRINE:persist-insight}}'s bar — most reports carry no feedback at all.
|
|
42
|
+
<!-- INCLUDE: agents/_self-improvement.md -->
|
package/src/agents/visionary.md
CHANGED
|
@@ -26,11 +26,4 @@
|
|
|
26
26
|
- The bold case: the transformative upside in a line, what the motion could become if pushed, the capability it would unlock, and the single bet it depends on. No timid hedging.
|
|
27
27
|
- If the motion genuinely has no bigger version — the ambitious form is just the same thing, larger — say so; a forced 10× pitch is timidity wearing a costume.
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
If this spec misled you — an input you needed but were not given, a boundary
|
|
32
|
-
that proved wrong, a step you could not execute — end your report with one line:
|
|
33
|
-
`spec-feedback: <what failed — the one-line fix>`. Omit it when there is no
|
|
34
|
-
friction. The caller weighs the feedback, folds a real flaw back into this file
|
|
35
|
-
with the user's assent, and records it to {{MEMORY}} only if it clears
|
|
36
|
-
{{DOCTRINE:persist-insight}}'s bar — most reports carry no feedback at all.
|
|
29
|
+
<!-- INCLUDE: agents/_self-improvement.md -->
|
package/src/doctrines/comms.md
CHANGED
|
@@ -70,3 +70,24 @@ interfaces first. Genuine forks only, never naming or formatting; trivial work o
|
|
|
70
70
|
Where {{LAW:echo-the-intent}} checks the goal before, this exposes the choices made during —
|
|
71
71
|
never a call it says to ask about.
|
|
72
72
|
<!-- LEAN:end -->
|
|
73
|
+
|
|
74
|
+
### {{DOCTRINE:simplified-technical-english}} Simplified Technical English
|
|
75
|
+
<!-- LEAN:begin -->
|
|
76
|
+
Write every prose reply and report in ASD-STE100 Simplified Technical English, the
|
|
77
|
+
controlled language of aerospace maintenance: a tired reader, or one reading a second
|
|
78
|
+
language, gets one meaning on the first read. Code, commands, paths, identifiers and quoted
|
|
79
|
+
output stay as they are. One topic per sentence: at most 20 words in an instruction, 25 in
|
|
80
|
+
a description, six sentences per paragraph. Write an instruction in the imperative, one
|
|
81
|
+
action per sentence, condition first (`If the test fails, read the log.`); a warning comes
|
|
82
|
+
before its step. Use the active voice and simple tenses, no -ing forms, no dropped
|
|
83
|
+
articles. Use one word per meaning, every time: `use`, not `utilize`; `stop`, not
|
|
84
|
+
`terminate`. Project names are technical names and stay. Keep noun clusters to three words.
|
|
85
|
+
In another language, answer in it ({{ONT_CONDUCT}}) and keep these sentence rules; the
|
|
86
|
+
theme keeps its voice, and this rule governs the sentences that carry the content.
|
|
87
|
+
<!-- LEAN:else -->
|
|
88
|
+
Write every prose reply and report in ASD-STE100 Simplified Technical English; code,
|
|
89
|
+
commands, paths and quoted output stay as they are. One topic per sentence: 20 words at
|
|
90
|
+
most in an instruction, 25 in a description. Instructions: imperative, one action each,
|
|
91
|
+
condition first. Active voice, no -ing forms, no dropped articles, one word per meaning
|
|
92
|
+
(`use`, not `utilize`). In another language, keep it and these rules.
|
|
93
|
+
<!-- LEAN:end -->
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
### React kit
|
|
2
|
+
|
|
3
|
+
Applies to React 18 or 19 apps built with Vite or webpack, in TypeScript or JavaScript, tested with Jest and React Testing Library. Read `package.json` first and use only the APIs its React major provides.
|
|
4
|
+
|
|
5
|
+
- Function components and hooks only. No new class components, except an error boundary where the project has no library for it.
|
|
6
|
+
- Hooks at the top level only. Never disable `react-hooks/rules-of-hooks` or `react-hooks/exhaustive-deps` to make a warning go away.
|
|
7
|
+
- Derive values during render; never copy props or state into state through an effect. Every effect that subscribes cleans up.
|
|
8
|
+
- Server data goes through the project's server-state library, with loading, error and empty states.
|
|
9
|
+
- Keep each folder's language: TypeScript stays typed, with no `any` or `@ts-ignore` to get green; JavaScript stays JavaScript.
|
|
10
|
+
- Env values the bundler inlines (`import.meta.env.VITE_*`, webpack `DefinePlugin`) are public. No secret there, and no session token in `localStorage`.
|
|
11
|
+
- Interactive elements are native (`<button>`, `<a href>`, `<input>` with a label) and keyboard-reachable.
|
|
12
|
+
- Tests query by role or label and act with `userEvent`; the network is mocked with MSW, not by mocking the fetch client.
|
|
13
|
+
- Match the project's existing styling, state library and CI before introducing another.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "React on Vite or webpack, in TypeScript or JavaScript, tested with Jest and Testing Library: components, hooks, state, data fetching, accessibility, build and test failures, review.",
|
|
3
|
+
"skills": ["react", "react-testing"],
|
|
4
|
+
"agents": ["react-engineer", "react-reviewer"],
|
|
5
|
+
"rules": "kits/react/rules.md",
|
|
6
|
+
"rulesWordBudget": 300,
|
|
7
|
+
"banned": ["ReactDOM.render(", "findDOMNode", "enzyme", "react-test-renderer", "@testing-library/react-hooks"],
|
|
8
|
+
"catalogue": {
|
|
9
|
+
"skills": [
|
|
10
|
+
"| [react]({{DIR_SKILLS}}/react.md) | building or changing React components, hooks, state or data fetching in a Vite or webpack app; bundler config, client-side routing, env variables and build failures; accessibility |",
|
|
11
|
+
"| [react-testing]({{DIR_SKILLS}}/react-testing.md) | writing or fixing React tests with Jest and Testing Library, MSW network mocks, jest-axe; making Jest run against a Vite or webpack project |"
|
|
12
|
+
],
|
|
13
|
+
"agents": [
|
|
14
|
+
"| [react-engineer]({{DIR_AGENTS}}/react-engineer.md) | a React component, page, hook or form must be implemented, or a broken Vite or webpack build or Jest run made green |",
|
|
15
|
+
"| [react-reviewer]({{DIR_AGENTS}}/react-reviewer.md) | a React change needs a framework-aware review: hooks, state, data fetching, accessibility, React security, tests |"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Affaan Mustafa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
## Self-improvement
|
|
2
2
|
|
|
3
3
|
<!-- LEAN:begin -->
|
|
4
|
+
This {{SKILL}} keeps its own notes in `{{DIR_NOTEBOOK}}/skill-notes/<name>.md`,
|
|
5
|
+
`<name>` being this {{SKILL}}'s name. When that file exists, read it before the
|
|
6
|
+
first step — where it disagrees with this file, the notes win. They are yours to
|
|
7
|
+
write, and no rebuild touches them.
|
|
8
|
+
|
|
4
9
|
Close each run with one beat of reflection on the {{SKILL}} itself:
|
|
5
10
|
- A step misled, a needed step was missing, or the trigger fired wrongly — that
|
|
6
|
-
is a flaw in this file.
|
|
7
|
-
done-when)
|
|
11
|
+
is a flaw in this file. Write the exact correction (trigger, procedure, or
|
|
12
|
+
done-when) into the notes file, with the user's assent ({{LAW:one-intent-one-act}}), as one line:
|
|
13
|
+
`- [skill|general] <correction> — seen: <what happened, against what you expected> (<date>)`.
|
|
14
|
+
`seen:` is the evidence the correction is later judged by; `general` marks one
|
|
15
|
+
that would fix other {{SKILLS}} too. Never
|
|
16
|
+
edit this file: it is a rendered copy, a rebuild overwrites it, and the doctor
|
|
17
|
+
reports the edit as drift. `geneseed diff` carries the notes back to the source.
|
|
18
|
+
- Keep the notes sharp: amend or delete a line before adding one — a line with no
|
|
19
|
+
`seen:`, or whose `seen:` no longer happens, goes first — and prune past about
|
|
20
|
+
twenty lines.
|
|
8
21
|
- A lesson that is *not* a flaw in this file goes to {{MEMORY}} only if it
|
|
9
22
|
clears {{DOCTRINE:persist-insight}}'s bar: it would change how a future session behaves, and a
|
|
10
23
|
fresh read of the repo would not re-derive it. Update an existing memory over
|
|
@@ -13,7 +26,11 @@ Close each run with one beat of reflection on the {{SKILL}} itself:
|
|
|
13
26
|
runs end here.
|
|
14
27
|
<!-- LEAN:else -->
|
|
15
28
|
One beat of reflection on this {{SKILL}}: a step that misled, a missing step, or a
|
|
16
|
-
wrong trigger is a flaw in this file —
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
wrong trigger is a flaw in this file — write the exact correction, with the user's
|
|
30
|
+
assent ({{LAW:one-intent-one-act}}), into `{{DIR_NOTEBOOK}}/skill-notes/<name>.md` (`<name>` is this {{SKILL}}'s
|
|
31
|
+
name) as `- [skill|general] <correction> — seen: <what happened vs expected> (<date>)`,
|
|
32
|
+
never into this rendered file, which a rebuild overwrites. Read that notes
|
|
33
|
+
file before the first step when it exists; it wins where it disagrees. Keep it short.
|
|
34
|
+
A lesson that is not about this file goes to {{MEMORY}} only if it clears
|
|
35
|
+
{{DOCTRINE:persist-insight}}'s bar. Nothing learned — move on.
|
|
19
36
|
<!-- LEAN:end -->
|
package/src/skills/brainstorm.md
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
{{CREDIT:mattpocock-skills:skills/productivity/grilling/SKILL.md}}
|
|
9
9
|
|
|
10
|
+
{{CREDIT:mattpocock-skills:skills/productivity/to-questionnaire/SKILL.md}}
|
|
11
|
+
|
|
10
12
|
**Trigger:** a new feature, behaviour change, or project arrives without a design, or the
|
|
11
13
|
user says "brainstorm", "interview me" or "grill me". Also when goal, scope or success
|
|
12
14
|
criteria are unstated ("let's design this", "clarify this first", "stress-test this plan"),
|
|
@@ -27,8 +29,11 @@ the design is skipped.
|
|
|
27
29
|
libraries) the user wants to own. Existing work decides by default
|
|
28
30
|
({{DOCTRINE:respect-conventions}}); a choice you take goes in the ledger as **your
|
|
29
31
|
call**, never as agreed. Stop when each is unambiguous. Facts are yours to find (read
|
|
30
|
-
the code, dispatch a subagent), never the user's
|
|
31
|
-
|
|
32
|
+
the code, dispatch a subagent), never the user's; a pending lookup holds back only the
|
|
33
|
+
questions that depend on it. A decision someone else owns gets a drafted
|
|
34
|
+
`questionnaire-<slug>.md` for them — ask the user only who and what they need back. Most
|
|
35
|
+
important first (async gets one pass), one idea per question with an empty answer stub
|
|
36
|
+
under it, and say "I don't know" is a useful answer.
|
|
32
37
|
3. **Ledger the decisions.** Name every KEY DECISION the answers imply or leave open —
|
|
33
38
|
direction chosen, trade-offs accepted, load-bearing constraints, assumptions,
|
|
34
39
|
non-goals. Surface each silent assumption as a decision to ratify, not a settled
|
|
@@ -16,7 +16,8 @@ a design talk that keeps stumbling over ambiguous terms, or another {{SKILL}} ne
|
|
|
16
16
|
`GLOSSARY-MAP.md` means several contexts — find the one in play) and the
|
|
17
17
|
area's ADRs in `docs/adr/`; use their terms verbatim in code, tests, prose.
|
|
18
18
|
When the user says how something works, check the code agrees; surface any
|
|
19
|
-
contradiction.
|
|
19
|
+
contradiction. An ADR is settled: a proposal that contradicts one says so,
|
|
20
|
+
and why the friction justifies reopening it — never silently.
|
|
20
21
|
2. Use this vocabulary exactly — **module** (anything with an interface and an
|
|
21
22
|
implementation, any scale), **interface** (all a caller must know: types,
|
|
22
23
|
invariants, ordering, error modes, performance), **depth** (behaviour per
|
|
@@ -25,7 +26,10 @@ a design talk that keeps stumbling over ambiguous terms, or another {{SKILL}} ne
|
|
|
25
26
|
"component", "service", "API", "boundary".
|
|
26
27
|
3. Aim for **deep modules** — much behaviour behind a small interface: callers
|
|
27
28
|
get leverage, maintainers get locality. To find what to deepen, start from
|
|
28
|
-
`git log` hot spots — what keeps changing.
|
|
29
|
+
`git log` hot spots — what keeps changing. Design a new or reshaped interface
|
|
30
|
+
twice before choosing: 2–3 radically different shapes (in parallel subagents
|
|
31
|
+
where the host runs them), compared on depth, locality and seam placement;
|
|
32
|
+
recommend one — a hybrid if parts combine — never a menu.
|
|
29
33
|
4. Seams sparingly: the interface is the test surface. Internal seams for the
|
|
30
34
|
module's own tests are fine but never exposed; a test that must reach past
|
|
31
35
|
the interface means the wrong shape. One adapter is a hypothesis; a second
|
package/src/skills/debug.md
CHANGED
|
@@ -28,6 +28,6 @@ faster than thrashing; do not trade it away under pressure.
|
|
|
28
28
|
**CI branch (a red run)** → read [debug/ci.md](debug/ci.md) and follow it.
|
|
29
29
|
|
|
30
30
|
## Done when
|
|
31
|
-
- The failure is reproduced by a command that went red on it, root-caused, fixed at the cause, and that command passes with no new breakage; every tagged probe is gone.
|
|
31
|
+
- The failure is reproduced by a command that went red on it, root-caused, fixed at the cause, and that command passes with no new breakage; every tagged probe is gone, and the step-1 repro is deleted or kept as the regression test.
|
|
32
32
|
|
|
33
33
|
<!-- INCLUDE: skills/_self-improvement.md -->
|
package/src/skills/develop.md
CHANGED
|
@@ -33,7 +33,7 @@ case where the seam is only known once the change is made.
|
|
|
33
33
|
change ({{DOCTRINE:cover-and-verify}}), then break the implementation on purpose once to
|
|
34
34
|
see the test go red before trusting it.
|
|
35
35
|
4. Write the minimum code that makes it pass; add nothing the test doesn't demand.
|
|
36
|
-
5. Run the *affected* tests and read the output ({{LAW:verify-before-asserting}}); on failure fix the
|
|
36
|
+
5. Run the *affected* tests, and the typecheck where the project has one, and read the output ({{LAW:verify-before-asserting}}); on failure fix the
|
|
37
37
|
cause, never mask it ({{LAW:cure-the-cause}}). Dispatch the
|
|
38
38
|
[tester {{AGENT}}](../{{DIR_AGENTS}}/tester.md) for heavier or unfamiliar coverage,
|
|
39
39
|
or when the blast radius is unclear.
|
|
@@ -50,7 +50,9 @@ case where the seam is only known once the change is made.
|
|
|
50
50
|
## Anti-patterns — name the one you catch
|
|
51
51
|
- **Implementation-coupled** — mocks an internal collaborator, tests a private method,
|
|
52
52
|
or checks through a side channel (querying the database instead of the interface).
|
|
53
|
-
The tell: it breaks on a refactor that changed no behaviour.
|
|
53
|
+
The tell: it breaks on a refactor that changed no behaviour. Mock only at system
|
|
54
|
+
boundaries — external APIs, time, randomness, sometimes the database or filesystem —
|
|
55
|
+
passed in rather than built inside; never a module you control.
|
|
54
56
|
- **Tautological** — the expected value is recomputed the way the code computes it, so
|
|
55
57
|
the test passes by construction and can never disagree with the code.
|
|
56
58
|
- **Horizontal slicing** — all the tests first, then all the code: the tests pin an
|
package/src/skills/handoff.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
2. Record open decisions, dead ends already ruled out, blockers, and any irreversible changes already made ({{DOCTRINE:plan-before-acting}}) — so the next agent neither re-derives nor repeats them.
|
|
12
12
|
3. Promote any durable fact or correction learned this session into {{MEMORY}} (§5), not just the worklog.
|
|
13
13
|
4. Point to the live artifacts: branch name, changed files, how to run the tests, and where any failure reproduces. Link specs, plans, ADRs, issues and commits by path or URL — never copy them in.
|
|
14
|
-
5. Put a one-line "resume here" pointer at the top so a fresh context picks up in a single read ({{DOCTRINE:context-economy}}), and list the {{SKILL}}s the next agent should load.
|
|
14
|
+
5. Put a one-line "resume here" pointer at the top so a fresh context picks up in a single read ({{DOCTRINE:context-economy}}), and list the {{SKILL}}s the next agent should load. When the user names what the next session is for, write toward that focus.
|
|
15
15
|
6. Redact keys, passwords and PII ({{LAW:sealed-secrets}}).
|
|
16
16
|
7. Verify it: re-read the worklog as a cold reader ({{LAW:verify-before-asserting}}) — goal, progress, next step, and blockers must be answerable from it alone. Fix what isn't.
|
|
17
17
|
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
{{CREDIT:superpowers:skills/subagent-driven-development/SKILL.md}}
|
|
6
6
|
|
|
7
|
+
{{CREDIT:mattpocock-skills:skills/engineering/implement-spec/SKILL.md}}
|
|
8
|
+
|
|
7
9
|
**Trigger:** two or more independent subtasks with no shared state or ordering between them — and a tool that can run subagents. The units run side by side and never see each other's work; when one agent must build on what the previous one produced, that is a relay — use [pipeline](pipeline.md).
|
|
8
10
|
|
|
9
11
|
## Procedure
|
|
@@ -12,7 +14,7 @@
|
|
|
12
14
|
3. Dispatch each unit to its own subagent in one batch, each under a handoff envelope: the unit's goal, the inputs it needs, its **write set** (edit nothing outside it; return rows for a shared file instead of writing it), the observable check that proves it done, its output contract — naming every file it changed — and the inherited constraints (no commit/push — {{DOCTRINE:consent-before-push}} stays with you; no sub-agents of its own — review comes from you; gaps reported, never invented). Hand each unit only the access its goal needs ({{LAW:least-privilege}}). Prefer the read-only [explorer {{AGENT}}](../{{DIR_AGENTS}}/explorer.md) for investigation so the heavy reading stays out of the main context ({{DOCTRINE:context-economy}}). Where no subagent capability exists, run the units sequentially as personas instead, converging the same way.
|
|
13
15
|
4. Keep the main context lean: collect each subagent's distilled result, not its working transcript.
|
|
14
16
|
5. Converge: compare each unit's changed files against its write set and against its siblings' — an edit outside the set, a file two units touched, or a file in a batch's set that never changed is a conflict you resolve before anything else — apply the shared-file rows yourself, then verify the combined outcome. A conflict or ambiguity between the plan, the findings and the code is yours to decide: decide it, record `Ruling: <choice> — <why> — <cost if wrong>` in the worklog, and continue. Stop only for what {{LAW:echo-the-intent}}, {{LAW:deletion-is-deliberate}} or {{DOCTRINE:consent-before-push}} names; every ruling goes in the final report ({{DOCTRINE:declare-the-judgment-calls}}).
|
|
15
|
-
6. **A plan with blocking edges.** To build a [plan](plan.md) file's slices — each with its `Blocked by:` line — in one run, dispatch every unblocked slice on its own branch off one integration branch, merge each into it as it returns (each merge is a commit — {{DOCTRINE:consent-before-push}} stays with you), and recompute the unblocked set from the plan after every merge — newly freed slices go out at once. When the plan names a `Spec:`, every slice reads it once; the spec outranks the plan where they conflict.
|
|
17
|
+
6. **A plan with blocking edges.** To build a [plan](plan.md) file's slices — each with its `Blocked by:` line — in one run, dispatch every unblocked slice on its own branch off one integration branch, merge each into it as it returns (each merge is a commit — {{DOCTRINE:consent-before-push}} stays with you), and recompute the unblocked set from the plan after every merge — newly freed slices go out at once. When the plan names a `Spec:`, every slice reads it once; the spec outranks the plan where they conflict. Each slice branches off the integration tip at its own dispatch (its BASE) and merges the current tip back into its branch before returning, so a conflict with a sibling resolves on the slice's branch; before re-running the proof, confirm the branch descends from BASE and the diff is non-empty — an empty diff is a failure, not a clean result. Never diff against `HEAD~1`. When the plan is exhausted, review the integration branch whole with [geneseed-code-review](geneseed-code-review.md) before reporting.
|
|
16
18
|
|
|
17
19
|
## Done when
|
|
18
20
|
- Independent units ran concurrently, each returned a distilled result, and the reconciled outcome is verified.
|
package/src/skills/plan.md
CHANGED
|
@@ -20,10 +20,13 @@
|
|
|
20
20
|
which the work can be verified and reviewed. Cut the steps as **vertical slices** —
|
|
21
21
|
thin end-to-end pieces, each green and verifiable on its own, never one horizontal
|
|
22
22
|
layer at a time — and give each a `Blocked by:` line naming the slices it waits on
|
|
23
|
-
(`none` when it can start now).
|
|
23
|
+
(`none` when it can start now). Size each slice to finish in one fresh context. When the
|
|
24
|
+
code fights the change, the first slice is a prefactor, behaviour unchanged, that makes
|
|
25
|
+
the change easy. Sequence a wide refactor as expand → migrate
|
|
24
26
|
callers in batches → contract, so every slice leaves the build green. A step records
|
|
25
27
|
decisions, not code: the files, the exact signatures and the spec's values, the test
|
|
26
|
-
that proves it
|
|
28
|
+
that proves it (through an existing seam, as high as possible; a new seam is a decision,
|
|
29
|
+
named as one), and the check command. Write a body only for an algorithm those leave
|
|
27
30
|
open; a plan longer than the code it describes has written the code, and "TBD",
|
|
28
31
|
"handle edge cases" or "add tests" decide nothing. The file's first line names the
|
|
29
32
|
task or branch, then `Spec: <path>` when a spec exists — the spec outranks the plan
|
package/src/skills/prototype.md
CHANGED
|
@@ -20,14 +20,16 @@ real implementation.
|
|
|
20
20
|
state the assumption.
|
|
21
21
|
2. Throwaway from day one, and marked as such: place it near the code it
|
|
22
22
|
prototypes for, but name it so a casual reader sees it is not production.
|
|
23
|
-
No persistence (state lives in memory)
|
|
23
|
+
No persistence (state lives in memory) and no real mutations (a variant that must
|
|
24
|
+
write hits a stub), no tests, no error handling beyond
|
|
24
25
|
what makes it runnable, no abstractions ({{DOCTRINE:smallest-viable-diff}}).
|
|
25
26
|
3. One command to run, using the project's existing task runner — the user
|
|
26
27
|
must be able to start it without thinking.
|
|
27
28
|
4. Surface the full relevant state after every action or variant switch, so
|
|
28
29
|
the user sees exactly what changed.
|
|
29
30
|
5. When the question is answered: fold the validated decision (and a logic
|
|
30
|
-
prototype's pure module) into the real code
|
|
31
|
+
prototype's pure module) into the real code (a winning UI variant is rewritten to production standard, never
|
|
32
|
+
promoted as-is), record the verdict and the
|
|
31
33
|
question it settled (issue comment, ADR, or commit message), park the prototype on a throwaway branch, and keep the
|
|
32
34
|
main branch clean of prototype code.
|
|
33
35
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# {{SKILL}}: react — accessibility
|
|
2
|
+
|
|
3
|
+
{{CREDIT:everything-claude-code:skills/frontend-a11y/SKILL.md}}
|
|
4
|
+
|
|
5
|
+
Accessibility for React components: what to write, and what the reviewer will refuse.
|
|
6
|
+
|
|
7
|
+
## Semantic HTML first
|
|
8
|
+
- A clickable thing is a `<button>` (an action) or an `<a href>` (navigation). `<div onClick>` is not keyboard-reachable and has no role; do not add `role` and `tabIndex` to make it one.
|
|
9
|
+
- One `<main>`, landmarks (`<nav>`, `<header>`, `<footer>`), headings in order without skipped levels.
|
|
10
|
+
- `<img>` always has `alt`: a description for content, `alt=""` for decoration. An icon-only button has `aria-label`.
|
|
11
|
+
|
|
12
|
+
## Forms
|
|
13
|
+
- Every input has a label: `<label htmlFor={id}>` with `useId()` for the id, or `aria-label` when the label is visual only.
|
|
14
|
+
- Required fields carry `required` (or `aria-required`), not only a red asterisk.
|
|
15
|
+
- An error is linked with `aria-describedby`, flags the field `aria-invalid="true"`, and is announced (`role="alert"` on the message). Never signal an error by colour alone.
|
|
16
|
+
- Use a real `<form>` with `onSubmit` so Enter submits; inputs have a `name`.
|
|
17
|
+
|
|
18
|
+
## Dynamic content
|
|
19
|
+
- A status that changes without focus moving (saved, loading, results count) sits in an `aria-live="polite"` region that is present before its text changes.
|
|
20
|
+
- A disclosure (accordion, dropdown) toggles `aria-expanded` on its trigger and points `aria-controls` at the panel.
|
|
21
|
+
|
|
22
|
+
## Keyboard and focus
|
|
23
|
+
- Every interaction works with Tab, Shift+Tab, Enter, Space and Escape. A custom widget (menu, listbox, tabs) follows the WAI-ARIA Authoring Practices pattern for it, arrow keys included; prefer the project's component library over hand-rolling one.
|
|
24
|
+
- A modal moves focus into itself on open, traps it, closes on Escape and returns focus to the trigger on close. The native `<dialog>` with `showModal()` does most of this.
|
|
25
|
+
- On a client-side route change, move focus to the new page's heading or main region.
|
|
26
|
+
- Never remove the focus outline without a visible replacement (`:focus-visible`).
|
|
27
|
+
|
|
28
|
+
## Motion
|
|
29
|
+
Respect `prefers-reduced-motion`: disable or shorten non-essential animation under it.
|
|
30
|
+
|
|
31
|
+
## Checking
|
|
32
|
+
- `eslint-plugin-jsx-a11y` in the lint config.
|
|
33
|
+
- `jest-axe` in component tests for interactive components (react-testing skill). jsdom has no layout, so contrast and focus-visible need a real browser check.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# {{SKILL}}: react — Vite
|
|
2
|
+
|
|
3
|
+
{{CREDIT:everything-claude-code:skills/vite-patterns/SKILL.md}}
|
|
4
|
+
|
|
5
|
+
Configuration, environment variables and build failures for a React app on Vite. Check the Vite major in `package.json` before reaching for an option; config keys move between majors.
|
|
6
|
+
|
|
7
|
+
## Config
|
|
8
|
+
- One `vite.config.ts` (or `.js`) with `defineConfig`. React support is `@vitejs/plugin-react` or `@vitejs/plugin-react-swc`; keep whichever the project has.
|
|
9
|
+
- Path aliases are declared twice: `resolve.alias` in the Vite config and `paths` in `tsconfig.json` / `jsconfig.json` (or the `vite-tsconfig-paths` plugin reads the second). Jest needs a third copy in `moduleNameMapper` (react-testing skill).
|
|
10
|
+
- Dev API calls go through `server.proxy` (`'/api': { target: 'http://localhost:8080', changeOrigin: true }`), not a hard-coded backend URL in the code.
|
|
11
|
+
|
|
12
|
+
## Environment variables
|
|
13
|
+
- Client code reads `import.meta.env.VITE_*`. Only `VITE_`-prefixed variables reach the bundle, and they are inlined at build time: changing one means rebuilding, and every value is public.
|
|
14
|
+
- `process.env` does not exist in client code; do not add a polyfill to make it work.
|
|
15
|
+
- `.env.local` and `.env.*.local` stay out of git. A per-environment value that must change without a rebuild comes from a runtime config file (`/config.json`) fetched at start, not from `VITE_*`.
|
|
16
|
+
- TypeScript: declare the variables in `src/vite-env.d.ts` (`interface ImportMetaEnv { readonly VITE_API_URL: string }`).
|
|
17
|
+
|
|
18
|
+
## Type and lint checks
|
|
19
|
+
`vite build` transpiles but never type-checks. Keep `tsc --noEmit` (or `tsc -b`) in the build script or CI, and ESLint with `eslint-plugin-react-hooks` (`rules-of-hooks`, `exhaustive-deps`) and `eslint-plugin-jsx-a11y`.
|
|
20
|
+
|
|
21
|
+
## Build failures
|
|
22
|
+
Run the project's own `build` script, read the first error, fix only that, rebuild. One error at a time.
|
|
23
|
+
|
|
24
|
+
| Error | Cause | Fix |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `Invalid hook call` | Two copies of React | `npm ls react` must show one; dedupe with `overrides` in `package.json` |
|
|
27
|
+
| `Element type is invalid ... got: undefined` | Default vs named import mismatch | Match the import to the component's export |
|
|
28
|
+
| `Cannot find module 'react'` types (TS) | `@types/react` missing or a different major than `react` | Install the matching `@types/react` and `@types/react-dom` |
|
|
29
|
+
| `Failed to resolve import "@/..."` | Alias in tsconfig but not in Vite | Add it to `resolve.alias` or use `vite-tsconfig-paths` |
|
|
30
|
+
| `require is not defined` / CJS-only dependency errors | CommonJS dependency in the ESM pipeline | Add it to `optimizeDeps.include`; prefer an ESM build of the library |
|
|
31
|
+
| Works in `vite dev`, broken after `vite build` | Dev serves unbundled modules | Reproduce with `vite build && vite preview`, not dev |
|
|
32
|
+
| Blank page or 404 on assets after deploy | App served from a sub-path | Set `base` to that path |
|
|
33
|
+
| Old chunk 404 after a deploy | Browser holds the previous `index.html` | Serve `index.html` with `Cache-Control: no-cache`; hashed assets can stay immutable |
|
|
34
|
+
|
|
35
|
+
Never silence a build or type error with `// @ts-ignore`, `any` or a disabled lint rule; fix the cause or stop and report it.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# {{SKILL}}: react — webpack
|
|
2
|
+
|
|
3
|
+
Configuration, client-side routing, environment variables and build failures for a React app on webpack. Check the webpack major in `package.json` first: webpack 5 removed the Node core-module polyfills and the `process` global that 4 shipped, and most config questions turn on that.
|
|
4
|
+
|
|
5
|
+
## Config
|
|
6
|
+
- The config is `webpack.config.*`, often split into `common`/`dev`/`prod` files joined with `webpack-merge`; edit the file the setting belongs to, not the merged result. Read the `build` and `start` scripts to see which file each loads.
|
|
7
|
+
- JSX and TypeScript go through `babel-loader` (`@babel/preset-react` with `runtime: 'automatic'`, `@babel/preset-typescript`), `ts-loader` or `swc-loader`; keep whichever the project has. A loader rule's `test` must match `.jsx`/`.tsx`, and `resolve.extensions` must list them.
|
|
8
|
+
- Path aliases are declared twice: `resolve.alias` in the webpack config and `paths` in `tsconfig.json` / `jsconfig.json` (or `tsconfig-paths-webpack-plugin` reads the second). Jest needs a third copy in `moduleNameMapper` (react-testing skill).
|
|
9
|
+
|
|
10
|
+
## Client-side routing
|
|
11
|
+
- With `BrowserRouter` (or any history-API router), the dev server needs `devServer.historyApiFallback: true`, or a refresh on `/users/42` is a 404. The production server needs the same fallback to `index.html`; that is server config, not webpack.
|
|
12
|
+
- Set `output.publicPath` to `'/'` (or the deploy sub-path). A relative public path makes chunks load from `/users/main.js` on a nested route.
|
|
13
|
+
- Split per route with `React.lazy(() => import('./pages/Users'))`; webpack turns each dynamic `import()` into its own chunk. Do not add an entry point per route to a single-page app.
|
|
14
|
+
- Dev API calls go through `devServer.proxy`, not a hard-coded backend URL in the code.
|
|
15
|
+
|
|
16
|
+
## Environment variables
|
|
17
|
+
- `process.env.X` in client code is not read at runtime: `DefinePlugin`, `EnvironmentPlugin` or `dotenv-webpack` replaces it with a literal at build time. Changing one means rebuilding, and every value is public. `mode` sets `process.env.NODE_ENV`.
|
|
18
|
+
- On webpack 5 an undefined `process.env.X` is `process is not defined` at runtime. Define the variable; do not add a `process` polyfill through `ProvidePlugin`.
|
|
19
|
+
- `.env.local` stays out of git. A per-environment value that must change without a rebuild comes from a runtime config file (`/config.json`) fetched at start.
|
|
20
|
+
|
|
21
|
+
## Type and lint checks
|
|
22
|
+
`babel-loader`, `swc-loader` and `ts-loader` with `transpileOnly` never type-check. Keep `tsc --noEmit` in the build script or CI (or `fork-ts-checker-webpack-plugin`), and ESLint with `eslint-plugin-react-hooks` and `eslint-plugin-jsx-a11y`.
|
|
23
|
+
|
|
24
|
+
## Build failures
|
|
25
|
+
Run the project's own `build` script, read the first error, fix only that, rebuild. One error at a time.
|
|
26
|
+
|
|
27
|
+
| Error | Cause | Fix |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `Invalid hook call` | Two copies of React | `npm ls react` must show one; dedupe with `overrides`, or `resolve.alias` `react` to one path for a linked package. Module Federation: `shared: { react: { singleton: true }, 'react-dom': { singleton: true } }` |
|
|
30
|
+
| `Module not found: Can't resolve '@/...'` | Alias in tsconfig but not in webpack | Add it to `resolve.alias` |
|
|
31
|
+
| `Can't resolve './Button'` for a `.tsx` file | Extension not resolved | Add `.tsx`/`.jsx` to `resolve.extensions` |
|
|
32
|
+
| `Module parse failed: Unexpected token` on JSX | No loader matched the file | Widen the rule's `test`, or narrow an `exclude` that drops the folder |
|
|
33
|
+
| `BREAKING CHANGE: webpack < 5 used to include polyfills` | A dependency imports a Node core module | Prefer a browser build of the dependency; otherwise `resolve.fallback` with a named polyfill package |
|
|
34
|
+
| `process is not defined` | `process.env.X` not defined at build time | Add it to `DefinePlugin` / `EnvironmentPlugin` |
|
|
35
|
+
| 404 on refresh of a deep link | No history fallback | `devServer.historyApiFallback: true`, and the same fallback on the production server |
|
|
36
|
+
| Blank page on a nested route, chunk 404s | Relative `output.publicPath` | Set `output.publicPath: '/'` or the deploy sub-path |
|
|
37
|
+
| Works with `start`, broken after `build` | Dev and production configs differ | Build with `mode: 'production'` and serve `dist/` with a static server to reproduce |
|
|
38
|
+
| `ChunkLoadError` after a deploy | Browser holds the previous `index.html` | `[contenthash]` in chunk names, and serve `index.html` with `Cache-Control: no-cache` |
|
|
39
|
+
|
|
40
|
+
Never silence a build or type error with `// @ts-ignore`, `any` or a disabled lint rule; fix the cause or stop and report it.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# {{SKILL}}: react-testing
|
|
2
|
+
|
|
3
|
+
> {{DESC_REACT_TESTING}}
|
|
4
|
+
|
|
5
|
+
{{CREDIT:everything-claude-code:skills/react-testing/SKILL.md}}
|
|
6
|
+
|
|
7
|
+
**Trigger:** writing or fixing tests for React components, hooks or pages in a Vite or webpack project tested with Jest and React Testing Library, in TypeScript or JavaScript; or getting Jest to run at all against bundler-shaped code. React-specific; core test discipline lives in the develop skill. End-to-end flows across pages belong to the project's browser tests (Playwright, Cypress), not here.
|
|
8
|
+
|
|
9
|
+
Target stack: Jest, `@testing-library/react`, `@testing-library/user-event`, `@testing-library/jest-dom`, MSW for network mocks, `jest-axe`.
|
|
10
|
+
|
|
11
|
+
## What a test does
|
|
12
|
+
Render the component with the providers it has in production, act through `userEvent` the way a user would, assert what the user sees or what leaves the component (a callback called, a request sent). Never assert on internal state, hook calls, props passed to children, or render counts. Never mock React.
|
|
13
|
+
|
|
14
|
+
## Queries, in this order
|
|
15
|
+
1. `getByRole(..., { name })`, `getByLabelText`: what assistive technology sees. A test that cannot find the button by role has found an accessibility bug.
|
|
16
|
+
2. `getByText`, `getByDisplayValue`, `getByAltText`.
|
|
17
|
+
3. `getByTestId`: last resort.
|
|
18
|
+
|
|
19
|
+
`getBy*` throws when missing; `queryBy*` returns `null` (assert absence); `findBy*` waits (things that appear after async work). No `container.querySelector`.
|
|
20
|
+
|
|
21
|
+
## Interaction and async
|
|
22
|
+
```tsx
|
|
23
|
+
test('saves the email', async () => {
|
|
24
|
+
const user = userEvent.setup();
|
|
25
|
+
const onSave = jest.fn();
|
|
26
|
+
render(<EmailForm onSave={onSave} />);
|
|
27
|
+
|
|
28
|
+
await user.type(screen.getByLabelText('Email'), 'a@example.com');
|
|
29
|
+
await user.click(screen.getByRole('button', { name: /save/i }));
|
|
30
|
+
|
|
31
|
+
expect(onSave).toHaveBeenCalledWith('a@example.com');
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
- `userEvent.setup()` once per test, every call awaited. `fireEvent` only for an event `userEvent` cannot produce.
|
|
35
|
+
- Wait with `findBy*` or `waitFor`; never `setTimeout` or a sleep. With `jest.useFakeTimers()`, pass `userEvent.setup({ advanceTimers: jest.advanceTimersByTime })`.
|
|
36
|
+
- An `act(...)` warning is a real bug (an update after the test ended or an unawaited promise); fix it, do not silence `console.error`.
|
|
37
|
+
|
|
38
|
+
## Network with MSW
|
|
39
|
+
Mock at the network layer, so the fetch client and the server-state library run as in production. Start the server in the setup file with `onUnhandledRequest: 'error'`, `resetHandlers()` after each test, override per test with `server.use(...)`. Each test covers the error and empty responses, not only success.
|
|
40
|
+
|
|
41
|
+
## Providers
|
|
42
|
+
One `renderWithProviders` in a test-utils file wraps the router (`MemoryRouter`), the store and the query client. Create a fresh query client per test with `retry: false`, so cache and retries never leak between tests. Hooks: `renderHook` from `@testing-library/react`, with the same wrapper.
|
|
43
|
+
|
|
44
|
+
## Accessibility
|
|
45
|
+
`expect(await axe(container)).toHaveNoViolations()` (`jest-axe`) on every interactive component. jsdom has no layout: contrast and focus visibility need a browser.
|
|
46
|
+
|
|
47
|
+
## Jest beside the bundler
|
|
48
|
+
The bundler and Jest resolve code differently; each gap is configured once in `jest.config.*`. Rows marked Vite or webpack apply only to that bundler:
|
|
49
|
+
|
|
50
|
+
| Gap | Fix |
|
|
51
|
+
|---|---|
|
|
52
|
+
| No DOM | `testEnvironment: 'jsdom'` with `jest-environment-jsdom` installed; with MSW 2 use `jest-fixed-jsdom`, which keeps Node's `fetch` globals |
|
|
53
|
+
| JSX / TS not transformed | `babel-jest` with `@babel/preset-env`, `@babel/preset-react` (`runtime: 'automatic'`), `@babel/preset-typescript`; or `ts-jest` / `@swc/jest`, whichever the project has |
|
|
54
|
+
| Vite: `import.meta.env` is a syntax error | Read env in one module (`src/config/env.ts`) and replace it in tests via `moduleNameMapper` or `jest.mock`; do not scatter `import.meta.env` |
|
|
55
|
+
| Path aliases (`@/...`) | Mirror the bundler's `resolve.alias` in `moduleNameMapper` |
|
|
56
|
+
| webpack: `process.env.X` is `undefined` in tests | Jest does not run `DefinePlugin`; set the values in a `setupFiles` module |
|
|
57
|
+
| webpack: `require.context is not a function` | Jest has no `require.context`; import the modules explicitly, or mock the module that calls it |
|
|
58
|
+
| CSS and asset imports | `identity-obj-proxy` for CSS modules, a file stub for images and SVG |
|
|
59
|
+
| ESM-only package in `node_modules` | Let it through `transformIgnorePatterns: ['node_modules/(?!(pkg-a|pkg-b)/)']` |
|
|
60
|
+
| `toBeInTheDocument` undefined | `import '@testing-library/jest-dom'` in a `setupFilesAfterEnv` file |
|
|
61
|
+
|
|
62
|
+
## Snapshots
|
|
63
|
+
No snapshots of rendered components: they break on every markup change and get approved unread. Snapshot only a pure data serialiser.
|
|
64
|
+
|
|
65
|
+
## Done when
|
|
66
|
+
- The new tests fail without the change and pass with it; the project's test script passes, read from real output; no `act` warning, no unhandled MSW request, no skipped test left behind.
|
|
67
|
+
|
|
68
|
+
<!-- INCLUDE: skills/_self-improvement.md -->
|