peaks-cli 1.4.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +51 -0
- package/CHANGELOG.md +238 -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/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 +86 -0
- package/dist/src/cli/program.js +30 -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 +92 -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 +35 -2
- package/dist/src/services/config/config-service.js +81 -0
- package/dist/src/services/config/config-types.d.ts +58 -0
- package/dist/src/services/config/config-types.js +6 -0
- 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/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 +43 -0
- package/dist/src/services/skills/sync-service.js +99 -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/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-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 +10 -4
- 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
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skills-tree-scanner — walks each `skills/<name>/SKILL.md` and returns
|
|
3
|
+
* each file's raw lines for the classifier to consume.
|
|
4
|
+
*
|
|
5
|
+
* Per `static-scan-must-cover-skills-tree-not-just-src.md`, the red-line
|
|
6
|
+
* audit MUST cover the skills tree, not just `src/`. This scanner is the
|
|
7
|
+
* entry point for that coverage.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
10
|
+
import { join, relative } from 'node:path';
|
|
11
|
+
const SKILLS_DIR = 'skills';
|
|
12
|
+
function readSkillFile(projectRoot, skillDir, file) {
|
|
13
|
+
const fullPath = join(projectRoot, SKILLS_DIR, skillDir, file);
|
|
14
|
+
if (!existsSync(fullPath))
|
|
15
|
+
return [];
|
|
16
|
+
const rel = relative(projectRoot, fullPath).split('\\').join('/');
|
|
17
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
18
|
+
const lines = content.split(/\r?\n/);
|
|
19
|
+
return lines.map((text, idx) => ({ file: rel, line: idx + 1, text }));
|
|
20
|
+
}
|
|
21
|
+
export function scanSkillsTree(input) {
|
|
22
|
+
const skillsRoot = join(input.projectRoot, SKILLS_DIR);
|
|
23
|
+
if (!existsSync(skillsRoot)) {
|
|
24
|
+
return { lines: [], warnings: [] };
|
|
25
|
+
}
|
|
26
|
+
const lines = [];
|
|
27
|
+
const warnings = [];
|
|
28
|
+
let entries;
|
|
29
|
+
try {
|
|
30
|
+
entries = readdirSync(skillsRoot, { withFileTypes: true });
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
warnings.push({
|
|
34
|
+
file: SKILLS_DIR,
|
|
35
|
+
message: `readdir failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
36
|
+
});
|
|
37
|
+
return { lines, warnings };
|
|
38
|
+
}
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
if (!entry.isDirectory() || entry.name.startsWith('.'))
|
|
41
|
+
continue;
|
|
42
|
+
const skillMd = readSkillFile(input.projectRoot, entry.name, 'SKILL.md');
|
|
43
|
+
lines.push(...skillMd);
|
|
44
|
+
}
|
|
45
|
+
return { lines, warnings };
|
|
46
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static audit service — `peaks audit static`.
|
|
3
|
+
*
|
|
4
|
+
* Slice #6 L2.3 P2-a: soft-optional ECC AgentShield integration.
|
|
5
|
+
*
|
|
6
|
+
* Per spec §5.3, the audit framework integrates with ECC AgentShield
|
|
7
|
+
* (102 lint rules) on a soft-optional basis. When ECC is installed
|
|
8
|
+
* AND `agentShieldEnabled: true`, the audit subprocess spawns the
|
|
9
|
+
* ECC scanner and merges its findings; when either is missing, the
|
|
10
|
+
* audit completes with peaks-cli-only findings.
|
|
11
|
+
*
|
|
12
|
+
* The subprocess is **observability enhancement**, not a structural
|
|
13
|
+
* gate — every soft-fail path returns a well-formed audit report.
|
|
14
|
+
*/
|
|
15
|
+
import type { EnforcerFinding, RedLineAudit } from './types.js';
|
|
16
|
+
export interface StaticAuditInput {
|
|
17
|
+
readonly projectRoot: string;
|
|
18
|
+
/** Override the preference for a single call. Default: read from preferences. */
|
|
19
|
+
readonly enableAgentShield?: boolean | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Optional subprocess runner injection point. Used by tests
|
|
22
|
+
* to mock `npx ecc-agentshield`. Production callers should
|
|
23
|
+
* leave this undefined; the default uses `child_process.spawnSync`.
|
|
24
|
+
*/
|
|
25
|
+
readonly subprocessRunner?: SubprocessRunner | undefined;
|
|
26
|
+
}
|
|
27
|
+
export interface StaticAuditResult {
|
|
28
|
+
readonly audit: RedLineAudit;
|
|
29
|
+
readonly agentShield: AgentShieldState;
|
|
30
|
+
readonly warnings: readonly string[];
|
|
31
|
+
}
|
|
32
|
+
export interface AgentShieldState {
|
|
33
|
+
/** Whether the agent-shield subprocess was spawned. */
|
|
34
|
+
readonly spawned: boolean;
|
|
35
|
+
/** Whether ECC AgentShield is installed (regardless of whether it was spawned). */
|
|
36
|
+
readonly installed: boolean;
|
|
37
|
+
/** Why the subprocess was or was not spawned. */
|
|
38
|
+
readonly reason: 'enabled-and-installed' | 'disabled-by-preference' | 'flag-disabled' | 'flag-enabled-but-ecc-missing' | 'disabled-and-ecc-missing';
|
|
39
|
+
/** The merged ECC findings (empty if not spawned). */
|
|
40
|
+
readonly findings: readonly EnforcerFinding[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Subprocess runner interface — the only seam tests need to
|
|
44
|
+
* mock the `npx ecc-agentshield` subprocess. Production callers
|
|
45
|
+
* leave `subprocessRunner` undefined; the default delegates to
|
|
46
|
+
* `child_process.spawnSync` (synchronous, captures stdout).
|
|
47
|
+
*/
|
|
48
|
+
export interface SubprocessRunner {
|
|
49
|
+
run(command: string, args: readonly string[], timeoutMs: number): SubprocessResult;
|
|
50
|
+
}
|
|
51
|
+
export interface SubprocessResult {
|
|
52
|
+
readonly status: number | null;
|
|
53
|
+
readonly stdout: string;
|
|
54
|
+
readonly stderr: string;
|
|
55
|
+
readonly error?: Error;
|
|
56
|
+
}
|
|
57
|
+
export declare function runStaticAudit(input: StaticAuditInput): StaticAuditResult;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static audit service — `peaks audit static`.
|
|
3
|
+
*
|
|
4
|
+
* Slice #6 L2.3 P2-a: soft-optional ECC AgentShield integration.
|
|
5
|
+
*
|
|
6
|
+
* Per spec §5.3, the audit framework integrates with ECC AgentShield
|
|
7
|
+
* (102 lint rules) on a soft-optional basis. When ECC is installed
|
|
8
|
+
* AND `agentShieldEnabled: true`, the audit subprocess spawns the
|
|
9
|
+
* ECC scanner and merges its findings; when either is missing, the
|
|
10
|
+
* audit completes with peaks-cli-only findings.
|
|
11
|
+
*
|
|
12
|
+
* The subprocess is **observability enhancement**, not a structural
|
|
13
|
+
* gate — every soft-fail path returns a well-formed audit report.
|
|
14
|
+
*/
|
|
15
|
+
import { spawnSync } from 'node:child_process';
|
|
16
|
+
import { runRedLinesAudit } from './red-lines-service.js';
|
|
17
|
+
import { loadPreferences } from '../preferences/preferences-service.js';
|
|
18
|
+
const ECC_DETECT_TIMEOUT_MS = 5000;
|
|
19
|
+
const ECC_SCAN_TIMEOUT_MS = 30000;
|
|
20
|
+
const defaultSubprocessRunner = {
|
|
21
|
+
run(command, args, timeoutMs) {
|
|
22
|
+
try {
|
|
23
|
+
const r = spawnSync(command, args, {
|
|
24
|
+
timeout: timeoutMs,
|
|
25
|
+
encoding: 'utf8',
|
|
26
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
27
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
status: r.status,
|
|
31
|
+
stdout: r.stdout ?? '',
|
|
32
|
+
stderr: r.stderr ?? '',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
return {
|
|
37
|
+
status: null,
|
|
38
|
+
stdout: '',
|
|
39
|
+
stderr: '',
|
|
40
|
+
error: err,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
function isEccInstalled(runner) {
|
|
46
|
+
const result = runner.run('npx', ['ecc-agentshield', '--version'], ECC_DETECT_TIMEOUT_MS);
|
|
47
|
+
if (result.error)
|
|
48
|
+
return false;
|
|
49
|
+
return result.status === 0;
|
|
50
|
+
}
|
|
51
|
+
function runEccScan(projectRoot, runner) {
|
|
52
|
+
try {
|
|
53
|
+
// Per spec §7.2 line 828: the canonical ECC subprocess call uses
|
|
54
|
+
// `--target <path>`, NOT `--project`. The peaks-cli CLI flag
|
|
55
|
+
// (`peaks audit static --project <path>`) follows peaks-cli
|
|
56
|
+
// convention; the inner ecc-agentshield call follows the
|
|
57
|
+
// upstream ECC contract.
|
|
58
|
+
const result = runner.run('npx', ['ecc-agentshield', 'scan', '--json', '--target', projectRoot], ECC_SCAN_TIMEOUT_MS);
|
|
59
|
+
if (result.error || result.status !== 0)
|
|
60
|
+
return [];
|
|
61
|
+
const stdout = result.stdout;
|
|
62
|
+
let parsed;
|
|
63
|
+
try {
|
|
64
|
+
parsed = JSON.parse(stdout);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
if (!parsed.findings)
|
|
70
|
+
return [];
|
|
71
|
+
return parsed.findings.map((f, idx) => ({
|
|
72
|
+
enforcerId: `ecc-agentshield:${f.ruleId ?? `unknown-${idx}`}`,
|
|
73
|
+
rule: f.rule ?? 'ECC AgentShield rule',
|
|
74
|
+
severity: f.severity ?? 'warn',
|
|
75
|
+
file: f.file ?? '(unknown)',
|
|
76
|
+
detail: f.detail ?? '',
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export function runStaticAudit(input) {
|
|
84
|
+
// Read the project-local preferences; the CLI flag overrides.
|
|
85
|
+
const prefs = loadPreferences(input.projectRoot);
|
|
86
|
+
const prefEnabled = prefs.agentShieldEnabled;
|
|
87
|
+
const flagEnabled = input.enableAgentShield;
|
|
88
|
+
const runner = input.subprocessRunner ?? defaultSubprocessRunner;
|
|
89
|
+
// Resolve the effective "should spawn" decision.
|
|
90
|
+
// flagEnabled (CLI override) > preference > false
|
|
91
|
+
const shouldSpawn = flagEnabled ?? prefEnabled;
|
|
92
|
+
// Detect ECC.
|
|
93
|
+
const installed = isEccInstalled(runner);
|
|
94
|
+
const warnings = [];
|
|
95
|
+
let state;
|
|
96
|
+
if (!shouldSpawn) {
|
|
97
|
+
// Disabled path — no subprocess, no warnings.
|
|
98
|
+
const reason = flagEnabled === false
|
|
99
|
+
? 'flag-disabled'
|
|
100
|
+
: 'disabled-by-preference';
|
|
101
|
+
state = { spawned: false, installed, reason, findings: [] };
|
|
102
|
+
}
|
|
103
|
+
else if (!installed) {
|
|
104
|
+
// Enabled but ECC missing — soft-fail with a warning.
|
|
105
|
+
warnings.push('agentShieldEnabled is true but `npx ecc-agentshield --version` failed. ' +
|
|
106
|
+
'Run `npx ecc-agentshield --help` to install. Audit ran with peaks-cli findings only.');
|
|
107
|
+
state = { spawned: false, installed: false, reason: 'flag-enabled-but-ecc-missing', findings: [] };
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// Enabled and installed — spawn the subprocess.
|
|
111
|
+
const findings = runEccScan(input.projectRoot, runner);
|
|
112
|
+
state = { spawned: true, installed: true, reason: 'enabled-and-installed', findings };
|
|
113
|
+
}
|
|
114
|
+
// Always run the peaks-cli lint layer; merge ECC findings.
|
|
115
|
+
const peaksResult = runRedLinesAudit({ projectRoot: input.projectRoot });
|
|
116
|
+
const mergedAudit = {
|
|
117
|
+
...peaksResult.audit,
|
|
118
|
+
enforcerFindings: [...peaksResult.audit.enforcerFindings, ...state.findings],
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
audit: mergedAudit,
|
|
122
|
+
agentShield: state,
|
|
123
|
+
warnings,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Red-line audit framework — types.
|
|
3
|
+
*
|
|
4
|
+
* Spec: docs/superpowers/specs/2026-06-11-peaks-cli-l1-l2-l3-redesign.md §5
|
|
5
|
+
* PRD: .peaks/_runtime/2026-06-11-session-f0312d/prd/requests/001-001-l2-1-redlines-audit.md
|
|
6
|
+
* OpenSpec: openspec/changes/2026-06-11-l2-1-redlines-audit/
|
|
7
|
+
*
|
|
8
|
+
* The audit framework classifies MANDATORY / BLOCKING / MUST NOT / RED LINE
|
|
9
|
+
* markers across skills/, .claude/rules/, and openspec/changes/. Each
|
|
10
|
+
* discovered red line is tagged with its backing (cli-backed / partial /
|
|
11
|
+
* prose-only) so the L2 redesign can track the prose-only ratio over time.
|
|
12
|
+
*/
|
|
13
|
+
export type RedLineMarker = 'MANDATORY' | 'BLOCKING' | 'MUST NOT' | 'RED LINE';
|
|
14
|
+
export type RedLineBacking = 'cli-backed' | 'partial' | 'prose-only';
|
|
15
|
+
export interface RedLineSource {
|
|
16
|
+
/** Path relative to project root, posix-style (forward slashes). */
|
|
17
|
+
readonly file: string;
|
|
18
|
+
readonly line: number;
|
|
19
|
+
readonly marker: RedLineMarker;
|
|
20
|
+
/** ±2 lines of surrounding context for human review. */
|
|
21
|
+
readonly context: string;
|
|
22
|
+
}
|
|
23
|
+
export interface RedLineEntry {
|
|
24
|
+
/** Stable id, e.g. "rl-solo-code-ban-001". */
|
|
25
|
+
readonly id: string;
|
|
26
|
+
/** Human-readable rule name, e.g. "Solo Code-Change Red Line". */
|
|
27
|
+
readonly rule: string;
|
|
28
|
+
readonly source: RedLineSource;
|
|
29
|
+
readonly backing: RedLineBacking;
|
|
30
|
+
/** Relative path to the enforcement file, or null when prose-only. */
|
|
31
|
+
readonly enforcerRef: string | null;
|
|
32
|
+
}
|
|
33
|
+
export interface RedLineAudit {
|
|
34
|
+
readonly totalRedLines: number;
|
|
35
|
+
readonly cliBacked: number;
|
|
36
|
+
readonly partial: number;
|
|
37
|
+
readonly proseOnly: number;
|
|
38
|
+
readonly audit: readonly RedLineEntry[];
|
|
39
|
+
/** Findings from running the 7 file-system enforcers during the scan (L2.4 P2-b). */
|
|
40
|
+
readonly enforcerFindings: readonly EnforcerFinding[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Enforcer finding — emitted by an enforcer function that runs as part
|
|
44
|
+
* of the audit scan. Distinct from `RedLineEntry` (which is catalog-matched
|
|
45
|
+
* markdown text). L2.4 P2-b ships this dimension: the audit framework
|
|
46
|
+
* actually invokes the 7 file-system enforcers during a scan, not just
|
|
47
|
+
* catalogs them.
|
|
48
|
+
*/
|
|
49
|
+
export type EnforcerFindingSeverity = 'pass' | 'warn' | 'fail';
|
|
50
|
+
export interface EnforcerFinding {
|
|
51
|
+
readonly enforcerId: string;
|
|
52
|
+
readonly rule: string;
|
|
53
|
+
readonly severity: EnforcerFindingSeverity;
|
|
54
|
+
readonly file: string;
|
|
55
|
+
readonly detail: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A single markdown line discovered by a tree scanner. The classifier turns
|
|
59
|
+
* these into RedLineEntry by matching against the red-line catalog.
|
|
60
|
+
*/
|
|
61
|
+
export interface MarkdownLine {
|
|
62
|
+
readonly file: string;
|
|
63
|
+
readonly line: number;
|
|
64
|
+
readonly text: string;
|
|
65
|
+
}
|
|
66
|
+
export interface ScanWarning {
|
|
67
|
+
readonly file: string;
|
|
68
|
+
readonly message: string;
|
|
69
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Red-line audit framework — types.
|
|
3
|
+
*
|
|
4
|
+
* Spec: docs/superpowers/specs/2026-06-11-peaks-cli-l1-l2-l3-redesign.md §5
|
|
5
|
+
* PRD: .peaks/_runtime/2026-06-11-session-f0312d/prd/requests/001-001-l2-1-redlines-audit.md
|
|
6
|
+
* OpenSpec: openspec/changes/2026-06-11-l2-1-redlines-audit/
|
|
7
|
+
*
|
|
8
|
+
* The audit framework classifies MANDATORY / BLOCKING / MUST NOT / RED LINE
|
|
9
|
+
* markers across skills/, .claude/rules/, and openspec/changes/. Each
|
|
10
|
+
* discovered red line is tagged with its backing (cli-backed / partial /
|
|
11
|
+
* prose-only) so the L2 redesign can track the prose-only ratio over time.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L1a task classification service.
|
|
3
|
+
*
|
|
4
|
+
* Spec: docs/superpowers/specs/2026-06-11-peaks-cli-l1-l2-l3-redesign.md §4
|
|
5
|
+
*
|
|
6
|
+
* Hybrid mechanism: signal-based heuristic + user override + audit log.
|
|
7
|
+
*
|
|
8
|
+
* Signal rules (per the spec, conservative defaults):
|
|
9
|
+
* - filesChanged >= feature_threshold_files OR linesChanged >= feature_threshold_lines
|
|
10
|
+
* AND touchesDependencies → 'migration'
|
|
11
|
+
* - touchesMigrationScripts → 'migration'
|
|
12
|
+
* - isPureRefactor AND linesChanged > 50 → 'refactor'
|
|
13
|
+
* - filesChanged >= feature_threshold_files OR linesChanged >= feature_threshold_lines
|
|
14
|
+
* → 'feature'
|
|
15
|
+
* - keywords contains 'fix' / 'bug' / 'broken' → 'bug'
|
|
16
|
+
* - filesChanged <= 3 AND linesChanged <= 5 → 'typo'
|
|
17
|
+
* - default → 'bug' (mid-low)
|
|
18
|
+
*
|
|
19
|
+
* Conservatism:
|
|
20
|
+
* - 'strict' promotes the result by one level
|
|
21
|
+
* - 'lax' demotes the result by one level
|
|
22
|
+
* - 'default' leaves it as-is
|
|
23
|
+
*
|
|
24
|
+
* Override (the user can force a level):
|
|
25
|
+
* - `peaks classify override --level <level> --reason "<text>"` writes
|
|
26
|
+
* to the audit log; cannot be downgraded (per spec: downgrade
|
|
27
|
+
* is always refused)
|
|
28
|
+
*/
|
|
29
|
+
import { type ClassifyResult, type ClassifySignals, type TaskLevel } from './classify-types.js';
|
|
30
|
+
import type { ClassifyConservatism } from '../preferences/preferences-types.js';
|
|
31
|
+
export interface ClassifyInput {
|
|
32
|
+
readonly signals: ClassifySignals;
|
|
33
|
+
readonly conservatism: ClassifyConservatism;
|
|
34
|
+
/** When set, force the level (bypasses the heuristic). */
|
|
35
|
+
readonly override?: {
|
|
36
|
+
level: TaskLevel;
|
|
37
|
+
reason: string;
|
|
38
|
+
};
|
|
39
|
+
/** Optional clock for testability. */
|
|
40
|
+
readonly clock?: () => string;
|
|
41
|
+
}
|
|
42
|
+
export declare function classifyTask(input: ClassifyInput, featureThresholdFiles?: number, featureThresholdLines?: number): ClassifyResult;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L1a task classification service.
|
|
3
|
+
*
|
|
4
|
+
* Spec: docs/superpowers/specs/2026-06-11-peaks-cli-l1-l2-l3-redesign.md §4
|
|
5
|
+
*
|
|
6
|
+
* Hybrid mechanism: signal-based heuristic + user override + audit log.
|
|
7
|
+
*
|
|
8
|
+
* Signal rules (per the spec, conservative defaults):
|
|
9
|
+
* - filesChanged >= feature_threshold_files OR linesChanged >= feature_threshold_lines
|
|
10
|
+
* AND touchesDependencies → 'migration'
|
|
11
|
+
* - touchesMigrationScripts → 'migration'
|
|
12
|
+
* - isPureRefactor AND linesChanged > 50 → 'refactor'
|
|
13
|
+
* - filesChanged >= feature_threshold_files OR linesChanged >= feature_threshold_lines
|
|
14
|
+
* → 'feature'
|
|
15
|
+
* - keywords contains 'fix' / 'bug' / 'broken' → 'bug'
|
|
16
|
+
* - filesChanged <= 3 AND linesChanged <= 5 → 'typo'
|
|
17
|
+
* - default → 'bug' (mid-low)
|
|
18
|
+
*
|
|
19
|
+
* Conservatism:
|
|
20
|
+
* - 'strict' promotes the result by one level
|
|
21
|
+
* - 'lax' demotes the result by one level
|
|
22
|
+
* - 'default' leaves it as-is
|
|
23
|
+
*
|
|
24
|
+
* Override (the user can force a level):
|
|
25
|
+
* - `peaks classify override --level <level> --reason "<text>"` writes
|
|
26
|
+
* to the audit log; cannot be downgraded (per spec: downgrade
|
|
27
|
+
* is always refused)
|
|
28
|
+
*/
|
|
29
|
+
import { TASK_LEVELS, TASK_LEVEL_GATE_SETS, TASK_LEVEL_ORDER, } from './classify-types.js';
|
|
30
|
+
const FEATURE_KEYWORDS = ['fix', 'bug', 'broken', 'crash', 'regression'];
|
|
31
|
+
const MIGRATION_KEYWORDS = ['migrate', 'migration', 'codemod', 'backfill', 'schema', 'bump'];
|
|
32
|
+
const REFACTOR_KEYWORDS = ['refactor', 'rename', 'extract', 'inline', 'cleanup'];
|
|
33
|
+
function detectLevel(signals, featureThresholdFiles, featureThresholdLines) {
|
|
34
|
+
// 1. Migration takes priority.
|
|
35
|
+
if (signals.touchesMigrationScripts)
|
|
36
|
+
return 'migration';
|
|
37
|
+
const lower = signals.keywords.map((k) => k.toLowerCase());
|
|
38
|
+
if (signals.touchesDependencies && lower.some((k) => MIGRATION_KEYWORDS.includes(k))) {
|
|
39
|
+
return 'migration';
|
|
40
|
+
}
|
|
41
|
+
if (signals.touchesDependencies)
|
|
42
|
+
return 'migration';
|
|
43
|
+
if (signals.touchesDependencies === false && signals.isPureRefactor && signals.linesChanged > 50) {
|
|
44
|
+
return 'refactor';
|
|
45
|
+
}
|
|
46
|
+
if (lower.some((k) => REFACTOR_KEYWORDS.includes(k)) && signals.isPureRefactor) {
|
|
47
|
+
return 'refactor';
|
|
48
|
+
}
|
|
49
|
+
// 2. Feature threshold.
|
|
50
|
+
if (signals.filesChanged >= featureThresholdFiles || signals.linesChanged >= featureThresholdLines) {
|
|
51
|
+
return 'feature';
|
|
52
|
+
}
|
|
53
|
+
// 3. Bug-fix keywords.
|
|
54
|
+
if (lower.some((k) => FEATURE_KEYWORDS.includes(k))) {
|
|
55
|
+
return 'bug';
|
|
56
|
+
}
|
|
57
|
+
// 4. Small diff: typo.
|
|
58
|
+
if (signals.filesChanged <= 3 && signals.linesChanged <= 5) {
|
|
59
|
+
return 'typo';
|
|
60
|
+
}
|
|
61
|
+
// 5. Default: bug (mid-low).
|
|
62
|
+
return 'bug';
|
|
63
|
+
}
|
|
64
|
+
function applyConservatism(level, conservatism) {
|
|
65
|
+
if (conservatism === 'default')
|
|
66
|
+
return level;
|
|
67
|
+
const order = TASK_LEVEL_ORDER[level];
|
|
68
|
+
const index = TASK_LEVELS.indexOf(level);
|
|
69
|
+
if (conservatism === 'strict') {
|
|
70
|
+
const next = Math.min(index + 1, TASK_LEVELS.length - 1);
|
|
71
|
+
return TASK_LEVELS[next] ?? level;
|
|
72
|
+
}
|
|
73
|
+
// 'lax'
|
|
74
|
+
const prev = Math.max(index - 1, 0);
|
|
75
|
+
return TASK_LEVELS[prev] ?? level;
|
|
76
|
+
}
|
|
77
|
+
function buildRationale(signals, level, overrideApplied) {
|
|
78
|
+
if (overrideApplied)
|
|
79
|
+
return `level forced via override`;
|
|
80
|
+
const parts = [];
|
|
81
|
+
parts.push(`${signals.filesChanged} file(s), ${signals.linesChanged} line(s)`);
|
|
82
|
+
if (signals.touchesMigrationScripts)
|
|
83
|
+
parts.push('touches migration scripts');
|
|
84
|
+
if (signals.touchesDependencies)
|
|
85
|
+
parts.push('touches dependencies');
|
|
86
|
+
if (signals.isPureRefactor)
|
|
87
|
+
parts.push('pure refactor (no behavior change)');
|
|
88
|
+
if (signals.keywords.length > 0)
|
|
89
|
+
parts.push(`keywords: ${signals.keywords.join(', ')}`);
|
|
90
|
+
parts.push(`→ ${level}`);
|
|
91
|
+
return parts.join('; ');
|
|
92
|
+
}
|
|
93
|
+
export function classifyTask(input, featureThresholdFiles = 10, featureThresholdLines = 100) {
|
|
94
|
+
const heuristicLevel = detectLevel(input.signals, featureThresholdFiles, featureThresholdLines);
|
|
95
|
+
let finalLevel;
|
|
96
|
+
let overrideApplied = false;
|
|
97
|
+
if (input.override !== undefined) {
|
|
98
|
+
finalLevel = input.override.level;
|
|
99
|
+
overrideApplied = true;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
finalLevel = applyConservatism(heuristicLevel, input.conservatism);
|
|
103
|
+
}
|
|
104
|
+
const gateSet = TASK_LEVEL_GATE_SETS[finalLevel];
|
|
105
|
+
const rationale = buildRationale(input.signals, finalLevel, overrideApplied);
|
|
106
|
+
const timestamp = (input.clock ?? (() => new Date().toISOString()))();
|
|
107
|
+
const audit = {
|
|
108
|
+
timestamp,
|
|
109
|
+
inputs: input.signals,
|
|
110
|
+
output: finalLevel,
|
|
111
|
+
conservatism: input.conservatism,
|
|
112
|
+
overrideApplied,
|
|
113
|
+
reason: input.override?.reason ?? rationale,
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
level: finalLevel,
|
|
117
|
+
signals: input.signals,
|
|
118
|
+
rationale,
|
|
119
|
+
gateSet,
|
|
120
|
+
audit,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L1a task classification — types and per-level gate sets.
|
|
3
|
+
*
|
|
4
|
+
* Spec: docs/superpowers/specs/2026-06-11-peaks-cli-l1-l2-l3-redesign.md §4
|
|
5
|
+
*
|
|
6
|
+
* Five task levels: typo / bug / feature / refactor / migration. Each
|
|
7
|
+
* level has a gate set (the "配套 gate set" — L1b) that the slice
|
|
8
|
+
* checker runs. Higher levels = more gates = slower but safer.
|
|
9
|
+
*
|
|
10
|
+
* The classification is a HYBRID mechanism:
|
|
11
|
+
* 1. Heuristic signal (file count, line count, keyword presence)
|
|
12
|
+
* 2. User override (`peaks classify override --level <level> --reason "<>"`)
|
|
13
|
+
* 3. Audit log of every classification (forensics)
|
|
14
|
+
*
|
|
15
|
+
* Conservatism modifier (per .peaks/preferences.json:classifyConservatism):
|
|
16
|
+
* - 'default' — use the signal thresholds as-is
|
|
17
|
+
* - 'strict' — always upgrade to next level
|
|
18
|
+
* - 'lax' — always downgrade to previous level
|
|
19
|
+
*/
|
|
20
|
+
export type TaskLevel = 'typo' | 'bug' | 'feature' | 'refactor' | 'migration';
|
|
21
|
+
export declare const TASK_LEVELS: readonly TaskLevel[];
|
|
22
|
+
/** Numeric ordering for "next level" / "previous level" promotion. */
|
|
23
|
+
export declare const TASK_LEVEL_ORDER: Readonly<Record<TaskLevel, number>>;
|
|
24
|
+
export interface ClassifySignals {
|
|
25
|
+
/** Number of files changed in the diff. */
|
|
26
|
+
readonly filesChanged: number;
|
|
27
|
+
/** Number of lines added + removed in the diff. */
|
|
28
|
+
readonly linesChanged: number;
|
|
29
|
+
/** Whether the diff includes dependency files (package.json, etc.). */
|
|
30
|
+
readonly touchesDependencies: boolean;
|
|
31
|
+
/** Whether the diff includes migration scripts / codemods. */
|
|
32
|
+
readonly touchesMigrationScripts: boolean;
|
|
33
|
+
/** Whether the diff is mostly renames / formatting / comment changes. */
|
|
34
|
+
readonly isPureRefactor: boolean;
|
|
35
|
+
/** Keywords found in the change description or commit message. */
|
|
36
|
+
readonly keywords: readonly string[];
|
|
37
|
+
}
|
|
38
|
+
/** The gate set that runs for a given task level (L1b). */
|
|
39
|
+
export interface TaskLevelGateSet {
|
|
40
|
+
readonly level: TaskLevel;
|
|
41
|
+
/** Human-readable description. */
|
|
42
|
+
readonly description: string;
|
|
43
|
+
/** Which slice-check stages run at this level. */
|
|
44
|
+
readonly stages: readonly string[];
|
|
45
|
+
/** Whether PRD is required at this level. */
|
|
46
|
+
readonly requiresPrd: boolean;
|
|
47
|
+
/** Whether a tech-doc is required at this level. */
|
|
48
|
+
readonly requiresTechDoc: boolean;
|
|
49
|
+
/** Whether a code review is required at this level. */
|
|
50
|
+
readonly requiresCodeReview: boolean;
|
|
51
|
+
/** Whether a security review is required at this level. */
|
|
52
|
+
readonly requiresSecurityReview: boolean;
|
|
53
|
+
/** Whether a perf baseline is required at this level. */
|
|
54
|
+
readonly requiresPerfBaseline: boolean;
|
|
55
|
+
/** Whether the slice must transition through QA handoff. */
|
|
56
|
+
readonly requiresQaHandoff: boolean;
|
|
57
|
+
/** Whether the user must explicitly confirm destructive paths. */
|
|
58
|
+
readonly requiresDestructiveConfirmation: boolean;
|
|
59
|
+
}
|
|
60
|
+
export declare const TASK_LEVEL_GATE_SETS: Readonly<Record<TaskLevel, TaskLevelGateSet>>;
|
|
61
|
+
/** Result of a classification (deterministic given signals + conservatism). */
|
|
62
|
+
export interface ClassifyResult {
|
|
63
|
+
readonly level: TaskLevel;
|
|
64
|
+
readonly signals: ClassifySignals;
|
|
65
|
+
/** Why this level was chosen (1-2 sentence explanation). */
|
|
66
|
+
readonly rationale: string;
|
|
67
|
+
/** The gate set that will run for this level. */
|
|
68
|
+
readonly gateSet: TaskLevelGateSet;
|
|
69
|
+
/** The audit log entry (every classification is logged). */
|
|
70
|
+
readonly audit: ClassifyAuditEntry;
|
|
71
|
+
}
|
|
72
|
+
export interface ClassifyAuditEntry {
|
|
73
|
+
readonly timestamp: string;
|
|
74
|
+
readonly inputs: ClassifySignals;
|
|
75
|
+
readonly output: TaskLevel;
|
|
76
|
+
readonly conservatism: 'default' | 'strict' | 'lax';
|
|
77
|
+
readonly overrideApplied: boolean;
|
|
78
|
+
readonly reason: string;
|
|
79
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L1a task classification — types and per-level gate sets.
|
|
3
|
+
*
|
|
4
|
+
* Spec: docs/superpowers/specs/2026-06-11-peaks-cli-l1-l2-l3-redesign.md §4
|
|
5
|
+
*
|
|
6
|
+
* Five task levels: typo / bug / feature / refactor / migration. Each
|
|
7
|
+
* level has a gate set (the "配套 gate set" — L1b) that the slice
|
|
8
|
+
* checker runs. Higher levels = more gates = slower but safer.
|
|
9
|
+
*
|
|
10
|
+
* The classification is a HYBRID mechanism:
|
|
11
|
+
* 1. Heuristic signal (file count, line count, keyword presence)
|
|
12
|
+
* 2. User override (`peaks classify override --level <level> --reason "<>"`)
|
|
13
|
+
* 3. Audit log of every classification (forensics)
|
|
14
|
+
*
|
|
15
|
+
* Conservatism modifier (per .peaks/preferences.json:classifyConservatism):
|
|
16
|
+
* - 'default' — use the signal thresholds as-is
|
|
17
|
+
* - 'strict' — always upgrade to next level
|
|
18
|
+
* - 'lax' — always downgrade to previous level
|
|
19
|
+
*/
|
|
20
|
+
export const TASK_LEVELS = ['typo', 'bug', 'feature', 'refactor', 'migration'];
|
|
21
|
+
/** Numeric ordering for "next level" / "previous level" promotion. */
|
|
22
|
+
export const TASK_LEVEL_ORDER = {
|
|
23
|
+
typo: 0,
|
|
24
|
+
bug: 1,
|
|
25
|
+
feature: 2,
|
|
26
|
+
refactor: 3,
|
|
27
|
+
migration: 4,
|
|
28
|
+
};
|
|
29
|
+
export const TASK_LEVEL_GATE_SETS = {
|
|
30
|
+
typo: {
|
|
31
|
+
level: 'typo',
|
|
32
|
+
description: 'Single-line fix: typo, comment, formatting. No new logic.',
|
|
33
|
+
stages: ['typecheck', 'lint'],
|
|
34
|
+
requiresPrd: false,
|
|
35
|
+
requiresTechDoc: false,
|
|
36
|
+
requiresCodeReview: false,
|
|
37
|
+
requiresSecurityReview: false,
|
|
38
|
+
requiresPerfBaseline: false,
|
|
39
|
+
requiresQaHandoff: false,
|
|
40
|
+
requiresDestructiveConfirmation: false,
|
|
41
|
+
},
|
|
42
|
+
bug: {
|
|
43
|
+
level: 'bug',
|
|
44
|
+
description: 'Bug fix: existing behavior wrong, patched in 1-3 files.',
|
|
45
|
+
stages: ['typecheck', 'unit-tests', 'lint'],
|
|
46
|
+
requiresPrd: false,
|
|
47
|
+
requiresTechDoc: false,
|
|
48
|
+
requiresCodeReview: true,
|
|
49
|
+
requiresSecurityReview: false,
|
|
50
|
+
requiresPerfBaseline: false,
|
|
51
|
+
requiresQaHandoff: false,
|
|
52
|
+
requiresDestructiveConfirmation: false,
|
|
53
|
+
},
|
|
54
|
+
feature: {
|
|
55
|
+
level: 'feature',
|
|
56
|
+
description: 'New feature: new behavior, new files, new tests.',
|
|
57
|
+
stages: ['typecheck', 'unit-tests', 'lint', 'review-fanout', 'gate-verify-pipeline'],
|
|
58
|
+
requiresPrd: true,
|
|
59
|
+
requiresTechDoc: true,
|
|
60
|
+
requiresCodeReview: true,
|
|
61
|
+
requiresSecurityReview: true,
|
|
62
|
+
requiresPerfBaseline: true,
|
|
63
|
+
requiresQaHandoff: true,
|
|
64
|
+
requiresDestructiveConfirmation: true,
|
|
65
|
+
},
|
|
66
|
+
refactor: {
|
|
67
|
+
level: 'refactor',
|
|
68
|
+
description: 'Refactor: behavior-preserving structural change.',
|
|
69
|
+
stages: ['typecheck', 'unit-tests', 'lint', 'review-fanout'],
|
|
70
|
+
requiresPrd: false,
|
|
71
|
+
requiresTechDoc: true,
|
|
72
|
+
requiresCodeReview: true,
|
|
73
|
+
requiresSecurityReview: true,
|
|
74
|
+
requiresPerfBaseline: false,
|
|
75
|
+
requiresQaHandoff: true,
|
|
76
|
+
requiresDestructiveConfirmation: false,
|
|
77
|
+
},
|
|
78
|
+
migration: {
|
|
79
|
+
level: 'migration',
|
|
80
|
+
description: 'Migration: codemod, schema change, data backfill, dependency upgrade.',
|
|
81
|
+
stages: ['typecheck', 'unit-tests', 'lint', 'review-fanout', 'gate-verify-pipeline', 'backward-compat'],
|
|
82
|
+
requiresPrd: true,
|
|
83
|
+
requiresTechDoc: true,
|
|
84
|
+
requiresCodeReview: true,
|
|
85
|
+
requiresSecurityReview: true,
|
|
86
|
+
requiresPerfBaseline: true,
|
|
87
|
+
requiresQaHandoff: true,
|
|
88
|
+
requiresDestructiveConfirmation: true,
|
|
89
|
+
},
|
|
90
|
+
};
|