@harness-engineering/cli 1.25.7 → 1.26.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.
Files changed (189) hide show
  1. package/dist/agents/skills/README.md +1 -0
  2. package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +33 -5
  3. package/dist/agents/skills/claude-code/harness-execution/SKILL.md +6 -0
  4. package/dist/agents/skills/claude-code/harness-knowledge-pipeline/SKILL.md +277 -0
  5. package/dist/agents/skills/claude-code/harness-knowledge-pipeline/skill.yaml +60 -0
  6. package/dist/agents/skills/claude-code/harness-planning/SKILL.md +25 -1
  7. package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +22 -6
  8. package/dist/agents/skills/claude-code/initialize-harness-project/skill.yaml +2 -1
  9. package/dist/agents/skills/claude-code/initialize-test-suite-project/SKILL.md +415 -0
  10. package/dist/agents/skills/claude-code/initialize-test-suite-project/skill.yaml +35 -0
  11. package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +33 -5
  12. package/dist/agents/skills/codex/harness-execution/SKILL.md +6 -0
  13. package/dist/agents/skills/codex/harness-knowledge-pipeline/SKILL.md +277 -0
  14. package/dist/agents/skills/codex/harness-knowledge-pipeline/skill.yaml +60 -0
  15. package/dist/agents/skills/codex/harness-planning/SKILL.md +25 -1
  16. package/dist/agents/skills/codex/initialize-harness-project/SKILL.md +22 -6
  17. package/dist/agents/skills/codex/initialize-harness-project/skill.yaml +2 -1
  18. package/dist/agents/skills/codex/initialize-test-suite-project/SKILL.md +415 -0
  19. package/dist/agents/skills/codex/initialize-test-suite-project/skill.yaml +35 -0
  20. package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +33 -5
  21. package/dist/agents/skills/cursor/harness-execution/SKILL.md +6 -0
  22. package/dist/agents/skills/cursor/harness-knowledge-pipeline/SKILL.md +277 -0
  23. package/dist/agents/skills/cursor/harness-knowledge-pipeline/skill.yaml +60 -0
  24. package/dist/agents/skills/cursor/harness-planning/SKILL.md +25 -1
  25. package/dist/agents/skills/cursor/initialize-harness-project/SKILL.md +22 -6
  26. package/dist/agents/skills/cursor/initialize-harness-project/skill.yaml +2 -1
  27. package/dist/agents/skills/cursor/initialize-test-suite-project/SKILL.md +415 -0
  28. package/dist/agents/skills/cursor/initialize-test-suite-project/skill.yaml +35 -0
  29. package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +33 -5
  30. package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +6 -0
  31. package/dist/agents/skills/gemini-cli/harness-knowledge-pipeline/SKILL.md +277 -0
  32. package/dist/agents/skills/gemini-cli/harness-knowledge-pipeline/skill.yaml +60 -0
  33. package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +25 -1
  34. package/dist/agents/skills/gemini-cli/initialize-harness-project/SKILL.md +22 -6
  35. package/dist/agents/skills/gemini-cli/initialize-harness-project/skill.yaml +2 -1
  36. package/dist/agents/skills/gemini-cli/initialize-test-suite-project/SKILL.md +415 -0
  37. package/dist/agents/skills/gemini-cli/initialize-test-suite-project/skill.yaml +35 -0
  38. package/dist/agents/skills/package.json +2 -2
  39. package/dist/agents/skills/tests/initialize-test-suite-project.test.ts +152 -0
  40. package/dist/{agents-md-QPO3H5HX.js → agents-md-VI3HLR7E.js} +3 -3
  41. package/dist/{architecture-IJLXRHZA.js → architecture-ZDDKEVID.js} +4 -4
  42. package/dist/{assess-project-QU6XIVJK.js → assess-project-Y6W7YDUA.js} +1 -1
  43. package/dist/bin/harness-mcp.js +16 -15
  44. package/dist/bin/harness.js +27 -27
  45. package/dist/{check-phase-gate-TNY64AOS.js → check-phase-gate-CXR3VM22.js} +4 -4
  46. package/dist/{chunk-JJQ3TW2E.js → chunk-2BPPS6YQ.js} +804 -93
  47. package/dist/{chunk-NKQEMWGT.js → chunk-2FPUPRCY.js} +3419 -126
  48. package/dist/{chunk-MLOGYWLY.js → chunk-3AMQYWGT.js} +2 -2
  49. package/dist/{chunk-AS5DQT4S.js → chunk-56A6OXVA.js} +9 -9
  50. package/dist/{chunk-G5SNXUIK.js → chunk-7GY6WNEI.js} +1 -1
  51. package/dist/{chunk-SZ3Q4XEO.js → chunk-AMRC4FU2.js} +441 -288
  52. package/dist/{chunk-K533WNZG.js → chunk-B66LRB5M.js} +1 -1
  53. package/dist/{chunk-YRBNAHH4.js → chunk-BK4DJIIY.js} +4 -4
  54. package/dist/{chunk-2DF6OZLG.js → chunk-DBIX3X4H.js} +2 -2
  55. package/dist/{chunk-LXPRO2FH.js → chunk-FUND5WJR.js} +2 -2
  56. package/dist/{chunk-FRDS4XGD.js → chunk-JV4Y2U5F.js} +1 -1
  57. package/dist/{chunk-XVJRFP7W.js → chunk-K56DTX7G.js} +6 -6
  58. package/dist/{chunk-K35D7HF3.js → chunk-N6B6RKQQ.js} +1 -1
  59. package/dist/{chunk-LTCEV7VF.js → chunk-NY7DTZ6K.js} +3 -3
  60. package/dist/{chunk-JPZY7ZQX.js → chunk-OLW7BJ5N.js} +1 -1
  61. package/dist/{chunk-KVJZQ2MV.js → chunk-ORNEK65Y.js} +1 -1
  62. package/dist/{chunk-D3XL2FLX.js → chunk-PNNFCVW4.js} +5 -5
  63. package/dist/{chunk-E5Z6NTTQ.js → chunk-Q3ZLVMQM.js} +1 -1
  64. package/dist/{chunk-PCOU2UXU.js → chunk-RAVD7QLY.js} +8 -8
  65. package/dist/{chunk-IQO7IINR.js → chunk-TSVYBDDE.js} +1 -1
  66. package/dist/{chunk-MCDCZMKN.js → chunk-TY2ESLVL.js} +1 -1
  67. package/dist/{chunk-TQRCODRJ.js → chunk-VKS3F46M.js} +1 -1
  68. package/dist/{chunk-GVNT2YC7.js → chunk-WZ7UHPT3.js} +9 -9
  69. package/dist/{chunk-ZIYLIYN4.js → chunk-YC4EYIER.js} +8 -2
  70. package/dist/{chunk-IT2KORSK.js → chunk-ZN6ROTYP.js} +1 -1
  71. package/dist/{ci-workflow-FJYRFZYQ.js → ci-workflow-EW37KVPS.js} +3 -3
  72. package/dist/{create-skill-6QWJHQYS.js → create-skill-4T5CBSJ2.js} +2 -2
  73. package/dist/{dist-ZV6GO6FA.js → dist-CJDGASPP.js} +2 -2
  74. package/dist/{dist-HPWNWCT6.js → dist-NCNAXUFD.js} +41 -1
  75. package/dist/{docs-7DW3DI4Z.js → docs-4XI2FQW2.js} +4 -4
  76. package/dist/{engine-P7EE2IWO.js → engine-4L4CDTHU.js} +3 -3
  77. package/dist/{entropy-HCXRTDFU.js → entropy-PBYSIQYS.js} +3 -3
  78. package/dist/{feedback-Y4FYN3NR.js → feedback-OTIFW5MK.js} +1 -1
  79. package/dist/{generate-agent-definitions-3EHPIWBO.js → generate-agent-definitions-CZGUXIIN.js} +4 -4
  80. package/dist/{graph-loader-KXVS3YK3.js → graph-loader-RDXSEBD7.js} +1 -1
  81. package/dist/index.d.ts +8 -8
  82. package/dist/index.js +27 -27
  83. package/dist/{loader-SKHF3JVV.js → loader-UZOXCWFC.js} +3 -3
  84. package/dist/{mcp-MWYIPDQU.js → mcp-GWVVV6LH.js} +16 -15
  85. package/dist/{performance-ADWH5NJY.js → performance-5UQPP3XX.js} +4 -4
  86. package/dist/{review-pipeline-TLKE5OQD.js → review-pipeline-65V4EO6O.js} +3 -3
  87. package/dist/{runtime-7LYAW7GU.js → runtime-PXX7HNB3.js} +3 -3
  88. package/dist/{scan-BGJ7TLLV.js → scan-WM7XDUF7.js} +1 -1
  89. package/dist/{security-5XWINYVB.js → security-CAYDRZIZ.js} +1 -1
  90. package/dist/{validate-BFFHYHY7.js → validate-CWGXR7QM.js} +4 -4
  91. package/dist/{validate-cross-check-GQX7OVCR.js → validate-cross-check-BKCNLZYG.js} +3 -3
  92. package/package.json +10 -10
  93. package/dist/agents/commands/claude-code/harness/harness.md +0 -36
  94. package/dist/agents/commands/codex/AGENTS.md +0 -39
  95. package/dist/agents/commands/codex/harness/add-harness-component/SKILL.md +0 -204
  96. package/dist/agents/commands/codex/harness/add-harness-component/agents/openai.yaml +0 -3
  97. package/dist/agents/commands/codex/harness/cleanup-dead-code/SKILL.md +0 -257
  98. package/dist/agents/commands/codex/harness/cleanup-dead-code/agents/openai.yaml +0 -3
  99. package/dist/agents/commands/codex/harness/detect-doc-drift/SKILL.md +0 -191
  100. package/dist/agents/commands/codex/harness/detect-doc-drift/agents/openai.yaml +0 -3
  101. package/dist/agents/commands/codex/harness/enforce-architecture/SKILL.md +0 -289
  102. package/dist/agents/commands/codex/harness/enforce-architecture/agents/openai.yaml +0 -3
  103. package/dist/agents/commands/codex/harness/harness-architecture-advisor/SKILL.md +0 -442
  104. package/dist/agents/commands/codex/harness/harness-architecture-advisor/agents/openai.yaml +0 -3
  105. package/dist/agents/commands/codex/harness/harness-autopilot/SKILL.md +0 -929
  106. package/dist/agents/commands/codex/harness/harness-autopilot/agents/openai.yaml +0 -3
  107. package/dist/agents/commands/codex/harness/harness-brainstorming/SKILL.md +0 -418
  108. package/dist/agents/commands/codex/harness/harness-brainstorming/agents/openai.yaml +0 -3
  109. package/dist/agents/commands/codex/harness/harness-code-review/SKILL.md +0 -850
  110. package/dist/agents/commands/codex/harness/harness-code-review/agents/openai.yaml +0 -3
  111. package/dist/agents/commands/codex/harness/harness-codebase-cleanup/SKILL.md +0 -236
  112. package/dist/agents/commands/codex/harness/harness-codebase-cleanup/agents/openai.yaml +0 -3
  113. package/dist/agents/commands/codex/harness/harness-debugging/SKILL.md +0 -378
  114. package/dist/agents/commands/codex/harness/harness-debugging/agents/openai.yaml +0 -3
  115. package/dist/agents/commands/codex/harness/harness-dependency-health/SKILL.md +0 -190
  116. package/dist/agents/commands/codex/harness/harness-dependency-health/agents/openai.yaml +0 -3
  117. package/dist/agents/commands/codex/harness/harness-docs-pipeline/SKILL.md +0 -472
  118. package/dist/agents/commands/codex/harness/harness-docs-pipeline/agents/openai.yaml +0 -3
  119. package/dist/agents/commands/codex/harness/harness-execution/SKILL.md +0 -522
  120. package/dist/agents/commands/codex/harness/harness-execution/agents/openai.yaml +0 -3
  121. package/dist/agents/commands/codex/harness/harness-hotspot-detector/SKILL.md +0 -172
  122. package/dist/agents/commands/codex/harness/harness-hotspot-detector/agents/openai.yaml +0 -3
  123. package/dist/agents/commands/codex/harness/harness-impact-analysis/SKILL.md +0 -195
  124. package/dist/agents/commands/codex/harness/harness-impact-analysis/agents/openai.yaml +0 -3
  125. package/dist/agents/commands/codex/harness/harness-integrity/SKILL.md +0 -178
  126. package/dist/agents/commands/codex/harness/harness-integrity/agents/openai.yaml +0 -3
  127. package/dist/agents/commands/codex/harness/harness-onboarding/SKILL.md +0 -299
  128. package/dist/agents/commands/codex/harness/harness-onboarding/agents/openai.yaml +0 -3
  129. package/dist/agents/commands/codex/harness/harness-perf/SKILL.md +0 -272
  130. package/dist/agents/commands/codex/harness/harness-perf/agents/openai.yaml +0 -3
  131. package/dist/agents/commands/codex/harness/harness-planning/SKILL.md +0 -592
  132. package/dist/agents/commands/codex/harness/harness-planning/agents/openai.yaml +0 -3
  133. package/dist/agents/commands/codex/harness/harness-refactoring/SKILL.md +0 -181
  134. package/dist/agents/commands/codex/harness/harness-refactoring/agents/openai.yaml +0 -3
  135. package/dist/agents/commands/codex/harness/harness-release-readiness/SKILL.md +0 -701
  136. package/dist/agents/commands/codex/harness/harness-release-readiness/agents/openai.yaml +0 -3
  137. package/dist/agents/commands/codex/harness/harness-roadmap/SKILL.md +0 -607
  138. package/dist/agents/commands/codex/harness/harness-roadmap/agents/openai.yaml +0 -3
  139. package/dist/agents/commands/codex/harness/harness-security-scan/SKILL.md +0 -147
  140. package/dist/agents/commands/codex/harness/harness-security-scan/agents/openai.yaml +0 -3
  141. package/dist/agents/commands/codex/harness/harness-skill-authoring/SKILL.md +0 -314
  142. package/dist/agents/commands/codex/harness/harness-skill-authoring/agents/openai.yaml +0 -3
  143. package/dist/agents/commands/codex/harness/harness-soundness-review/SKILL.md +0 -1280
  144. package/dist/agents/commands/codex/harness/harness-soundness-review/agents/openai.yaml +0 -3
  145. package/dist/agents/commands/codex/harness/harness-supply-chain-audit/SKILL.md +0 -255
  146. package/dist/agents/commands/codex/harness/harness-supply-chain-audit/agents/openai.yaml +0 -3
  147. package/dist/agents/commands/codex/harness/harness-tdd/SKILL.md +0 -189
  148. package/dist/agents/commands/codex/harness/harness-tdd/agents/openai.yaml +0 -3
  149. package/dist/agents/commands/codex/harness/harness-test-advisor/SKILL.md +0 -171
  150. package/dist/agents/commands/codex/harness/harness-test-advisor/agents/openai.yaml +0 -3
  151. package/dist/agents/commands/codex/harness/harness-verification/SKILL.md +0 -433
  152. package/dist/agents/commands/codex/harness/harness-verification/agents/openai.yaml +0 -3
  153. package/dist/agents/commands/codex/harness/harness-verify/SKILL.md +0 -170
  154. package/dist/agents/commands/codex/harness/harness-verify/agents/openai.yaml +0 -3
  155. package/dist/agents/commands/codex/harness/initialize-harness-project/SKILL.md +0 -244
  156. package/dist/agents/commands/codex/harness/initialize-harness-project/agents/openai.yaml +0 -3
  157. package/dist/agents/commands/cursor/harness/add-harness-component.mdc +0 -200
  158. package/dist/agents/commands/cursor/harness/cleanup-dead-code.mdc +0 -253
  159. package/dist/agents/commands/cursor/harness/detect-doc-drift.mdc +0 -187
  160. package/dist/agents/commands/cursor/harness/enforce-architecture.mdc +0 -304
  161. package/dist/agents/commands/cursor/harness/harness-architecture-advisor.mdc +0 -457
  162. package/dist/agents/commands/cursor/harness/harness-autopilot.mdc +0 -924
  163. package/dist/agents/commands/cursor/harness/harness-brainstorming.mdc +0 -414
  164. package/dist/agents/commands/cursor/harness/harness-code-review.mdc +0 -865
  165. package/dist/agents/commands/cursor/harness/harness-codebase-cleanup.mdc +0 -232
  166. package/dist/agents/commands/cursor/harness/harness-debugging.mdc +0 -374
  167. package/dist/agents/commands/cursor/harness/harness-dependency-health.mdc +0 -187
  168. package/dist/agents/commands/cursor/harness/harness-docs-pipeline.mdc +0 -468
  169. package/dist/agents/commands/cursor/harness/harness-execution.mdc +0 -518
  170. package/dist/agents/commands/cursor/harness/harness-hotspot-detector.mdc +0 -169
  171. package/dist/agents/commands/cursor/harness/harness-impact-analysis.mdc +0 -192
  172. package/dist/agents/commands/cursor/harness/harness-integrity.mdc +0 -175
  173. package/dist/agents/commands/cursor/harness/harness-onboarding.mdc +0 -296
  174. package/dist/agents/commands/cursor/harness/harness-perf.mdc +0 -268
  175. package/dist/agents/commands/cursor/harness/harness-planning.mdc +0 -587
  176. package/dist/agents/commands/cursor/harness/harness-refactoring.mdc +0 -177
  177. package/dist/agents/commands/cursor/harness/harness-release-readiness.mdc +0 -697
  178. package/dist/agents/commands/cursor/harness/harness-roadmap.mdc +0 -603
  179. package/dist/agents/commands/cursor/harness/harness-security-scan.mdc +0 -162
  180. package/dist/agents/commands/cursor/harness/harness-skill-authoring.mdc +0 -300
  181. package/dist/agents/commands/cursor/harness/harness-soundness-review.mdc +0 -1275
  182. package/dist/agents/commands/cursor/harness/harness-supply-chain-audit.mdc +0 -252
  183. package/dist/agents/commands/cursor/harness/harness-tdd.mdc +0 -185
  184. package/dist/agents/commands/cursor/harness/harness-test-advisor.mdc +0 -168
  185. package/dist/agents/commands/cursor/harness/harness-verification.mdc +0 -429
  186. package/dist/agents/commands/cursor/harness/harness-verify.mdc +0 -167
  187. package/dist/agents/commands/cursor/harness/initialize-harness-project.mdc +0 -240
  188. package/dist/agents/commands/gemini-cli/harness/harness.toml +0 -277
  189. package/dist/{chunk-RRHUCDRD.js → chunk-ZP5E7YET.js} +3 -3
@@ -0,0 +1,415 @@
1
+ # Initialize Test Suite Project
2
+
3
+ > Scaffold or migrate a test-suite project — API, E2E/UI, or shared test library. Owns test-suite-specific archetype selection, shared-library vs in-repo scaffolding decision, layer variants, tag taxonomy, reporter stack, and custom report. Cross-cutting concerns (adoption level, personas, AGENTS.md base template, i18n, knowledge graph, roadmap nudge, final commit) delegate to `initialize-harness-project`.
4
+
5
+ ## When to Use
6
+
7
+ - Initializing a new test-suite project (you already know it is a test suite)
8
+ - Migrating an existing test-suite project to the next adoption level
9
+ - When `initialize-harness-project`'s Phase 1 classification step hands off here
10
+ - NOT when the project is a product or service (use `initialize-harness-project`)
11
+ - NOT when adding a single spec, domain, or fixture to an already-configured test suite (use `add-harness-component`)
12
+
13
+ ## Composition with `initialize-harness-project`
14
+
15
+ This skill owns only the _test-suite-specific_ pieces. The generic harness flow belongs to the parent skill. Two invocation patterns:
16
+
17
+ 1. **Parent dispatches here.** The user runs `initialize-harness-project`; its Phase 1 step 5 classifies the project as a test suite and dispatches to this skill. Run the parent's Phase 2 (scaffolding) first, then this skill's full flow, then return to the parent for Phase 4 wrap-up (knowledge graph, roadmap, commit).
18
+
19
+ 2. **Direct invocation.** The user knows up front it's a test suite and invokes this skill directly. Run the parent's Phase 1 (assess state), Phase 2 (`harness init`), and Phase 3 steps 1–2 and 5 (personas, AGENTS.md base, i18n) inline or by invoking the parent explicitly, then apply this skill's Phase 1–4, then hand back to the parent's Phase 4 steps 4–5.
20
+
21
+ Either way, what this skill owns: archetype selection, shared-library vs scaffold decision, layer-model variants A/B, ESLint flat-config fix, test-framework delegation, env and secrets, auth abstraction, schema validation, fixtures isolation, mocking support, tag-driven organization, reporters, the custom report, CI integration, and "prove the guards fire" verification.
22
+
23
+ ## Process
24
+
25
+ ### Phase 1: CLASSIFY — Pick the Archetype
26
+
27
+ Before scaffolding, classify the project and record in the assessment.
28
+
29
+ **Test-suite signals** (at least one must apply — re-check even if dispatched from the parent):
30
+
31
+ - Repo or package name matches `*test*`, `*-e2e*`, `*-qa*`, `*-automation*`
32
+ - `package.json` has `@playwright/test`, `cypress`, `webdriverio`, `mocha`, or `testcafe` as a direct dep (frameworks that are _only_ test-related — presence of `vitest`/`jest` alone is not enough)
33
+ - Top-level `tests/`, `e2e/`, `specs/`, or `playwright/` directories are the primary source tree, not an adjunct to `src/`
34
+ - Config files like `playwright.config.*`, `cypress.config.*`, `wdio.conf.*`
35
+ - No production runtime — build output is consumed only by other test repos (shared library)
36
+
37
+ **Archetypes:**
38
+
39
+ - **API test suite** — exercises HTTP APIs end-to-end (e.g. Playwright API tests)
40
+ - **E2E / UI suite** — browser-driven tests (Playwright, Cypress, WebdriverIO)
41
+ - **Shared test library** — API clients, Page Object Models, fixtures, or test users consumed by the above; no tests in-repo
42
+
43
+ ### Phase 2: DECIDE — Shared Library or Scaffold In-Repo?
44
+
45
+ For **API** and **E2E/UI** suites, check whether a shared library already exists — typically a team-specific `@<org>/<team>-testing-api-library` for API clients, or an equivalent for Page Object Models. If one exists, consuming it is strongly preferred: one client implementation shared by all test suites is the contract source of truth and avoids drift. Only scaffold an in-repo `src/api/` or `src/page-objects/` tree if no shared library exists or the suite has a genuinely different contract.
46
+
47
+ For **Shared test library** archetypes, this phase is trivial — you _are_ the shared library; scaffold in-repo.
48
+
49
+ Record the decision in AGENTS.md. It determines which layer-model variant applies in Phase 3 step 2.
50
+
51
+ ### Phase 3: CONFIGURE — Test-Suite Shape
52
+
53
+ Apply these steps before running validation. Record decisions in AGENTS.md as you go.
54
+
55
+ 1. **Pick a domain layout.** Independent of whether clients are in-repo or imported, domains drive the folder layout:
56
+ - **Self-contained suite:** one folder per API domain, feature area, or user flow under `src/api/` or `src/page-objects/`, each exposing a manager/client class (API suites) or Page Object Model (UI suites) that takes an HTTP client or browser context in its constructor. A single composition module wires everything together.
57
+ - **Shared-library consumer:** no per-domain folders in `src/`. Instead, a thin `config/` adapter wraps the shared library's entry point (e.g. exposes `{api, user}` on the Playwright test fixture). Tests are still organized by domain — see step 10 — but the domain folders live under `tests/<domain>/`, not `src/api/<domain>/`.
58
+
59
+ Document the chosen layout in AGENTS.md with a directory tree.
60
+
61
+ 2. **Define the layer model.** Two variants — pick the one matching Phase 2.
62
+
63
+ **Variant A — self-contained test suite.** Record in `harness.config.json`:
64
+ - `utils` → helpers, date/string/id utilities (no internal deps)
65
+ - `composition` → single wiring module (e.g. `managers.ts`) → allowed to import every layer below
66
+ - `common` → shared DTOs, enums, error types → `utils`
67
+ - `config` → HTTP client, auth service, environment loader → `utils`, `common`
68
+ - `api` / `domains` / `page-objects` → per-domain managers or POMs → `utils`, `common`, `config`
69
+ - `fixtures` → deterministic seed data, factories, builders → `utils`, `common`, `config`
70
+ - `specs` → top layer; imports composition + fixtures; nothing imports specs
71
+
72
+ Forbid (same-layer rules, enforced via `forbiddenImports`):
73
+ - A domain/POM importing a sibling domain/POM (domains are peers, not hierarchical)
74
+ - `fixtures` importing specs
75
+ - Specs importing each other (tests must be independently runnable in any order)
76
+
77
+ **Variant B — shared-library consumer.** No `common`, no `api` layer — those live in the shared library. Record in `harness.config.json`:
78
+ - `utils` → helpers with no internal deps
79
+ - `config` → thin adapter wrapping the shared library (e.g. builds the `Managers` from the shared lib + current env), token handler, constants → `utils`
80
+ - `fixtures` → Playwright test fixtures that expose `{api, user, ...}` to specs → `utils`, `config`
81
+ - `specs` → top layer; imports `fixtures` → `utils`, `config`, `fixtures`
82
+
83
+ Forbid:
84
+ - Specs bypassing `fixtures` and instantiating the shared library directly — always go through the fixture so auth, base URL, and teardown are consistent
85
+ - `fixtures` importing specs
86
+ - Any layer importing the shared library from outside `config` (forces single adapter point, keeps upgrades localized)
87
+
88
+ **Layer-ordering gotcha — `harness check-deps` and `@harness-engineering/eslint-plugin` both use first-match-wins layer resolution.** Put more-specific patterns _before_ more-general ones in the `layers` array. For Variant A, `composition` (pattern `src/config/managers.ts`) must come before `config` (pattern `src/config/**`), otherwise `managers.ts` is classified as `config` and every `api` import becomes a layer violation. Do not rely on per-layer `excludePatterns` — the CLI and the ESLint plugin both drop that field.
89
+
90
+ **`forbiddenImports` gotcha — no `exceptPaths` support.** The ESLint plugin schema for `forbiddenImports` only accepts `from`, `disallow`, `message` — any other keys (including `exceptPaths`) are silently stripped. Do not write `from: src/config/**, disallow: [src/api/**], exceptPaths: [src/config/managers.ts]` and expect it to work. Use layer ordering (above) to carve out the composition file; reserve `forbiddenImports` for same-layer rules like sibling-domain isolation that the layer graph cannot express.
91
+
92
+ 3. **Wire up the ESLint flat config so the forbidden-imports rule actually runs.** `harness init` scaffolds `eslint.config.mjs` that spreads `harnessPlugin.configs.recommended` but does not declare a `files:` glob or a TypeScript parser. Under ESLint 9 flat config this means every `.ts` file is ignored and the rule never fires. Replace the scaffolded config with an explicit block: `files: ['src/**/*.ts', 'tests/**/*.ts']`, `languageOptions: { parser: tsParser, parserOptions: { ecmaVersion: 'latest', sourceType: 'module' } }`, `plugins: { '@harness-engineering': harnessPlugin }`, and the three `'error'` rules (`no-layer-violation`, `no-forbidden-imports`, `no-circular-deps`). Add `@typescript-eslint/parser` to devDependencies. Verify by running `npx eslint 'src/**/*.ts'` and seeing it actually report errors on a deliberately bad file.
93
+
94
+ 4. **Pick the test framework(s) and delegate detailed setup to the right skill.** Do not configure the framework here — just record the choice in AGENTS.md and point the human at the follow-up skill:
95
+ - Playwright (API or E2E) → `test-playwright-setup` then `test-playwright-patterns`
96
+ - Vitest → `test-vitest-config`
97
+ - Contract tests → `api-contract-testing` and `test-contract-testing`
98
+ - Mocking (MSW, route interception) → `test-msw-pattern`, `test-mock-patterns`
99
+ - Fixtures / factories → `test-factory-patterns`, `harness-test-data`
100
+ - For shared libraries that are _consumed_ by tests but contain none themselves, skip framework setup entirely — record this in AGENTS.md under "Gotchas" so agents do not try to add Vitest later.
101
+
102
+ 5. **Environment and secret handling.** Require a committed `.env.example` listing every variable the suite reads (API base URLs, OAuth client IDs, registry tokens, feature flags). Actual `.env*` files must be gitignored. For multi-environment suites, encode environments as `.env.dev`, `.env.stage`, `.env.prod` and document in AGENTS.md how the runner selects one (env var, CLI flag, or config). Never commit real credentials even as examples — use placeholders like `REPLACE_ME`.
103
+
104
+ 6. **Authentication abstraction.** Record in AGENTS.md: token source (OAuth client-credentials, CIAM, basic auth, session cookie), caching strategy (in-memory, file, Redis), and how test users or parent/child scopes are resolved. If a shared test-user library exists (typically `@<org>/<team>-testing-user-library` or similar), link it and forbid inlining user credentials in specs.
105
+
106
+ 7. **Schema / contract validation.** Decide whether request and response DTOs are validated at runtime (zod, ajv, io-ts) or only compile-time. Intermediate and above should validate at runtime for contract-drift detection. If adopting zod, reference `zod-schema-definition`.
107
+
108
+ 8. **Fixtures and test-data isolation.** Document the per-test isolation strategy in AGENTS.md: unique IDs per run (UUID suffixes, timestamps), teardown hooks, no shared mutable state between specs. Forbid hard-coded production record IDs in fixtures.
109
+
110
+ 9. **Mocking support (shared libraries and API clients).** If the project will be consumed by FE or UI test suites that need to mock upstream responses, expose mock response builders (e.g. `buildMockResponse`, `buildMockErrorResponse`) and document the override API in AGENTS.md so consumer projects know the contract.
111
+
112
+ 10. **Test organization: tags over folders.** Do _not_ split specs into `tests/smoke/`, `tests/regression/`, etc. Organize specs by domain / feature area (`tests/<domain>/<feature>.spec.ts`) and filter run shape with tags. This matches how Playwright (and most modern runners) expect grep-based filtering to work, and avoids moving a spec file whenever its coverage tier changes.
113
+
114
+ Record the tag taxonomy in AGENTS.md. Baseline for a Playwright API suite:
115
+ - `@smoke` — fast subset; PR gate. Applied per-test or per-describe.
116
+ - Untagged = regression. "Full suite" is just `playwright test` with no grep.
117
+ - **Quarantine tags (never run):** `@known-failure`, `@wip`, `@blocked`, `@archived`. Exclude these globally via `grepInvert` in `playwright.config.ts`:
118
+ ```ts
119
+ grepInvert: [/@known-failure/, /@wip/, /@blocked/, /@archived/],
120
+ ```
121
+
122
+ Filter commands (bake into `package.json` scripts, not ad-hoc CI yaml):
123
+ - `npm run smoke` → `playwright test --grep @smoke`
124
+ - `npm run exhaustive` → `playwright test` (full regression, quarantine excluded)
125
+ - `npm run list` → `playwright test --list` (sanity check after tag edits)
126
+
127
+ **Reporters.** Configure `playwright.config.ts` with the stack that feeds both human and machine consumers:
128
+
129
+ ```ts
130
+ reporter: [
131
+ ['html', {outputFolder: './test-results/html-test-results', open: 'never'}],
132
+ ['list'],
133
+ ['github'],
134
+ ['json', {outputFile: 'test-results/json-results/results.json'}],
135
+ ],
136
+ ```
137
+
138
+ The `json` reporter is the input to the custom report in step 11. The `github` reporter produces annotations on PRs; `list` is for local stdout; `html` is for deep-dive failure triage.
139
+
140
+ 11. **Custom report (enriched HTML + Slack + history).** Playwright's stock HTML report is fine for a single run but does not track trends, categorize failures, or know which tests are quarantined. Scaffold a `scripts/generate-reports.ts` that reads the JSON reporter output (`test-results/json-results/results.json`) and emits an enriched report. Modeled on reference implementations running in production test suites, it should produce:
141
+ - **Failure categorization:** bucket each failure into one of `schema | auth | server | client | timeout | network | other` based on the error message. Surfaces whether a red run is an API regression (schema) vs. infrastructure (timeout/network) vs. test-data problem (auth).
142
+ - **Per-area health:** group by domain folder (first path segment under `tests/`), report pass rate and failing titles per area. Tells you which surface of the product is drifting.
143
+ - **Delta vs history:** append each run to a JSONL ledger keyed by commit. Report new failures since last run and failures since last green — not just "X failed" but "X started failing at commit Y."
144
+ - **Quarantine ledger:** scan for `@known-failure`-tagged tests, track age since first seen in a JSON ledger, flag tests quarantined longer than 14 days.
145
+ - **Slack summary:** short markdown block with pass rate, new failures, and a link to the HTML report. Optional but cheap once the categorization exists.
146
+ - **Environment + git context:** node version, base URL, commit SHA, branch, commit message — so a report opened later tells you where and when it ran.
147
+
148
+ Wire the script into `package.json`:
149
+
150
+ ```json
151
+ {
152
+ "scripts": {
153
+ "generate-custom-reports": "npx ts-node scripts/generate-reports.ts",
154
+ "show-custom-report": "open test-results/reports/test-report.html"
155
+ }
156
+ }
157
+ ```
158
+
159
+ Do not block CI on the custom report — run it as a post-step and upload the output as an artifact. If categorization throws on an unexpected error shape, the exit code should be non-fatal.
160
+
161
+ 12. **CI integration.** For intermediate+: PR pipeline runs `npm run smoke` (tag-filtered, not folder-filtered); main merges trigger `npm run exhaustive`; nightly runs `npm run exhaustive` plus a quarantine audit (step 11) reporting quarantined-too-long tests. Record the flake policy (max retries, quarantine threshold) in `harness.config.json` so agents do not silently raise retries to hide flakes.
162
+
163
+ ### Phase 4: VALIDATE — Prove the Guards Fire
164
+
165
+ Run the three gates on the clean tree:
166
+
167
+ ```bash
168
+ harness validate
169
+ harness check-deps
170
+ npx eslint 'src/**/*.ts' 'tests/**/*.ts'
171
+ ```
172
+
173
+ All three must pass before proceeding.
174
+
175
+ **Clean-tree passing is necessary but not sufficient.** All three tools can pass while the rules are silently misconfigured (layer ordering wrong, ESLint files glob missing, forbidden-imports schema fields dropped). Before handing back to `initialize-harness-project` for wrap-up:
176
+
177
+ - Insert one deliberate forbidden import — a sibling-domain import is the easiest (e.g. `src/api/users/users-manager.ts` importing `../auth/auth-manager`). Run `npx eslint <file>` and confirm it reports the violation.
178
+ - Insert one deliberate cross-layer import (e.g. `src/utils/foo.ts` importing from `src/api/users/`). Run `harness check-deps` and confirm it reports the violation.
179
+ - Revert both edits. Confirm the clean tree is green on all three gates.
180
+
181
+ After verification passes, return to `initialize-harness-project`'s Phase 4 for:
182
+
183
+ - `harness scan` (knowledge graph)
184
+ - Roadmap nudge
185
+ - Final commit
186
+
187
+ ## Harness Integration
188
+
189
+ - **`initialize-harness-project`** — parent skill. Owns adoption-level selection, `harness init` invocation, persona configuration, AGENTS.md base template, i18n decision, knowledge-graph build, roadmap nudge, final commit.
190
+ - **`harness validate`** — verifies `harness.config.json` schema, AGENTS.md, layers, persona config.
191
+ - **`harness check-deps`** — verifies layer-graph dependency constraints at the file level.
192
+ - **`@harness-engineering/eslint-plugin`** — enforces `forbiddenImports` (same-layer rules) and surfaces layer-graph violations at lint time.
193
+ - **Follow-up test skills** — `test-playwright-setup`, `test-playwright-patterns`, `test-vitest-config`, `test-msw-pattern`, `test-mock-patterns`, `test-factory-patterns`, `harness-test-data`, `api-contract-testing`, `test-contract-testing`.
194
+ - **Related libraries** — `zod-schema-definition` (runtime DTO validation).
195
+
196
+ ## Success Criteria
197
+
198
+ - Archetype is recorded in AGENTS.md (API / E2E-UI / Shared library)
199
+ - Shared-library decision is recorded in AGENTS.md
200
+ - Layer model matches the chosen variant (A self-contained or B shared-library consumer) from Phase 3 step 2
201
+ - Layer ordering puts `composition` before `config` (Variant A only)
202
+ - `forbiddenImports` uses only `{from, disallow, message}` — no silently-dropped `exceptPaths`
203
+ - `eslint.config.mjs` declares an explicit `files:` glob and imports a TypeScript parser
204
+ - `.env.example` is present with `REPLACE_ME` placeholders
205
+ - No real secrets are committed (real `.env*` gitignored)
206
+ - Test framework choice and tag taxonomy (including `@smoke` + quarantine tags) are recorded in AGENTS.md
207
+ - Specs are organized `tests/<domain>/<feature>.spec.ts` — no `tests/smoke/` or `tests/regression/` folders
208
+ - `playwright.config.ts` declares html + list + github + json reporters and `grepInvert` for quarantine tags
209
+ - `scripts/generate-reports.ts` exists and is wired to `npm run generate-custom-reports`
210
+ - All three Phase 4 gates pass on the clean tree
211
+ - "Prove the guards fire" step completed — deliberate violations were caught and reverted
212
+ - Control returned to `initialize-harness-project` for knowledge-graph build and final commit
213
+
214
+ ## Rationalizations to Reject
215
+
216
+ | Rationalization | Why It Is Wrong |
217
+ | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
218
+ | "This is a test suite, so strict layer constraints are overkill" | Test suites benefit _more_ from layer constraints than product code — peer-domain imports and spec coupling are the top sources of flaky, hard-to-maintain suites. |
219
+ | "We can commit a real `.env` for convenience, CI will ignore it" | Phase 3 step 5 forbids committing real credentials. A leaked `.env` in a test repo leaks the same secrets as a product repo. Use `.env.example` with placeholders. |
220
+ | "Tests don't need tags — we'll run everything every time" | Without a `@smoke` tag the PR pipeline grows to 30+ minutes and drives developers to skip CI. Record a tag taxonomy in Phase 3 step 10 even if enforcement comes later. |
221
+ | "We'll split specs into `tests/smoke/` and `tests/regression/` for filtering" | Folder-based filtering forces a file move every time a spec's tier changes. Modern runners (Playwright, Vitest, Cypress) expect `--grep @tag`. Keep `tests/<domain>/<feature>.spec.ts` flat and tag per-test. |
222
+ | "We'll add schema validation later once the client stabilizes" | Runtime DTO validation is the primary contract-drift detector for API test suites. Adding it after tests exist means updating every spec. Decide in Phase 3 step 7. |
223
+ | "We'll copy the API client code into this test suite for convenience" | If a shared API client library already exists, consume it — do not fork. Forked clients drift immediately; the shared library is the contract source of truth. Only scaffold in-repo clients if no shared library exists. See Phase 2. |
224
+ | "Playwright's built-in HTML report is enough" | The built-in report shows a single run. It does not categorize failures (schema vs auth vs timeout), does not track regressions by commit, and does not surface tests quarantined for weeks. Scaffold `scripts/generate-reports.ts` per Phase 3 step 11. |
225
+ | "All three gates passed, so we're done" | Clean-tree passing can co-exist with silently-misconfigured rules (layer ordering wrong, eslint glob missing, forbidden-imports fields dropped). Phase 4 requires deliberately inserting a violation and confirming the tool catches it. |
226
+
227
+ ## Examples
228
+
229
+ ### Example: Initializing a Shared API Test Library (Intermediate)
230
+
231
+ **CLASSIFY:**
232
+
233
+ ```
234
+ Human: "New repo. It's a shared TypeScript HTTP client for our API test suites — consumed by Playwright API tests and also used to mock responses in FE tests. No tests live in this repo."
235
+ package.json has no Playwright/Vitest as direct deps (shared library, not a test runner).
236
+ Archetype: Shared test library.
237
+ ```
238
+
239
+ **DECIDE (Phase 2):**
240
+
241
+ ```
242
+ This is the shared library itself — scaffold in-repo. Phase 2 is trivial.
243
+ ```
244
+
245
+ **SCAFFOLD (delegated to `initialize-harness-project`):**
246
+
247
+ ```bash
248
+ harness init --level intermediate --language typescript
249
+ ```
250
+
251
+ **CONFIGURE (Phase 3):**
252
+
253
+ ```text
254
+ Domain layout: one folder per API domain under src/api/ (challenges, rewards,
255
+ user, oauth, ...). Each domain exposes <domain>-manager.ts taking HttpClient
256
+ in its constructor. Single composition module src/config/managers.ts wires
257
+ every domain from one HttpClient.
258
+
259
+ Layer model (Variant A, harness.config.json):
260
+ utils → src/utils/** (no internal deps)
261
+ composition → src/config/managers.ts → utils, common, config, api
262
+ common → src/api/common/** → utils
263
+ config → src/config/** → utils, common
264
+ api → src/api/** → utils, common, config
265
+
266
+ Layer ordering: composition BEFORE config (first-match-wins).
267
+
268
+ Forbidden (forbiddenImports):
269
+ - any src/api/<domain> importing a sibling src/api/<domain>
270
+ - src/api/common importing config or sibling domains
271
+
272
+ Framework: none in-repo (shared library). Gotcha recorded in AGENTS.md so
273
+ future agents don't scaffold Vitest.
274
+
275
+ Env: .env.example committed with GITHUB_ACCESS_TOKEN placeholder (registry
276
+ auth only). No runtime env vars — consumers pass config explicitly.
277
+
278
+ Auth: OAuth client-credentials with pluggable TokenStorage interface; parent
279
+ vs child scope resolution documented in docs/auth-flow.md. Link to
280
+ a shared test-user library for test-user data.
281
+
282
+ Schema validation: zod at runtime for all response DTOs. Reference
283
+ zod-schema-definition skill for future domain additions.
284
+
285
+ Mocking: expose buildMockResponse / buildMockSuccessResponse /
286
+ buildMockErrorResponse from src/config/mock-response.ts so FE test repos
287
+ can override per spec. Document override contract in docs/mock-response.md.
288
+ ```
289
+
290
+ **VALIDATE (Phase 4):**
291
+
292
+ ```bash
293
+ harness validate # Pass
294
+ harness check-deps # Pass — no sibling-domain violations
295
+ npx eslint 'src/**/*.ts' # Pass
296
+
297
+ # Prove the guards fire: insert a sibling-domain import, eslint reports it, revert.
298
+
299
+ # Hand back to initialize-harness-project:
300
+ harness scan # Builds .harness/graph/
301
+ git commit -m "feat: initialize harness project at intermediate level for shared API test library"
302
+ ```
303
+
304
+ ### Example: Playwright API Test Suite Consuming a Shared Library (Intermediate)
305
+
306
+ **CLASSIFY:**
307
+
308
+ ```
309
+ Human: "New repo. Playwright API tests for one of our backend services. A shared API client library already exists at @<org>/<team>-testing-api-library and a shared test-user library at @<org>/<team>-testing-user-library."
310
+ package.json will have @playwright/test as a direct dep → test suite signal.
311
+ Archetype: API test suite.
312
+ ```
313
+
314
+ **DECIDE (Phase 2):**
315
+
316
+ ```
317
+ Shared library exists → consume it. Layer variant B (shared-library consumer).
318
+ Do NOT scaffold src/api/. Record decision in AGENTS.md.
319
+ ```
320
+
321
+ **SCAFFOLD (delegated to `initialize-harness-project`):**
322
+
323
+ ```bash
324
+ harness init --level intermediate --language typescript
325
+ # Scaffolded output is a starting point — replace generic layers and eslint config.
326
+ ```
327
+
328
+ **CONFIGURE (Phase 3, Variant B):**
329
+
330
+ ```text
331
+ Dependencies: @<org>/<team>-testing-api-library, @<org>/<team>-testing-user-library,
332
+ @playwright/test, dotenv, zod.
333
+
334
+ Directory layout (no src/api/, no src/page-objects/):
335
+ config/
336
+ api-adapter.ts # Builds Managers from the shared library + env vars
337
+ api-client.ts # Fetcher wrapping Playwright's APIRequestContext
338
+ token-handler.ts # OAuth + test-user token resolution
339
+ constants.ts # TEST_ARTIFACTS_DIR, URLs, etc.
340
+ fixtures/
341
+ test-fixture.ts # Playwright fixture exposing {api, user}
342
+ test-no-init-auth-fixture.ts # Fixture for 401/auth-failure tests
343
+ expects.ts # expectOkResponse, expectUnauthorized, ...
344
+ tests/
345
+ challenges/
346
+ create.spec.ts
347
+ checkin.spec.ts
348
+ ...
349
+ oauth/
350
+ login.spec.ts
351
+ user-profile/
352
+ ...
353
+ global.setup.ts
354
+ global.teardown.ts
355
+ scripts/
356
+ generate-reports.ts
357
+ playwright.config.ts
358
+ .env.example
359
+ harness.config.json
360
+ AGENTS.md
361
+
362
+ Layer model (Variant B, harness.config.json):
363
+ utils → src/utils/** (no internal deps)
364
+ config → config/** → utils
365
+ fixtures → fixtures/** → utils, config
366
+ specs → tests/** → utils, config, fixtures
367
+
368
+ Forbidden (same-layer or cross-cutting):
369
+ - tests/** importing @<org>/<team>-testing-api-library directly
370
+ (must go through fixtures → config adapter)
371
+ - fixtures/** importing tests/**
372
+ - Specs importing each other
373
+
374
+ Tags (playwright.config.ts):
375
+ grepInvert: [/@known-failure/, /@wip/, /@blocked/, /@archived/]
376
+ Tag @smoke on PR-gate specs; untagged = regression.
377
+
378
+ Reporters (playwright.config.ts):
379
+ ['html', {outputFolder: './test-results/html-test-results', open: 'never'}],
380
+ ['list'],
381
+ ['github'],
382
+ ['json', {outputFile: 'test-results/json-results/results.json'}],
383
+
384
+ Custom report (scripts/generate-reports.ts):
385
+ Reads test-results/json-results/results.json. Emits HTML + Slack with:
386
+ failure categorization, per-area health, delta vs history, quarantine ledger.
387
+ Wired to `npm run generate-custom-reports` / `npm run show-custom-report`.
388
+
389
+ package.json scripts:
390
+ smoke: playwright test --grep @smoke
391
+ exhaustive: playwright test
392
+ list: playwright test --list
393
+ generate-custom-reports: npx ts-node scripts/generate-reports.ts
394
+ show-custom-report: open test-results/reports/test-report.html
395
+
396
+ .env.example: API_BASE_URL, OAUTH_TOKEN_URL, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET,
397
+ TEST_USER_POOL_URL, TEST_USER_POOL_TOKEN. Real .env is gitignored.
398
+ ```
399
+
400
+ **VALIDATE (Phase 4):**
401
+
402
+ ```bash
403
+ harness validate # Pass
404
+ harness check-deps # Pass
405
+ npm run lint # Pass
406
+ npm run smoke # Sanity: runs only @smoke-tagged specs
407
+
408
+ # Prove the forbidden-imports rule fires:
409
+ # temporarily add an import of @<org>/<team>-testing-api-library to a spec
410
+ npx eslint tests/challenges/create.spec.ts # Should report violation
411
+ # revert, confirm green
412
+
413
+ # Hand back to initialize-harness-project:
414
+ git commit -m "feat: initialize harness project at intermediate level for Playwright API suite"
415
+ ```
@@ -0,0 +1,35 @@
1
+ name: initialize-test-suite-project
2
+ version: "1.0.0"
3
+ description: Scaffold or migrate a test-suite project (API, E2E/UI, or shared library) with test-suite-specific layer models, tags, reporter stack, and custom report
4
+ stability: static
5
+ cognitive_mode: constructive-architect
6
+ triggers:
7
+ - manual
8
+ platforms:
9
+ - claude-code
10
+ - gemini-cli
11
+ - cursor
12
+ - codex
13
+ tools:
14
+ - Bash
15
+ - Read
16
+ - Write
17
+ - Glob
18
+ cli:
19
+ command: harness skill run initialize-test-suite-project
20
+ args:
21
+ - name: path
22
+ description: Project root path
23
+ required: false
24
+ mcp:
25
+ tool: run_skill
26
+ input:
27
+ skill: initialize-test-suite-project
28
+ path: string
29
+ type: flexible
30
+ tier: 1
31
+ state:
32
+ persistent: false
33
+ files: []
34
+ depends_on:
35
+ - initialize-harness-project
@@ -9,9 +9,9 @@
9
9
  "test:coverage": "vitest run --coverage"
10
10
  },
11
11
  "devDependencies": {
12
- "@vitest/coverage-v8": "^4.1.2",
12
+ "@vitest/coverage-v8": "^4.1.5",
13
13
  "glob": "^10.5.0",
14
- "vitest": "^4.1.2",
14
+ "vitest": "^4.1.5",
15
15
  "yaml": "^2.8.3",
16
16
  "zod": "^3.25.76"
17
17
  }
@@ -0,0 +1,152 @@
1
+ // agents/skills/tests/initialize-test-suite-project.test.ts
2
+ //
3
+ // Contract tests for the initialize-test-suite-project skill. Generic schema,
4
+ // structure, and platform-parity checks live in the sibling *.test.ts files;
5
+ // this file locks in invariants specific to this skill — its composition with
6
+ // initialize-harness-project, phase structure, and the cross-file references
7
+ // that make the slash command and docs discoverable.
8
+
9
+ import { describe, it, expect } from 'vitest';
10
+ import { readFileSync, existsSync } from 'fs';
11
+ import { resolve, dirname } from 'path';
12
+ import { fileURLToPath } from 'url';
13
+ import { parse } from 'yaml';
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const SKILLS_DIR = resolve(__dirname, '..');
17
+ const REPO_ROOT = resolve(SKILLS_DIR, '..', '..');
18
+
19
+ const SKILL_NAME = 'initialize-test-suite-project';
20
+ const PARENT_SKILL = 'initialize-harness-project';
21
+ const PLATFORMS = ['claude-code', 'gemini-cli', 'cursor', 'codex'] as const;
22
+
23
+ function readSkillYaml(platform: string): Record<string, unknown> {
24
+ const path = resolve(SKILLS_DIR, platform, SKILL_NAME, 'skill.yaml');
25
+ return parse(readFileSync(path, 'utf-8'));
26
+ }
27
+
28
+ function readSkillMd(platform: string): string {
29
+ return readFileSync(resolve(SKILLS_DIR, platform, SKILL_NAME, 'SKILL.md'), 'utf-8');
30
+ }
31
+
32
+ describe('initialize-test-suite-project metadata', () => {
33
+ it.each(PLATFORMS)('%s skill.yaml declares correct name and tier', (platform) => {
34
+ const meta = readSkillYaml(platform);
35
+ expect(meta.name).toBe(SKILL_NAME);
36
+ expect(meta.tier).toBe(1);
37
+ expect(meta.type).toBe('flexible');
38
+ expect(meta.cognitive_mode).toBe('constructive-architect');
39
+ });
40
+
41
+ it.each(PLATFORMS)('%s skill.yaml depends on initialize-harness-project', (platform) => {
42
+ const meta = readSkillYaml(platform);
43
+ expect(meta.depends_on).toContain(PARENT_SKILL);
44
+ });
45
+
46
+ it.each(PLATFORMS)('%s skill.yaml is registered for all four platforms', (platform) => {
47
+ const meta = readSkillYaml(platform) as { platforms: string[] };
48
+ for (const p of PLATFORMS) {
49
+ expect(meta.platforms).toContain(p);
50
+ }
51
+ });
52
+
53
+ it.each(PLATFORMS)('%s skill.yaml does not set a custom command_namespace', (platform) => {
54
+ const meta = readSkillYaml(platform) as Record<string, unknown>;
55
+ expect(meta.command_namespace).toBeUndefined();
56
+ });
57
+ });
58
+
59
+ describe('initialize-test-suite-project SKILL.md structure', () => {
60
+ const REQUIRED_PHASES = [
61
+ '### Phase 1: CLASSIFY',
62
+ '### Phase 2: DECIDE',
63
+ '### Phase 3: CONFIGURE',
64
+ '### Phase 4: VALIDATE',
65
+ ];
66
+
67
+ it.each(PLATFORMS)('%s SKILL.md declares all four phases', (platform) => {
68
+ const body = readSkillMd(platform);
69
+ for (const phase of REQUIRED_PHASES) {
70
+ expect(body, `missing phase heading "${phase}" in ${platform}`).toContain(phase);
71
+ }
72
+ });
73
+
74
+ it.each(PLATFORMS)('%s SKILL.md names all three archetypes', (platform) => {
75
+ const body = readSkillMd(platform);
76
+ expect(body).toMatch(/API test suite/i);
77
+ expect(body).toMatch(/E2E ?\/ ?UI/i);
78
+ expect(body).toMatch(/Shared test library/i);
79
+ });
80
+
81
+ it.each(PLATFORMS)('%s SKILL.md documents both layer variants A and B', (platform) => {
82
+ const body = readSkillMd(platform);
83
+ expect(body).toMatch(/Variant A/);
84
+ expect(body).toMatch(/Variant B/);
85
+ });
86
+
87
+ it.each(PLATFORMS)(
88
+ '%s SKILL.md includes the "Prove the guards fire" verification step',
89
+ (platform) => {
90
+ const body = readSkillMd(platform);
91
+ expect(body).toMatch(/Prove the [Gg]uards [Ff]ire/);
92
+ }
93
+ );
94
+
95
+ it.each(PLATFORMS)('%s SKILL.md describes the custom report scaffolding', (platform) => {
96
+ const body = readSkillMd(platform);
97
+ expect(body).toMatch(/scripts\/generate-reports\.ts/);
98
+ });
99
+
100
+ it.each(PLATFORMS)('%s SKILL.md documents quarantine tag grepInvert', (platform) => {
101
+ const body = readSkillMd(platform);
102
+ expect(body).toMatch(/grepInvert/);
103
+ expect(body).toMatch(/@known-failure/);
104
+ expect(body).toMatch(/@wip/);
105
+ });
106
+
107
+ it.each(PLATFORMS)('%s SKILL.md hands control back to parent skill', (platform) => {
108
+ const body = readSkillMd(platform);
109
+ expect(body).toContain(PARENT_SKILL);
110
+ });
111
+ });
112
+
113
+ describe('initialize-test-suite-project composition with initialize-harness-project', () => {
114
+ it.each(PLATFORMS)('%s parent skill dispatches to initialize-test-suite-project', (platform) => {
115
+ const parentPath = resolve(SKILLS_DIR, platform, PARENT_SKILL, 'SKILL.md');
116
+ if (!existsSync(parentPath)) return;
117
+ const parent = readFileSync(parentPath, 'utf-8');
118
+ expect(
119
+ parent,
120
+ `${platform}/${PARENT_SKILL}/SKILL.md must reference ${SKILL_NAME} for dispatch`
121
+ ).toContain(SKILL_NAME);
122
+ });
123
+ });
124
+
125
+ describe('initialize-test-suite-project cross-file registration', () => {
126
+ it('is listed in docs/reference/skills-catalog.md under Tier 1', () => {
127
+ const catalog = readFileSync(
128
+ resolve(REPO_ROOT, 'docs', 'reference', 'skills-catalog.md'),
129
+ 'utf-8'
130
+ );
131
+ const tier1Section = catalog.split('## Tier 2')[0] ?? '';
132
+ expect(tier1Section).toContain(`### ${SKILL_NAME}`);
133
+ });
134
+
135
+ it('is referenced in docs/guides/qa-quickstart.md as a slash command', () => {
136
+ const guide = readFileSync(resolve(REPO_ROOT, 'docs', 'guides', 'qa-quickstart.md'), 'utf-8');
137
+ expect(guide).toContain(`/harness:${SKILL_NAME}`);
138
+ });
139
+
140
+ it('is referenced in docs/guides/features-overview.md', () => {
141
+ const overview = readFileSync(
142
+ resolve(REPO_ROOT, 'docs', 'guides', 'features-overview.md'),
143
+ 'utf-8'
144
+ );
145
+ expect(overview).toContain(`/harness:${SKILL_NAME}`);
146
+ });
147
+
148
+ it('is listed in agents/skills/README.md Setup section', () => {
149
+ const readme = readFileSync(resolve(SKILLS_DIR, 'README.md'), 'utf-8');
150
+ expect(readme).toContain(SKILL_NAME);
151
+ });
152
+ });
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  generateAgentsMd
3
- } from "./chunk-IT2KORSK.js";
4
- import "./chunk-ZIYLIYN4.js";
3
+ } from "./chunk-ZN6ROTYP.js";
4
+ import "./chunk-YC4EYIER.js";
5
5
  import "./chunk-RL4VMEXL.js";
6
- import "./chunk-NKQEMWGT.js";
6
+ import "./chunk-2FPUPRCY.js";
7
7
  import "./chunk-KFQGP6VL.js";
8
8
  export {
9
9
  generateAgentsMd
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  checkDependenciesDefinition,
3
3
  handleCheckDependencies
4
- } from "./chunk-YRBNAHH4.js";
5
- import "./chunk-IQO7IINR.js";
4
+ } from "./chunk-BK4DJIIY.js";
5
+ import "./chunk-TSVYBDDE.js";
6
6
  import "./chunk-EPUKTTJZ.js";
7
7
  import "./chunk-W6Y7ZW3Y.js";
8
- import "./chunk-ZIYLIYN4.js";
8
+ import "./chunk-YC4EYIER.js";
9
9
  import "./chunk-RL4VMEXL.js";
10
- import "./chunk-NKQEMWGT.js";
10
+ import "./chunk-2FPUPRCY.js";
11
11
  import "./chunk-KFQGP6VL.js";
12
12
  export {
13
13
  checkDependenciesDefinition,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  assessProjectDefinition,
3
3
  handleAssessProject
4
- } from "./chunk-XVJRFP7W.js";
4
+ } from "./chunk-K56DTX7G.js";
5
5
  import "./chunk-W6Y7ZW3Y.js";
6
6
  import "./chunk-KFQGP6VL.js";
7
7
  export {