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.
- package/.claude-plugin/marketplace.json +51 -0
- package/CHANGELOG.md +279 -0
- package/README-en.md +226 -0
- package/README.md +152 -122
- package/dist/src/cli/commands/agent-commands.d.ts +20 -0
- package/dist/src/cli/commands/agent-commands.js +48 -0
- package/dist/src/cli/commands/audit-commands.d.ts +18 -0
- package/dist/src/cli/commands/audit-commands.js +138 -0
- package/dist/src/cli/commands/capability-commands.js +2 -1
- package/dist/src/cli/commands/classify-classify-commands.d.ts +19 -0
- package/dist/src/cli/commands/classify-classify-commands.js +151 -0
- package/dist/src/cli/commands/code-review-commands.d.ts +34 -0
- package/dist/src/cli/commands/code-review-commands.js +83 -0
- package/dist/src/cli/commands/config-commands.js +90 -0
- package/dist/src/cli/commands/context-commands.d.ts +21 -0
- package/dist/src/cli/commands/context-commands.js +167 -0
- package/dist/src/cli/commands/core-artifact-commands.js +60 -2
- package/dist/src/cli/commands/hook-handle.js +50 -0
- package/dist/src/cli/commands/loop-commands.d.ts +21 -0
- package/dist/src/cli/commands/loop-commands.js +128 -0
- package/dist/src/cli/commands/openspec-commands.js +37 -0
- package/dist/src/cli/commands/preferences-commands.d.ts +2 -0
- package/dist/src/cli/commands/preferences-commands.js +147 -0
- package/dist/src/cli/commands/skill-conformance-commands.d.ts +9 -0
- package/dist/src/cli/commands/skill-conformance-commands.js +39 -0
- package/dist/src/cli/commands/understand-commands.js +34 -0
- package/dist/src/cli/commands/upgrade-commands.d.ts +23 -0
- package/dist/src/cli/commands/upgrade-commands.js +57 -0
- package/dist/src/cli/commands/workflow-commands.js +70 -0
- package/dist/src/cli/commands/workspace-commands.js +117 -2
- package/dist/src/cli/program.js +30 -0
- package/dist/src/lib/render/message-renderer.d.ts +20 -0
- package/dist/src/lib/render/message-renderer.js +80 -0
- package/dist/src/services/agent/ecc-agent-service.d.ts +47 -0
- package/dist/src/services/agent/ecc-agent-service.js +143 -0
- package/dist/src/services/artifacts/request-artifact-service.js +14 -0
- package/dist/src/services/audit/backing-detector.d.ts +24 -0
- package/dist/src/services/audit/backing-detector.js +59 -0
- package/dist/src/services/audit/classifier.d.ts +38 -0
- package/dist/src/services/audit/classifier.js +127 -0
- package/dist/src/services/audit/enforcers/active-skill-resolver.d.ts +29 -0
- package/dist/src/services/audit/enforcers/active-skill-resolver.js +71 -0
- package/dist/src/services/audit/enforcers/design-draft-confirm.d.ts +25 -0
- package/dist/src/services/audit/enforcers/design-draft-confirm.js +54 -0
- package/dist/src/services/audit/enforcers/lint-audit-regression.d.ts +21 -0
- package/dist/src/services/audit/enforcers/lint-audit-regression.js +86 -0
- package/dist/src/services/audit/enforcers/lint-catalog-governance.d.ts +27 -0
- package/dist/src/services/audit/enforcers/lint-catalog-governance.js +38 -0
- package/dist/src/services/audit/enforcers/lint-cli-back.d.ts +16 -0
- package/dist/src/services/audit/enforcers/lint-cli-back.js +35 -0
- package/dist/src/services/audit/enforcers/lint-output-style.d.ts +11 -0
- package/dist/src/services/audit/enforcers/lint-output-style.js +94 -0
- package/dist/src/services/audit/enforcers/lint-reference-integrity.d.ts +6 -0
- package/dist/src/services/audit/enforcers/lint-reference-integrity.js +83 -0
- package/dist/src/services/audit/enforcers/lint-reference-shape.d.ts +30 -0
- package/dist/src/services/audit/enforcers/lint-reference-shape.js +272 -0
- package/dist/src/services/audit/enforcers/lint-style.d.ts +49 -0
- package/dist/src/services/audit/enforcers/lint-style.js +173 -0
- package/dist/src/services/audit/enforcers/lint-workflow-shape.d.ts +5 -0
- package/dist/src/services/audit/enforcers/lint-workflow-shape.js +141 -0
- package/dist/src/services/audit/enforcers/login-gate.d.ts +23 -0
- package/dist/src/services/audit/enforcers/login-gate.js +40 -0
- package/dist/src/services/audit/enforcers/mock-placement.d.ts +25 -0
- package/dist/src/services/audit/enforcers/mock-placement.js +48 -0
- package/dist/src/services/audit/enforcers/no-root-pollution.d.ts +21 -0
- package/dist/src/services/audit/enforcers/no-root-pollution.js +56 -0
- package/dist/src/services/audit/enforcers/pre-rd-scan.d.ts +22 -0
- package/dist/src/services/audit/enforcers/pre-rd-scan.js +23 -0
- package/dist/src/services/audit/enforcers/prototype-fidelity.d.ts +25 -0
- package/dist/src/services/audit/enforcers/prototype-fidelity.js +75 -0
- package/dist/src/services/audit/enforcers/resume-detection.d.ts +21 -0
- package/dist/src/services/audit/enforcers/resume-detection.js +52 -0
- package/dist/src/services/audit/enforcers/solo-code-ban.d.ts +23 -0
- package/dist/src/services/audit/enforcers/solo-code-ban.js +27 -0
- package/dist/src/services/audit/enforcers/sub-agent-sid.d.ts +25 -0
- package/dist/src/services/audit/enforcers/sub-agent-sid.js +63 -0
- package/dist/src/services/audit/enforcers/tech-doc-presence.d.ts +28 -0
- package/dist/src/services/audit/enforcers/tech-doc-presence.js +35 -0
- package/dist/src/services/audit/red-line-catalog-p2-a.d.ts +21 -0
- package/dist/src/services/audit/red-line-catalog-p2-a.js +233 -0
- package/dist/src/services/audit/red-line-catalog-p2-b.d.ts +19 -0
- package/dist/src/services/audit/red-line-catalog-p2-b.js +225 -0
- package/dist/src/services/audit/red-line-catalog.d.ts +51 -0
- package/dist/src/services/audit/red-line-catalog.js +210 -0
- package/dist/src/services/audit/red-lines-service.d.ts +23 -0
- package/dist/src/services/audit/red-lines-service.js +486 -0
- package/dist/src/services/audit/scanners/openspec-scanner.d.ts +15 -0
- package/dist/src/services/audit/scanners/openspec-scanner.js +55 -0
- package/dist/src/services/audit/scanners/rules-tree-scanner.d.ts +16 -0
- package/dist/src/services/audit/scanners/rules-tree-scanner.js +56 -0
- package/dist/src/services/audit/scanners/skills-tree-scanner.d.ts +17 -0
- package/dist/src/services/audit/scanners/skills-tree-scanner.js +46 -0
- package/dist/src/services/audit/static-service.d.ts +57 -0
- package/dist/src/services/audit/static-service.js +125 -0
- package/dist/src/services/audit/types.d.ts +69 -0
- package/dist/src/services/audit/types.js +13 -0
- package/dist/src/services/classify/classify-service.d.ts +42 -0
- package/dist/src/services/classify/classify-service.js +122 -0
- package/dist/src/services/classify/classify-types.d.ts +79 -0
- package/dist/src/services/classify/classify-types.js +90 -0
- package/dist/src/services/code-review/ocr-service.d.ts +129 -0
- package/dist/src/services/code-review/ocr-service.js +362 -0
- package/dist/src/services/config/config-migration.d.ts +32 -0
- package/dist/src/services/config/config-migration.js +111 -0
- package/dist/src/services/config/config-restore.d.ts +10 -0
- package/dist/src/services/config/config-restore.js +47 -0
- package/dist/src/services/config/config-rollback.d.ts +13 -0
- package/dist/src/services/config/config-rollback.js +26 -0
- package/dist/src/services/config/config-service.d.ts +36 -2
- package/dist/src/services/config/config-service.js +105 -0
- package/dist/src/services/config/config-types.d.ts +73 -0
- package/dist/src/services/config/config-types.js +28 -13
- package/dist/src/services/config/model-routing.js +5 -3
- package/dist/src/services/doctor/doctor-service.js +96 -0
- package/dist/src/services/ide/adapters/hermes-adapter.d.ts +21 -0
- package/dist/src/services/ide/adapters/hermes-adapter.js +51 -0
- package/dist/src/services/ide/adapters/openclaw-adapter.d.ts +14 -0
- package/dist/src/services/ide/adapters/openclaw-adapter.js +42 -0
- package/dist/src/services/ide/ide-registry.js +7 -0
- package/dist/src/services/ide/ide-types.d.ts +1 -1
- package/dist/src/services/openspec/openspec-propose-from-doctor-service.d.ts +31 -0
- package/dist/src/services/openspec/openspec-propose-from-doctor-service.js +95 -0
- package/dist/src/services/preferences/preferences-service.d.ts +6 -0
- package/dist/src/services/preferences/preferences-service.js +43 -0
- package/dist/src/services/preferences/preferences-types.d.ts +90 -0
- package/dist/src/services/preferences/preferences-types.js +38 -0
- package/dist/src/services/rd/rd-service.js +29 -1
- package/dist/src/services/skills/skill-conformance-service.d.ts +40 -0
- package/dist/src/services/skills/skill-conformance-service.js +136 -0
- package/dist/src/services/skills/skill-runbook-service.js +44 -10
- package/dist/src/services/skills/sync-service.d.ts +86 -0
- package/dist/src/services/skills/sync-service.js +271 -0
- package/dist/src/services/slice/slice-check-service.js +166 -13
- package/dist/src/services/slice/slice-check-types.d.ts +1 -1
- package/dist/src/services/standards/migrate-claude-rules-service.d.ts +19 -0
- package/dist/src/services/standards/migrate-claude-rules-service.js +193 -0
- package/dist/src/services/understand/understand-scan-service.js +15 -2
- package/dist/src/services/understand/understand-types.d.ts +26 -0
- package/dist/src/services/upgrade/1x-detector-service.d.ts +7 -0
- package/dist/src/services/upgrade/1x-detector-service.js +94 -0
- package/dist/src/services/upgrade/gitignore-migrate-service.d.ts +56 -0
- package/dist/src/services/upgrade/gitignore-migrate-service.js +170 -0
- package/dist/src/services/upgrade/upgrade-service.d.ts +47 -0
- package/dist/src/services/upgrade/upgrade-service.js +381 -0
- package/dist/src/services/workflow/workflow-router-service.js +15 -4
- package/dist/src/services/workspace/claude-settings-template.d.ts +53 -0
- package/dist/src/services/workspace/claude-settings-template.js +133 -0
- package/dist/src/services/workspace/sid-naming-guard.d.ts +14 -0
- package/dist/src/services/workspace/sid-naming-guard.js +31 -0
- package/dist/src/services/workspace/workspace-archive-service.d.ts +19 -0
- package/dist/src/services/workspace/workspace-archive-service.js +32 -0
- package/dist/src/services/workspace/workspace-clean-service.d.ts +41 -0
- package/dist/src/services/workspace/workspace-clean-service.js +86 -0
- package/dist/src/services/workspace/workspace-service.d.ts +24 -0
- package/dist/src/services/workspace/workspace-service.js +124 -2
- package/dist/src/services/workspace/workspace-state-service.d.ts +7 -0
- package/dist/src/services/workspace/workspace-state-service.js +43 -0
- package/dist/src/shared/change-id.js +4 -1
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/package.json +8 -2
- package/schemas/doctor-report.schema.json +1 -1
- package/scripts/install-skills.mjs +296 -12
- package/skills/peaks-doctor/SKILL.md +59 -0
- package/skills/peaks-doctor/references/doctor-check-catalog.md +31 -0
- package/skills/peaks-doctor/references/from-doctor-flow.md +64 -0
- package/skills/peaks-doctor/test_prompts.json +17 -0
- package/skills/peaks-ide/SKILL.md +2 -0
- package/skills/peaks-qa/SKILL.md +9 -7
- package/skills/peaks-qa/references/artifact-per-request.md +19 -5
- package/skills/peaks-qa/references/qa-perf-test-plan.md +6 -6
- package/skills/peaks-qa/references/qa-runbook.md +1 -1
- package/skills/peaks-rd/SKILL.md +25 -10
- package/skills/peaks-rd/references/ocr-integration.md +214 -0
- package/skills/peaks-rd/references/rd-fanout-contracts.md +70 -0
- package/skills/peaks-rd/references/rd-runbook.md +1 -1
- package/skills/peaks-solo/SKILL.md +16 -4
- package/skills/peaks-solo/references/anchoring-and-session-info.md +9 -0
- package/skills/peaks-solo/references/step-0-55-1x-detection.md +82 -0
- 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':
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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
|
-
|
|
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)
|
package/skills/peaks-qa/SKILL.md
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
86
|
+
→ see `references/artifact-per-request.md` for the 3-file contract and the do-not-execute upstream guard.
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
## Default runbook
|
|
89
89
|
|
|
90
|
-
|
|
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
|
|
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/<
|
|
8
|
-
| 2 | Test report | `.peaks/_runtime/<
|
|
9
|
-
| 3 | Request artifact | `.peaks/_runtime/<
|
|
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
|
-
|
|
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.
|