vanara 0.1.0 → 0.3.0

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.
Files changed (195) hide show
  1. package/README.md +14 -0
  2. package/bin/vanara.js +66 -2
  3. package/catalog/agents/api-designer/AGENT.md +156 -0
  4. package/catalog/agents/api-designer/examples/openapi-snippet.yaml +130 -0
  5. package/catalog/agents/api-designer/examples/review-notes.md +61 -0
  6. package/catalog/agents/api-designer/references/contract-and-openapi.md +82 -0
  7. package/catalog/agents/api-designer/references/design-checklist.md +68 -0
  8. package/catalog/agents/api-designer/references/versioning-and-evolution.md +63 -0
  9. package/catalog/agents/api-designer/scripts/lint-openapi.mjs +180 -0
  10. package/catalog/agents/code-reviewer/AGENT.md +184 -0
  11. package/catalog/agents/code-reviewer/examples/pr-comment-template.md +48 -0
  12. package/catalog/agents/code-reviewer/examples/sample-review-output.md +38 -0
  13. package/catalog/agents/code-reviewer/references/review-checklist.md +46 -0
  14. package/catalog/agents/code-reviewer/references/security-review.md +62 -0
  15. package/catalog/agents/code-reviewer/references/severity-rubric.md +63 -0
  16. package/catalog/agents/code-reviewer/scripts/review-guard.mjs +102 -0
  17. package/catalog/agents/debugger/AGENT.md +128 -0
  18. package/catalog/agents/debugger/examples/postmortem-template.md +59 -0
  19. package/catalog/agents/debugger/examples/repro-template.md +50 -0
  20. package/catalog/agents/debugger/references/bisection.md +63 -0
  21. package/catalog/agents/debugger/references/debugging-method.md +57 -0
  22. package/catalog/agents/debugger/references/observability.md +61 -0
  23. package/catalog/agents/debugger/scripts/parse-stacktrace.mjs +109 -0
  24. package/catalog/agents/pr-summarizer/AGENT.md +172 -0
  25. package/catalog/agents/pr-summarizer/examples/sample-pr-summary.md +46 -0
  26. package/catalog/agents/pr-summarizer/examples/weak-vs-strong-summary.md +68 -0
  27. package/catalog/agents/pr-summarizer/references/identifying-risk.md +68 -0
  28. package/catalog/agents/pr-summarizer/references/reading-the-diff.md +68 -0
  29. package/catalog/agents/pr-summarizer/references/test-plan-and-missing-tests.md +64 -0
  30. package/catalog/agents/pr-summarizer/references/writing-the-summary.md +63 -0
  31. package/catalog/agents/pr-summarizer/scripts/diff-risk.mjs +111 -0
  32. package/catalog/agents/refactoring-specialist/AGENT.md +201 -0
  33. package/catalog/agents/refactoring-specialist/examples/before-after.md +91 -0
  34. package/catalog/agents/refactoring-specialist/examples/refactor-plan.md +97 -0
  35. package/catalog/agents/refactoring-specialist/references/large-scale-refactor.md +50 -0
  36. package/catalog/agents/refactoring-specialist/references/safe-workflow.md +75 -0
  37. package/catalog/agents/refactoring-specialist/references/smell-catalog.md +76 -0
  38. package/catalog/agents/refactoring-specialist/scripts/detect-smells.mjs +150 -0
  39. package/catalog/agents/security-auditor/AGENT.md +184 -0
  40. package/catalog/agents/security-auditor/examples/audit-report.md +68 -0
  41. package/catalog/agents/security-auditor/examples/finding-template.md +31 -0
  42. package/catalog/agents/security-auditor/references/audit-workflow.md +116 -0
  43. package/catalog/agents/security-auditor/references/severity-and-reporting.md +56 -0
  44. package/catalog/agents/security-auditor/references/vuln-classes.md +129 -0
  45. package/catalog/agents/security-auditor/scripts/scan-secrets.mjs +86 -0
  46. package/catalog/agents/technical-writer/AGENT.md +179 -0
  47. package/catalog/agents/technical-writer/examples/how-to-example.md +76 -0
  48. package/catalog/agents/technical-writer/examples/reference-example.md +75 -0
  49. package/catalog/agents/technical-writer/references/clarity-and-style.md +52 -0
  50. package/catalog/agents/technical-writer/references/diataxis-and-doc-types.md +61 -0
  51. package/catalog/agents/technical-writer/references/structure-and-maintenance.md +59 -0
  52. package/catalog/agents/technical-writer/scripts/readability.mjs +103 -0
  53. package/catalog/agents/test-author/AGENT.md +193 -0
  54. package/catalog/agents/test-author/examples/test-plan.md +54 -0
  55. package/catalog/agents/test-author/examples/unit-test-example.ts +55 -0
  56. package/catalog/agents/test-author/references/aaa-and-naming.md +75 -0
  57. package/catalog/agents/test-author/references/mocking-and-fixtures.md +94 -0
  58. package/catalog/agents/test-author/references/test-types-and-pyramid.md +60 -0
  59. package/catalog/agents/test-author/scripts/check-coverage.mjs +145 -0
  60. package/catalog/agents/threat-modeler/AGENT.md +179 -0
  61. package/catalog/agents/threat-modeler/examples/dfd-example.md +55 -0
  62. package/catalog/agents/threat-modeler/examples/threat-model.md +81 -0
  63. package/catalog/agents/threat-modeler/references/dfd-and-trust-boundaries.md +76 -0
  64. package/catalog/agents/threat-modeler/references/mitigation-catalog.md +77 -0
  65. package/catalog/agents/threat-modeler/references/stride-method.md +68 -0
  66. package/catalog/agents/threat-modeler/scripts/stride-checklist.mjs +183 -0
  67. package/catalog/agents/vuln-scanner/AGENT.md +162 -0
  68. package/catalog/agents/vuln-scanner/examples/finding-template.md +57 -0
  69. package/catalog/agents/vuln-scanner/examples/scan-report.md +49 -0
  70. package/catalog/agents/vuln-scanner/references/remediation-and-severity.md +68 -0
  71. package/catalog/agents/vuln-scanner/references/scan-types-and-tools.md +83 -0
  72. package/catalog/agents/vuln-scanner/references/triage-and-false-positives.md +73 -0
  73. package/catalog/agents/vuln-scanner/scripts/parse-scan-results.mjs +133 -0
  74. package/catalog/packs/code-review-pack/PACK.md +100 -0
  75. package/catalog/packs/code-review-pack/examples/pr-flow-example.md +50 -0
  76. package/catalog/packs/code-review-pack/references/rollout-guide.md +40 -0
  77. package/catalog/packs/security-pack/PACK.md +128 -0
  78. package/catalog/packs/security-pack/examples/owasp-vuln-triage-and-fix.md +66 -0
  79. package/catalog/packs/security-pack/examples/threat-model-then-audit.md +77 -0
  80. package/catalog/packs/security-pack/references/choosing-the-right-tool.md +37 -0
  81. package/catalog/packs/security-pack/references/threat-model-to-remediation.md +69 -0
  82. package/catalog/packs/security-pack/references/workflow.md +56 -0
  83. package/catalog/skills/api-pagination/SKILL.md +83 -0
  84. package/catalog/skills/api-pagination/examples/keyset-queries.sql +38 -0
  85. package/catalog/skills/api-pagination/examples/response-shapes.md +51 -0
  86. package/catalog/skills/api-pagination/references/consuming-pages.md +39 -0
  87. package/catalog/skills/api-pagination/references/counting-and-totals.md +41 -0
  88. package/catalog/skills/api-pagination/references/cursor-encoding.md +34 -0
  89. package/catalog/skills/api-pagination/scripts/check-cursor.mjs +51 -0
  90. package/catalog/skills/caching-strategies/SKILL.md +180 -0
  91. package/catalog/skills/caching-strategies/examples/http-cache-headers.md +82 -0
  92. package/catalog/skills/caching-strategies/examples/redis-cache-aside.js +110 -0
  93. package/catalog/skills/caching-strategies/references/cache-patterns.md +93 -0
  94. package/catalog/skills/caching-strategies/references/eviction-and-ttl.md +67 -0
  95. package/catalog/skills/caching-strategies/references/invalidation-and-stampede.md +99 -0
  96. package/catalog/skills/caching-strategies/scripts/ttl-jitter.mjs +99 -0
  97. package/catalog/skills/conventional-commits/SKILL.md +135 -0
  98. package/catalog/skills/conventional-commits/examples/commit-examples.md +60 -0
  99. package/catalog/skills/conventional-commits/examples/commitlint.config.js +31 -0
  100. package/catalog/skills/conventional-commits/references/breaking-changes-semver.md +50 -0
  101. package/catalog/skills/conventional-commits/references/scoping-commits.md +42 -0
  102. package/catalog/skills/conventional-commits/references/spec.md +78 -0
  103. package/catalog/skills/conventional-commits/scripts/lint-commit.mjs +97 -0
  104. package/catalog/skills/database-migrations/SKILL.md +137 -0
  105. package/catalog/skills/database-migrations/examples/add-column-safe.sql +34 -0
  106. package/catalog/skills/database-migrations/examples/migration-config.example.json +27 -0
  107. package/catalog/skills/database-migrations/references/expand-contract.md +74 -0
  108. package/catalog/skills/database-migrations/references/rollback-and-safety.md +71 -0
  109. package/catalog/skills/database-migrations/references/zero-downtime-changes.md +84 -0
  110. package/catalog/skills/database-migrations/scripts/check-migration-reversible.mjs +139 -0
  111. package/catalog/skills/error-handling-patterns/SKILL.md +136 -0
  112. package/catalog/skills/error-handling-patterns/examples/express-error-middleware.js +93 -0
  113. package/catalog/skills/error-handling-patterns/examples/result-pattern.ts +81 -0
  114. package/catalog/skills/error-handling-patterns/references/error-taxonomy.md +91 -0
  115. package/catalog/skills/error-handling-patterns/references/language-patterns.md +102 -0
  116. package/catalog/skills/error-handling-patterns/references/retry-and-backoff.md +76 -0
  117. package/catalog/skills/error-handling-patterns/scripts/lint-empty-catch.mjs +113 -0
  118. package/catalog/skills/git-collaboration-workflows/SKILL.md +104 -0
  119. package/catalog/skills/git-collaboration-workflows/examples/branch-protection.md +48 -0
  120. package/catalog/skills/git-collaboration-workflows/examples/pr-review-playbook.md +48 -0
  121. package/catalog/skills/git-collaboration-workflows/references/branching-models.md +52 -0
  122. package/catalog/skills/git-collaboration-workflows/references/history-hygiene.md +44 -0
  123. package/catalog/skills/git-collaboration-workflows/scripts/check-branch-hygiene.mjs +62 -0
  124. package/catalog/skills/owasp-top10/SKILL.md +112 -0
  125. package/catalog/skills/owasp-top10/examples/sql-injection-fix.md +33 -0
  126. package/catalog/skills/owasp-top10/examples/xss-fix.md +27 -0
  127. package/catalog/skills/owasp-top10/references/access-control.md +36 -0
  128. package/catalog/skills/owasp-top10/references/crypto-failures.md +29 -0
  129. package/catalog/skills/owasp-top10/references/injection.md +39 -0
  130. package/catalog/skills/owasp-top10/references/ssrf-and-design.md +35 -0
  131. package/catalog/skills/owasp-top10/scripts/scan-injection.mjs +73 -0
  132. package/catalog/skills/prompt-engineering/SKILL.md +100 -0
  133. package/catalog/skills/prompt-engineering/examples/classification-prompt.md +29 -0
  134. package/catalog/skills/prompt-engineering/examples/extraction-prompt.md +25 -0
  135. package/catalog/skills/prompt-engineering/references/prompt-injection.md +34 -0
  136. package/catalog/skills/prompt-engineering/references/structured-output.md +34 -0
  137. package/catalog/skills/prompt-engineering/references/techniques.md +33 -0
  138. package/catalog/skills/prompt-engineering/scripts/validate-output.mjs +71 -0
  139. package/catalog/skills/readme-writing/SKILL.md +176 -0
  140. package/catalog/skills/readme-writing/examples/README.template.md +73 -0
  141. package/catalog/skills/readme-writing/examples/good-readme-example.md +95 -0
  142. package/catalog/skills/readme-writing/references/anatomy.md +107 -0
  143. package/catalog/skills/readme-writing/references/maintenance.md +68 -0
  144. package/catalog/skills/readme-writing/references/writing-style.md +79 -0
  145. package/catalog/skills/readme-writing/scripts/lint-readme.mjs +117 -0
  146. package/catalog/skills/refactoring-patterns/SKILL.md +178 -0
  147. package/catalog/skills/refactoring-patterns/examples/extract-function.before-after.js +57 -0
  148. package/catalog/skills/refactoring-patterns/examples/replace-conditional-with-polymorphism.before-after.ts +63 -0
  149. package/catalog/skills/refactoring-patterns/references/code-smells.md +92 -0
  150. package/catalog/skills/refactoring-patterns/references/refactoring-catalog.md +78 -0
  151. package/catalog/skills/refactoring-patterns/references/safe-workflow.md +74 -0
  152. package/catalog/skills/refactoring-patterns/scripts/detect-smells.mjs +137 -0
  153. package/catalog/skills/rest-api-design/SKILL.md +147 -0
  154. package/catalog/skills/rest-api-design/examples/error-envelope.json +26 -0
  155. package/catalog/skills/rest-api-design/examples/orders-api.openapi.yaml +106 -0
  156. package/catalog/skills/rest-api-design/references/error-handling.md +43 -0
  157. package/catalog/skills/rest-api-design/references/pagination.md +41 -0
  158. package/catalog/skills/rest-api-design/references/status-codes.md +32 -0
  159. package/catalog/skills/rest-api-design/references/versioning.md +31 -0
  160. package/catalog/skills/rest-api-design/scripts/check-envelope.mjs +62 -0
  161. package/catalog/skills/secrets-management/SKILL.md +134 -0
  162. package/catalog/skills/secrets-management/examples/env-example.md +41 -0
  163. package/catalog/skills/secrets-management/examples/rotation-runbook.md +50 -0
  164. package/catalog/skills/secrets-management/references/leak-response.md +47 -0
  165. package/catalog/skills/secrets-management/references/rotation.md +46 -0
  166. package/catalog/skills/secrets-management/references/secret-managers.md +52 -0
  167. package/catalog/skills/secrets-management/scripts/detect-hardcoded.mjs +96 -0
  168. package/catalog/skills/secure-auth/SKILL.md +135 -0
  169. package/catalog/skills/secure-auth/examples/auth-flow.md +60 -0
  170. package/catalog/skills/secure-auth/examples/jwt-verify.ts +89 -0
  171. package/catalog/skills/secure-auth/references/auth-attacks.md +76 -0
  172. package/catalog/skills/secure-auth/references/oauth2-oidc.md +65 -0
  173. package/catalog/skills/secure-auth/references/password-hashing.md +70 -0
  174. package/catalog/skills/secure-auth/references/sessions-vs-jwt.md +69 -0
  175. package/catalog/skills/secure-auth/scripts/check-password-policy.mjs +114 -0
  176. package/catalog/skills/sql-index-tuning/SKILL.md +171 -0
  177. package/catalog/skills/sql-index-tuning/examples/explain-walkthrough.sql +91 -0
  178. package/catalog/skills/sql-index-tuning/examples/index-ddl.sql +67 -0
  179. package/catalog/skills/sql-index-tuning/references/btree-internals.md +58 -0
  180. package/catalog/skills/sql-index-tuning/references/composite-and-covering.md +60 -0
  181. package/catalog/skills/sql-index-tuning/references/reading-explain.md +54 -0
  182. package/catalog/skills/sql-index-tuning/references/selectivity-and-cardinality.md +62 -0
  183. package/catalog/skills/sql-index-tuning/scripts/suggest-index.mjs +213 -0
  184. package/catalog/skills/test-plan-design/SKILL.md +154 -0
  185. package/catalog/skills/test-plan-design/examples/test-case-template.md +45 -0
  186. package/catalog/skills/test-plan-design/examples/test-plan.md +57 -0
  187. package/catalog/skills/test-plan-design/references/case-design.md +79 -0
  188. package/catalog/skills/test-plan-design/references/risk-prioritization.md +58 -0
  189. package/catalog/skills/test-plan-design/references/test-pyramid.md +58 -0
  190. package/catalog/skills/test-plan-design/scripts/coverage-gaps.mjs +109 -0
  191. package/free-tier.json +15 -0
  192. package/package.json +15 -4
  193. package/premium-index.json +1 -0
  194. package/src/config.js +31 -1
  195. package/src/license.js +143 -0
@@ -0,0 +1,61 @@
1
+ # Diátaxis and the four doc types
2
+
3
+ Diátaxis splits documentation into four modes along two axes: **practical vs theoretical** (doing vs
4
+ knowing) and **study vs work** (acquiring skill vs applying it). Each mode answers a different reader
5
+ question. Mixing them is the single most common documentation failure.
6
+
7
+ ## The four quadrants
8
+
9
+ | Type | Reader's question | Mode | Posture |
10
+ |---|---|---|---|
11
+ | **Tutorial** | "Teach me, I'm new." | learning / doing | Hand-holding, linear, builds confidence |
12
+ | **How-to guide** | "Help me do X." | working / doing | Goal-first, assumes competence |
13
+ | **Reference** | "What is the exact behavior of Y?" | working / knowing | Dry, exhaustive, consistent |
14
+ | **Explanation** | "Why does it work this way?" | learning / knowing | Discursive, gives context and trade-offs |
15
+
16
+ ## Decision table
17
+
18
+ Pick the type from the reader's *intent*, not the subject matter:
19
+
20
+ | If the reader wants to… | Write a… |
21
+ |---|---|
22
+ | Get a first win and learn by doing | Tutorial |
23
+ | Accomplish a specific, known task | How-to guide |
24
+ | Look up a flag, field, signature, or value | Reference |
25
+ | Understand a concept, decision, or trade-off | Explanation |
26
+
27
+ ## Tell-tale signs of a blended (broken) doc
28
+
29
+ - A "getting started" page that pauses to enumerate every config option → tutorial leaking into reference.
30
+ - A how-to that stops to explain the underlying theory → how-to leaking into explanation. Link instead.
31
+ - A reference page with a friendly narrative arc → reference leaking into tutorial. References are lookup
32
+ tables, not stories.
33
+ - An explanation page with copy-paste steps → split the steps into a how-to.
34
+
35
+ ## Per-type skeletons
36
+
37
+ **Tutorial** — linear, every step succeeds, no choices to make:
38
+ 1. Promise a concrete outcome ("by the end you'll have a running X").
39
+ 2. List prerequisites once, up front.
40
+ 3. Numbered steps, each producing visible progress.
41
+ 4. Show expected output after each meaningful step.
42
+ 5. End with what they built and where to go next.
43
+
44
+ **How-to guide** — goal-first, assumes competence (see `examples/how-to-example.md`):
45
+ - One-line goal → prerequisites → steps → verify → rollback/troubleshooting.
46
+
47
+ **Reference** — exhaustive and *consistent* (see `examples/reference-example.md`):
48
+ - Every entry uses the same structure (name, type, default, description, example).
49
+ - Alphabetical or grouped, never narrative. Optimized for scanning and `Ctrl-F`.
50
+
51
+ **Explanation** — discursive, makes trade-offs explicit:
52
+ - State the question, give context, walk through alternatives, explain why this choice, note the costs.
53
+ - No step lists; this is prose for understanding, not doing.
54
+
55
+ ## Cross-linking strategy
56
+
57
+ Keep each doc single-purpose and connect them:
58
+ - Tutorials link *out* to how-tos and references for "more detail."
59
+ - How-tos link to explanations for "why," and to references for exact values.
60
+ - References link to explanations for concepts and to how-tos for tasks.
61
+ - Explanations link to how-tos so a convinced reader can act.
@@ -0,0 +1,59 @@
1
+ # Structure and maintenance
2
+
3
+ Individual docs must be clear; the *set* of docs must be navigable and must not rot. This reference covers
4
+ information architecture and keeping documentation alive.
5
+
6
+ ## Information architecture
7
+
8
+ Organize the documentation set around the four Diátaxis types and the reader's journey, not around the
9
+ codebase's module layout:
10
+
11
+ ```text
12
+ docs/
13
+ ├── tutorials/ # learning-oriented, linear
14
+ │ └── getting-started.md
15
+ ├── how-to/ # task-oriented
16
+ │ ├── rotate-signing-key.md
17
+ │ └── configure-timeouts.md
18
+ ├── reference/ # lookup-oriented, exhaustive
19
+ │ ├── cli.md
20
+ │ └── config.md
21
+ └── explanation/ # understanding-oriented
22
+ └── why-cursor-pagination.md
23
+ ```
24
+
25
+ - A reader who knows their *intent* should land in the right folder immediately.
26
+ - Name files by the reader's task ("rotate-signing-key"), not the implementation ("key-service-internals").
27
+
28
+ ## Linking
29
+
30
+ - Link generously between types (tutorial → how-to → reference → explanation), but never inline another
31
+ type's full content. A link keeps each page single-purpose.
32
+ - Use descriptive link text ("see the CLI reference"), never "click here."
33
+ - Keep a single entry point (an index/README) that routes by reader intent.
34
+
35
+ ## Keeping docs from rotting
36
+
37
+ Documentation rots when it duplicates a source of truth that changes without it. Defenses, in order of
38
+ preference:
39
+
40
+ 1. **Generate from source.** CLI help, config schemas, API specs, and route tables should be generated
41
+ (or extracted) so they can't drift. Pair with the `update-docs` skill.
42
+ 2. **Link to source.** When you can't generate, link to the authoritative file instead of copying values.
43
+ 3. **Single source per fact.** A given default/flag/limit is documented in exactly one place; everything
44
+ else links to it.
45
+ 4. **Date and version.** Stamp docs with the version they describe so readers can judge staleness.
46
+
47
+ ## Review and verification cadence
48
+
49
+ - Re-run every example when the documented surface changes (a flag rename, a new required arg).
50
+ - Treat a failed copy-paste as a P1 doc bug — it destroys trust instantly.
51
+ - On each release, diff the changelog against the docs: any user-visible change needs a doc change.
52
+
53
+ ## Anti-patterns
54
+
55
+ - **Docs as a dumping ground:** an "FAQ" or "notes" page that accumulates everything no one filed properly.
56
+ - **Mirror-the-code structure:** folders named after services, so readers must understand the architecture
57
+ to find a task.
58
+ - **Copy-pasted constants:** the same timeout value written in five guides; change one, the rest lie.
59
+ - **Orphan pages:** docs with no inbound links, found only by search, never maintained.
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ // Runnable readability signal for prose. Computes two cheap proxies for
3
+ // hard-to-read writing and flags text that trips either threshold:
4
+ // 1. average sentence length (words per sentence)
5
+ // 2. long-word ratio (share of words with >= LONG_WORD_LEN letters)
6
+ //
7
+ // These are intentionally simple, dependency-free heuristics — not a true
8
+ // Flesch score — meant to catch the dense, run-on prose the clarity pass exists
9
+ // to remove (see references/clarity-and-style.md).
10
+ //
11
+ // Usage:
12
+ // node readability.mjs "Some prose to score." # score a literal string
13
+ // echo "Some prose" | node readability.mjs # score from stdin
14
+ // node readability.mjs --selftest # run built-in test cases
15
+ //
16
+ // Exit code: 0 if the text reads clearly, 1 if it is flagged as hard to read.
17
+
18
+ const MAX_AVG_SENTENCE_WORDS = 25; // longer average => likely run-on prose
19
+ const MAX_LONG_WORD_RATIO = 0.2; // more than 20% long words => dense
20
+ const LONG_WORD_LEN = 12; // letters; "configuration" (13) counts
21
+
22
+ export function analyze(text) {
23
+ const sentences = splitSentences(text);
24
+ const words = (text.match(/[A-Za-z][A-Za-z'-]*/g) || []);
25
+ const wordCount = words.length;
26
+ const sentenceCount = Math.max(sentences.length, 1);
27
+ const avgSentenceWords = wordCount / sentenceCount;
28
+ const longWords = words.filter((w) => w.replace(/[^A-Za-z]/g, '').length >= LONG_WORD_LEN);
29
+ const longWordRatio = wordCount === 0 ? 0 : longWords.length / wordCount;
30
+
31
+ const reasons = [];
32
+ if (avgSentenceWords > MAX_AVG_SENTENCE_WORDS) {
33
+ reasons.push(`avg sentence length ${avgSentenceWords.toFixed(1)} words > ${MAX_AVG_SENTENCE_WORDS}`);
34
+ }
35
+ if (longWordRatio > MAX_LONG_WORD_RATIO) {
36
+ reasons.push(`long-word ratio ${(longWordRatio * 100).toFixed(0)}% > ${MAX_LONG_WORD_RATIO * 100}%`);
37
+ }
38
+
39
+ return {
40
+ ok: reasons.length === 0,
41
+ wordCount,
42
+ sentenceCount,
43
+ avgSentenceWords,
44
+ longWordRatio,
45
+ reasons,
46
+ };
47
+ }
48
+
49
+ function splitSentences(text) {
50
+ return text
51
+ .split(/[.!?]+/)
52
+ .map((s) => s.trim())
53
+ .filter((s) => s.length > 0);
54
+ }
55
+
56
+ function report(label, text) {
57
+ const r = analyze(text);
58
+ const stats = `avg ${r.avgSentenceWords.toFixed(1)} w/sentence, ${(r.longWordRatio * 100).toFixed(0)}% long words`;
59
+ if (r.ok) {
60
+ console.log(`OK ${label}: reads clearly (${stats})`);
61
+ } else {
62
+ console.error(`FLAG ${label}: hard to read (${stats})`);
63
+ r.reasons.forEach((reason) => console.error(` - ${reason}`));
64
+ }
65
+ return r.ok;
66
+ }
67
+
68
+ function selftest() {
69
+ const simple = 'Set the timeout. Raise it if requests stall. The default is thirty seconds.';
70
+ const dense =
71
+ 'Notwithstanding the aforementioned considerations regarding configuration, the implementation ' +
72
+ 'necessitates comprehensive understanding of the interdependent architectural characteristics ' +
73
+ 'whose interrelationships fundamentally determine the operational behaviour exhibited throughout ' +
74
+ 'the entirety of the distributed infrastructure under consideration herein presently.';
75
+
76
+ const cases = [
77
+ ['simple_text_passes', simple, true],
78
+ ['dense_text_flags', dense, false],
79
+ ];
80
+
81
+ let allExpected = true;
82
+ for (const [name, text, shouldPass] of cases) {
83
+ const { ok } = analyze(text);
84
+ const correct = ok === shouldPass;
85
+ allExpected = allExpected && correct;
86
+ console.log(
87
+ `${correct ? 'OK' : 'FAIL'} selftest ${name}: ${ok ? 'clear' : 'flagged'} ` +
88
+ `(expected ${shouldPass ? 'clear' : 'flagged'})`
89
+ );
90
+ }
91
+ process.exit(allExpected ? 0 : 1);
92
+ }
93
+
94
+ const arg = process.argv[2];
95
+ if (arg === '--selftest') {
96
+ selftest();
97
+ } else if (arg) {
98
+ process.exit(report('text', arg) ? 0 : 1);
99
+ } else {
100
+ let buf = '';
101
+ process.stdin.on('data', (c) => (buf += c));
102
+ process.stdin.on('end', () => process.exit(report('stdin', buf) ? 0 : 1));
103
+ }
@@ -0,0 +1,193 @@
1
+ ---
2
+ name: test-author
3
+ description: Use PROACTIVELY when adding a feature or fixing a bug — writes tests FIRST (TDD red-green-refactor). Detects the repo's existing framework, captures the spec as failing AAA tests, drives implementation to green, and reports coverage against the 80% target with gaps called out.
4
+ tools: Read, Write, Edit, Bash, Grep
5
+ model: claude-sonnet-4-6
6
+ type: agent
7
+ version: 2.0.0
8
+ updated: 2026-06-29
9
+ ---
10
+ # Test Author
11
+
12
+ You are a disciplined test-driven-development engineer. Your job is to turn a described
13
+ behavior into **executable specification** — tests written *before* the implementation
14
+ exists — and then to drive that implementation to green without ever weakening the tests
15
+ to make them pass. You produce tests that fail for the right reason, pass once the code is
16
+ correct, and keep failing if the code regresses. You treat a test that cannot fail as worse
17
+ than no test at all.
18
+
19
+ You operate in any language. You never introduce a new test framework, runner, assertion
20
+ library, or fixture convention; you detect what the repository already uses and conform to
21
+ it exactly. Heavy reference detail lives in `references/`; copy-ready material in `examples/`;
22
+ a runnable coverage gate in `scripts/`.
23
+
24
+ ## Role and mandate
25
+
26
+ - **Tests come first.** No production code is written or accepted until a failing test
27
+ captures the intended behavior. If implementation already exists, you still write the
28
+ characterization or regression test first, observe it pass/fail honestly, and proceed.
29
+ - **Behavior over implementation.** You assert on observable outcomes — return values,
30
+ emitted events, persisted state, HTTP responses — never on private internals, call order,
31
+ or incidental structure that refactoring would break.
32
+ - **You are the spec's lawyer.** When a requirement is ambiguous, you enumerate the cases
33
+ explicitly (happy path, boundaries, error modes) and surface the ambiguity rather than
34
+ guessing silently.
35
+ - **Determinism is non-negotiable.** Every test must produce the same result on every run,
36
+ in any order, on any machine. Time, randomness, network, and filesystem are controlled.
37
+
38
+ ## TDD workflow: red → green → refactor
39
+
40
+ Follow this loop for every unit of behavior. Do not batch many behaviors into one giant test.
41
+
42
+ 1. **Detect conventions.** `Grep`/`Read` the repo to find the test runner, file naming
43
+ (`*.test.ts`, `*_test.go`, `test_*.py`), assertion style, and fixture/mocking patterns.
44
+ Match them. Detecting the framework wrong is the most common failure of this agent.
45
+ 2. **Decompose the behavior** into concrete cases: the happy path, every boundary
46
+ (empty, single, max, off-by-one), and every failure mode (invalid input, missing
47
+ dependency, thrown error). Write the list before writing code.
48
+ 3. **RED — write the test(s) first.** Use Arrange-Act-Assert. Give each test a name that
49
+ states the behavior under test. Run the suite and confirm it **fails for the expected
50
+ reason** (assertion failure or missing symbol — not a syntax error or import typo).
51
+ 4. **GREEN — minimal implementation.** Write the least code that makes the test pass.
52
+ Resist gold-plating; unneeded code has no test and is a liability.
53
+ 5. **REFACTOR — improve with the net up.** Clean up names, extract helpers, remove
54
+ duplication, while the suite stays green. Tests are the safety net that makes this safe.
55
+ 6. **Report.** Show the run output (RED first, then GREEN), the coverage delta against the
56
+ 80% target, and any remaining gaps or design smells you uncovered.
57
+
58
+ ## Arrange-Act-Assert structure
59
+
60
+ Every test has three visually separated phases and **one logical assertion target**:
61
+
62
+ - **Arrange** — build inputs, fixtures, and doubles. No assertions here.
63
+ - **Act** — invoke exactly one behavior, the thing under test.
64
+ - **Assert** — verify the observable outcome. Prefer one concept per test; multiple
65
+ `expect` lines are fine if they describe one behavior.
66
+
67
+ ```ts
68
+ // Vitest / Jest — a focused unit test written BEFORE the implementation
69
+ import { describe, it, expect } from 'vitest';
70
+ import { applyDiscount } from '../src/pricing';
71
+
72
+ describe('applyDiscount', () => {
73
+ it('subtracts a percentage discount and rounds to 2 decimals', () => {
74
+ // Arrange
75
+ const price = 49.99;
76
+ const percentOff = 10;
77
+
78
+ // Act
79
+ const result = applyDiscount(price, percentOff);
80
+
81
+ // Assert
82
+ expect(result).toBe(44.99);
83
+ });
84
+
85
+ it('throws RangeError when the discount exceeds 100 percent', () => {
86
+ // Arrange
87
+ const price = 10;
88
+
89
+ // Act + Assert (the throw IS the observable behavior)
90
+ expect(() => applyDiscount(price, 150)).toThrow(RangeError);
91
+ });
92
+
93
+ it('returns the original price when the discount is zero', () => {
94
+ expect(applyDiscount(20, 0)).toBe(20); // boundary: identity
95
+ });
96
+ });
97
+ ```
98
+
99
+ ## Output format
100
+
101
+ Deliver, in order:
102
+
103
+ 1. **Case list** — the behaviors you are about to test (happy / boundary / failure).
104
+ 2. **Test files** — full contents, matching repo conventions, written first.
105
+ 3. **A test plan** — what is covered, what is intentionally out of scope, and how to run it.
106
+ 4. **Run evidence** — the RED output, then the GREEN output after implementation.
107
+ 5. **Coverage summary** — percentage vs. the 80% target and named gaps.
108
+
109
+ ```md
110
+ ## Test plan: refund eligibility
111
+
112
+ | Case | Type | Expected |
113
+ |---|---|---|
114
+ | order within 30 days, unused | happy | eligible = true |
115
+ | order on day 30 exactly | boundary | eligible = true |
116
+ | order on day 31 | boundary | eligible = false |
117
+ | already refunded order | failure | throws AlreadyRefunded |
118
+ | missing order id | failure | throws NotFound |
119
+
120
+ Out of scope: partial refunds (tracked separately).
121
+ Run: `npm test -- refund` · Coverage gate: `node scripts/check-coverage.mjs coverage/coverage-summary.json`
122
+ ```
123
+
124
+ ## Self-check before you finish
125
+
126
+ - [ ] Did each test **fail first** for the right reason? (A test never seen red is suspect.)
127
+ - [ ] Does every test assert a real observable outcome — not "it ran without throwing"?
128
+ - [ ] Are boundaries and error modes covered, not just the happy path?
129
+ - [ ] Is every test deterministic and isolated (no shared mutable state, no real I/O)?
130
+ - [ ] Did I avoid asserting on private internals that refactoring would break?
131
+ - [ ] Does coverage meet 80%, and are remaining gaps named rather than hidden?
132
+
133
+ ## Common pitfalls (failure modes to avoid)
134
+
135
+ - **Testing implementation, not behavior.** Asserting that a private method was called, or
136
+ snapshotting internal structure, couples the test to the code's shape. Refactoring then
137
+ breaks green tests even though behavior is unchanged. Assert on outputs and effects.
138
+ - **Asserting nothing.** A test that calls a function and never checks the result only
139
+ proves "it didn't throw." It passes for broken code. Every test needs a real assertion.
140
+ - **No edge cases.** Happy-path-only suites give false confidence. The bugs live at the
141
+ boundaries — empty collections, zero, negative, max, off-by-one, null — and in error
142
+ paths. Enumerate them explicitly.
143
+ - **Flaky tests.** Dependence on wall-clock time, real network, random seeds, ordering, or
144
+ unawaited async makes a test pass-then-fail at random. A flaky test is noise that trains
145
+ the team to ignore red. Freeze time, seed RNG, mock the boundary, await everything.
146
+ - **Over-mocking.** Mocking the thing under test, or mocking so deeply the test only
147
+ verifies the mock, tests nothing real. Mock at the system boundary only.
148
+ - **Tests that never went red.** If you write a test against already-working code without
149
+ watching it fail, you can't trust it catches the bug. Break the code or invert the assert
150
+ once to confirm the test bites.
151
+
152
+ ## When NOT to use / boundaries
153
+
154
+ - **Not for exhaustive E2E or browser flows** — for full user-journey testing through a real
155
+ browser, hand off to the **e2e-playwright** skill. This agent owns unit and integration
156
+ tests close to the code.
157
+ - **Not a code reviewer** — it writes and runs tests; it does not perform security or
158
+ architecture review. Pair it with the **code-reviewer** agent afterward.
159
+ - **Not for throwaway spikes** — during a genuine exploratory prototype that will be
160
+ deleted, strict TDD can be deferred; write tests before the code is promoted to keep.
161
+ - **It will not weaken a test to force green.** If a test is hard to write, that signals a
162
+ design problem; it surfaces the smell instead of deleting the assertion.
163
+
164
+ ## Files in this package
165
+
166
+ - `AGENT.md` — this system prompt
167
+ - `references/test-types-and-pyramid.md` — unit vs integration vs E2E, the test pyramid, what to put where
168
+ - `references/aaa-and-naming.md` — Arrange-Act-Assert in depth and behavior-driven test names
169
+ - `references/mocking-and-fixtures.md` — test doubles, fixtures, and controlling time/randomness/I/O
170
+ - `examples/unit-test-example.ts` — a complete, runnable-shaped AAA unit test
171
+ - `examples/test-plan.md` — a filled-in test plan template
172
+ - `scripts/check-coverage.mjs` — Node coverage gate that fails below a threshold (default 80%); `--selftest` exits 0/1
173
+
174
+ Pairs with the **e2e-playwright** skill (full browser journeys) and the **code-reviewer**
175
+ agent (quality and security pass after tests are green). See
176
+ [references/test-types-and-pyramid.md](references/test-types-and-pyramid.md) for where each
177
+ layer belongs.
178
+
179
+
180
+ ## Memory — learn across sessions
181
+
182
+ You keep a persistent, per-project memory at `.claude/memory/test-author.md`. It is
183
+ how you get sharper on *this* codebase over time instead of starting cold every run.
184
+
185
+ - **Before you start:** read `.claude/memory/test-author.md` if it exists and apply what
186
+ it holds — corrections you were given before, this project's conventions, decisions
187
+ and their rationale, and recurring pitfalls. If it is missing, continue without it.
188
+ - **After you finish:** if this task taught you something durable — a correction from
189
+ the user, a project-specific convention, a mistake worth not repeating — append it as
190
+ a short dated bullet under a relevant heading, and prune anything now stale or wrong.
191
+ Keep entries terse and general.
192
+ - **Never record** secrets, credentials, tokens, personal data, or one-off trivia, and
193
+ never write anywhere except your own `.claude/memory/` file.
@@ -0,0 +1,54 @@
1
+ # Test Plan: Refund Eligibility
2
+
3
+ A filled-in example of the test plan this agent produces before writing code. Copy the shape
4
+ for any new behavior: enumerate cases by type, mark scope, and state how to run + gate.
5
+
6
+ ## Behavior under test
7
+
8
+ `isRefundEligible(order, now)` decides whether an order can be refunded. An order is eligible
9
+ when it was placed within the last 30 days, is unused, and has not already been refunded.
10
+
11
+ ## Cases
12
+
13
+ | # | Case | Type | Expected |
14
+ |---|---|---|---|
15
+ | 1 | order placed 5 days ago, unused | happy | `true` |
16
+ | 2 | order placed exactly 30 days ago | boundary | `true` (inclusive) |
17
+ | 3 | order placed 31 days ago | boundary | `false` |
18
+ | 4 | order placed 0 days ago (today) | boundary | `true` |
19
+ | 5 | order already marked refunded | failure | throws `AlreadyRefunded` |
20
+ | 6 | order is `null` / missing | failure | throws `NotFound` |
21
+ | 7 | order used (redeemed) | edge | `false` |
22
+
23
+ ## Determinism notes
24
+
25
+ - `now` is **injected**, not read from the system clock, so the 30-day boundary tests are
26
+ stable. The suite freezes `now` to `2026-06-29T12:00:00Z`.
27
+ - No network or DB access — `order` is built by a `makeOrder(overrides)` factory.
28
+
29
+ ## Out of scope (tracked separately)
30
+
31
+ - Partial refunds and refund *amount* calculation — separate behavior, separate plan.
32
+ - Payment-provider interaction — covered by an integration test, not this unit.
33
+
34
+ ## Coverage target
35
+
36
+ 80% minimum (branch coverage emphasized — every `true`/`false`/throw path above is exercised).
37
+
38
+ ## How to run
39
+
40
+ ```bash
41
+ # Run just this behavior's tests
42
+ npm test -- refund
43
+
44
+ # Gate coverage in CI (fails below 80%)
45
+ node scripts/check-coverage.mjs coverage/coverage-summary.json --min=80
46
+ ```
47
+
48
+ ## Red → Green evidence (to be filled at implementation time)
49
+
50
+ ```text
51
+ RED: 5 failing — isRefundEligible is not defined
52
+ GREEN: 7 passing — statements 92% · branches 88% · target 80% met
53
+ Gaps: none for this behavior; partial-refund path intentionally deferred
54
+ ```
@@ -0,0 +1,55 @@
1
+ // A complete, AAA-structured unit test written BEFORE the implementation.
2
+ // Framework-agnostic shape shown with Vitest/Jest-style globals — adapt imports to the
3
+ // runner the repository already uses. The point is the structure, not the library.
4
+ //
5
+ // Behavior under test: applyDiscount(price, percentOff)
6
+ // - subtracts a percentage discount and rounds to 2 decimal places
7
+ // - returns the original price when percentOff is 0 (boundary: identity)
8
+ // - returns 0 when percentOff is 100 (boundary: full discount)
9
+ // - throws RangeError when percentOff < 0 or > 100 (failure mode)
10
+
11
+ import { describe, it, expect } from 'vitest';
12
+ import { applyDiscount } from '../src/pricing';
13
+
14
+ // A small factory keeps tests readable and resilient to signature changes.
15
+ const cents = (n: number) => Math.round(n * 100) / 100;
16
+
17
+ describe('applyDiscount', () => {
18
+ // --- Happy path ---------------------------------------------------------
19
+ it('subtracts a percentage discount and rounds to two decimals', () => {
20
+ // Arrange
21
+ const price = 49.99;
22
+ const percentOff = 10;
23
+
24
+ // Act
25
+ const result = applyDiscount(price, percentOff);
26
+
27
+ // Assert
28
+ expect(result).toBe(cents(44.991)); // 44.99
29
+ });
30
+
31
+ // --- Boundaries ---------------------------------------------------------
32
+ it('returns the original price when the discount is zero', () => {
33
+ expect(applyDiscount(20, 0)).toBe(20);
34
+ });
35
+
36
+ it('returns zero when the discount is one hundred percent', () => {
37
+ expect(applyDiscount(20, 100)).toBe(0);
38
+ });
39
+
40
+ // --- Failure modes ------------------------------------------------------
41
+ it('throws RangeError when the discount exceeds one hundred percent', () => {
42
+ // The throw IS the observable behavior — assert on it directly.
43
+ expect(() => applyDiscount(10, 150)).toThrow(RangeError);
44
+ });
45
+
46
+ it('throws RangeError when the discount is negative', () => {
47
+ expect(() => applyDiscount(10, -5)).toThrow(RangeError);
48
+ });
49
+ });
50
+
51
+ // Notes on why this is a good test file:
52
+ // - Each test has one Act and asserts a real, observable outcome (no "didn't throw" tests).
53
+ // - Boundaries (0, 100) and error modes (negative, > 100) are covered, not just happy path.
54
+ // - No time, randomness, network, or shared state — fully deterministic and order-independent.
55
+ // - Names state the behavior, so the suite reads as a specification of applyDiscount.
@@ -0,0 +1,75 @@
1
+ # Arrange-Act-Assert and Test Naming
2
+
3
+ A good test reads like a specification. Two habits get you most of the way: a consistent
4
+ three-phase body (AAA) and a name that states the behavior, not the method.
5
+
6
+ ## Arrange-Act-Assert (AAA)
7
+
8
+ Structure every test in three visually separated phases:
9
+
10
+ ```ts
11
+ it('caps the cart total at the configured maximum', () => {
12
+ // Arrange — set up inputs, fixtures, doubles
13
+ const cart = makeCart({ items: 5, unitPrice: 100 });
14
+ const maxTotal = 400;
15
+
16
+ // Act — invoke exactly ONE behavior
17
+ const total = cart.totalWithCap(maxTotal);
18
+
19
+ // Assert — verify the observable outcome
20
+ expect(total).toBe(400);
21
+ });
22
+ ```
23
+
24
+ Why it works:
25
+
26
+ - **One Act per test.** If you need two actions, you probably have two tests. A single Act
27
+ keeps failures unambiguous — you know exactly what broke.
28
+ - **Assertions only in Assert.** An assertion buried in Arrange hides setup failures as
29
+ behavior failures.
30
+ - **No logic in tests.** Loops, conditionals, and try/catch in a test are a smell; they can
31
+ hide bugs in the test itself. Prefer table-driven cases or parameterized tests instead.
32
+
33
+ ## Given-When-Then
34
+
35
+ The same shape, phrased for behavior-driven tests: *Given* a context, *When* an action
36
+ occurs, *Then* an outcome is observed. Map Given→Arrange, When→Act, Then→Assert.
37
+
38
+ ## Naming tests
39
+
40
+ A test name should let a reader understand the requirement **without reading the body**.
41
+ State the scenario and the expected outcome.
42
+
43
+ **Weak (restates the method):**
44
+ ```
45
+ test('applyDiscount')
46
+ test('test refund')
47
+ test('works')
48
+ ```
49
+
50
+ **Strong (states the behavior):**
51
+ ```
52
+ test('subtracts a percentage discount and rounds to two decimals')
53
+ test('throws RangeError when the discount exceeds 100 percent')
54
+ test('returns empty array when no markets match the query')
55
+ test('falls back to substring search when Redis is unavailable')
56
+ ```
57
+
58
+ A useful template: **`<does X> when <condition Y>`** or **`<verb> <expected> given <state>`**.
59
+
60
+ ## One behavior per test
61
+
62
+ When a test fails, its name plus its single Act should tell you what's broken without
63
+ debugging. Resist the "mega test" that arranges a huge world and asserts twenty things — the
64
+ first failure masks the rest, and the name can't describe what it covers. Split by behavior.
65
+
66
+ ## Multiple assertions are fine — if they describe one behavior
67
+
68
+ ```ts
69
+ // OK: these three assertions all describe "creates an open order"
70
+ expect(order.id).toBeDefined();
71
+ expect(order.status).toBe('open');
72
+ expect(order.createdAt).toBeInstanceOf(Date);
73
+ ```
74
+
75
+ The guideline is *one logical concept per test*, not literally one `expect`.