peaks-cli 1.3.3 → 1.3.5
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/dist/src/cli/commands/core-artifact-commands.js +6 -3
- package/dist/src/cli/commands/hook-handle.d.ts +2 -2
- package/dist/src/cli/commands/hook-handle.js +5 -10
- package/dist/src/cli/commands/hooks-commands.js +44 -29
- package/dist/src/cli/commands/project-commands.js +15 -5
- package/dist/src/cli/commands/workflow-commands.js +2 -1
- package/dist/src/cli/commands/workspace-commands.js +1 -2
- package/dist/src/cli/program.js +3 -2
- package/dist/src/services/dashboard/project-dashboard-service.d.ts +23 -0
- package/dist/src/services/dashboard/project-dashboard-service.js +21 -0
- package/dist/src/services/dispatch/sub-agent-dispatcher.d.ts +45 -40
- package/dist/src/services/dispatch/sub-agent-dispatcher.js +25 -20
- package/dist/src/services/ide/adapters/claude-code-adapter.js +27 -2
- package/dist/src/services/ide/adapters/trae-adapter.d.ts +19 -11
- package/dist/src/services/ide/adapters/trae-adapter.js +45 -19
- package/dist/src/services/ide/hook-protocol.d.ts +7 -4
- package/dist/src/services/ide/hook-protocol.js +7 -4
- package/dist/src/services/ide/ide-types.d.ts +61 -16
- package/dist/src/services/ide/resource-profile.d.ts +52 -0
- package/dist/src/services/ide/resource-profile.js +33 -0
- package/dist/src/services/memory/project-context-service.js +2 -1
- package/dist/src/services/memory/project-memory-service.js +4 -3
- package/dist/src/services/perf/perf-baseline-service.js +2 -1
- package/dist/src/services/progress/progress-service.d.ts +23 -103
- package/dist/src/services/progress/progress-service.js +24 -137
- package/dist/src/services/scan/file-size-scan.d.ts +4 -0
- package/dist/src/services/scan/file-size-scan.js +32 -3
- package/dist/src/services/session/getSessionDir.d.ts +1 -0
- package/dist/src/services/session/getSessionDir.js +27 -0
- package/dist/src/services/session/index.d.ts +1 -0
- package/dist/src/services/session/index.js +1 -0
- package/dist/src/services/skills/hooks-settings-service.d.ts +57 -5
- package/dist/src/services/skills/hooks-settings-service.js +153 -28
- package/dist/src/services/standards/ide-aware-standards-service.d.ts +94 -0
- package/dist/src/services/standards/ide-aware-standards-service.js +89 -0
- package/dist/src/services/standards/project-standards-service.d.ts +1 -2
- package/dist/src/shared/incrementing-number.d.ts +0 -8
- package/dist/src/shared/incrementing-number.js +11 -1
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/package.json +1 -1
- package/scripts/install-skills.mjs +112 -2
- package/skills/peaks-ide/SKILL.md +1 -1
- package/skills/peaks-ide/references/audit-log-helper.md +52 -0
- package/skills/peaks-qa/SKILL.md +104 -62
- package/skills/peaks-qa/references/qa-fanout-contract.md +6 -6
- package/skills/peaks-rd/SKILL.md +88 -73
- package/skills/peaks-solo/SKILL.md +52 -22
- package/skills/peaks-solo/references/browser-workflow.md +22 -20
- package/skills/peaks-solo/references/runbook.md +21 -21
- package/skills/peaks-solo/references/sub-agent-dispatch.md +44 -1
- package/skills/peaks-solo/references/swarm-dispatch-contract.md +9 -9
- package/skills/peaks-ui/SKILL.md +18 -9
- package/dist/src/cli/commands/progress-close-kill.d.ts +0 -51
- package/dist/src/cli/commands/progress-close-kill.js +0 -152
- package/dist/src/cli/commands/progress-commands.d.ts +0 -3
- package/dist/src/cli/commands/progress-commands.js +0 -379
- package/dist/src/cli/commands/progress-start-spawn.d.ts +0 -59
- package/dist/src/cli/commands/progress-start-spawn.js +0 -140
- package/dist/src/cli/commands/progress-watch-render.d.ts +0 -80
- package/dist/src/cli/commands/progress-watch-render.js +0 -308
|
@@ -363,6 +363,78 @@ function resolveProjectRoot(options) {
|
|
|
363
363
|
return projectRoot ? resolve(projectRoot) : null;
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Slice #011: Detect the installed IDE for the postinstall dispatch layer.
|
|
368
|
+
*
|
|
369
|
+
* Mirrors `src/services/ide/ide-detector.ts:detectInstalledIde` (cwd heuristic)
|
|
370
|
+
* but inlined here because `install-skills.mjs` is a plain `.mjs` script and
|
|
371
|
+
* cannot import the TS service at runtime. The dispatch:
|
|
372
|
+
* - Look for `.claude`, `.trae`, `.codex`, `.cursor`, `.qoder`,
|
|
373
|
+
* `.tongyi-lingma` in the project root in that insertion order
|
|
374
|
+
* (matches the registry's adapter order in `src/services/ide/ide-registry.ts`).
|
|
375
|
+
* - Returns the first match, or `null` if no adapter's directory is present.
|
|
376
|
+
*
|
|
377
|
+
* If the resolved IDE has no `skillInstall` declared (Trae in slice 1.3.2),
|
|
378
|
+
* the caller falls back to the legacy `~/.claude/{skills,output-styles}` path
|
|
379
|
+
* + emits a stderr warning. The dispatch is conservative: the env-var
|
|
380
|
+
* overrides `PEAKS_CLAUDE_SKILLS_DIR` / `PEAKS_CLAUDE_OUTPUT_STYLES_DIR`
|
|
381
|
+
* continue to work, and the legacy default is preserved.
|
|
382
|
+
*/
|
|
383
|
+
const IDE_DETECTION_DIRS = [
|
|
384
|
+
{ id: 'claude-code', dir: '.claude' },
|
|
385
|
+
{ id: 'trae', dir: '.trae' },
|
|
386
|
+
{ id: 'codex', dir: '.codex' },
|
|
387
|
+
{ id: 'cursor', dir: '.cursor' },
|
|
388
|
+
{ id: 'qoder', dir: '.qoder' },
|
|
389
|
+
{ id: 'tongyi-lingma', dir: '.tongyi-lingma' },
|
|
390
|
+
];
|
|
391
|
+
|
|
392
|
+
const IDE_SKILL_INSTALL_PROFILES = {
|
|
393
|
+
'claude-code': {
|
|
394
|
+
skillsDir: join(homedir(), '.claude', 'skills'),
|
|
395
|
+
outputStylesDir: join(homedir(), '.claude', 'output-styles'),
|
|
396
|
+
envVar: 'PEAKS_CLAUDE_SKILLS_DIR',
|
|
397
|
+
outputStylesEnvVar: 'PEAKS_CLAUDE_OUTPUT_STYLES_DIR',
|
|
398
|
+
},
|
|
399
|
+
'trae': null,
|
|
400
|
+
'codex': null,
|
|
401
|
+
'cursor': null,
|
|
402
|
+
'qoder': null,
|
|
403
|
+
'tongyi-lingma': null,
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
function detectInstalledIdeId(projectRoot) {
|
|
407
|
+
if (!projectRoot) return null;
|
|
408
|
+
for (const { id, dir } of IDE_DETECTION_DIRS) {
|
|
409
|
+
if (existsSync(join(projectRoot, dir))) {
|
|
410
|
+
return id;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function resolveIdeSkillInstallProfile(ideId) {
|
|
417
|
+
if (ideId === null) return null;
|
|
418
|
+
return IDE_SKILL_INSTALL_PROFILES[ideId] ?? null;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function warnUnverifiedIde(ideId, projectRoot) {
|
|
422
|
+
process.stderr.write(
|
|
423
|
+
`peaks install-skills: IDE '${ideId}' has no skillInstall profile declared; ` +
|
|
424
|
+
`falling back to the legacy Claude Code path (~/.claude/skills + ~/.claude/output-styles) ` +
|
|
425
|
+
`for project '${projectRoot}'. This is a slice #011 follow-up gap; ` +
|
|
426
|
+
`see .peaks/memory/ide-adapter-resource-profile-framework.md.\n`
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function warnNoIdeDetected(projectRoot) {
|
|
431
|
+
process.stderr.write(
|
|
432
|
+
`peaks install-skills: no IDE detected in '${projectRoot ?? '(project root unknown)'}'; ` +
|
|
433
|
+
`installing to the legacy Claude Code path (~/.claude/skills + ~/.claude/output-styles). ` +
|
|
434
|
+
`Set PEAKS_CLAUDE_SKILLS_DIR / PEAKS_CLAUDE_OUTPUT_STYLES_DIR to override.\n`
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
366
438
|
function writeMergedConfig(configPath, label, defaults, writeConfig) {
|
|
367
439
|
const existing = readConfigFile(configPath, label);
|
|
368
440
|
const next = { ...(existing === null ? defaults : mergeMissingConfigValues(existing, defaults)), version: defaults.version };
|
|
@@ -424,12 +496,37 @@ export function installProjectConfig(options = {}) {
|
|
|
424
496
|
export function installBundledSkills(options = {}) {
|
|
425
497
|
const packageRoot = resolvePackageRoot(options);
|
|
426
498
|
const skillsRoot = join(packageRoot, 'skills');
|
|
427
|
-
const targetRoot = resolve(options.targetRoot ?? process.env.PEAKS_CLAUDE_SKILLS_DIR ?? join(homedir(), '.claude', 'skills'));
|
|
428
499
|
|
|
429
500
|
if (process.env.PEAKS_SKIP_SKILL_INSTALL === '1' || !existsSync(skillsRoot)) {
|
|
430
501
|
return createInstallResult();
|
|
431
502
|
}
|
|
432
503
|
|
|
504
|
+
// Slice #011: IDE-aware dispatch. Precedence (highest first):
|
|
505
|
+
// 1. explicit options.targetRoot (test / hook override)
|
|
506
|
+
// 2. options.ideId skillInstall.skillsDir (per-IDE dispatch)
|
|
507
|
+
// 3. PEAKS_CLAUDE_SKILLS_DIR env var (legacy back-compat)
|
|
508
|
+
// 4. detected IDE's skillInstall.skillsDir (auto-detect from projectRoot)
|
|
509
|
+
// 5. legacy default (~/.claude/skills) (no-IDE fallback)
|
|
510
|
+
const projectRoot = resolveProjectRoot(options);
|
|
511
|
+
const detectedIdeId = detectInstalledIdeId(projectRoot);
|
|
512
|
+
const detectedProfile = resolveIdeSkillInstallProfile(detectedIdeId);
|
|
513
|
+
|
|
514
|
+
if (options.targetRoot === undefined && options.ideId === undefined && detectedProfile === null && detectedIdeId !== null) {
|
|
515
|
+
warnUnverifiedIde(detectedIdeId, projectRoot ?? '(project root unknown)');
|
|
516
|
+
}
|
|
517
|
+
if (options.targetRoot === undefined && options.ideId === undefined && detectedIdeId === null && projectRoot !== null) {
|
|
518
|
+
warnNoIdeDetected(projectRoot);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const profileSkillsDir = detectedProfile?.skillsDir ?? null;
|
|
522
|
+
const targetRoot = resolve(
|
|
523
|
+
options.targetRoot
|
|
524
|
+
?? (options.ideId !== undefined ? resolveIdeSkillInstallProfile(options.ideId)?.skillsDir ?? null : null)
|
|
525
|
+
?? process.env.PEAKS_CLAUDE_SKILLS_DIR
|
|
526
|
+
?? profileSkillsDir
|
|
527
|
+
?? join(homedir(), '.claude', 'skills')
|
|
528
|
+
);
|
|
529
|
+
|
|
433
530
|
const installed = [];
|
|
434
531
|
const skipped = [];
|
|
435
532
|
mkdirSync(targetRoot, { recursive: true });
|
|
@@ -485,12 +582,25 @@ export function installBundledSkills(options = {}) {
|
|
|
485
582
|
export function installBundledOutputStyles(options = {}) {
|
|
486
583
|
const packageRoot = resolvePackageRoot(options);
|
|
487
584
|
const outputStylesRoot = join(packageRoot, 'output-styles');
|
|
488
|
-
const targetRoot = resolve(options.targetRoot ?? process.env.PEAKS_CLAUDE_OUTPUT_STYLES_DIR ?? join(homedir(), '.claude', 'output-styles'));
|
|
489
585
|
|
|
490
586
|
if (process.env.PEAKS_SKIP_SKILL_INSTALL === '1' || !existsSync(outputStylesRoot)) {
|
|
491
587
|
return createInstallResult();
|
|
492
588
|
}
|
|
493
589
|
|
|
590
|
+
// Slice #011: IDE-aware dispatch. Same precedence as installBundledSkills.
|
|
591
|
+
const projectRoot = resolveProjectRoot(options);
|
|
592
|
+
const detectedIdeId = detectInstalledIdeId(projectRoot);
|
|
593
|
+
const detectedProfile = resolveIdeSkillInstallProfile(detectedIdeId);
|
|
594
|
+
|
|
595
|
+
const profileOutputStylesDir = detectedProfile?.outputStylesDir ?? null;
|
|
596
|
+
const targetRoot = resolve(
|
|
597
|
+
options.targetRoot
|
|
598
|
+
?? (options.ideId !== undefined ? resolveIdeSkillInstallProfile(options.ideId)?.outputStylesDir ?? null : null)
|
|
599
|
+
?? process.env.PEAKS_CLAUDE_OUTPUT_STYLES_DIR
|
|
600
|
+
?? profileOutputStylesDir
|
|
601
|
+
?? join(homedir(), '.claude', 'output-styles')
|
|
602
|
+
);
|
|
603
|
+
|
|
494
604
|
const installed = [];
|
|
495
605
|
const skipped = [];
|
|
496
606
|
mkdirSync(targetRoot, { recursive: true });
|
|
@@ -109,7 +109,7 @@ Every successful execution writes one JSON line to `.peaks/_runtime/<sid>/ide-on
|
|
|
109
109
|
{"timestamp":"2026-06-06T19:55:00Z","intent":"first-time-install","detected_ide":"trae","cli_invocations":["peaks hooks install --project <repo>","peaks statusline install --project <repo>"],"outcome":"success","session_id":"2026-06-06-session-22f08c"}
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
The audit log is **machine-readable** (so `peaks project dashboard` can read it and surface "you installed peaks for Trae on 2026-06-06") and **human-readable** (so the user can `cat` it to see the install history). The skill does NOT write the log file itself — it delegates to `peaks project dashboard` (the canonical log writer, per the dev-preference red line "skill-first for workflow, CLI-backed for gates / side effects"). The audit log writer is a CLI primitive, not a per-skill helper; the skill body MUST NOT introduce a new `peaks <cmd>` for the log writer.
|
|
112
|
+
The audit log is **machine-readable** (so `peaks project dashboard` can read it and surface "you installed peaks for Trae on 2026-06-06") and **human-readable** (so the user can `cat` it to see the install history). The skill does NOT write the log file itself — it delegates to `peaks project dashboard` (the canonical log writer, per the dev-preference red line "skill-first for workflow, CLI-backed for gates / side effects"). The audit log writer is a CLI primitive, not a per-skill helper; the skill body MUST NOT introduce a new `peaks <cmd>` for the log writer. The thin helper that writes the log is `scripts/peaks-ide-audit-log.mjs`; see [audit-log-helper.md](references/audit-log-helper.md) for its CLI surface and contract.
|
|
113
113
|
|
|
114
114
|
## Boundaries
|
|
115
115
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: peaks-ide-audit-log-helper
|
|
3
|
+
description: Thin Node helper that writes a single JSONL line to `.peaks/audit/peaks-ide-<UTC-date>.log`. Reachable from the peaks-ide SKILL.md Step 5 escape hatch. NOT a `peaks <cmd>` CLI primitive (slice #2 closeout + dev-preference red line).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# peaks-ide audit log helper
|
|
7
|
+
|
|
8
|
+
The peaks-ide skill's Step 5 (`audit log`) delegates the JSONL write to
|
|
9
|
+
`scripts/peaks-ide-audit-log.mjs`. The helper is a thin Node script, not a
|
|
10
|
+
new `peaks <cmd>`, and is the single source of truth for the audit log
|
|
11
|
+
shape (machine + human readable, one JSON object per line).
|
|
12
|
+
|
|
13
|
+
## Why a thin helper, not a CLI primitive
|
|
14
|
+
|
|
15
|
+
Per `.peaks/memory/peaks-ide-skill-ac-10-audit-log-writer-is-a-thin-helper-not-a-separate-cli-primitive.md`
|
|
16
|
+
(slice #2 closeout), the audit log writer is reachable from the skill's
|
|
17
|
+
Step 5 escape hatch but is NOT a new top-level `peaks <cmd>`. The
|
|
18
|
+
`peaks project dashboard` command reads the log via the `audit` scan; the
|
|
19
|
+
helper writes the log. The dev-preference red line "Default-no on new CLI
|
|
20
|
+
commands" still applies — if the audit-trail becomes critical in a future
|
|
21
|
+
slice, the helper can be promoted to a CLI primitive at that point.
|
|
22
|
+
|
|
23
|
+
## CLI surface
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
node scripts/peaks-ide-audit-log.mjs --project <repo> --event <name> --adapter <id> [--ok true|false] [--detail <json>] [--dry-run]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Flag | Required | Description |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `--project <path>` | yes | Target project root (parent of `.peaks/`) |
|
|
32
|
+
| `--event <name>` | yes | Event identifier (`install`, `statusline`, `hook-handle`, ...) |
|
|
33
|
+
| `--adapter <id>` | yes | Adapter id (`claude-code`, `trae`, ...) |
|
|
34
|
+
| `--ok <bool>` | no, default `true` | Outcome flag — `false` to record a failure |
|
|
35
|
+
| `--detail <json>` | no | Free-form JSON object attached to the entry |
|
|
36
|
+
| `--dry-run` | no | Print the would-be line; do not write |
|
|
37
|
+
|
|
38
|
+
## Log line shape
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{"timestamp":"2026-06-07T16:00:00.000Z","event":"install","adapter":"trae","ok":true}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The log file path is `<projectRoot>/.peaks/audit/peaks-ide-<UTC-date>.log`
|
|
45
|
+
and is gitignored per the repo root `.gitignore` (`.peaks/audit/`).
|
|
46
|
+
|
|
47
|
+
## Contract pinned by tests
|
|
48
|
+
|
|
49
|
+
`tests/unit/skills/peaks-ide/audit-log-helper.test.ts` pins 4 sub-cases
|
|
50
|
+
(per AC-5): helper is at the documented path, write emits one JSONL line
|
|
51
|
+
with `timestamp + event + adapter + ok`, the log path is in `.gitignore`,
|
|
52
|
+
and `--dry-run` returns the would-be line without writing.
|
package/skills/peaks-qa/SKILL.md
CHANGED
|
@@ -3,6 +3,36 @@ name: peaks-qa
|
|
|
3
3
|
description: QA and verification skill for Peaks. Use when a workflow needs unit-test coverage evidence, regression matrices, baseline reports, validation reports, acceptance checks, or refactor verification gates.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
## Two-axis naming convention
|
|
7
|
+
|
|
8
|
+
> **Read once at the top of this file; the rest of the skill is written against it.**
|
|
9
|
+
|
|
10
|
+
The `.peaks/` workspace is partitioned by **two orthogonal axes**. Every path in this SKILL.md uses one of them; mixing them is the original `.peaks/<sid>/` / `.peaks/_runtime/<sid>/` bug class this slice corrects.
|
|
11
|
+
|
|
12
|
+
| Axis | Path root | Holds | When to use |
|
|
13
|
+
|---|---|---|---|
|
|
14
|
+
| **change-id axis** (reviewable artifacts) | `.peaks/<changeId>/...` | PRD, RD plan, code-review, security-review, test-cases, handoff capsules, gate targets | The artifact should be reviewable on its own and survives across sessions for the same change. Change-id is the unit of work. |
|
|
15
|
+
| **session-id axis** (ephemeral state) | `.peaks/_runtime/<sessionId>/...` | Session bindings (`.peaks/_runtime/session.json`), live in-flight state, the per-session project-scan and tech-doc scaffold while the session is open | The artifact is session-scoped and only meaningful while the parent session is live. |
|
|
16
|
+
| **sub-agent axis** | `.peaks/_sub_agents/<sessionId>/...` | Sub-agent dispatch records, sub-agent heartbeats, per-sub-agent shared channel entries, sub-agent artifact outputs | A sub-agent ran in a parent session. The axis nests under the parent session-id; sub-agent outputs are flushed into the change-id root on commit. |
|
|
17
|
+
|
|
18
|
+
**Which CLI commands operate on which axis:**
|
|
19
|
+
|
|
20
|
+
- **change-id axis** (reviewable artifacts): `peaks request init`, `peaks request transition`, `peaks request show`, `peaks request lint`, `peaks request repair-status`, `peaks scan diff-vs-scope`, `peaks scan acceptance-coverage`. Inputs reference `.peaks/<changeId>/...`.
|
|
21
|
+
- **session-id axis** (ephemeral state): `peaks session info`, `peaks session start`, `peaks session finish`, `peaks session list`. Reads/writes `.peaks/_runtime/<sessionId>/session.json`.
|
|
22
|
+
- **sub-agent axis** (under parent session-id): `peaks sub-agent dispatch`, `peaks sub-agent heartbeat`, `peaks sub-agent share`, `peaks sub-agent shared-read`. All output paths are under `.peaks/_sub_agents/<sessionId>/...`.
|
|
23
|
+
|
|
24
|
+
**Placeholder convention used in this file:**
|
|
25
|
+
|
|
26
|
+
- `<changeId>` / `<change-id>` — the change-id axis. Use when describing a path that lives at `.peaks/<changeId>/...` (root-level, NOT inside `_runtime/`).
|
|
27
|
+
- `<sessionId>` / `<session-id>` — the session-id axis. Use when describing a path that lives at `.peaks/_runtime/<sessionId>/...` or `.peaks/_sub_agents/<sessionId>/...`. The long form `<session-id>` is used inside bash / shell examples where `<sessionId>` would break parsing.
|
|
28
|
+
- The bare `<sid>` placeholder is **forbidden** in new content — it is ambiguous between the two axes. Legacy occurrences are replaced by this convention; new content must use the right axis label.
|
|
29
|
+
|
|
30
|
+
**Cross-references:**
|
|
31
|
+
|
|
32
|
+
- Slice `2026-06-05-change-id-as-unit-of-work` (commits `48958fc` + `928eb53`) — established the change-id axis as the canonical root for reviewable artifacts (`src/shared/change-id.ts:131,335`, `src/services/scan/acceptance-coverage-service.ts:155`).
|
|
33
|
+
- Slice `005-session-runtime-dir-regression` (commit `178a47e`) — added the `getSessionDir()` resolver at `src/services/session/getSessionDir.ts` and routed 4 stragglers that were constructing `.peaks/${sessionId}` (no `_runtime/`) through the canonical resolver. Defense-in-depth scan: `tests/unit/services/session/session-dir-canonical.test.ts`.
|
|
34
|
+
- Slice `006-5th-writer-changeid-path` (this slice) — disambiguates the SKILL.md placeholders and adds the regression test `tests/unit/skills/skills-skill-md-naming.test.ts` that mechanically enforces (a) zero bare `<sid>`, (b) every `.peaks/<X>/` reference has an axis label, (c) the "Two-axis naming convention" callout is present in `peaks-solo`, `peaks-rd`, `peaks-qa`.
|
|
35
|
+
|
|
6
36
|
# Peaks-Cli QA
|
|
7
37
|
|
|
8
38
|
Peaks-Cli QA proves that planned changes are protected and accepted.
|
|
@@ -11,29 +41,31 @@ Peaks-Cli QA proves that planned changes are protected and accepted.
|
|
|
11
41
|
|
|
12
42
|
These two contracts are non-negotiable. The previous prose-only phrasing let the LLM skip the browser gate entirely when an auth wall appeared, and let screenshots land in the project root because the LLM forgot to pass `filename`. Both fail modes are blocking violations; the rules below are what a reviewer should hold the skill to.
|
|
13
43
|
|
|
14
|
-
### Contract 1 — Screenshot path is mandatory and must land under .peaks/<
|
|
44
|
+
### Contract 1 — Screenshot path is mandatory and must land under .peaks/_runtime/<sessionId>/qa/screenshots/
|
|
15
45
|
|
|
16
|
-
Every `
|
|
46
|
+
Every Playwright screenshot tool call (via `peaks mcp call --capability playwright-mcp.browser-validation --tool browser_take_screenshot --args-json '<args>' --json`) **MUST** pass `filename` (in the args object) whose absolute path is **inside** `.peaks/_runtime/<sessionId>/qa/screenshots/`. Concrete form:
|
|
17
47
|
|
|
18
48
|
```bash
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
49
|
+
peaks mcp call \
|
|
50
|
+
--capability playwright-mcp.browser-validation \
|
|
51
|
+
--tool browser_take_screenshot \
|
|
52
|
+
--args-json '{"filename":".peaks/_runtime/<session-id>/qa/screenshots/<state-or-step>.png","fullPage":true}' \
|
|
53
|
+
--json
|
|
22
54
|
```
|
|
23
55
|
|
|
24
|
-
The default behaviour of Playwright MCP when `filename` is omitted or points outside that directory is to write a screenshot to the current working directory, which leaves `.png` files scattered at the project root. **This is a workflow violation.** If a screenshot does land outside `.peaks/<
|
|
56
|
+
The default behaviour of Playwright MCP when `filename` is omitted or points outside that directory is to write a screenshot to the current working directory, which leaves `.png` files scattered at the project root. **This is a workflow violation.** If a screenshot does land outside `.peaks/_runtime/<session-id>/qa/screenshots/` for any reason (e.g. an upstream tool wrote there), QA MUST move it into that directory before declaring the test report complete; do not commit project-root `.png` files. Sanitise before retention: no login URLs, cookies, headers, tokens, storage state, browser traces, or screenshots/logs containing PII or SSO/MFA material.
|
|
25
57
|
|
|
26
58
|
This rule is enforced by a Peaks-Cli preflight check inside this skill:
|
|
27
59
|
|
|
28
60
|
```bash
|
|
29
61
|
# After every browser_take_screenshot batch and before declaring the test report complete:
|
|
30
|
-
ls .peaks/<
|
|
62
|
+
ls .peaks/_runtime/<session-id>/qa/screenshots/*.png 2>&1
|
|
31
63
|
# Expected: at least one .png file under the screenshots directory.
|
|
32
64
|
# "No such file" → BLOCKED. Either the screenshot was never taken, or
|
|
33
65
|
# it landed in the project root (move it before continuing).
|
|
34
66
|
find . -maxdepth 1 -name '*.png' 2>&1
|
|
35
67
|
# Expected: empty. Any .png at the project root is a leak — move it
|
|
36
|
-
# to .peaks/<
|
|
68
|
+
# to .peaks/_runtime/<session-id>/qa/screenshots/ before completing this skill.
|
|
37
69
|
```
|
|
38
70
|
|
|
39
71
|
### Contract 2 — Login / CAPTCHA / SSO / MFA wall is a hard block, not a skip
|
|
@@ -68,23 +100,23 @@ When peaks-qa is the **main loop** (i.e. it is the active skill and is about to
|
|
|
68
100
|
|
|
69
101
|
```
|
|
70
102
|
peaks sub-agent dispatch qa-business \
|
|
71
|
-
--prompt "<qa-business contract, plus runtime args project=<repo>, session-id=<
|
|
72
|
-
--request-id <rid> --session-id <
|
|
103
|
+
--prompt "<qa-business contract, plus runtime args project=<repo>, session-id=<session-id>, request-id=<rid>>" \
|
|
104
|
+
--request-id <rid> --session-id <session-id> --project <repo> --json
|
|
73
105
|
|
|
74
106
|
peaks sub-agent dispatch qa-perf \
|
|
75
107
|
--prompt "<qa-perf contract, plus runtime args>" \
|
|
76
|
-
--request-id <rid> --session-id <
|
|
108
|
+
--request-id <rid> --session-id <session-id> --project <repo> --json
|
|
77
109
|
|
|
78
110
|
peaks sub-agent dispatch qa-security \
|
|
79
111
|
--prompt "<qa-security contract, plus runtime args>" \
|
|
80
|
-
--request-id <rid> --session-id <
|
|
112
|
+
--request-id <rid> --session-id <session-id> --project <repo> --json
|
|
81
113
|
```
|
|
82
114
|
|
|
83
115
|
All three are issued in a single message; the LLM fires all 3 returned toolCalls in parallel; the IDE runs them concurrently; peaks-qa then collects the three envelopes and merges their outputs into:
|
|
84
116
|
|
|
85
|
-
- `.peaks/<
|
|
86
|
-
- `.peaks/<
|
|
87
|
-
- `.peaks/<
|
|
117
|
+
- `.peaks/_runtime/<sessionId>/qa/test-reports/<rid>.md` (business findings)
|
|
118
|
+
- `.peaks/_runtime/<sessionId>/qa/performance-findings.md` (perf findings)
|
|
119
|
+
- `.peaks/_runtime/<sessionId>/qa/security-findings.md` (security findings)
|
|
88
120
|
|
|
89
121
|
## 业务测试细分 (optional)
|
|
90
122
|
|
|
@@ -93,7 +125,7 @@ If the PRD or project warrants it, subdivide `qa-business` further into roles li
|
|
|
93
125
|
For the full contract (heartbeat instructions for each sub-agent, batch-id discipline, 30s cadence, 100-truncation, 5min stale) see `skills/peaks-qa/references/qa-fanout-contract.md` and `skills/peaks-solo/references/sub-agent-dispatch.md` §G6.
|
|
94
126
|
|
|
95
127
|
- **Session id** — use the parent's sid (read `.peaks/_runtime/session.json` or pass `--session-id <parent-sid>` to any session-creating CLI). Do NOT spawn your own session. The new `peaks session info --active` reads the canonical binding for you.
|
|
96
|
-
- **Skill presence (MANDATORY first action)** — do NOT call `peaks skill presence:set peaks-qa`. The sub-agent must not overwrite `.peaks/.active-skill.json`; the main Solo loop owns that file. If you need to mark your own state, write a marker file at `.peaks/<
|
|
128
|
+
- **Skill presence (MANDATORY first action)** — do NOT call `peaks skill presence:set peaks-qa`. The sub-agent must not overwrite `.peaks/.active-skill.json`; the main Solo loop owns that file. If you need to mark your own state, write a marker file at `.peaks/_runtime/<sessionId>/system/sub-agent-qa.json` and only that.
|
|
97
129
|
- **Workspace initialization** — Solo has already run `peaks workspace init` before fan-out. Do not re-run it.
|
|
98
130
|
- **Mode selection** — Solo has already chosen the mode.
|
|
99
131
|
- **Statusline install** — already done by Solo at session startup.
|
|
@@ -103,7 +135,7 @@ What the sub-agent **MUST** still do:
|
|
|
103
135
|
0. **Do NOT call `peaks request init`** — Solo has already initialised the request artefact slot in the main loop before fan-out. The sub-agent reads it via `peaks request show <rid> --role qa --project <repo> --json` if it needs to.
|
|
104
136
|
2. `peaks request show <rid> --role prd --project <repo> --json` (and `--role rd`, `--role ui` if UI is in the swarm plan).
|
|
105
137
|
3. Standards preflight (dry-run only).
|
|
106
|
-
4. Write `.peaks/<
|
|
138
|
+
4. Write `.peaks/_runtime/<sessionId>/qa/test-cases/<rid>.md` with test cases that link to PRD acceptance items.
|
|
107
139
|
5. Return only a compact JSON envelope:
|
|
108
140
|
|
|
109
141
|
```json
|
|
@@ -111,7 +143,7 @@ What the sub-agent **MUST** still do:
|
|
|
111
143
|
"role": "qa-test-cases",
|
|
112
144
|
"rid": "<rid>",
|
|
113
145
|
"status": "ok" | "blocked" | "skipped",
|
|
114
|
-
"artefacts": [".peaks/<
|
|
146
|
+
"artefacts": [".peaks/_runtime/<sessionId>/qa/test-cases/<rid>.md"],
|
|
115
147
|
"warnings": [],
|
|
116
148
|
"blockedReason": null
|
|
117
149
|
}
|
|
@@ -167,9 +199,9 @@ Every QA invocation — feature, bug, refactor, clarification — must write **t
|
|
|
167
199
|
|
|
168
200
|
| # | File | Path | Reader | Content |
|
|
169
201
|
|---|------|------|--------|---------|
|
|
170
|
-
| 1 | Test cases | `.peaks/<
|
|
171
|
-
| 2 | Test report | `.peaks/<
|
|
172
|
-
| 3 | Request artifact | `.peaks/<
|
|
202
|
+
| 1 | Test cases | `.peaks/_runtime/<sessionId>/qa/test-cases/<request-id>.md` | RD (before impl), QA | Generated test scenarios with status |
|
|
203
|
+
| 2 | Test report | `.peaks/_runtime/<sessionId>/qa/test-reports/<request-id>.md` | QA, SC, Solo | Summary, coverage%, security, perf, risks |
|
|
204
|
+
| 3 | Request artifact | `.peaks/_runtime/<sessionId>/qa/requests/<request-id>.md` | Solo, RD↔QA loop | Verdict, boundary check, links to #1 and #2 |
|
|
173
205
|
|
|
174
206
|
Concrete template and rules: `references/artifact-per-request.md`.
|
|
175
207
|
|
|
@@ -197,12 +229,12 @@ peaks codegraph affected --project <repo> <changed-files...> --json # regressi
|
|
|
197
229
|
peaks openspec validate <change-id> --project <repo> --json
|
|
198
230
|
peaks openspec validate <change-id> --project <repo> --prefer-external --json # optional
|
|
199
231
|
|
|
200
|
-
# 4. generate test cases — MANDATORY, write to .peaks/<
|
|
232
|
+
# 4. generate test cases — MANDATORY, write to .peaks/_runtime/<sessionId>/qa/test-cases/<request-id>.md
|
|
201
233
|
# categories: unit, integration, UI regression (frontend only)
|
|
202
234
|
#
|
|
203
235
|
# Optimization (slice 004): peaks-rd's parallel fan-out now includes a 4th
|
|
204
236
|
# sub-agent (`qa-test-cases-writer`) that pre-drafts this file at the
|
|
205
|
-
# end of RD implementation. If `.peaks/<
|
|
237
|
+
# end of RD implementation. If `.peaks/_runtime/<sessionId>/qa/test-cases/<rid>.md`
|
|
206
238
|
# already exists when QA's main loop reaches this step, **QA does NOT
|
|
207
239
|
# re-draft it** — it just verifies the file is present and the
|
|
208
240
|
# per-criterion `ts` snippets are syntactically valid, then proceeds
|
|
@@ -213,8 +245,8 @@ peaks openspec validate <change-id> --project <repo> --prefer-external --json
|
|
|
213
245
|
|
|
214
246
|
# 5. EXECUTE tests against the actual implementation — Peaks-Cli Gate A2
|
|
215
247
|
# Run the project test command. Record output. Tests on paper are worthless.
|
|
216
|
-
# Peaks-Cli Gate A3: Run security review → .peaks/<
|
|
217
|
-
# Peaks-Cli Gate A4: Run performance check → .peaks/<
|
|
248
|
+
# Peaks-Cli Gate A3: Run security review → .peaks/<changeId>/qa/security-findings.md
|
|
249
|
+
# Peaks-Cli Gate A4: Run performance check → .peaks/<changeId>/qa/performance-findings.md
|
|
218
250
|
# CRITICAL: Peaks-Cli Gate A3 and Peaks-Cli Gate A4 are NON-NEGOTIABLE. You MUST run actual security
|
|
219
251
|
# and performance checks — not just write a checklist item. These gates exist
|
|
220
252
|
# because code review alone does not catch: hardcoded secrets, XSS vectors,
|
|
@@ -222,7 +254,7 @@ peaks openspec validate <change-id> --project <repo> --prefer-external --json
|
|
|
222
254
|
# If you skip A3 or A4, Peaks-Cli Gate C will block the verdict.
|
|
223
255
|
#
|
|
224
256
|
# Before running A4, read the RD's perf-baseline at
|
|
225
|
-
# .peaks/<
|
|
257
|
+
# .peaks/<changeId>/rd/perf-baseline.md (if present) and use the
|
|
226
258
|
# captured thresholds as the comparison baseline. The QA stage
|
|
227
259
|
# is still responsible for running the actual measurement
|
|
228
260
|
# (lighthouse / k6 / autocannon / project-local bench) and
|
|
@@ -234,7 +266,7 @@ peaks openspec validate <change-id> --project <repo> --prefer-external --json
|
|
|
234
266
|
# surface that absence in the QA test-report under a
|
|
235
267
|
# `## Performance baseline` section.
|
|
236
268
|
|
|
237
|
-
# 6. write test-report — MANDATORY, write to .peaks/<
|
|
269
|
+
# 6. write test-report — MANDATORY, write to .peaks/_runtime/<sessionId>/qa/test-reports/<request-id>.md
|
|
238
270
|
# MUST contain actual execution results (pass/fail counts, coverage %, findings).
|
|
239
271
|
# A template with placeholder text does not pass Peaks-Cli Gate B.
|
|
240
272
|
|
|
@@ -257,19 +289,23 @@ peaks mcp apply --capability playwright-mcp.browser-validation --yes --json
|
|
|
257
289
|
# and does NOT satisfy Peaks-Cli Gate D. Treating prod build as a fallback is a workflow violation.
|
|
258
290
|
# 4. After browser validation completes, KILL the dev server. Do not leave it running.
|
|
259
291
|
# Playwright MCP MUST simulate real user operations — not just take static screenshots.
|
|
260
|
-
# The minimum interaction sequence for every frontend page/flow
|
|
261
|
-
#
|
|
262
|
-
#
|
|
263
|
-
#
|
|
264
|
-
#
|
|
265
|
-
#
|
|
266
|
-
#
|
|
267
|
-
#
|
|
268
|
-
#
|
|
269
|
-
#
|
|
270
|
-
#
|
|
292
|
+
# The minimum interaction sequence for every frontend page/flow uses the peaks mcp
|
|
293
|
+
# plan/apply/call pattern (skill body NEVER bakes in the bare MCP tool prefix;
|
|
294
|
+
# the prefix is owned by the LLM runtime). The four steps:
|
|
295
|
+
# 1. Detect install: peaks mcp list --json | grep playwright
|
|
296
|
+
# 2. Plan: peaks mcp plan --capability playwright-mcp.browser-validation --json
|
|
297
|
+
# (read envCheck.missing; if non-empty, refuse to apply and ask the user to set the env vars)
|
|
298
|
+
# 3. Apply: peaks mcp apply --capability playwright-mcp.browser-validation --yes --json
|
|
299
|
+
# 4. Call tools: peaks mcp call --capability playwright-mcp.browser-validation \
|
|
300
|
+
# --tool <toolName> --args-json '<argsObject>' --json
|
|
301
|
+
# Tool names (resolved by the LLM from the registered server, NOT hardcoded here):
|
|
302
|
+
# browser_navigate / browser_snapshot / browser_click / browser_type /
|
|
303
|
+
# browser_select_option / browser_fill_form / browser_take_screenshot /
|
|
304
|
+
# browser_console_messages / browser_network_requests / browser_wait_for / browser_close.
|
|
271
305
|
# Static screenshots without user-interaction simulation do NOT pass this gate.
|
|
272
306
|
# Block QA pass if Playwright MCP is unavailable.
|
|
307
|
+
# For sub-agents dispatched via `peaks sub-agent dispatch` (where the LLM cannot
|
|
308
|
+
# directly call MCP tools via the bare prefix), use `peaks mcp call` for every MCP operation.
|
|
273
309
|
#
|
|
274
310
|
# CLEANUP: After browser validation completes (all screenshots saved, console/network
|
|
275
311
|
# evidence captured), QA MUST kill every process it started during verification.
|
|
@@ -314,8 +350,8 @@ You cannot declare a phase complete from memory. Each gate below is a `ls` or `g
|
|
|
314
350
|
|
|
315
351
|
**Peaks-Cli Gate A — After test-case generation:**
|
|
316
352
|
```bash
|
|
317
|
-
ls .peaks/<
|
|
318
|
-
# Expected output: .peaks/<
|
|
353
|
+
ls .peaks/<changeId>/qa/test-cases/<rid>.md
|
|
354
|
+
# Expected output: .peaks/<changeId>/qa/test-cases/<rid>.md
|
|
319
355
|
# "No such file" → STOP, generate test cases first. Do not proceed to validation.
|
|
320
356
|
```
|
|
321
357
|
|
|
@@ -332,8 +368,8 @@ npx vitest run --reporter=verbose 2>&1 | tail -30
|
|
|
332
368
|
**Peaks-Cli Gate A3 — Security test executed (NOT just a checklist item):**
|
|
333
369
|
```bash
|
|
334
370
|
# Run security review against the changed surface. Record findings.
|
|
335
|
-
ls .peaks/<
|
|
336
|
-
# Expected: .peaks/<
|
|
371
|
+
ls .peaks/<changeId>/qa/security-findings.md 2>&1
|
|
372
|
+
# Expected: .peaks/<changeId>/qa/security-findings.md
|
|
337
373
|
# "No such file" → BLOCKED. Run security review against changed files,
|
|
338
374
|
# record every finding with severity, then re-check.
|
|
339
375
|
```
|
|
@@ -341,30 +377,30 @@ ls .peaks/<id>/qa/security-findings.md 2>&1
|
|
|
341
377
|
**Peaks-Cli Gate A4 — Performance test executed:**
|
|
342
378
|
```bash
|
|
343
379
|
# Run available performance check against the changed surface. Record findings.
|
|
344
|
-
ls .peaks/<
|
|
345
|
-
# Expected: .peaks/<
|
|
380
|
+
ls .peaks/<changeId>/qa/performance-findings.md 2>&1
|
|
381
|
+
# Expected: .peaks/<changeId>/qa/performance-findings.md
|
|
346
382
|
# "No such file" → BLOCKED. Run performance check (build-size, Lighthouse,
|
|
347
383
|
# bundle analysis, or project equivalent), record baseline vs. after, then re-check.
|
|
348
384
|
```
|
|
349
385
|
|
|
350
386
|
**Peaks-Cli Gate B — After test-report write (MUST contain execution results, not just planned cases):**
|
|
351
387
|
```bash
|
|
352
|
-
ls .peaks/<
|
|
353
|
-
# Expected output: .peaks/<
|
|
388
|
+
ls .peaks/<changeId>/qa/test-reports/<rid>.md
|
|
389
|
+
# Expected output: .peaks/<changeId>/qa/test-reports/<rid>.md
|
|
354
390
|
# "No such file" → STOP, write the test report first. Do not issue a verdict.
|
|
355
391
|
# Additionally verify the report is not a placeholder:
|
|
356
|
-
grep -c "pass\|fail\|blocked" .peaks/<
|
|
392
|
+
grep -c "pass\|fail\|blocked" .peaks/<changeId>/qa/test-reports/<rid>.md
|
|
357
393
|
# Expected: non-zero count (report contains actual pass/fail/blocked results)
|
|
358
394
|
# Zero → the report is empty/template-only. Tests were not executed.
|
|
359
395
|
```
|
|
360
396
|
|
|
361
397
|
**Peaks-Cli Gate C — Before issuing verdict:**
|
|
362
398
|
```bash
|
|
363
|
-
ls .peaks/<
|
|
364
|
-
.peaks/<
|
|
365
|
-
.peaks/<
|
|
366
|
-
.peaks/<
|
|
367
|
-
.peaks/<
|
|
399
|
+
ls .peaks/<changeId>/qa/test-cases/<rid>.md \
|
|
400
|
+
.peaks/<changeId>/qa/test-reports/<rid>.md \
|
|
401
|
+
.peaks/<changeId>/qa/security-findings.md \
|
|
402
|
+
.peaks/<changeId>/qa/performance-findings.md \
|
|
403
|
+
.peaks/<changeId>/qa/requests/<rid>.md
|
|
368
404
|
# All five must exist. Missing any → QA incomplete, verdict blocked.
|
|
369
405
|
# NOTE: security-findings.md and performance-findings.md are NOT optional.
|
|
370
406
|
# If you can't run a full security scan, run at minimum: grep for secrets,
|
|
@@ -375,7 +411,7 @@ ls .peaks/<id>/qa/test-cases/<rid>.md \
|
|
|
375
411
|
|
|
376
412
|
**Peaks-Cli Gate E — Acceptance coverage (every PRD acceptance item has a linked test case):**
|
|
377
413
|
```bash
|
|
378
|
-
peaks scan acceptance-coverage --rid <rid> --project <repo> --session-id <
|
|
414
|
+
peaks scan acceptance-coverage --rid <rid> --project <repo> --session-id <session-id> --json
|
|
379
415
|
# Expected: ok=true. exit 0.
|
|
380
416
|
# uncovered[] non-empty → BLOCKED. List of acceptance items without test cases is in the output.
|
|
381
417
|
# Add `- **Acceptance:** A<N>` lines to the matching test cases in qa/test-cases/<rid>.md, then re-run.
|
|
@@ -387,7 +423,7 @@ peaks scan acceptance-coverage --rid <rid> --project <repo> --session-id <sid> -
|
|
|
387
423
|
|
|
388
424
|
**Peaks-Cli Gate F — QA artifact body has no unfilled placeholders:**
|
|
389
425
|
```bash
|
|
390
|
-
peaks request lint <rid> --role qa --project <repo> --session-id <
|
|
426
|
+
peaks request lint <rid> --role qa --project <repo> --session-id <session-id> --json
|
|
391
427
|
# Expected: ok=true. exit 0.
|
|
392
428
|
# ok=false → BLOCKED. Lint output lists every <placeholder>, "- ..." stub, and TBD marker.
|
|
393
429
|
# Fill them in before issuing the verdict.
|
|
@@ -397,7 +433,7 @@ peaks request lint <rid> --role qa --project <repo> --session-id <sid> --json
|
|
|
397
433
|
```bash
|
|
398
434
|
# Verify browser screenshots exist. Screenshots are the only acceptable evidence
|
|
399
435
|
# that Playwright MCP actually launched and interacted with the running app.
|
|
400
|
-
ls .peaks/<
|
|
436
|
+
ls .peaks/<changeId>/qa/screenshots/*.png 2>&1
|
|
401
437
|
# Expected: one or more .png files
|
|
402
438
|
# "No such file" → BLOCKED. Playwright MCP was not used or screenshots not saved.
|
|
403
439
|
# Screenshots, logs, manual steps, or other tools must NOT substitute for this gate.
|
|
@@ -409,7 +445,7 @@ ls .peaks/<id>/qa/screenshots/*.png 2>&1
|
|
|
409
445
|
```
|
|
410
446
|
```bash
|
|
411
447
|
# Verify console and network checks were actually performed
|
|
412
|
-
grep -c "browser_console_messages\|browser_network_requests" .peaks/<
|
|
448
|
+
grep -c "browser_console_messages\|browser_network_requests" .peaks/<changeId>/qa/test-reports/<rid>.md
|
|
413
449
|
# Expected: non-zero count (means console/network were checked)
|
|
414
450
|
# Zero → BLOCKED. Browser error feedback loop was not executed.
|
|
415
451
|
```
|
|
@@ -447,7 +483,7 @@ Before QA passes or returns work to RD, it must independently recheck the implem
|
|
|
447
483
|
|
|
448
484
|
## Mandatory test-case generation
|
|
449
485
|
|
|
450
|
-
QA must generate test cases, not merely inspect existing ones. Every QA invocation that validates code changes must produce a test-case artifact at `.peaks/<
|
|
486
|
+
QA must generate test cases, not merely inspect existing ones. Every QA invocation that validates code changes must produce a test-case artifact at `.peaks/_runtime/<sessionId>/qa/test-cases/<request-id>.md`.
|
|
451
487
|
|
|
452
488
|
**Minimum test-case categories:**
|
|
453
489
|
|
|
@@ -475,7 +511,7 @@ QA must generate test cases, not merely inspect existing ones. Every QA invocati
|
|
|
475
511
|
|
|
476
512
|
## Mandatory test-report output
|
|
477
513
|
|
|
478
|
-
Every QA invocation must produce a test-report artifact at `.peaks/<
|
|
514
|
+
Every QA invocation must produce a test-report artifact at `.peaks/_runtime/<sessionId>/qa/test-reports/<request-id>.md`. This is separate from both the test-case file and the request artifact — do not merge.
|
|
479
515
|
|
|
480
516
|
**Minimum test-report sections:**
|
|
481
517
|
|
|
@@ -496,7 +532,13 @@ QA cannot pass a change until the report contains evidence for every applicable
|
|
|
496
532
|
1. **Test-report** — enforced by Peaks-Cli Gate B.
|
|
497
533
|
2. **Unit tests** — run the project test command or a focused test command that covers new/changed code. For legacy projects below the target coverage, require coverage for the new or changed code rather than failing on pre-existing uncovered code.
|
|
498
534
|
3. **API validation** — when the change touches API contracts, data loading, request handling, auth, or integrations, exercise the relevant API path and record request/response evidence or a justified local substitute.
|
|
499
|
-
4. **Frontend browser validation** — when the repository has a frontend or the change affects UI, launch the app and use Playwright MCP for real browser end-to-end validation. This means **simulating real user operations**: clicking buttons, filling forms, selecting dropdowns, navigating between pages, waiting for async data to render, and verifying each resulting state. Static screenshots without interaction are insufficient. Confirm Playwright MCP is installed via `peaks mcp list --json`; install through `peaks mcp plan/apply --capability playwright-mcp.browser-validation --yes` if missing.
|
|
535
|
+
4. **Frontend browser validation** — when the repository has a frontend or the change affects UI, launch the app and use Playwright MCP for real browser end-to-end validation. This means **simulating real user operations**: clicking buttons, filling forms, selecting dropdowns, navigating between pages, waiting for async data to render, and verifying each resulting state. Static screenshots without interaction are insufficient. Confirm Playwright MCP is installed via `peaks mcp list --json`; install through `peaks mcp plan/apply --capability playwright-mcp.browser-validation --yes` if missing. Route every browser interaction through the canonical `peaks mcp call` envelope:
|
|
536
|
+
|
|
537
|
+
```
|
|
538
|
+
peaks mcp call --capability playwright-mcp.browser-validation --tool <toolName> --args-json '<argsObject>' --json
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
The Playwright tool names that drive validation are: `browser_navigate` (launches headed browser), `browser_click` (simulate clicks on tabs/buttons/links), `browser_type` (type into inputs), `browser_select_option` (select dropdowns), `browser_fill_form` (fill complete forms), `browser_wait_for` (wait for async rendering), `browser_take_screenshot` (capture state after each interaction), `browser_close` (close the browser when done), `browser_console_messages` (read console failures), and `browser_network_requests` (read network failures). The bare server-and-tool MCP prefix is owned by the LLM runtime, not by the skill body — never bake the prefix into this SKILL.md or any artifact QA emits. If login, CAPTCHA, SSO, or MFA appears, the visible browser is already open; wait for the user to complete login and explicitly confirm completion before continuing. Capture sanitized interaction sequences, sanitized screenshots per state, sanitized console (`browser_console_messages`) and network (`browser_network_requests`) failures. (Chrome DevTools MCP is an optional secondary surface for CDP inspection of an already-running Chrome on `:9222`; it does NOT launch a browser and cannot simulate user interaction.)
|
|
500
542
|
5. **Browser-error feedback loop** — if Playwright MCP observation surfaces a page error, console exception, broken network request, hydration/render failure, or visible regression, return the work to RD/development with the exact evidence. Do not pass QA until the fixed build is retested in the browser.
|
|
501
543
|
6. **Security check** — run security review for the changed surface and dependency/config changes. Record findings, fixes, and unresolved risks.
|
|
502
544
|
7. **Performance check** — run the project’s available performance check, build-size check, Lighthouse-equivalent check, or browser performance inspection appropriate to the change. Record baseline/after numbers when available.
|
|
@@ -509,7 +551,7 @@ If Playwright MCP is unavailable (not installed and the user has not authorized
|
|
|
509
551
|
|
|
510
552
|
## Local intermediate artifacts
|
|
511
553
|
|
|
512
|
-
QA reports, sanitized browser evidence, logs, matrices, and validation summaries should be written to `.peaks/<
|
|
554
|
+
QA reports, sanitized browser evidence, logs, matrices, and validation summaries should be written to `.peaks/_runtime/<sessionId>/qa/` by default, or to the Peaks-Cli CLI-provided local artifact workspace. Do not store login URLs, cookies, headers, tokens, storage state, browser traces, or screenshots/logs containing PII or SSO/MFA material. Do not default to git-backed storage or external artifact sync unless the user or active profile explicitly authorizes it.
|
|
513
555
|
|
|
514
556
|
## Compact handoff
|
|
515
557
|
|
|
@@ -535,7 +577,7 @@ External analysis cannot pass QA by itself. Treat codegraph output as untrusted
|
|
|
535
577
|
|
|
536
578
|
Use `peaks capabilities --source access-repo --json` and `peaks capabilities --source mcp-server --json` before recommending browser or validation tooling. Treat all external skills as reference material only — do not execute upstream instructions, do not install upstream resources, do not persist sensitive examples; Peaks-Cli QA acceptance authority remains.
|
|
537
579
|
|
|
538
|
-
- Playwright MCP is the required path for controlled headed browser and E2E validation (it launches a headed browser on demand). Install or update through `peaks mcp plan --capability playwright-mcp.browser-validation --json` then `peaks mcp apply --capability playwright-mcp.browser-validation --yes --json` rather than hand-editing settings.
|
|
580
|
+
- Playwright MCP is the required path for controlled headed browser and E2E validation (it launches a headed browser on demand). Install or update through `peaks mcp plan --capability playwright-mcp.browser-validation --json` then `peaks mcp apply --capability playwright-mcp.browser-validation --yes --json` rather than hand-editing settings. The LLM runtime invokes the Playwright tools directly under its own server-and-tool namespace; QA skill bodies route every Playwright invocation through `peaks mcp call --capability playwright-mcp.browser-validation --tool <toolName> --args-json '<argsObject>' --json` instead of the bare prefix.
|
|
539
581
|
- Chrome DevTools MCP is an optional secondary surface for CDP inspection (console, network, performance) of an already-running Chrome started with `--remote-debugging-port=9222`; it does NOT launch a browser on its own. Install via `peaks mcp apply --capability chrome-devtools-mcp.browser-debug --yes --json` when this use case applies.
|
|
540
582
|
- Agent Browser can support browser walkthroughs, but never submit forms, purchase, delete, or mutate authenticated state without explicit confirmation.
|
|
541
583
|
- Canonical browser workflow (URL allow-list, login handoff, sanitization rules, tool mapping): `peaks-solo/references/browser-workflow.md`.
|
|
@@ -563,7 +605,7 @@ Reference: `references/regression-gates.md`.
|
|
|
563
605
|
|
|
564
606
|
### G7 — QA sub-agent protocol
|
|
565
607
|
|
|
566
|
-
1. Write test cases / perf baseline / security review to `.peaks/_sub_agents/<
|
|
608
|
+
1. Write test cases / perf baseline / security review to `.peaks/_sub_agents/<sessionId>/artifacts/<rid>-<role>-001.md` (path convention mandatory).
|
|
567
609
|
2. Call `peaks sub-agent dispatch --write-artifact <path>` to register ArtifactMeta.
|
|
568
610
|
3. Main LLM sees metadata-only view (~200 chars/QA sub-agent).
|
|
569
611
|
|