yadflow 2.2.0 → 2.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.
- package/CHANGELOG.md +2 -9
- package/README.md +36 -15
- package/cli/doctor.mjs +23 -3
- package/cli/epic-state.mjs +19 -2
- package/cli/errors.mjs +1 -0
- package/cli/manifest.mjs +11 -1
- package/cli/setup.mjs +60 -10
- package/docs/index.html +37 -11
- package/package.json +1 -1
- package/skills/sdlc/config.yaml +20 -4
- package/skills/sdlc/install.sh +1 -1
- package/skills/sdlc/module-help.csv +3 -1
- package/skills/yad-analysis/SKILL.md +10 -5
- package/skills/yad-connect-design/SKILL.md +1 -1
- package/skills/yad-connect-design/references/design-registry.md +4 -2
- package/skills/yad-connect-testing/SKILL.md +121 -0
- package/skills/yad-connect-testing/references/testing-context.md +67 -0
- package/skills/yad-connect-testing/references/testing-registry.md +55 -0
- package/skills/yad-epic/SKILL.md +10 -5
- package/skills/yad-epic/references/state-schema.md +42 -11
- package/skills/yad-hub-bridge/SKILL.md +2 -2
- package/skills/yad-review-gate/SKILL.md +14 -11
- package/skills/yad-review-gate/references/gating.md +1 -1
- package/skills/yad-run/references/run-loop.md +3 -3
- package/skills/yad-spec/SKILL.md +3 -1
- package/skills/yad-status/SKILL.md +8 -5
- package/skills/yad-stories/SKILL.md +3 -1
- package/skills/yad-test-cases/SKILL.md +173 -0
- package/skills/yad-test-cases/references/test-cases-schema.md +70 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
# [2.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
### Bug Fixes
|
|
5
|
-
|
|
6
|
-
* address code review on the design-tool connection ([1275146](https://github.com/abdelrahmannasr/yadflow/commit/1275146e9e24251d481d90eb26894a729e894997))
|
|
1
|
+
# [2.3.0](https://github.com/abdelrahmannasr/yadflow/compare/v2.2.0...v2.3.0) (2026-06-13)
|
|
7
2
|
|
|
8
3
|
|
|
9
4
|
### Features
|
|
10
5
|
|
|
11
|
-
* add
|
|
12
|
-
* materialize the feature design in yad-ui (generate or link) ([e440571](https://github.com/abdelrahmannasr/yadflow/commit/e44057131e86fed45d9a9c4151cd762eb98f24e8))
|
|
13
|
-
* wire the design-tool connection through the CLI ([1867ed4](https://github.com/abdelrahmannasr/yadflow/commit/1867ed433dd57025ae4143f5a236db32f1a99c41))
|
|
6
|
+
* add parallel test-cases step with pluggable testing-tool connection ([#45](https://github.com/abdelrahmannasr/yadflow/issues/45)) ([19c282f](https://github.com/abdelrahmannasr/yadflow/commit/19c282f6bd737364bca122179b05de8ea94493a9))
|
|
14
7
|
|
|
15
8
|
# [1.1.0](https://github.com/abdelrahmannasr/sdlc-workflow/compare/v1.0.3...v1.1.0) (2026-06-09)
|
|
16
9
|
|
package/README.md
CHANGED
|
@@ -49,8 +49,9 @@ human**. Detailed walkthroughs for each phase follow below.
|
|
|
49
49
|
| `skills/yad-architecture/` | Front state 3: author `architecture.md` + the locked `contract.md`; hash-lock the contract surface. |
|
|
50
50
|
| `skills/yad-ui/` | Front state 5: author `ui-design.md` + `DESIGN.md` (Impeccable slash-commands, or graceful fallback). |
|
|
51
51
|
| `skills/yad-stories/` | Front state 7: break the epic into repo-tagged stories with stable `EP-<slug>-S0N` IDs. |
|
|
52
|
+
| `skills/yad-test-cases/` | Front state 9: with the test architect author `test-cases.md`; implement the automation in the connected testing tool, or produce artifacts only. |
|
|
52
53
|
| `skills/yad-connect-repos/` | Connect code repos to the hub (GitHub/GitLab, local-user auth); cache a Repomix pack + **code-map** per repo so the front phases are code-aware. |
|
|
53
|
-
| `skills/yad-review-gate/` | The reusable **team review + approve gate** (used for all
|
|
54
|
+
| `skills/yad-review-gate/` | The reusable **team review + approve gate** (used for all five reviews). |
|
|
54
55
|
| `skills/yad-spec/` | Build Step A: run the Spec Kit ceremony once per story per repo → `specs/<story-id>/`. |
|
|
55
56
|
| `skills/yad-implement/` | Build Step B: implement ONE atomic task as a small diff on its own branch. |
|
|
56
57
|
| `skills/yad-checks/` | Build Step C: wire + run the CI gates (spec-link, contract-check, build/test/lint, verified-commits). |
|
|
@@ -122,18 +123,21 @@ a manual `yad gate sync` racing CI, or GitLab pipelines — two simultaneous syn
|
|
|
122
123
|
*commits* via the rebase retry but each works from the state it read at start, so the rarer of two
|
|
123
124
|
simultaneous advancements can be lost; the next event or scheduled sweep re-syncs and converges.
|
|
124
125
|
|
|
125
|
-
### What `setup` walks you through (
|
|
126
|
+
### What `setup` walks you through (9 steps)
|
|
126
127
|
|
|
127
128
|
1. **Preflight** — confirm the hub is a git repo (offers `git init`); check `git`/`node`/`npx`.
|
|
128
|
-
2. **Install the module** — copy all
|
|
129
|
+
2. **Install the module** — copy all 20 `yad-*` skills into the IDE skill dirs you pick
|
|
129
130
|
(`.claude/`, `.agents/`, `.zencoder/`, `.opencode/`) and register `_bmad/sdlc/`.
|
|
130
131
|
3. **Hub platform & roster** — detect GitHub/GitLab from the remote; record reviewers → `.sdlc/hub.json`.
|
|
131
132
|
4. **Connect a design tool** — record the design tool (Figma / pencil / none) → `.sdlc/design.json` so
|
|
132
133
|
the UI step can materialize the design; the MCP itself is confirmed later by `yad-connect-design`.
|
|
133
|
-
5. **Connect
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
5. **Connect a testing tool** — record the testing tool (Playwright / cypress / pytest / none) →
|
|
135
|
+
`.sdlc/testing.json` so the test-cases step can implement the automation; the MCP itself is confirmed
|
|
136
|
+
later by `yad-connect-testing`.
|
|
137
|
+
6. **Connect code repos** — register each repo into `.sdlc/repos.json` and cache a Repomix pack.
|
|
138
|
+
7. **Wire each repo** — CI gates, PR/MR template, and review-comment scaffold.
|
|
139
|
+
8. **AI review** — optionally write `.coderabbit.yaml`.
|
|
140
|
+
9. **Done** — stamp `.sdlc/cli-version.json` and hand off the AI-only steps (code-maps; first epic).
|
|
137
141
|
|
|
138
142
|
The deterministic file work runs automatically; the AI-only steps are handed to the Claude Code skills
|
|
139
143
|
with a printed next-action. Re-run `… check --fix` any time the workflow updates — it never re-asks for
|
|
@@ -170,10 +174,11 @@ with a fix-it hint per finding. Failures carry stable, greppable codes, also pri
|
|
|
170
174
|
| `YAD-STATE-003` | a registered repo path is missing or not a git repo | fix the path in `.sdlc/repos.json` or re-connect the repo |
|
|
171
175
|
| `YAD-CFG-001` | `hub.json` names an unknown platform | expected `github`, `gitlab`, or `null` — fix it or re-run `yad setup` |
|
|
172
176
|
| `YAD-CFG-002` | `design.json` names an unknown design tool | expected one of `config.yaml` `design.tools` (e.g. `figma`, `pencil`), or `none` — fix it or re-run `yad setup` |
|
|
177
|
+
| `YAD-CFG-003` | `testing.json` names an unknown testing tool | expected one of `config.yaml` `testing.tools` (e.g. `playwright`, `cypress`, `pytest`), or `none` — fix it or re-run `yad setup` |
|
|
173
178
|
|
|
174
179
|
Filing a bug? Attach `yad doctor --json` — it contains no secrets (names, paths, and check results only).
|
|
175
180
|
|
|
176
|
-
## Agent skills (all
|
|
181
|
+
## Agent skills (all 20)
|
|
177
182
|
|
|
178
183
|
The CLI **installs and wires** the module; the skills below are the **agents you invoke by name** in your
|
|
179
184
|
AI IDE (e.g. *“run `yad-epic`”*) to actually do the work. State lives in files you can also edit
|
|
@@ -191,12 +196,17 @@ directly. Each skill stops at a gate and never auto-advances unless a step has *
|
|
|
191
196
|
Records the tool + project/file references in `.sdlc/design.json` (local-user / MCP-session auth, no
|
|
192
197
|
stored tokens), detecting the design-tool MCP and degrading to markdown-only when absent. Idempotent
|
|
193
198
|
and refreshable; one connection per project.
|
|
199
|
+
- **`yad-connect-testing`** — Connects a testing tool (Playwright-first, pluggable) so the test-cases
|
|
200
|
+
step can implement the actual automation tests inside it, alongside the Markdown. Records the tool +
|
|
201
|
+
project/suite references in `.sdlc/testing.json` (local-user / MCP-session auth, no stored tokens),
|
|
202
|
+
detecting the testing-tool MCP and degrading to artifacts-only when absent. Idempotent and
|
|
203
|
+
refreshable; one connection per project.
|
|
194
204
|
|
|
195
205
|
### Front half — author the "thinking" (once per epic, human-gated)
|
|
196
206
|
|
|
197
207
|
- **`yad-analysis`** — *Optional* front state 1. With the analyst, pressure-test a feature idea
|
|
198
208
|
and write the discovery brief into `analysis.md`. Assigns the `EP-<slug>` ID and seeds `.sdlc/` state
|
|
199
|
-
(the
|
|
209
|
+
(the 12-step chain that puts analysis before epic). If skipped, the epic step does this shaping inline.
|
|
200
210
|
- **`yad-epic`** — The epic front state. Shape the idea with the analyst (or read `analysis.md`
|
|
201
211
|
when it already ran), then write the epic with the pm into `epic.md`. The entry point when analysis is
|
|
202
212
|
skipped: assigns the `EP-<slug>` ID and seeds `.sdlc/` state.
|
|
@@ -211,6 +221,13 @@ directly. Each skill stops at a gate and never auto-advances unless a step has *
|
|
|
211
221
|
- **`yad-stories`** — Front state 7. With the pm, break the approved epic into user stories, each
|
|
212
222
|
tagged with the repos that must implement it. Assigns zero-padded `EP-<slug>-S0N` IDs, one file per
|
|
213
223
|
story under `stories/`. Reads epic + architecture + contract + UI.
|
|
224
|
+
- **`yad-test-cases`** — Front state 9, a **parallel, non-blocking** track: it opens when the stories
|
|
225
|
+
gate passes (the epic is already `ready-for-build`, so the build half runs alongside it). With the
|
|
226
|
+
test architect (Murat), author `test-cases.md` covering the approved stories (risk-based P0–P3 cases +
|
|
227
|
+
story→case traceability). When a testing tool is connected (`yad-connect-testing`), also **implements
|
|
228
|
+
the automation tests** in the connected code repo(s) (generate or link), recording the case→test map in
|
|
229
|
+
`test-links.json`; degrades to artifacts-only otherwise. Reads epic + architecture + contract + UI +
|
|
230
|
+
stories.
|
|
214
231
|
|
|
215
232
|
### The review gate (cross-cutting — used by every review)
|
|
216
233
|
|
|
@@ -269,7 +286,7 @@ merging the approved, fully-resolved review PR — never on a machine.
|
|
|
269
286
|
|
|
270
287
|
As of **Phase 4a** the `automation` dial is no longer inert: the orchestrator `yad-run` reads it and,
|
|
271
288
|
for the safe **back** steps, advances on its own when a step is set to `machine_advance` (and has
|
|
272
|
-
*earned* it — see "Run the back half on the dial" below). The engineer review and all
|
|
289
|
+
*earned* it — see "Run the back half on the dial" below). The engineer review and all five front
|
|
273
290
|
states stay `human_approve` forever.
|
|
274
291
|
|
|
275
292
|
## Using the workflow end to end (all the steps, in order)
|
|
@@ -320,7 +337,10 @@ threads are resolved. Details: **“Run the full front half by hand”** below.
|
|
|
320
337
|
7. `yad-architecture` → `architecture.md` + locked `contract.md` → review (**escalated**: contract).
|
|
321
338
|
8. `yad-ui` → `ui-design.md` + `DESIGN.md` → review (base rule).
|
|
322
339
|
9. `yad-stories` → repo-tagged `stories/EP-<slug>-S0N.md` → review (**per-repo**).
|
|
323
|
-
→ `state.json` reaches `currentStep: ready-for-build
|
|
340
|
+
→ `state.json` reaches `currentStep: ready-for-build` — **the build half can start now.**
|
|
341
|
+
10. `yad-test-cases` → `test-cases.md` (+ automation tests when a testing tool is connected) → review (base rule).
|
|
342
|
+
**Parallel, non-blocking:** opens when the stories gate passes and runs alongside the build half; its
|
|
343
|
+
review never moves `currentStep` off `ready-for-build`.
|
|
324
344
|
|
|
325
345
|
### B — Build half (per story, per repo)
|
|
326
346
|
From a `ready-for-build` story, for **each** repo the story is tagged with. Details: **“Run the full
|
|
@@ -355,12 +375,13 @@ Details: **“Run the back half on the dial”** below.
|
|
|
355
375
|
## Run the full front half by hand
|
|
356
376
|
|
|
357
377
|
The front half walks **epic → review → architecture+contract → review → UI design → review → stories
|
|
358
|
-
→ review → `ready-for-build
|
|
359
|
-
|
|
378
|
+
→ review → `ready-for-build`**, then **test cases → review** runs as a **parallel, non-blocking track**
|
|
379
|
+
alongside the build half. It is all files under `epics/EP-<slug>/`. The skills below guide you, but you
|
|
380
|
+
can also edit the files directly — that's the point.
|
|
360
381
|
|
|
361
382
|
Each authoring step is the same shape: an author skill produces an artifact, sets its step `done`,
|
|
362
383
|
moves `currentStep` to the matching review, and **stops at the gate**. Then **`yad-review-gate`**
|
|
363
|
-
(one gate, reused for all
|
|
384
|
+
(one gate, reused for all five reviews) takes `open → comment → approve → advance`. When the hub is on a
|
|
364
385
|
platform, the **`yad gate`** CLI runs that gate over a real PR/MR — `open` raises the review PR, `sync`
|
|
365
386
|
pulls approvals + comment threads into the ledger, and the step **auto-advances when the approved,
|
|
366
387
|
fully-resolved PR is merged** (the merge is the human approval act).
|
|
@@ -417,7 +438,7 @@ accumulate, and the step moves forward only when the rule is met. **File-only**
|
|
|
417
438
|
in any story's `repos`**.
|
|
418
439
|
|
|
419
440
|
### Check status anytime
|
|
420
|
-
Invoke **`yad-status`** (read-only) to see the full
|
|
441
|
+
Invoke **`yad-status`** (read-only) to see the full 10-step chain, every step's dials/status, the
|
|
421
442
|
contract lock, story repo tags, and which approvals the active gate still needs.
|
|
422
443
|
|
|
423
444
|
## Worked example (already in this repo)
|
package/cli/doctor.mjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import fs from 'node:fs';
|
|
7
7
|
import { c, log, ok, info, warn, fail, hand, run, has, exists, readJSON, readJSONStrict } from './lib.mjs';
|
|
8
|
-
import { VERSION, PROJECT_FILES, DESIGN_TOOLS } from './manifest.mjs';
|
|
8
|
+
import { VERSION, PROJECT_FILES, DESIGN_TOOLS, TESTING_TOOLS } from './manifest.mjs';
|
|
9
9
|
import { loadLedger, epicRoot } from './epic-state.mjs';
|
|
10
10
|
import { gitHead } from './setup.mjs';
|
|
11
11
|
import { cliFor } from './platform.mjs';
|
|
@@ -88,13 +88,33 @@ export function projectChecks(checks, root) {
|
|
|
88
88
|
}
|
|
89
89
|
if (designBroken) { /* reported above */ }
|
|
90
90
|
else if (typeof design !== 'object' || Array.isArray(design) || design === null) check(checks, 'design', 'project', 'fail', `${PROJECT_FILES.designConfig} has the wrong shape [YAD-STATE-002]`, 'expected a JSON object');
|
|
91
|
-
else if (
|
|
92
|
-
else if (!
|
|
91
|
+
else if (design.tool === 'none') check(checks, 'design', 'project', 'ok', 'design: markdown-only');
|
|
92
|
+
else if (!DESIGN_TOOLS.includes(design.tool)) check(checks, 'design', 'project', 'fail', `${PROJECT_FILES.designConfig}: unknown or missing design tool '${design.tool}' [YAD-CFG-002]`, `expected one of ${DESIGN_TOOLS.join(', ')}, or none`);
|
|
93
93
|
else if (design.source && design.source !== 'unavailable') check(checks, 'design', 'project', 'ok', `design: ${design.tool} (${design.source})`);
|
|
94
94
|
else if (design.source === 'unavailable') check(checks, 'design', 'project', 'warn', `design: ${design.tool} MCP unavailable — yad-ui runs markdown-only`, 'connect the MCP, then run `yad-connect-design` (action: refresh)');
|
|
95
95
|
else check(checks, 'design', 'project', 'warn', `design: ${design.tool} recorded but the MCP is not confirmed`, 'run `yad-connect-design` in Claude Code to detect the MCP');
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
// testing.json: parse + shape + tool + MCP confirmation (absent is the normal artifacts-only default —
|
|
99
|
+
// pre-feature projects have none, so silence rather than warn when the file does not exist).
|
|
100
|
+
const testingPath = path.join(root, PROJECT_FILES.testingConfig);
|
|
101
|
+
if (exists(testingPath)) {
|
|
102
|
+
let testing = null, testingBroken = false;
|
|
103
|
+
try {
|
|
104
|
+
testing = readJSONStrict(testingPath, null);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
testingBroken = true;
|
|
107
|
+
check(checks, 'testing', 'project', 'fail', `${PROJECT_FILES.testingConfig} does not parse [${e.code || 'YAD-STATE-001'}]`, e.hint || 'fix the JSON or restore it from git');
|
|
108
|
+
}
|
|
109
|
+
if (testingBroken) { /* reported above */ }
|
|
110
|
+
else if (typeof testing !== 'object' || Array.isArray(testing) || testing === null) check(checks, 'testing', 'project', 'fail', `${PROJECT_FILES.testingConfig} has the wrong shape [YAD-STATE-002]`, 'expected a JSON object');
|
|
111
|
+
else if (testing.tool === 'none') check(checks, 'testing', 'project', 'ok', 'testing: artifacts-only');
|
|
112
|
+
else if (!TESTING_TOOLS.includes(testing.tool)) check(checks, 'testing', 'project', 'fail', `${PROJECT_FILES.testingConfig}: unknown or missing testing tool '${testing.tool}' [YAD-CFG-003]`, `expected one of ${TESTING_TOOLS.join(', ')}, or none`);
|
|
113
|
+
else if (testing.source && testing.source !== 'unavailable') check(checks, 'testing', 'project', 'ok', `testing: ${testing.tool} (${testing.source})`);
|
|
114
|
+
else if (testing.source === 'unavailable') check(checks, 'testing', 'project', 'warn', `testing: ${testing.tool} MCP unavailable — yad-test-cases runs artifacts-only`, 'connect the MCP, then run `yad-connect-testing` (action: refresh)');
|
|
115
|
+
else check(checks, 'testing', 'project', 'warn', `testing: ${testing.tool} recorded but the MCP is not confirmed`, 'run `yad-connect-testing` in Claude Code to detect the MCP');
|
|
116
|
+
}
|
|
117
|
+
|
|
98
118
|
// repos.json: parse + every entry is a live git repo; staleness vs syncedHead
|
|
99
119
|
let registry = { repos: [] };
|
|
100
120
|
let regBroken = false;
|
package/cli/epic-state.mjs
CHANGED
|
@@ -197,9 +197,24 @@ export function gatePredicate({
|
|
|
197
197
|
|
|
198
198
|
// Advance the step in state.json once the predicate passes. Mirrors yad-review-gate Step 3:
|
|
199
199
|
// mark this review step done, unblock the next step, or set `ready-for-build` for the last one.
|
|
200
|
+
//
|
|
201
|
+
// `test-cases` is a PARALLEL, non-blocking track so the build half can start while the tester works:
|
|
202
|
+
// approving `stories-review` makes the epic `ready-for-build` (the build half keys off this) AND opens
|
|
203
|
+
// `test-cases` for the tester; completing `test-cases-review` never pulls `currentStep` back from
|
|
204
|
+
// `ready-for-build`. Both rules degrade safely for an old chain that has no test-cases steps.
|
|
200
205
|
export function advanceState(state, step) {
|
|
201
206
|
const i = state.steps.findIndex((s) => s.id === step.id);
|
|
202
207
|
state.steps[i] = { ...state.steps[i], status: 'done' };
|
|
208
|
+
if (step.id === 'stories-review') {
|
|
209
|
+
const tc = state.steps.find((s) => s.id === 'test-cases');
|
|
210
|
+
if (tc && tc.status === 'blocked') tc.status = 'in_progress';
|
|
211
|
+
state.currentStep = 'ready-for-build';
|
|
212
|
+
return state;
|
|
213
|
+
}
|
|
214
|
+
if (step.id === 'test-cases-review') {
|
|
215
|
+
state.currentStep = 'ready-for-build';
|
|
216
|
+
return state;
|
|
217
|
+
}
|
|
203
218
|
const next = state.steps[i + 1];
|
|
204
219
|
if (next) {
|
|
205
220
|
next.status = next.type === 'review+approve' ? 'in_review' : 'in_progress';
|
|
@@ -210,11 +225,13 @@ export function advanceState(state, step) {
|
|
|
210
225
|
return state;
|
|
211
226
|
}
|
|
212
227
|
|
|
213
|
-
// Mark a step in-review (idempotent) and point currentStep at it
|
|
228
|
+
// Mark a step in-review (idempotent) and point currentStep at it — EXCEPT once the epic is
|
|
229
|
+
// `ready-for-build`: the parallel `test-cases` track must not pull currentStep back (the build half
|
|
230
|
+
// runs alongside the tester, and only the test-cases review is in flight at that point).
|
|
214
231
|
export function markInReview(state, step) {
|
|
215
232
|
const i = state.steps.findIndex((s) => s.id === step.id);
|
|
216
233
|
if (state.steps[i].status !== 'done') state.steps[i].status = 'in_review';
|
|
217
|
-
state.currentStep = step.id;
|
|
234
|
+
if (state.currentStep !== 'ready-for-build') state.currentStep = step.id;
|
|
218
235
|
return state;
|
|
219
236
|
}
|
|
220
237
|
|
package/cli/errors.mjs
CHANGED
|
@@ -21,6 +21,7 @@ export const CODES = {
|
|
|
21
21
|
'YAD-STATE-003': 'a registered repo path is missing or not a git repository',
|
|
22
22
|
'YAD-CFG-001': 'hub.json names an unknown platform (expected github, gitlab, or null)',
|
|
23
23
|
'YAD-CFG-002': 'design.json names an unknown design tool (expected one of config.yaml design.tools, or none)',
|
|
24
|
+
'YAD-CFG-003': 'testing.json names an unknown testing tool (expected one of config.yaml testing.tools, or none)',
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
export const err = (code, message, hint) => new YadError(code, message, hint);
|
package/cli/manifest.mjs
CHANGED
|
@@ -10,15 +10,17 @@ import { readFileSync } from 'node:fs';
|
|
|
10
10
|
const { version } = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
11
11
|
export const VERSION = version;
|
|
12
12
|
|
|
13
|
-
// The
|
|
13
|
+
// The 20 hand-authored yad-* skills (mirrors skills/sdlc/install.sh).
|
|
14
14
|
export const SKILLS = [
|
|
15
15
|
'yad-analysis',
|
|
16
16
|
'yad-epic',
|
|
17
17
|
'yad-architecture',
|
|
18
18
|
'yad-ui',
|
|
19
19
|
'yad-stories',
|
|
20
|
+
'yad-test-cases',
|
|
20
21
|
'yad-connect-repos',
|
|
21
22
|
'yad-connect-design',
|
|
23
|
+
'yad-connect-testing',
|
|
22
24
|
'yad-spec',
|
|
23
25
|
'yad-implement',
|
|
24
26
|
'yad-checks',
|
|
@@ -87,11 +89,19 @@ export const MODULE_FILES = ['config.yaml', 'module-help.csv'];
|
|
|
87
89
|
export const DESIGN_TOOLS = ['figma', 'pencil'];
|
|
88
90
|
export const DESIGN_PRIMARY = 'figma';
|
|
89
91
|
|
|
92
|
+
// Supported testing-tool adapters (mirrors skills/sdlc/config.yaml `testing.tools`); `TESTING_PRIMARY`
|
|
93
|
+
// is the fallback `registerTesting`/setup use when an unknown tool is named, and `none` is the explicit
|
|
94
|
+
// artifacts-only choice. (doctor does NOT fall back — an unknown tool there is a hard YAD-CFG-003 fail,
|
|
95
|
+
// mirroring the design-tool YAD-CFG-002.)
|
|
96
|
+
export const TESTING_TOOLS = ['playwright', 'cypress', 'pytest'];
|
|
97
|
+
export const TESTING_PRIMARY = 'playwright';
|
|
98
|
+
|
|
90
99
|
// Project-level files setup produces (used by `check` to spot missing setup).
|
|
91
100
|
export const PROJECT_FILES = {
|
|
92
101
|
reposRegistry: '.sdlc/repos.json',
|
|
93
102
|
hubConfig: '.sdlc/hub.json',
|
|
94
103
|
designConfig: '.sdlc/design.json',
|
|
104
|
+
testingConfig: '.sdlc/testing.json',
|
|
95
105
|
version: '.sdlc/cli-version.json',
|
|
96
106
|
};
|
|
97
107
|
|
package/cli/setup.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
c, log, step, ok, info, warn, hand, fail, ask, askYesNo, run, has,
|
|
6
6
|
exists, readJSON, writeJSON,
|
|
7
7
|
} from './lib.mjs';
|
|
8
|
-
import { VERSION, IDE_FOLDER_TARGETS, PROJECT_FILES, DESIGN_TOOLS, DESIGN_PRIMARY } from './manifest.mjs';
|
|
8
|
+
import { VERSION, IDE_FOLDER_TARGETS, PROJECT_FILES, DESIGN_TOOLS, DESIGN_PRIMARY, TESTING_TOOLS, TESTING_PRIMARY } from './manifest.mjs';
|
|
9
9
|
import { moduleActions, repoActions, hubActions, authorsActions } from './plan.mjs';
|
|
10
10
|
|
|
11
11
|
const ALL_IDES = [...IDE_FOLDER_TARGETS, '.opencode'];
|
|
@@ -87,6 +87,34 @@ export function registerDesign(root, { tool, project_url = null, files = null, t
|
|
|
87
87
|
return design;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
// Record the project's testing-tool connection into .sdlc/testing.json (the deterministic half of the
|
|
91
|
+
// connect loop; MCP detection itself is an AI step, handed off to `yad-connect-testing`). An unknown
|
|
92
|
+
// tool falls back to the primary adapter rather than being rejected — mirrors registerDesign. `none` is
|
|
93
|
+
// the explicit artifacts-only choice.
|
|
94
|
+
export function registerTesting(root, { tool, project_url = null, suites = null, today = null } = {}) {
|
|
95
|
+
// Idempotent re-connect: carry the original first-connect date forward; only lastSyncedAt moves.
|
|
96
|
+
const testingPath = path.join(root, PROJECT_FILES.testingConfig);
|
|
97
|
+
const prev = readJSON(testingPath, null);
|
|
98
|
+
const connectedAt = prev && prev.connectedAt ? prev.connectedAt : today;
|
|
99
|
+
let t = (tool || '').toLowerCase();
|
|
100
|
+
if (t === 'none' || t === '') {
|
|
101
|
+
const off = { tool: 'none', provider: null, project_url: null, auth: 'user',
|
|
102
|
+
suites: {}, connectedAt, lastSyncedAt: today, source: 'unavailable' };
|
|
103
|
+
writeJSON(testingPath, off);
|
|
104
|
+
return off;
|
|
105
|
+
}
|
|
106
|
+
if (!TESTING_TOOLS.includes(t)) { warn(`unknown testing tool '${tool}' — using ${TESTING_PRIMARY}`); t = TESTING_PRIMARY; }
|
|
107
|
+
// source stays null until `yad-connect-testing` detects the MCP in the harness (AI step). doctor
|
|
108
|
+
// reports a recorded-but-unconfirmed connection as a warning pointing at that skill.
|
|
109
|
+
const testing = {
|
|
110
|
+
tool: t, provider: null, project_url: project_url || null, auth: 'user',
|
|
111
|
+
suites: suites || {},
|
|
112
|
+
connectedAt, lastSyncedAt: today, source: null,
|
|
113
|
+
};
|
|
114
|
+
writeJSON(testingPath, testing);
|
|
115
|
+
return testing;
|
|
116
|
+
}
|
|
117
|
+
|
|
90
118
|
function applyActions(actions, { force = false } = {}) {
|
|
91
119
|
let changed = 0;
|
|
92
120
|
for (const a of actions) {
|
|
@@ -100,7 +128,7 @@ function applyActions(actions, { force = false } = {}) {
|
|
|
100
128
|
}
|
|
101
129
|
|
|
102
130
|
export async function runSetup(root, opts = {}) {
|
|
103
|
-
const total =
|
|
131
|
+
const total = 9;
|
|
104
132
|
log(c.bold(`\nSDLC Workflow setup ${c.dim('v' + VERSION)}`));
|
|
105
133
|
log(c.dim(`target: ${root}`));
|
|
106
134
|
|
|
@@ -178,8 +206,26 @@ export async function runSetup(root, opts = {}) {
|
|
|
178
206
|
: `wrote ${PROJECT_FILES.designConfig} (${tool})`);
|
|
179
207
|
}
|
|
180
208
|
|
|
181
|
-
// 5. Connect
|
|
182
|
-
step(5, total, 'Connect
|
|
209
|
+
// 5. Connect a testing tool (Playwright-first, pluggable; the test-cases step implements automation here)
|
|
210
|
+
step(5, total, 'Connect a testing tool (playwright / cypress / pytest / none)');
|
|
211
|
+
const testingPath = path.join(root, PROJECT_FILES.testingConfig);
|
|
212
|
+
if (exists(testingPath) && !(await askYesNo('testing.json exists — reconfigure?', false))) {
|
|
213
|
+
info('keeping existing .sdlc/testing.json');
|
|
214
|
+
} else {
|
|
215
|
+
let tool = (await ask(`Testing tool (${TESTING_TOOLS.join('/')}/none)`, TESTING_PRIMARY)).toLowerCase();
|
|
216
|
+
if (![...TESTING_TOOLS, 'none'].includes(tool)) {
|
|
217
|
+
warn(`unknown testing tool '${tool}' — using ${TESTING_PRIMARY}`);
|
|
218
|
+
tool = TESTING_PRIMARY;
|
|
219
|
+
}
|
|
220
|
+
const project_url = tool === 'none' ? null : (await ask(' project/config reference (blank to set later)', '')) || null;
|
|
221
|
+
registerTesting(root, { tool, project_url, today: opts.today ?? null });
|
|
222
|
+
ok(tool === 'none'
|
|
223
|
+
? `wrote ${PROJECT_FILES.testingConfig} (artifacts-only)`
|
|
224
|
+
: `wrote ${PROJECT_FILES.testingConfig} (${tool})`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 6. Connect code repos
|
|
228
|
+
step(6, total, 'Connect code repos');
|
|
183
229
|
const regPath = path.join(root, PROJECT_FILES.reposRegistry);
|
|
184
230
|
const registry = readJSON(regPath, { repos: [] });
|
|
185
231
|
const known = new Set(registry.repos.map((r) => r.name));
|
|
@@ -202,8 +248,8 @@ export async function runSetup(root, opts = {}) {
|
|
|
202
248
|
}
|
|
203
249
|
}
|
|
204
250
|
|
|
205
|
-
//
|
|
206
|
-
step(
|
|
251
|
+
// 7. Wire each connected repo + the hub itself
|
|
252
|
+
step(7, total, 'Wire connected repos + the hub (CI gates, PR template, comment scaffold, gate-sync)');
|
|
207
253
|
if (registry.repos.length === 0) info('no repos to wire');
|
|
208
254
|
for (const repo of registry.repos) {
|
|
209
255
|
log(` ${c.bold(repo.name)} ${c.dim(`(${repo.platform})`)}`);
|
|
@@ -218,8 +264,8 @@ export async function runSetup(root, opts = {}) {
|
|
|
218
264
|
// author allowlists for the verified-commits gate (hub + every repo), from the roster emails
|
|
219
265
|
applyActions(authorsActions(root, registry.repos), { force: true });
|
|
220
266
|
|
|
221
|
-
//
|
|
222
|
-
step(
|
|
267
|
+
// 8. Optional CodeRabbit
|
|
268
|
+
step(8, total, 'AI review (CodeRabbit)');
|
|
223
269
|
for (const repo of registry.repos) {
|
|
224
270
|
const cr = path.join(path.resolve(root, repo.path), '.coderabbit.yaml');
|
|
225
271
|
if (exists(cr)) { info(`${repo.name}: .coderabbit.yaml present`); continue; }
|
|
@@ -229,8 +275,8 @@ export async function runSetup(root, opts = {}) {
|
|
|
229
275
|
}
|
|
230
276
|
}
|
|
231
277
|
|
|
232
|
-
//
|
|
233
|
-
step(
|
|
278
|
+
// 9. Summary + version stamp
|
|
279
|
+
step(9, total, 'Done');
|
|
234
280
|
writeJSON(path.join(root, PROJECT_FILES.version), { version: VERSION, ideTargets, updatedAt: opts.today ?? null });
|
|
235
281
|
ok(`stamped ${PROJECT_FILES.version} (v${VERSION})`);
|
|
236
282
|
log('');
|
|
@@ -240,6 +286,10 @@ export async function runSetup(root, opts = {}) {
|
|
|
240
286
|
if (design && design.tool && design.tool !== 'none') {
|
|
241
287
|
hand(`confirm the design tool: run \`yad-connect-design\` to detect the ${design.tool} MCP (or it degrades to markdown-only)`);
|
|
242
288
|
}
|
|
289
|
+
const testing = readJSON(testingPath, null);
|
|
290
|
+
if (testing && testing.tool && testing.tool !== 'none') {
|
|
291
|
+
hand(`confirm the testing tool: run \`yad-connect-testing\` to detect the ${testing.tool} MCP (or it degrades to artifacts-only)`);
|
|
292
|
+
}
|
|
243
293
|
hand('author your first epic: run `yad-epic`');
|
|
244
294
|
log('');
|
|
245
295
|
log(c.dim('Re-run anytime: `yad check` (report) / `yad check --fix` (reconcile).'));
|
package/docs/index.html
CHANGED
|
@@ -284,7 +284,7 @@
|
|
|
284
284
|
<div class="lane">
|
|
285
285
|
<div class="lane-title">0 · One-time setup (team lead, per project)</div>
|
|
286
286
|
<div class="flow-v">
|
|
287
|
-
<div class="node plain"><strong>Install the module</strong><small><code>npx yadflow setup</code> — copies the
|
|
287
|
+
<div class="node plain"><strong>Install the module</strong><small><code>npx yadflow setup</code> — copies the 20 skills into your IDE dirs</small></div>
|
|
288
288
|
<div class="arrow-v">▼</div>
|
|
289
289
|
<div class="node plain"><strong>Wire each repo</strong><small><code>yad-checks</code> · <code>yad-pr-template</code> · <code>yad-review-comments</code> (CI gates, PR template, comment scaffold)</small></div>
|
|
290
290
|
<div class="arrow-v">▼</div>
|
|
@@ -292,6 +292,8 @@
|
|
|
292
292
|
<div class="arrow-v">▼</div>
|
|
293
293
|
<div class="node plain"><strong>Connect a design tool</strong><small><code>yad-connect-design</code> → <code>design.json</code> (Figma-first, pluggable) so <code>yad-ui</code> can materialize the screens <em>(optional — degrades to markdown-only)</em></small></div>
|
|
294
294
|
<div class="arrow-v">▼</div>
|
|
295
|
+
<div class="node plain"><strong>Connect a testing tool</strong><small><code>yad-connect-testing</code> → <code>testing.json</code> (Playwright-first, pluggable) so <code>yad-test-cases</code> can implement the automation <em>(optional — degrades to artifacts-only)</em></small></div>
|
|
296
|
+
<div class="arrow-v">▼</div>
|
|
295
297
|
<div class="node plain"><strong>Optional: hub on a platform</strong><small>detect GitHub/GitLab + reviewer roster, so reviews run on real PRs/MRs</small></div>
|
|
296
298
|
</div>
|
|
297
299
|
</div>
|
|
@@ -321,7 +323,9 @@
|
|
|
321
323
|
<div class="arrow-v">▼</div>
|
|
322
324
|
<div class="node gate">gate · stories review<small><strong>per-repo:</strong> base rule + the engineer of each touched repo</small></div>
|
|
323
325
|
<div class="arrow-v">▼</div>
|
|
324
|
-
<div class="node sentinel"><strong>ready-for-build</strong><small>the front half is done — building can start</small></div>
|
|
326
|
+
<div class="node sentinel"><strong>ready-for-build</strong><small>the gating front half is done — building can start (and <code>yad-test-cases</code> opens in parallel)</small></div>
|
|
327
|
+
<div class="arrow-v">▼</div>
|
|
328
|
+
<div class="node artifact"><strong>yad-test-cases</strong> <em>(parallel · non-blocking)</em><small>opens when the stories gate passes and runs <strong>alongside the build half</strong> — with the test architect → <code>test-cases.md</code> + the automation tests in the connected testing tool (<code>test-links.json</code>) → its own base-rule review. Never blocks <code>ready-for-build</code>.</small></div>
|
|
325
329
|
</div>
|
|
326
330
|
</div>
|
|
327
331
|
|
|
@@ -371,9 +375,10 @@
|
|
|
371
375
|
contract.md the LOCKED shared surface (APIs, events, data model)
|
|
372
376
|
ui-design.md + DESIGN.md (+ the screens in the connected design tool)
|
|
373
377
|
stories/ one file per story (EP-<slug>-S01.md …)
|
|
378
|
+
test-cases.md the test cases (+ the automation tests when a testing tool is connected)
|
|
374
379
|
reviews/ reviewer comments, per artifact
|
|
375
380
|
.sdlc/ state.json · approvals.json · contract-lock.json
|
|
376
|
-
design-links.json · build-state/ · trust-log.json · build-log.json
|
|
381
|
+
design-links.json · test-links.json · build-state/ · trust-log.json · build-log.json
|
|
377
382
|
|
|
378
383
|
each code repo/
|
|
379
384
|
specs/<story-id>/ spec, plan, tasks (+ link.md back to the story)
|
|
@@ -440,8 +445,8 @@ each code repo/
|
|
|
440
445
|
<div class="term"><strong>State machine</strong><span class="badge b-core">core</span><br>The core design: the workflow is a fixed set of <em>states</em> (steps). Each state does its work and waits at a gate. The states never change — only the <em>trigger</em> (who moves work forward) changes. That is what lets the team start fully manual and automate gradually without rebuilding anything.</div>
|
|
441
446
|
<div class="term"><strong>Product hub (product repo)</strong><span class="badge b-core">core</span><br>The git repo that holds the shared “thinking”: epics, architecture, the contract, UI design, stories, reviews and all state. The brain of the project. Code never lives here.</div>
|
|
442
447
|
<div class="term"><strong>Code repo</strong><span class="badge b-core">core</span><br>A separate git repo holding real application code (e.g. backend, mobile, dashboard). Each story’s spec lives inside the code repo it belongs to, with a link back to the story in the hub.</div>
|
|
443
|
-
<div class="term"><strong>Skills source (this repo)</strong><span class="badge b-core">core</span><br>The <code>yadflow</code> repo itself — where the
|
|
444
|
-
<div class="term"><strong>Front half (“decide” / the brain)</strong><span class="badge b-core">core</span><br>The first half of the workflow, run once per epic in the product hub: analysis (optional) → epic → architecture + contract → UI design → stories — each followed by a human review gate. Permanently human-approved.</div>
|
|
448
|
+
<div class="term"><strong>Skills source (this repo)</strong><span class="badge b-core">core</span><br>The <code>yadflow</code> repo itself — where the 20 skills live and where you pull updates from. No real product work happens inside it.</div>
|
|
449
|
+
<div class="term"><strong>Front half (“decide” / the brain)</strong><span class="badge b-core">core</span><br>The first half of the workflow, run once per epic in the product hub: analysis (optional) → epic → architecture + contract → UI design → stories — each followed by a human review gate, ending at <code>ready-for-build</code>. <strong>Test cases</strong> is a parallel, non-blocking track that opens at the stories gate and runs alongside the build half. Permanently human-approved.</div>
|
|
445
450
|
<div class="term"><strong>Back half / build half (“build”)</strong><span class="badge b-core">core</span><br>The second half, run once per story per code repo, inside that repo: spec → implement → checks → PR → ship. These mechanical steps may earn automation over time.</div>
|
|
446
451
|
<div class="term"><strong>Gate</strong><span class="badge b-core">core</span><br>A stopping point after a step. The step writes its output and <em>waits</em>; a human must approve before the workflow moves on. “Every step stops at a gate” is the heart of the whole system.</div>
|
|
447
452
|
<div class="term"><strong>Assistance dial</strong><span class="badge b-core">core</span><br>A per-step setting for how much AI helps with the work: <code>none</code>, <code>review</code> (AI checks human work), or <code>heavy</code> (AI does the drafting, human directs).</div>
|
|
@@ -520,7 +525,7 @@ each code repo/
|
|
|
520
525
|
<div class="term"><strong>Trust threshold</strong><span class="badge b-auto">automation</span><br>The bar a step must clear to earn automation — by default at least 5 runs with ≥80% “approved-unchanged” (configurable in <code>config.yaml</code>).</div>
|
|
521
526
|
<div class="term"><strong>Run verdicts</strong><span class="badge b-auto">automation</span><br>How each engineer review scores an automated run: <code>approved-unchanged</code> (merged exactly as authored — the strongest signal), <code>approved-with-edits</code> (a human fixed it first), <code>rejected</code> (failed).</div>
|
|
522
527
|
<div class="term"><strong>Kill switch</strong><span class="badge b-auto">automation</span><br><code>yad-run action: kill</code> — one move that forces <em>every</em> step system-wide back to <code>human_approve</code> instantly, no code change needed. <code>unkill</code> restores earned automation. Automation is always reversible in one move.</div>
|
|
523
|
-
<div class="term"><strong>Locked steps</strong><span class="badge b-auto">automation</span><br>The steps that may <em>never</em> be set to <code>machine_advance</code>: all
|
|
528
|
+
<div class="term"><strong>Locked steps</strong><span class="badge b-auto">automation</span><br>The steps that may <em>never</em> be set to <code>machine_advance</code>: all five front authoring steps, their reviews, and the engineer review. A front state advances only on a human act.</div>
|
|
524
529
|
<div class="term"><strong>Fleet roll-up</strong><span class="badge b-auto">automation</span><br>The cross-epic summary <code>yad-status</code> prints: where every epic stands, which steps are “earned but still manual” (nudge cost), at a glance.</div>
|
|
525
530
|
|
|
526
531
|
<h3>Tools the workflow builds on</h3>
|
|
@@ -531,7 +536,7 @@ each code repo/
|
|
|
531
536
|
<div class="term"><strong>CodeRabbit</strong><span class="badge b-tool">tools</span><br>An AI code-review service used as the advisory first pass on PRs. Optional; never the merge authority.</div>
|
|
532
537
|
<div class="term"><strong>Graceful degradation</strong><span class="badge b-tool">tools</span><br>The rule that every optional tool (Spec Kit, Impeccable, Repomix, CodeRabbit) can be absent: the workflow falls back to doing the work directly and <em>records</em> that the tool was missing. You can start with none of them.</div>
|
|
533
538
|
<div class="term"><strong>Tool-agnostic rule</strong><span class="badge b-tool">tools</span><br>Talk to every tool through its commands and files, never through its internal code — so each tool stays swappable.</div>
|
|
534
|
-
<div class="term"><strong>Skill</strong><span class="badge b-tool">tools</span><br>One of the
|
|
539
|
+
<div class="term"><strong>Skill</strong><span class="badge b-tool">tools</span><br>One of the 20 named agents (e.g. <code>yad-epic</code>) you invoke by name in your AI IDE. Each skill does one step’s work, writes files, and stops at its gate.</div>
|
|
535
540
|
<div class="term"><strong>The <code>yad</code> CLI</strong><span class="badge b-tool">tools</span><br>A zero-dependency command-line tool (npm: <code>yadflow</code>) that installs, wires and reconciles the workflow (<code>setup</code>, <code>check --fix</code>, <code>update</code>) and runs the deterministic pieces (<code>gate</code>, <code>commit</code>, <code>open-pr</code>, <code>repo</code>).</div>
|
|
536
541
|
|
|
537
542
|
<h3>People & AI roles</h3>
|
|
@@ -574,7 +579,7 @@ each code repo/
|
|
|
574
579
|
<div class="flow-v">
|
|
575
580
|
<div class="node plain"><strong>Setup</strong><small>install skills · create the hub repo · create empty code repos · wire each repo (CI gates + PR template) · <s>connect-repos</s> <em>skipped — nothing to map yet</em></small></div>
|
|
576
581
|
<div class="arrow-v">▼</div>
|
|
577
|
-
<div class="node artifact"><strong>Front half</strong><small>(analysis) → epic → architecture + contract → UI (<code>craft</code> → <code>extract</code>) → stories — all human-gated</small></div>
|
|
582
|
+
<div class="node artifact"><strong>Front half</strong><small>(analysis) → epic → architecture + contract → UI (<code>craft</code> → <code>extract</code>) → stories — all human-gated; then test cases runs in parallel with the build half</small></div>
|
|
578
583
|
<div class="arrow-v">▼</div>
|
|
579
584
|
<div class="node"><strong>Build half</strong><small>spec → implement → checks → PR → ship, per story per repo — specs exist for 100% of the code from day one</small></div>
|
|
580
585
|
<div class="arrow-v">▼</div>
|
|
@@ -674,7 +679,7 @@ each code repo/
|
|
|
674
679
|
|
|
675
680
|
<!-- ======================================================= -->
|
|
676
681
|
<section id="skills">
|
|
677
|
-
<h2>6. The
|
|
682
|
+
<h2>6. The 20 skills — what each does, how to use it, and when</h2>
|
|
678
683
|
<p>A <strong>skill</strong> is an agent you invoke <em>by name</em> in your AI IDE — you just ask in
|
|
679
684
|
plain words, e.g. <em>“run <code>yad-epic</code>”</em>, adding any inputs the skill needs
|
|
680
685
|
(<code>repo: backend</code>, <code>story: EP-…-S01</code>, <code>action: wire</code>, …).
|
|
@@ -685,11 +690,13 @@ each code repo/
|
|
|
685
690
|
<tr><th>Skill</th><th>Half</th><th>One line</th></tr>
|
|
686
691
|
<tr><td><a href="#sk-connect"><code>yad-connect-repos</code></a></td><td>Setup</td><td>Register a code repo with the hub + cache its code-map.</td></tr>
|
|
687
692
|
<tr><td><a href="#sk-connect-design"><code>yad-connect-design</code></a></td><td>Setup</td><td>Connect a design tool (Figma-first) so <code>yad-ui</code> can materialize the screens.</td></tr>
|
|
693
|
+
<tr><td><a href="#sk-connect-testing"><code>yad-connect-testing</code></a></td><td>Setup</td><td>Connect a testing tool (Playwright-first) so <code>yad-test-cases</code> can implement the automation.</td></tr>
|
|
688
694
|
<tr><td><a href="#sk-analysis"><code>yad-analysis</code></a></td><td>Front</td><td><em>(Optional)</em> pressure-test an idea into <code>analysis.md</code>.</td></tr>
|
|
689
695
|
<tr><td><a href="#sk-epic"><code>yad-epic</code></a></td><td>Front</td><td>Start a feature: write <code>epic.md</code>, assign the ID.</td></tr>
|
|
690
696
|
<tr><td><a href="#sk-arch"><code>yad-architecture</code></a></td><td>Front</td><td>Author <code>architecture.md</code> + the locked <code>contract.md</code>.</td></tr>
|
|
691
697
|
<tr><td><a href="#sk-ui"><code>yad-ui</code></a></td><td>Front</td><td>Author <code>ui-design.md</code> + <code>DESIGN.md</code>; materialize the screens in the connected design tool.</td></tr>
|
|
692
698
|
<tr><td><a href="#sk-stories"><code>yad-stories</code></a></td><td>Front</td><td>Break the epic into repo-tagged stories.</td></tr>
|
|
699
|
+
<tr><td><a href="#sk-test-cases"><code>yad-test-cases</code></a></td><td>Front</td><td>With the test architect, author the test cases; implement the automation when a testing tool is connected.</td></tr>
|
|
693
700
|
<tr><td><a href="#sk-gate"><code>yad-review-gate</code></a></td><td>Cross-cutting</td><td>Review / comment / approve / advance <strong>any</strong> gate.</td></tr>
|
|
694
701
|
<tr><td><a href="#sk-bridge"><code>yad-hub-bridge</code></a></td><td>Cross-cutting</td><td>Run front-half reviews over real PRs/MRs and sync them back.</td></tr>
|
|
695
702
|
<tr><td><a href="#sk-comments"><code>yad-review-comments</code></a></td><td>Setup</td><td>Install the structured review-comment scaffolds.</td></tr>
|
|
@@ -729,6 +736,17 @@ yad-connect-design action: disconnect</code></pre>
|
|
|
729
736
|
<div class="row"><span class="lbl lbl-when">When</span> During one-time setup (the wizard records it), and again any time you switch design tools. <strong>No design tool? Skip it</strong> — <code>yad-ui</code> simply authors the Markdown, exactly as before.</div>
|
|
730
737
|
</div>
|
|
731
738
|
|
|
739
|
+
<div class="skillcard" id="sk-connect-testing">
|
|
740
|
+
<h4><code>yad-connect-testing</code></h4>
|
|
741
|
+
<div class="row"><span class="lbl lbl-what">What</span> Connects a <strong>testing tool</strong> to the product hub so the test-cases step can implement the <em>actual</em> automation tests inside it, alongside the Markdown. <strong>Playwright-first but pluggable</strong> (a testing-tool adapter; <code>cypress</code> and <code>pytest</code> are second providers). It records the tool + project/suite references in <code>testing.json</code> through your own authenticated MCP session — <strong>no tokens are ever stored</strong> — and degrades to artifacts-only when no testing-tool MCP is available.</div>
|
|
742
|
+
<div class="row"><span class="lbl lbl-how">How</span> Run it in the product hub, once per project:</div>
|
|
743
|
+
<pre><code>yad-connect-testing action: connect tool: playwright project_url: tests/playwright.config.ts
|
|
744
|
+
yad-connect-testing action: list # show the connection + whether the MCP is available
|
|
745
|
+
yad-connect-testing action: refresh # re-detect the MCP (after authenticating a session)
|
|
746
|
+
yad-connect-testing action: disconnect</code></pre>
|
|
747
|
+
<div class="row"><span class="lbl lbl-when">When</span> During one-time setup (the wizard records it), and again any time you switch testing tools. <strong>No testing tool? Skip it</strong> — <code>yad-test-cases</code> simply authors the test cases, exactly as before.</div>
|
|
748
|
+
</div>
|
|
749
|
+
|
|
732
750
|
<h3>Front half — author the thinking (in the product hub)</h3>
|
|
733
751
|
|
|
734
752
|
<div class="skillcard" id="sk-analysis">
|
|
@@ -768,7 +786,15 @@ yad-connect-design action: disconnect</code></pre>
|
|
|
768
786
|
<div class="row"><span class="lbl lbl-what">What</span> With the pm AI, slices the approved epic into user stories small enough to build — one file each under <code>stories/</code>, with stable IDs (<code>EP-<slug>-S01</code>…) and a <code>repos:</code> tag naming which code repos must implement each one. Reads epic + architecture + contract + UI as input.</div>
|
|
769
787
|
<div class="row"><span class="lbl lbl-how">How</span> In the product hub, after the UI gate passes:</div>
|
|
770
788
|
<pre><code>run yad-stories — epic: EP-istifta-inquiries</code></pre>
|
|
771
|
-
<div class="row"><span class="lbl lbl-when">When</span>
|
|
789
|
+
<div class="row"><span class="lbl lbl-when">When</span> After the UI gate passes. Stops at the <strong>stories review gate</strong> (per-repo rule). When it passes the epic is <code>ready-for-build</code> — the build half can start, and <code>yad-test-cases</code> opens in parallel.</div>
|
|
790
|
+
</div>
|
|
791
|
+
|
|
792
|
+
<div class="skillcard" id="sk-test-cases">
|
|
793
|
+
<h4><code>yad-test-cases</code></h4>
|
|
794
|
+
<div class="row"><span class="lbl lbl-what">What</span> With the <strong>test architect</strong> AI (Murat), authors the risk-based test cases that cover the approved stories → <code>test-cases.md</code> (cases prioritised P0–P3, with story→case traceability). When a testing tool is connected (<code>yad-connect-testing</code>), it also <strong>implements the automation tests in that tool</strong> — generating them into the connected code repo(s) or linking an existing suite — and records the case→test map in <code>test-links.json</code>; otherwise it stays artifacts-only. Reads epic + architecture + contract + UI + stories as input.</div>
|
|
795
|
+
<div class="row"><span class="lbl lbl-how">How</span> In the product hub, after the stories gate passes:</div>
|
|
796
|
+
<pre><code>run yad-test-cases — epic: EP-istifta-inquiries</code></pre>
|
|
797
|
+
<div class="row"><span class="lbl lbl-when">When</span> A <strong>parallel, non-blocking</strong> track: it opens the moment the stories gate passes — the epic is already <code>ready-for-build</code>, so this runs <strong>alongside the build half</strong>, not before it. Stops at its own <strong>test-cases review gate</strong> (base rule); that review never blocks building.</div>
|
|
772
798
|
</div>
|
|
773
799
|
|
|
774
800
|
<h3>The review gate & its plumbing (cross-cutting)</h3>
|
|
@@ -897,7 +923,7 @@ yad-status EP-istifta-inquiries # one epic in detail</code></pre>
|
|
|
897
923
|
|
|
898
924
|
<div class="skillcard">
|
|
899
925
|
<h4><code>npx yadflow setup</code></h4>
|
|
900
|
-
<div class="row"><span class="lbl lbl-what">What</span> The guided first-run wizard.
|
|
926
|
+
<div class="row"><span class="lbl lbl-what">What</span> The guided first-run wizard. Nine steps: preflight (git/node check), install all 20 skills into the IDE dirs you pick, detect the hub’s platform + record the reviewer roster, connect a design tool (Figma-first; optional), connect a testing tool (Playwright-first; optional), connect your code repos, wire each one (CI gates, PR template, comment scaffold), optionally write the AI-review config, and stamp the installed version.</div>
|
|
901
927
|
<div class="row"><span class="lbl lbl-how">How</span></div>
|
|
902
928
|
<pre><code>cd <product-hub-repo>
|
|
903
929
|
npx yadflow setup</code></pre>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yadflow",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Yadflow — the gated, team, multi-repo SDLC: author → review → build with a PR-driven review gate and a zero-dependency `yad` CLI (setup, gate, commit, open-pr, repo). A BMAD module + 17 yad-* skills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "AbdelRahman Nasr",
|