peaks-cli 1.4.2 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/.claude-plugin/marketplace.json +51 -0
  2. package/CHANGELOG.md +279 -0
  3. package/README-en.md +226 -0
  4. package/README.md +152 -122
  5. package/dist/src/cli/commands/agent-commands.d.ts +20 -0
  6. package/dist/src/cli/commands/agent-commands.js +48 -0
  7. package/dist/src/cli/commands/audit-commands.d.ts +18 -0
  8. package/dist/src/cli/commands/audit-commands.js +138 -0
  9. package/dist/src/cli/commands/capability-commands.js +2 -1
  10. package/dist/src/cli/commands/classify-classify-commands.d.ts +19 -0
  11. package/dist/src/cli/commands/classify-classify-commands.js +151 -0
  12. package/dist/src/cli/commands/code-review-commands.d.ts +34 -0
  13. package/dist/src/cli/commands/code-review-commands.js +83 -0
  14. package/dist/src/cli/commands/config-commands.js +90 -0
  15. package/dist/src/cli/commands/context-commands.d.ts +21 -0
  16. package/dist/src/cli/commands/context-commands.js +167 -0
  17. package/dist/src/cli/commands/core-artifact-commands.js +60 -2
  18. package/dist/src/cli/commands/hook-handle.js +50 -0
  19. package/dist/src/cli/commands/loop-commands.d.ts +21 -0
  20. package/dist/src/cli/commands/loop-commands.js +128 -0
  21. package/dist/src/cli/commands/openspec-commands.js +37 -0
  22. package/dist/src/cli/commands/preferences-commands.d.ts +2 -0
  23. package/dist/src/cli/commands/preferences-commands.js +147 -0
  24. package/dist/src/cli/commands/skill-conformance-commands.d.ts +9 -0
  25. package/dist/src/cli/commands/skill-conformance-commands.js +39 -0
  26. package/dist/src/cli/commands/understand-commands.js +34 -0
  27. package/dist/src/cli/commands/upgrade-commands.d.ts +23 -0
  28. package/dist/src/cli/commands/upgrade-commands.js +57 -0
  29. package/dist/src/cli/commands/workflow-commands.js +70 -0
  30. package/dist/src/cli/commands/workspace-commands.js +117 -2
  31. package/dist/src/cli/program.js +30 -0
  32. package/dist/src/lib/render/message-renderer.d.ts +20 -0
  33. package/dist/src/lib/render/message-renderer.js +80 -0
  34. package/dist/src/services/agent/ecc-agent-service.d.ts +47 -0
  35. package/dist/src/services/agent/ecc-agent-service.js +143 -0
  36. package/dist/src/services/artifacts/request-artifact-service.js +14 -0
  37. package/dist/src/services/audit/backing-detector.d.ts +24 -0
  38. package/dist/src/services/audit/backing-detector.js +59 -0
  39. package/dist/src/services/audit/classifier.d.ts +38 -0
  40. package/dist/src/services/audit/classifier.js +127 -0
  41. package/dist/src/services/audit/enforcers/active-skill-resolver.d.ts +29 -0
  42. package/dist/src/services/audit/enforcers/active-skill-resolver.js +71 -0
  43. package/dist/src/services/audit/enforcers/design-draft-confirm.d.ts +25 -0
  44. package/dist/src/services/audit/enforcers/design-draft-confirm.js +54 -0
  45. package/dist/src/services/audit/enforcers/lint-audit-regression.d.ts +21 -0
  46. package/dist/src/services/audit/enforcers/lint-audit-regression.js +86 -0
  47. package/dist/src/services/audit/enforcers/lint-catalog-governance.d.ts +27 -0
  48. package/dist/src/services/audit/enforcers/lint-catalog-governance.js +38 -0
  49. package/dist/src/services/audit/enforcers/lint-cli-back.d.ts +16 -0
  50. package/dist/src/services/audit/enforcers/lint-cli-back.js +35 -0
  51. package/dist/src/services/audit/enforcers/lint-output-style.d.ts +11 -0
  52. package/dist/src/services/audit/enforcers/lint-output-style.js +94 -0
  53. package/dist/src/services/audit/enforcers/lint-reference-integrity.d.ts +6 -0
  54. package/dist/src/services/audit/enforcers/lint-reference-integrity.js +83 -0
  55. package/dist/src/services/audit/enforcers/lint-reference-shape.d.ts +30 -0
  56. package/dist/src/services/audit/enforcers/lint-reference-shape.js +272 -0
  57. package/dist/src/services/audit/enforcers/lint-style.d.ts +49 -0
  58. package/dist/src/services/audit/enforcers/lint-style.js +173 -0
  59. package/dist/src/services/audit/enforcers/lint-workflow-shape.d.ts +5 -0
  60. package/dist/src/services/audit/enforcers/lint-workflow-shape.js +141 -0
  61. package/dist/src/services/audit/enforcers/login-gate.d.ts +23 -0
  62. package/dist/src/services/audit/enforcers/login-gate.js +40 -0
  63. package/dist/src/services/audit/enforcers/mock-placement.d.ts +25 -0
  64. package/dist/src/services/audit/enforcers/mock-placement.js +48 -0
  65. package/dist/src/services/audit/enforcers/no-root-pollution.d.ts +21 -0
  66. package/dist/src/services/audit/enforcers/no-root-pollution.js +56 -0
  67. package/dist/src/services/audit/enforcers/pre-rd-scan.d.ts +22 -0
  68. package/dist/src/services/audit/enforcers/pre-rd-scan.js +23 -0
  69. package/dist/src/services/audit/enforcers/prototype-fidelity.d.ts +25 -0
  70. package/dist/src/services/audit/enforcers/prototype-fidelity.js +75 -0
  71. package/dist/src/services/audit/enforcers/resume-detection.d.ts +21 -0
  72. package/dist/src/services/audit/enforcers/resume-detection.js +52 -0
  73. package/dist/src/services/audit/enforcers/solo-code-ban.d.ts +23 -0
  74. package/dist/src/services/audit/enforcers/solo-code-ban.js +27 -0
  75. package/dist/src/services/audit/enforcers/sub-agent-sid.d.ts +25 -0
  76. package/dist/src/services/audit/enforcers/sub-agent-sid.js +63 -0
  77. package/dist/src/services/audit/enforcers/tech-doc-presence.d.ts +28 -0
  78. package/dist/src/services/audit/enforcers/tech-doc-presence.js +35 -0
  79. package/dist/src/services/audit/red-line-catalog-p2-a.d.ts +21 -0
  80. package/dist/src/services/audit/red-line-catalog-p2-a.js +233 -0
  81. package/dist/src/services/audit/red-line-catalog-p2-b.d.ts +19 -0
  82. package/dist/src/services/audit/red-line-catalog-p2-b.js +225 -0
  83. package/dist/src/services/audit/red-line-catalog.d.ts +51 -0
  84. package/dist/src/services/audit/red-line-catalog.js +210 -0
  85. package/dist/src/services/audit/red-lines-service.d.ts +23 -0
  86. package/dist/src/services/audit/red-lines-service.js +486 -0
  87. package/dist/src/services/audit/scanners/openspec-scanner.d.ts +15 -0
  88. package/dist/src/services/audit/scanners/openspec-scanner.js +55 -0
  89. package/dist/src/services/audit/scanners/rules-tree-scanner.d.ts +16 -0
  90. package/dist/src/services/audit/scanners/rules-tree-scanner.js +56 -0
  91. package/dist/src/services/audit/scanners/skills-tree-scanner.d.ts +17 -0
  92. package/dist/src/services/audit/scanners/skills-tree-scanner.js +46 -0
  93. package/dist/src/services/audit/static-service.d.ts +57 -0
  94. package/dist/src/services/audit/static-service.js +125 -0
  95. package/dist/src/services/audit/types.d.ts +69 -0
  96. package/dist/src/services/audit/types.js +13 -0
  97. package/dist/src/services/classify/classify-service.d.ts +42 -0
  98. package/dist/src/services/classify/classify-service.js +122 -0
  99. package/dist/src/services/classify/classify-types.d.ts +79 -0
  100. package/dist/src/services/classify/classify-types.js +90 -0
  101. package/dist/src/services/code-review/ocr-service.d.ts +129 -0
  102. package/dist/src/services/code-review/ocr-service.js +362 -0
  103. package/dist/src/services/config/config-migration.d.ts +32 -0
  104. package/dist/src/services/config/config-migration.js +111 -0
  105. package/dist/src/services/config/config-restore.d.ts +10 -0
  106. package/dist/src/services/config/config-restore.js +47 -0
  107. package/dist/src/services/config/config-rollback.d.ts +13 -0
  108. package/dist/src/services/config/config-rollback.js +26 -0
  109. package/dist/src/services/config/config-service.d.ts +36 -2
  110. package/dist/src/services/config/config-service.js +105 -0
  111. package/dist/src/services/config/config-types.d.ts +73 -0
  112. package/dist/src/services/config/config-types.js +28 -13
  113. package/dist/src/services/config/model-routing.js +5 -3
  114. package/dist/src/services/doctor/doctor-service.js +96 -0
  115. package/dist/src/services/ide/adapters/hermes-adapter.d.ts +21 -0
  116. package/dist/src/services/ide/adapters/hermes-adapter.js +51 -0
  117. package/dist/src/services/ide/adapters/openclaw-adapter.d.ts +14 -0
  118. package/dist/src/services/ide/adapters/openclaw-adapter.js +42 -0
  119. package/dist/src/services/ide/ide-registry.js +7 -0
  120. package/dist/src/services/ide/ide-types.d.ts +1 -1
  121. package/dist/src/services/openspec/openspec-propose-from-doctor-service.d.ts +31 -0
  122. package/dist/src/services/openspec/openspec-propose-from-doctor-service.js +95 -0
  123. package/dist/src/services/preferences/preferences-service.d.ts +6 -0
  124. package/dist/src/services/preferences/preferences-service.js +43 -0
  125. package/dist/src/services/preferences/preferences-types.d.ts +90 -0
  126. package/dist/src/services/preferences/preferences-types.js +38 -0
  127. package/dist/src/services/rd/rd-service.js +29 -1
  128. package/dist/src/services/skills/skill-conformance-service.d.ts +40 -0
  129. package/dist/src/services/skills/skill-conformance-service.js +136 -0
  130. package/dist/src/services/skills/skill-runbook-service.js +44 -10
  131. package/dist/src/services/skills/sync-service.d.ts +86 -0
  132. package/dist/src/services/skills/sync-service.js +271 -0
  133. package/dist/src/services/slice/slice-check-service.js +166 -13
  134. package/dist/src/services/slice/slice-check-types.d.ts +1 -1
  135. package/dist/src/services/standards/migrate-claude-rules-service.d.ts +19 -0
  136. package/dist/src/services/standards/migrate-claude-rules-service.js +193 -0
  137. package/dist/src/services/understand/understand-scan-service.js +15 -2
  138. package/dist/src/services/understand/understand-types.d.ts +26 -0
  139. package/dist/src/services/upgrade/1x-detector-service.d.ts +7 -0
  140. package/dist/src/services/upgrade/1x-detector-service.js +94 -0
  141. package/dist/src/services/upgrade/gitignore-migrate-service.d.ts +56 -0
  142. package/dist/src/services/upgrade/gitignore-migrate-service.js +170 -0
  143. package/dist/src/services/upgrade/upgrade-service.d.ts +47 -0
  144. package/dist/src/services/upgrade/upgrade-service.js +381 -0
  145. package/dist/src/services/workflow/workflow-router-service.js +15 -4
  146. package/dist/src/services/workspace/claude-settings-template.d.ts +53 -0
  147. package/dist/src/services/workspace/claude-settings-template.js +133 -0
  148. package/dist/src/services/workspace/sid-naming-guard.d.ts +14 -0
  149. package/dist/src/services/workspace/sid-naming-guard.js +31 -0
  150. package/dist/src/services/workspace/workspace-archive-service.d.ts +19 -0
  151. package/dist/src/services/workspace/workspace-archive-service.js +32 -0
  152. package/dist/src/services/workspace/workspace-clean-service.d.ts +41 -0
  153. package/dist/src/services/workspace/workspace-clean-service.js +86 -0
  154. package/dist/src/services/workspace/workspace-service.d.ts +24 -0
  155. package/dist/src/services/workspace/workspace-service.js +124 -2
  156. package/dist/src/services/workspace/workspace-state-service.d.ts +7 -0
  157. package/dist/src/services/workspace/workspace-state-service.js +43 -0
  158. package/dist/src/shared/change-id.js +4 -1
  159. package/dist/src/shared/version.d.ts +1 -1
  160. package/dist/src/shared/version.js +1 -1
  161. package/package.json +8 -2
  162. package/schemas/doctor-report.schema.json +1 -1
  163. package/scripts/install-skills.mjs +296 -12
  164. package/skills/peaks-doctor/SKILL.md +59 -0
  165. package/skills/peaks-doctor/references/doctor-check-catalog.md +31 -0
  166. package/skills/peaks-doctor/references/from-doctor-flow.md +64 -0
  167. package/skills/peaks-doctor/test_prompts.json +17 -0
  168. package/skills/peaks-ide/SKILL.md +2 -0
  169. package/skills/peaks-qa/SKILL.md +9 -7
  170. package/skills/peaks-qa/references/artifact-per-request.md +19 -5
  171. package/skills/peaks-qa/references/qa-perf-test-plan.md +6 -6
  172. package/skills/peaks-qa/references/qa-runbook.md +1 -1
  173. package/skills/peaks-rd/SKILL.md +25 -10
  174. package/skills/peaks-rd/references/ocr-integration.md +214 -0
  175. package/skills/peaks-rd/references/rd-fanout-contracts.md +70 -0
  176. package/skills/peaks-rd/references/rd-runbook.md +1 -1
  177. package/skills/peaks-solo/SKILL.md +16 -4
  178. package/skills/peaks-solo/references/anchoring-and-session-info.md +9 -0
  179. package/skills/peaks-solo/references/step-0-55-1x-detection.md +82 -0
  180. package/skills/peaks-solo/references/workflow-gates-and-types.md +9 -0
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { closeSync, constants, existsSync, fchmodSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readlinkSync, realpathSync, readdirSync, renameSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs';
3
+ import { spawnSync } from 'node:child_process';
3
4
  import { createHash, randomUUID } from 'node:crypto';
4
5
  import { homedir } from 'node:os';
5
6
  import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
@@ -389,6 +390,19 @@ const IDE_DETECTION_DIRS = [
389
390
  { id: 'tongyi-lingma', dir: '.tongyi-lingma' },
390
391
  ];
391
392
 
393
+ /**
394
+ * Per-IDE skill install paths. Per peaks-cli tenet
395
+ * "minimal-user-operation" (2026-06-11), the user should
396
+ * never have to run a per-platform install command — the
397
+ * `npm i -g peaks-cli` postinstall iterates ALL of these
398
+ * and symlinks the peaks-* skill family to every platform
399
+ * the user might be on.
400
+ *
401
+ * 1.x had only `claude-code` (the other 5 entries were
402
+ * `null`); real Trae users reported the Trae skill
403
+ * directory was never populated. 2.0 fixes this by giving
404
+ * all 8 platforms canonical install paths.
405
+ */
392
406
  const IDE_SKILL_INSTALL_PROFILES = {
393
407
  'claude-code': {
394
408
  skillsDir: join(homedir(), '.claude', 'skills'),
@@ -396,11 +410,48 @@ const IDE_SKILL_INSTALL_PROFILES = {
396
410
  envVar: 'PEAKS_CLAUDE_SKILLS_DIR',
397
411
  outputStylesEnvVar: 'PEAKS_CLAUDE_OUTPUT_STYLES_DIR',
398
412
  },
399
- 'trae': null,
400
- 'codex': null,
401
- 'cursor': null,
402
- 'qoder': null,
403
- 'tongyi-lingma': null,
413
+ 'trae': {
414
+ skillsDir: join(homedir(), '.trae', 'skills'),
415
+ outputStylesDir: join(homedir(), '.trae', 'output-styles'),
416
+ envVar: 'PEAKS_TRAE_SKILLS_DIR',
417
+ outputStylesEnvVar: 'PEAKS_TRAE_OUTPUT_STYLES_DIR',
418
+ },
419
+ 'codex': {
420
+ skillsDir: join(homedir(), '.codex', 'skills'),
421
+ outputStylesDir: join(homedir(), '.codex', 'output-styles'),
422
+ envVar: 'PEAKS_CODEX_SKILLS_DIR',
423
+ outputStylesEnvVar: 'PEAKS_CODEX_OUTPUT_STYLES_DIR',
424
+ },
425
+ 'cursor': {
426
+ skillsDir: join(homedir(), '.cursor', 'skills'),
427
+ outputStylesDir: join(homedir(), '.cursor', 'output-styles'),
428
+ envVar: 'PEAKS_CURSOR_SKILLS_DIR',
429
+ outputStylesEnvVar: 'PEAKS_CURSOR_OUTPUT_STYLES_DIR',
430
+ },
431
+ 'qoder': {
432
+ skillsDir: join(homedir(), '.qoder', 'skills'),
433
+ outputStylesDir: join(homedir(), '.qoder', 'output-styles'),
434
+ envVar: 'PEAKS_QODER_SKILLS_DIR',
435
+ outputStylesEnvVar: 'PEAKS_QODER_OUTPUT_STYLES_DIR',
436
+ },
437
+ 'tongyi-lingma': {
438
+ skillsDir: join(homedir(), '.tongyi-lingma', 'skills'),
439
+ outputStylesDir: join(homedir(), '.tongyi-lingma', 'output-styles'),
440
+ envVar: 'PEAKS_TONGYI_SKILLS_DIR',
441
+ outputStylesEnvVar: 'PEAKS_TONGYI_OUTPUT_STYLES_DIR',
442
+ },
443
+ 'hermes': {
444
+ skillsDir: join(homedir(), '.hermes', 'skills'),
445
+ outputStylesDir: join(homedir(), '.hermes', 'output-styles'),
446
+ envVar: 'PEAKS_HERMES_SKILLS_DIR',
447
+ outputStylesEnvVar: 'PEAKS_HERMES_OUTPUT_STYLES_DIR',
448
+ },
449
+ 'openclaw': {
450
+ skillsDir: join(homedir(), '.openclaw', 'skills'),
451
+ outputStylesDir: join(homedir(), '.openclaw', 'output-styles'),
452
+ envVar: 'PEAKS_OPENCLAW_SKILLS_DIR',
453
+ outputStylesEnvVar: 'PEAKS_OPENCLAW_OUTPUT_STYLES_DIR',
454
+ },
404
455
  };
405
456
 
406
457
  function detectInstalledIdeId(projectRoot) {
@@ -657,9 +708,228 @@ export function installBundledOutputStyles(options = {}) {
657
708
  return { installed, skipped };
658
709
  }
659
710
 
711
+ /**
712
+ * Per-platform fan-out — iterate ALL 8 IdeIds and call
713
+ * `installBundledSkills` for each. Per peaks-cli tenet
714
+ * "minimal-user-operation" (2026-06-11): the user should
715
+ * never have to run a per-platform install command. The
716
+ * 1.x postinstall only handled the auto-detected single
717
+ * IDE; 2.0 fixes this so the peaks-* skill family is
718
+ * symlinked to every platform the user might be on.
719
+ *
720
+ * Returns an array of { ideId, skillsDir, installed, skipped }
721
+ * per platform. Symlink failures are soft (logged to stderr,
722
+ * never throw) so one platform's failure doesn't block the
723
+ * other 7.
724
+ */
725
+ export function installBundledSkillsForAllPlatforms(options = {}) {
726
+ const platforms = Object.keys(IDE_SKILL_INSTALL_PROFILES);
727
+ const perPlatform = [];
728
+ // Back-compat precedence (regression fix 2026-06-12,
729
+ // slice 2026-06-12-postinstall-1x-detector-tdd):
730
+ // when iterating the 8 platforms, the claude-code install
731
+ // must still honor the PEAKS_CLAUDE_SKILLS_DIR env var
732
+ // (the legacy back-compat surface from 1.x). The other 7
733
+ // platforms use their per-IDE profile paths unconditionally.
734
+ // Without this fix the 8-IDE fan-out regresses the
735
+ // `peaks install-skills` env-var override contract that
736
+ // user CI / 1.x → 2.0 migration scripts depend on.
737
+ const claudeEnv = process.env.PEAKS_CLAUDE_SKILLS_DIR;
738
+ for (const ideId of platforms) {
739
+ try {
740
+ const platformOpts =
741
+ ideId === 'claude-code' && claudeEnv !== undefined && claudeEnv.length > 0
742
+ ? { ...options, ideId, targetRoot: claudeEnv }
743
+ : { ...options, ideId };
744
+ const result = installBundledSkills(platformOpts);
745
+ perPlatform.push({
746
+ ideId,
747
+ skillsDir: IDE_SKILL_INSTALL_PROFILES[ideId]?.skillsDir ?? '(unknown)',
748
+ installed: result.installed,
749
+ skipped: result.skipped,
750
+ });
751
+ } catch (err) {
752
+ const message = err instanceof Error ? err.message : String(err);
753
+ process.stderr.write(
754
+ `peaks install-skills: ${ideId} platform failed (continuing): ${message}\n`
755
+ );
756
+ perPlatform.push({
757
+ ideId,
758
+ skillsDir: IDE_SKILL_INSTALL_PROFILES[ideId]?.skillsDir ?? '(unknown)',
759
+ installed: [],
760
+ skipped: [],
761
+ error: message,
762
+ });
763
+ }
764
+ }
765
+ return perPlatform;
766
+ }
767
+
768
+ /**
769
+ * 1.x → 2.0 detection — sniff for legacy 1.x project state
770
+ * in `cwd`. Returns a 1.x detection envelope with the
771
+ * detected signals (so the postinstall can decide whether
772
+ * to auto-upgrade).
773
+ *
774
+ * 1.x signals (any one fires the detection):
775
+ * - `~/.peaks/config.json` exists with `version: '1.4.2'` (or
776
+ * any '1.x' version that predates the 2.0 schema)
777
+ * - `.claude/rules/common/dev-preference.md` exists and
778
+ * references "peaks progress" (the 1.x CLI surface
779
+ * removed in slice #014)
780
+ * - `<cwd>/.peaks/preferences.json` missing OR has no
781
+ * `schema_version: '2.0.0'` field
782
+ *
783
+ * Returns:
784
+ * { isOneX: boolean, signals: string[], projectRoot: string|null,
785
+ * configPath: string|null }
786
+ */
787
+ export function detect1xProjectState(cwd = process.cwd()) {
788
+ const home = homedir();
789
+ const signals = [];
790
+ let projectRoot = null;
791
+ let configPath = null;
792
+
793
+ // Walk up from cwd looking for .peaks/_runtime (signals
794
+ // we're inside a peaks project).
795
+ let dir = cwd;
796
+ for (let i = 0; i < 8; i += 1) {
797
+ const peaksRuntime = join(dir, '.peaks', '_runtime');
798
+ if (existsSync(peaksRuntime)) {
799
+ projectRoot = dir;
800
+ break;
801
+ }
802
+ const parent = dirname(dir);
803
+ if (parent === dir) break;
804
+ dir = parent;
805
+ }
806
+
807
+ // Signal 1: ~/.peaks/config.json with 1.x version
808
+ const globalConfig = join(home, '.peaks', 'config.json');
809
+ if (existsSync(globalConfig)) {
810
+ try {
811
+ const raw = JSON.parse(readFileSync(globalConfig, 'utf8'));
812
+ if (typeof raw.version === 'string' && /^1\./.test(raw.version)) {
813
+ signals.push(`global config at ${globalConfig} is 1.x (${raw.version})`);
814
+ if (configPath === null) configPath = globalConfig;
815
+ }
816
+ } catch {
817
+ // ignore parse error — the 1.x detection is best-effort
818
+ }
819
+ }
820
+
821
+ // Signal 2: .claude/rules/common/dev-preference.md with peaks progress
822
+ if (projectRoot !== null) {
823
+ const devPref = join(projectRoot, '.claude', 'rules', 'common', 'dev-preference.md');
824
+ if (existsSync(devPref)) {
825
+ try {
826
+ const body = readFileSync(devPref, 'utf8');
827
+ if (/peaks progress/i.test(body)) {
828
+ signals.push(`${devPref} references "peaks progress" (1.x CLI surface, removed in slice #014)`);
829
+ }
830
+ } catch {
831
+ // ignore
832
+ }
833
+ }
834
+ // Signal 3: project preferences.json missing or 1.x
835
+ const prefs = join(projectRoot, '.peaks', 'preferences.json');
836
+ if (!existsSync(prefs)) {
837
+ signals.push(`${prefs} does not exist (1.x project never migrated)`);
838
+ } else {
839
+ try {
840
+ const raw = JSON.parse(readFileSync(prefs, 'utf8'));
841
+ if (raw.schema_version !== '2.0.0') {
842
+ signals.push(`${prefs} has schema_version ${JSON.stringify(raw.schema_version)}, expected '2.0.0'`);
843
+ }
844
+ } catch {
845
+ signals.push(`${prefs} exists but is not valid JSON`);
846
+ }
847
+ }
848
+ }
849
+
850
+ return {
851
+ isOneX: signals.length > 0,
852
+ signals,
853
+ projectRoot,
854
+ configPath,
855
+ };
856
+ }
857
+
858
+ /**
859
+ * Postinstall auto-upgrade — when the user just ran
860
+ * `npm i -g peaks-cli@2.0` and `cwd` is a 1.x peaks-cli
861
+ * project, this shells out to the installed `peaks`
862
+ * binary to run the umbrella `peaks upgrade --to 2.0 --auto`.
863
+ *
864
+ * Per the "minimal-user-operation" tenet, the user should
865
+ * never have to run a second command after `npm i -g`. The
866
+ * upgrade CLI (if installed) is at the resolved `peaks`
867
+ * binary path; if not, the user gets a hint to run it
868
+ * manually.
869
+ *
870
+ * The auto-upgrade is opt-out via:
871
+ * PEAKS_SKIP_AUTO_UPGRADE=1
872
+ * (so a CI box that installs 2.0 but never wants the
873
+ * project-level migration can suppress the auto-step).
874
+ */
875
+ export async function autoUpgrade1xProjectIfPresent(options = {}) {
876
+ if (process.env.PEAKS_SKIP_AUTO_UPGRADE === '1') {
877
+ return { ran: false, reason: 'PEAKS_SKIP_AUTO_UPGRADE=1' };
878
+ }
879
+ const state = detect1xProjectState(options.cwd ?? process.cwd());
880
+ if (!state.isOneX) {
881
+ return { ran: false, reason: 'no 1.x project state detected' };
882
+ }
883
+ if (state.projectRoot === null) {
884
+ return { ran: false, reason: 'cwd is not a peaks project (no .peaks/_runtime/)' };
885
+ }
886
+ // The peaks binary should be on PATH after `npm i -g`.
887
+ // We shell out via spawnSync (synchronous; the postinstall
888
+ // is already synchronous and the umbrella is fast).
889
+ try {
890
+ const result = spawnSync('peaks', ['upgrade', '--to', '2.0', '--auto', '--project', state.projectRoot], {
891
+ encoding: 'utf8',
892
+ stdio: ['ignore', 'pipe', 'pipe'],
893
+ timeout: 120_000,
894
+ });
895
+ return {
896
+ ran: true,
897
+ reason: 'auto-upgrade dispatched',
898
+ signals: state.signals,
899
+ projectRoot: state.projectRoot,
900
+ exitCode: result.status,
901
+ stdout: result.stdout ?? '',
902
+ stderr: result.stderr ?? '',
903
+ };
904
+ } catch (err) {
905
+ return {
906
+ ran: true,
907
+ reason: 'auto-upgrade dispatched but failed',
908
+ signals: state.signals,
909
+ projectRoot: state.projectRoot,
910
+ error: err instanceof Error ? err.message : String(err),
911
+ };
912
+ }
913
+ }
914
+
660
915
  if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
661
916
  try {
662
- const skillsResult = installBundledSkills();
917
+ // 2.0 fix for the 1.x Trae bug (per real user feedback
918
+ // 2026-06-11): iterate ALL 8 platforms, not just the
919
+ // auto-detected one. Per the "minimal-user-operation"
920
+ // tenet, the user should never have to run a
921
+ // per-platform install command.
922
+ const perPlatform = installBundledSkillsForAllPlatforms();
923
+ let totalInstalled = 0;
924
+ for (const p of perPlatform) {
925
+ totalInstalled += p.installed.length;
926
+ }
927
+ if (totalInstalled > 0) {
928
+ process.stdout.write(
929
+ `Peaks skills linked across ${perPlatform.length} platforms ` +
930
+ `(${totalInstalled} total symlinks)\n`
931
+ );
932
+ }
663
933
  const outputStylesResult = installBundledOutputStyles();
664
934
  let userConfigResult = createConfigResult({ skipped: true });
665
935
  try {
@@ -668,12 +938,6 @@ if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(resolve(p
668
938
  const message = error instanceof Error ? error.message : String(error);
669
939
  process.stderr.write(`Peaks user config was not installed: ${message}\n`);
670
940
  }
671
- if (skillsResult.installed.length > 0) {
672
- process.stdout.write(`Peaks skills linked: ${skillsResult.installed.join(', ')}\n`);
673
- }
674
- if (skillsResult.skipped.length > 0) {
675
- process.stderr.write(`Peaks skills skipped because local files already exist: ${skillsResult.skipped.join(', ')}\n`);
676
- }
677
941
  if (outputStylesResult.installed.length > 0) {
678
942
  process.stdout.write(`Peaks output styles installed: ${outputStylesResult.installed.join(', ')}\n`);
679
943
  }
@@ -683,6 +947,26 @@ if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(resolve(p
683
947
  if (userConfigResult.created) {
684
948
  process.stdout.write('Peaks user config created: ~/.peaks/config.json\n');
685
949
  }
950
+
951
+ // 2.0 postinstall: auto-detect 1.x project state in cwd
952
+ // and dispatch the upgrade umbrella. This makes the
953
+ // user's `npm i -g peaks-cli@2.0` truly one-key.
954
+ if (process.env.PEAKS_SKIP_AUTO_UPGRADE !== '1') {
955
+ // Fire-and-forget; the upgrade is async by design so
956
+ // the npm install output isn't blocked. We print a
957
+ // one-line hint so the user knows the auto-step
958
+ // happened.
959
+ autoUpgrade1xProjectIfPresent().then((result) => {
960
+ if (result.ran) {
961
+ process.stdout.write(
962
+ `\n✓ Detected 1.x peaks-cli project at ${result.projectRoot}\n` +
963
+ ` → auto-upgraded to 2.0 (${result.signals?.length ?? 0} signals resolved)\n` +
964
+ ` Run \`peaks audit red-lines --project .\` to verify.\n`
965
+ );
966
+ }
967
+ // When !result.ran we say nothing — silent on success.
968
+ });
969
+ }
686
970
  if (userConfigResult.updated) {
687
971
  process.stdout.write('Peaks user config updated: ~/.peaks/config.json\n');
688
972
  }
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: peaks-doctor
3
+ description: Orchestrate peaks-cli's L3 doctor (peaks audit + peaks doctor + peaks openspec from-doctor) for project health. Use when the user asks for a project health check, doctor report, audit, or wants to convert doctor findings into OpenSpec change records. Coordinates the L2 audit framework + the L3.2 doctor + the L3.3 from-doctor proposal generator. Triggers on `/peaks-doctor`, "peaks doctor", "项目健康", "doctor report", "health check", "check the project", "audit my repo".
4
+ internal: true
5
+ ---
6
+ ---
7
+
8
+ # Peaks-Cli Doctor
9
+
10
+ Peaks-Cli Doctor is the orchestration facade for the L3 doctor workflow. It runs the L2 audit framework (`peaks audit red-lines`) + the L3.2 doctor checks (`peaks doctor`) + the L3.3 from-doctor proposal generator (`peaks openspec from-doctor`). Use it when the user wants a project health check, a red-line audit, or to convert doctor findings into OpenSpec change records.
11
+
12
+ ## Skill-first architecture note (read once, internalise)
13
+
14
+ This skill is the **primary surface**. The `peaks <cmd>` CLI is **auxiliary** — invoked by the skill prompt only when a primitive is the right tool. Behaviour only an LLM in a skill prompt would use lives **here in the SKILL.md**, not as a new CLI command. See `.claude/rules/common/dev-preference.md` for the decision template.
15
+
16
+ ## Code-Change Red Line (BLOCKING — read before ANY tool call)
17
+
18
+ **Peaks-Cli Doctor is a doctor orchestrator, NOT an implementer. You MUST NOT write, edit, or modify any application source code directly.**
19
+
20
+ The doctor workflow is read-only by design. It produces:
21
+ - `peaks audit red-lines` report (121 red lines in the current repo, 6 cli-backed)
22
+ - `peaks doctor` report (69 checks: 68 pass, 1 fail — L3:l3-memory-health)
23
+ - Optional OpenSpec change records via `peaks openspec from-doctor`
24
+
25
+ If a doctor finding requires a code change, the workflow hands off to `peaks-rd` (or `peaks-solo` for the full pipeline). The doctor itself does NOT modify code.
26
+
27
+ ## Workflow (5 steps)
28
+
29
+ 1. **Anchor**: `peaks workspace init --project <repo> --json` (idempotent; same as every peaks-* skill).
30
+ 2. **Run audit**: `peaks audit red-lines --project <repo> --json` — returns the red-line audit (catalog-matched markers + live enforcer findings). Inspect the `enforcerFindings` array for runtime-detected issues.
31
+ 3. **Run doctor**: `peaks doctor --json` — returns 69 checks. Pay special attention to:
32
+ - `L3:l3-orphan-sessions` — invalid sids in .peaks/_runtime/
33
+ - `L3:l3-memory-health` — .peaks/memory/index.json shape
34
+ - `integration:gateguard-peaks-conflict` — third-party Edit/Write hook interference
35
+ - `build:workspace-layout-canonical` — workspace layout
36
+ 4. **Triage findings**: For each FAIL check, decide:
37
+ - **Real bug requiring fix** → hand off to peaks-rd (run `peaks openspec from-doctor` first to generate a draft proposal; then peaks-rd to implement)
38
+ - **Acceptable false positive** → document in the handoff; do not act
39
+ - **Configuration drift** → run the suggested recovery command (e.g. `peaks workspace clean`)
40
+ 5. **Generate proposals** (per FAIL finding): `peaks openspec from-doctor --project <repo> --check-id <id>` writes `openspec/changes/<date>-fix-<slug>/proposal.md`. Hand off to peaks-rd for implementation.
41
+
42
+ ## CLI primitives the skill composes
43
+
44
+ - `peaks workspace init` — anchor the workspace (Step 0)
45
+ - `peaks audit red-lines` — L2 audit
46
+ - `peaks doctor` — L3.2 doctor
47
+ - `peaks openspec from-doctor` — L3.3 proposal generator
48
+ - `peaks openspec validate` — gate a draft proposal
49
+
50
+ ## Boundaries
51
+
52
+ - The doctor is read-only. It does NOT modify code, fix bugs, or clean up sessions.
53
+ - The doctor does NOT install UA or any third-party tool. The opt-in UX is surfaced via `peaks understand opt-in`; the doctor just reports state.
54
+ - The doctor does NOT generate change records automatically; it surfaces findings + the LLM calls `peaks openspec from-doctor` to generate them.
55
+
56
+ ## References
57
+
58
+ - `references/doctor-check-catalog.md` — every doctor check id + what it means
59
+ - `references/from-doctor-flow.md` — the end-to-end "finding → proposal" path
@@ -0,0 +1,31 @@
1
+ # Doctor check catalog (peaks-doctor skill reference)
2
+
3
+ Slice L3.2 ships 69 doctor checks. The most user-relevant ones:
4
+
5
+ ## L2 audit (slice #2)
6
+
7
+ - **`L2:audit:cli-backed`** — count of red lines whose catalog match has a real enforcer
8
+ - **`L2:audit:prose-only`** — count of red lines that need a future enforcer
9
+
10
+ ## L3.2 (slice #9)
11
+
12
+ - **`L3:l3-orphan-sessions`** — directories in `.peaks/_runtime/` that fail `isValidSessionId`. Recover with `peaks workspace clean`.
13
+ - **`L3:l3-memory-health`** — `.peaks/memory/index.json` must be well-formed JSON with a `schema_version` field and an array `entries`. Recovers by re-running `peaks memory extract`.
14
+
15
+ ## Build / workspace
16
+
17
+ - **`build:dist-version-matches-source`** — `dist/src/shared/version.js` matches the source `package.json` version
18
+ - **`build:workspace-layout-canonical`** — `.peaks/` follows the canonical `._archive` / `_runtime` / `_sub_agents` layout
19
+ - **`build:workspace-migrate-not-needed`** — when the layout is already canonical
20
+
21
+ ## Integration (third-party hooks)
22
+
23
+ - **`integration:gateguard-peaks-conflict`** — warns when `gateguard-fact-force` is installed without a `.peaks/**` skip pattern (the 3rd-party hook would block all peaks-qa .peaks/ artifact writes)
24
+
25
+ ## Skills
26
+
27
+ - **`skill:<required-skill>`** — each required skill (peaks-ide, peaks-prd, peaks-rd, peaks-qa, peaks-sc, peaks-solo, peaks-sop, peaks-txt, peaks-ui, peaks-doctor) must be installed in the bundled skills dir
28
+
29
+ ## Doctor self
30
+
31
+ - **`doctor-self:check-id-pattern`** — all check IDs match the `doctor-report.schema.json` regex pattern (prevents typos like `L3:l3-orphan-sesions`)
@@ -0,0 +1,64 @@
1
+ # from-doctor flow (peaks-doctor skill reference)
2
+
3
+ End-to-end path from a doctor finding to an OpenSpec change record.
4
+
5
+ ## Flow
6
+
7
+ ```
8
+ peaks doctor --json # 1. discover findings
9
+
10
+ match: any check where ok=false
11
+
12
+ peaks openspec from-doctor \
13
+ --project <repo> \
14
+ --check-id <id> # 2. generate draft proposal
15
+
16
+ openspec/changes/<date>-fix-<slug>/proposal.md # 3. LLM reviews + edits
17
+
18
+ peaks openspec validate <change-id> # 4. gate
19
+
20
+ [next slice: peaks-rd implements the change per the proposal]
21
+ ```
22
+
23
+ ## Example
24
+
25
+ ```bash
26
+ # Discover
27
+ $ peaks doctor --json | jq '.data.checks[] | select(.ok==false) | .id'
28
+ "L3:l3-memory-health"
29
+
30
+ # Generate draft
31
+ $ peaks openspec from-doctor \
32
+ --project . \
33
+ --check-id L3:l3-memory-health \
34
+ --json
35
+ {
36
+ "ok": true,
37
+ "command": "openspec.from-doctor",
38
+ "data": {
39
+ "changeId": "2026-06-11-fix-l3-l3-memory-health",
40
+ "proposalPath": ".../openspec/changes/2026-06-11-fix-l3-l3-memory-health/proposal.md",
41
+ "created": true
42
+ }
43
+ }
44
+
45
+ # LLM reviews + edits the draft (in this case: add a Why section
46
+ # explaining the missing schema_version field; add an Acceptance
47
+ # Criterion that requires peaks doctor to return ok=true for the check)
48
+
49
+ # Validate
50
+ $ peaks openspec validate 2026-06-11-fix-l3-l3-memory-health --json
51
+ {
52
+ "ok": true,
53
+ "data": { "valid": true, "issues": [] }
54
+ }
55
+
56
+ # Implement (peaks-rd)
57
+ $ /peaks-rd 2026-06-11-fix-l3-l3-memory-health
58
+ ```
59
+
60
+ ## Edge cases
61
+
62
+ - **CHECK_ALREADY_PASSING**: `--check-id` matches a passing check. The CLI returns code CHECK_ALREADY_PASSING. Pick a failing check.
63
+ - **CHECK_NOT_FOUND**: `--check-id` doesn't match any check id. Run `peaks doctor --json | jq '.data.checks[].id'` to list.
64
+ - **OPENSPEC_FROM_DOCTOR_FAILED**: filesystem write error (e.g. openspec/ not initialized). Run `peaks openspec init --apply` first.
@@ -0,0 +1,17 @@
1
+ [
2
+ {
3
+ "id": "doctor-baseline",
4
+ "prompt": "/peaks-doctor",
5
+ "expectedOutcome": "Runs peaks workspace init + peaks audit + peaks doctor; returns a triage of FAIL checks with hand-off suggestions."
6
+ },
7
+ {
8
+ "id": "doctor-from-finding",
9
+ "prompt": "peaks doctor flagged L3:l3-memory-health. Generate an OpenSpec change record from it.",
10
+ "expectedOutcome": "Calls peaks openspec from-doctor --check-id L3:l3-memory-health; verifies the proposal.md was written; suggests next step (peaks-rd)."
11
+ },
12
+ {
13
+ "id": "doctor-only-audit",
14
+ "prompt": "Run only the audit (not the full doctor).",
15
+ "expectedOutcome": "Calls peaks audit red-lines --project . --json; summarizes the enforcerFindings and the prose-only ratio."
16
+ }
17
+ ]
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: peaks-ide
3
3
  description: Orchestrate peaks-cli's IDE-aware behavior (hooks + statusline + handle) for a user's specific IDE. Detects the current state (which IDE the user is on, what peaks has already installed), plans the install / switch / status / uninstall actions, and invokes the existing peaks CLI primitives. Triggers on `/peaks-ide`, "set up peaks for my IDE", "switch peaks to Trae", "what did peaks install", "uninstall peaks hooks". Sits between the user and `peaks hooks install` / `peaks statusline install` / `peaks hook handle` — those are the CLI primitives; this skill is the user-facing surface.
4
+ internal: true
5
+ ---
4
6
  ---
5
7
 
6
8
  # Peaks-Cli IDE Setup (peaks-ide)
@@ -79,15 +79,15 @@ When this skill is running in the main Claude session (not as a sub-agent), befo
79
79
 
80
80
  ## Mandatory per-request artifact
81
81
 
82
- Every QA invocation — feature, bug, refactor, clarification — must write **three separate files** (test cases + test report + request artifact). Do not merge them into one. Each serves a different reader.
82
+ Every QA invocation — feature, bug, refactor, clarification — must write **three separate files** (test cases + test report + request artifact) under `.peaks/<session-id>/qa/` (canonical placeholder: `.peaks/<session-id>/qa/requests/<request-id>.md`; runtime path is `.peaks/_runtime/<session-id>/qa/...`). Do not merge them into one. Each serves a different reader.
83
83
 
84
- see `references/artifact-per-request.md` for the 3-file contract (test cases / test report / request artifact).
84
+ External-skill guard: when QA references external material (mattpocock/skills, gstack, superpowers, etc.) it is reference only do not execute upstream installer, do not persist sensitive upstream examples. Peaks-Cli artifacts and Peaks-Cli acceptance criteria remain authoritative.
85
85
 
86
- ## Default runbook
86
+ see `references/artifact-per-request.md` for the 3-file contract and the do-not-execute upstream guard.
87
87
 
88
- The default sequence the QA skill should execute. Do not skip the boundary check, the unit test gate, the validation report, or — when frontend is in scope — the Playwright MCP browser gate. The full 10-step runbook (steps #0–#9) with every CLI invocation, the rd-side pre-drafted test-cases optimization, the dev-server lifecycle requirement, the security/performance check discipline, and the 8 quality-gate CLI checks is in the references file.
88
+ ## Default runbook
89
89
 
90
- see `references/qa-runbook.md` for the full runbook.
90
+ See `references/qa-runbook.md` for the full 10-step runbook (steps #0–#9) with every CLI invocation, the rd-side pre-drafted test-cases optimization, the dev-server lifecycle requirement, the security/performance check discipline, and the 8 quality-gate CLI checks.
91
91
 
92
92
  ## Transition verification gates (MANDATORY — run the command, see the output)
93
93
 
@@ -125,6 +125,8 @@ Before QA passes or returns work to RD, it must independently recheck the implem
125
125
 
126
126
  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`. Minimum categories: Unit / Integration / UI regression. Each test case MUST have an `**Acceptance:**` field linking to PRD acceptance IDs (A1, A2, ...). The `peaks scan acceptance-coverage` command enforces coverage.
127
127
 
128
+ **Pre-drafted test cases (slice 004 optimization):** when peaks-rd's 4-way parallel fan-out ran a `qa-test-cases-writer` sub-agent, the test plan is pre-drafted at `.peaks/<id>/qa/test-cases/<rid>.md` and shipped through the rd:qa-handoff gate. QA main loop is aware of this and treats the pre-drafted file as the canonical starting point. **Missing** the pre-drafted file (sub-agent failed, or the slice was a config/docs/chore that did not fan out) → QA drafts it inline as before, falling back to the standard generation flow.
129
+
128
130
  → see `references/test-case-generation.md` for the full format + acceptance-linkage contract.
129
131
 
130
132
  ## Mandatory test-report output
@@ -137,7 +139,7 @@ Every QA invocation must produce a test-report artifact at `.peaks/_runtime/<ses
137
139
 
138
140
  QA cannot pass a change until the report contains evidence for every applicable gate. The 11 gates (0 test-case generation, 1 test-report, 2 unit tests, 3 API validation, 4 frontend browser validation, 5 browser-error feedback loop, 6 security check, 7 performance check, 8 library version regressions, 9 validation report, 10 acceptance coverage, 11 QA artifact lint) are mapped to Peaks-Cli Gates A/A2/A3/A4/B/C/D/E/F.
139
141
 
140
- If Playwright MCP is unavailable (not installed and the user has not authorized installation), mark the gate blocked with the missing capability. Screenshots, logs, manual steps, or other tools must not substitute for the mandatory frontend browser gate. Do not silently downgrade frontend validation to API-only testing.
142
+ If Playwright MCP is unavailable, the LLM checks its own tool list for the Playwright MCP server entry; if absent, the LLM tells the user the install command (`claude mcp add playwright -- npx @playwright/mcp@latest` for Claude Code) and marks the gate blocked with the missing capability. Screenshots, logs, manual steps, or other tools must not substitute for the mandatory frontend browser gate. Do not silently downgrade frontend validation to API-only testing.
141
143
 
142
144
  ## Local intermediate artifacts
143
145
 
@@ -159,7 +161,7 @@ When capability discovery exposes `mattpocock/skills`, use `tdd` / `triage` / `g
159
161
 
160
162
  ## Codegraph regression focus
161
163
 
162
- QA may use `peaks codegraph affected --project <path> <changed-files...> --json` as regression-surface evidence. External analysis cannot pass QA by itself — treat output as untrusted supporting evidence.
164
+ QA may use `peaks codegraph affected --project <path> <changed-files...> --json` as regression-surface evidence. External analysis cannot pass QA by itself — treat output as untrusted supporting evidence. External skill guidance cannot pass QA by itself — treat as supporting evidence, not a verdict. QA reads `.peaks/<session-id>/rd/codegraph-context.md` (or `qa/codegraph-context.md`) as input but never mutate agent settings, Claude settings, or hooks from it; QA does not commit `.codegraph/` artifacts or persist generated `.codegraph/` databases into git.
163
165
 
164
166
  → see `references/codegraph-regression-focus.md`.
165
167
 
@@ -1,11 +1,25 @@
1
1
  # QA per-request artifact contract
2
2
 
3
- > Body of `## Mandatory per-request artifact` (QA-flavored). Every QA invocation — feature, bug, refactor, clarification — must write **three separate files**. Do not merge them into one. Each serves a different reader:
3
+ > Body of `## Mandatory per-request artifact` (QA-flavored). Every QA invocation — feature, bug, refactor, clarification — must write **three separate files**. Do not merge them into one. Each serves a different reader.
4
+
5
+ ## Required path
6
+
7
+ The three files for any QA invocation land under the active session's `qa/` workspace, using the canonical placeholder `.peaks/<session-id>/qa/...` (e.g. `.peaks/<session-id>/qa/requests/<request-id>.md`).
4
8
 
5
9
  | # | File | Path | Reader | Content |
6
10
  |---|------|------|--------|---------|
7
- | 1 | Test cases | `.peaks/_runtime/<sessionId>/qa/test-cases/<request-id>.md` | RD (before impl), QA | Generated test scenarios with status |
8
- | 2 | Test report | `.peaks/_runtime/<sessionId>/qa/test-reports/<request-id>.md` | QA, SC, Solo | Summary, coverage%, security, perf, risks |
9
- | 3 | Request artifact | `.peaks/_runtime/<sessionId>/qa/requests/<request-id>.md` | Solo, RD↔QA loop | Verdict, boundary check, links to #1 and #2 |
11
+ | 1 | Test cases | `.peaks/_runtime/<session-id>/qa/test-cases/<request-id>.md` | RD (before impl), QA | Generated test scenarios with status |
12
+ | 2 | Test report | `.peaks/_runtime/<session-id>/qa/test-reports/<request-id>.md` | QA, SC, Solo | Summary, coverage%, security, perf, risks |
13
+ | 3 | Request artifact | `.peaks/_runtime/<session-id>/qa/requests/<request-id>.md` | Solo, RD↔QA loop | Verdict, boundary check, links to #1 and #2 |
14
+
15
+ ## Required content
16
+
17
+ The request artifact is the **verdict carrier** — it must include: QA verdict (`pass` / `return-to-rd` / `blocked`), the red-line audit outcome, links to the test-cases and test-report, the boundary check (acceptance items covered, gaps), and any cross-skill handoff notes for Solo. The test cases file enumerates every scenario with status; the test report summarises execution and links the security / performance / regression companion files.
18
+
19
+ ## Rules
20
+
21
+ The 3-file split is load-bearing. Do not merge. Use the `<request-id>` PRD assigned (`YYYY-MM-DD-<kebab-slug>`). QA may also produce companion artifacts (regression matrix, sanitized browser evidence, security findings, performance findings) under the same `qa/` workspace and link them from these files. Sanitize MCP / network / browser evidence before writing. Do not commit unless the user or active profile authorizes durable retention. Verdict `pass` is blocked while any of the three files is missing or the request artifact is in `draft` / `running` state.
22
+
23
+ ## External-skill invocation guard
10
24
 
11
- The 3-file split is load-bearing. Do not merge. Use the `<request-id>` PRD assigned (`YYYY-MM-DD-<kebab-slug>`). QA may also produce companion artifacts (regression matrix, sanitized browser evidence, security findings, performance findings) under the same `qa/` workspace and link them from these files. Sanitize MCP / network / browser evidence before writing. Do not commit unless the user or active profile authorizes durable retention. Verdict `pass` is blocked while any of the three files is missing or the request artifact is in `draft` / `running` state.
25
+ When QA references external material (mattpocock/skills, gstack, superpowers, etc.) treat it as reference only: do not execute upstream installer, do not run upstream installer commands, do not persist sensitive upstream examples to the working tree. Peaks-Cli artifacts, Peaks-Cli gates, and Peaks-Cli acceptance criteria remain authoritative.