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
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prototype-fidelity enforcer (L2.2 P1) — verifies a prototype is
|
|
3
|
+
* functional (not a stub).
|
|
4
|
+
*
|
|
5
|
+
* Two red lines:
|
|
6
|
+
* - rl-prototype-fidelity-001: prototype files must not contain TODO/FIXME/XXX
|
|
7
|
+
* - rl-prototype-fidelity-002: prototype must have at least 1 passing test
|
|
8
|
+
*
|
|
9
|
+
* (L2.2 ships the source-level check; deeper test-running integration is
|
|
10
|
+
* deferred to a follow-up slice.)
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
const STUB_MARKER_PATTERNS = [
|
|
15
|
+
/\bTODO\b/,
|
|
16
|
+
/\bFIXME\b/,
|
|
17
|
+
/\bXXX\b/,
|
|
18
|
+
/\bHACK\b/,
|
|
19
|
+
/\bstub\b\s*[:=]/i,
|
|
20
|
+
/\bnot implemented\b/i,
|
|
21
|
+
];
|
|
22
|
+
export function findStubMarkers(input) {
|
|
23
|
+
const markers = [];
|
|
24
|
+
for (const filePath of input.filePaths) {
|
|
25
|
+
const abs = join(input.projectRoot, filePath);
|
|
26
|
+
let content;
|
|
27
|
+
try {
|
|
28
|
+
content = readFileSync(abs, 'utf8');
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
for (const pattern of STUB_MARKER_PATTERNS) {
|
|
34
|
+
const match = pattern.exec(content);
|
|
35
|
+
if (match !== null) {
|
|
36
|
+
markers.push({ filePath, pattern: pattern.source, snippet: match[0] });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { stubMarkers: markers, testFiles: [] };
|
|
41
|
+
}
|
|
42
|
+
export function findTestFiles(projectRoot, sourceDir) {
|
|
43
|
+
const testsDir = join(projectRoot, sourceDir.replace(/^src\//, 'tests/'));
|
|
44
|
+
if (!existsSync(testsDir))
|
|
45
|
+
return [];
|
|
46
|
+
try {
|
|
47
|
+
const stat = statSync(testsDir);
|
|
48
|
+
if (!stat.isDirectory())
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
const result = [];
|
|
55
|
+
const walk = (dir) => {
|
|
56
|
+
let entries;
|
|
57
|
+
try {
|
|
58
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
for (const entry of entries) {
|
|
64
|
+
const full = join(dir, entry.name);
|
|
65
|
+
if (entry.isDirectory()) {
|
|
66
|
+
walk(full);
|
|
67
|
+
}
|
|
68
|
+
else if (entry.isFile() && /\.(test|spec)\.ts$/.test(entry.name)) {
|
|
69
|
+
result.push(full);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
walk(testsDir);
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resume-detection enforcer (L2.2 P1) — verifies a slice can be resumed
|
|
3
|
+
* before the LLM continues work on it.
|
|
4
|
+
*
|
|
5
|
+
* Two red lines:
|
|
6
|
+
* - rl-resume-detection-001: session-binding file must exist
|
|
7
|
+
* - rl-resume-detection-002: existing rd request state must be in
|
|
8
|
+
* {spec-locked, implemented, qa-handoff} (resumable states)
|
|
9
|
+
*/
|
|
10
|
+
export interface ResumeDetectionInput {
|
|
11
|
+
readonly projectRoot: string;
|
|
12
|
+
readonly sessionId: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ResumeDetectionResult {
|
|
15
|
+
readonly sessionBindingExists: boolean;
|
|
16
|
+
readonly sessionBindingPath: string;
|
|
17
|
+
readonly requestState: string | null;
|
|
18
|
+
readonly requestStatePath: string;
|
|
19
|
+
readonly canResume: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function checkResume(input: ResumeDetectionInput): ResumeDetectionResult;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resume-detection enforcer (L2.2 P1) — verifies a slice can be resumed
|
|
3
|
+
* before the LLM continues work on it.
|
|
4
|
+
*
|
|
5
|
+
* Two red lines:
|
|
6
|
+
* - rl-resume-detection-001: session-binding file must exist
|
|
7
|
+
* - rl-resume-detection-002: existing rd request state must be in
|
|
8
|
+
* {spec-locked, implemented, qa-handoff} (resumable states)
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
const RESUMABLE_STATES = new Set(['spec-locked', 'implemented', 'qa-handoff']);
|
|
13
|
+
export function checkResume(input) {
|
|
14
|
+
const sessionBindingPath = join(input.projectRoot, '.peaks/_runtime', input.sessionId, 'session.json');
|
|
15
|
+
const sessionBindingExists = existsSync(sessionBindingPath);
|
|
16
|
+
// The rd request artifact lives under .peaks/_runtime/<sid>/rd/requests/<rid>.md
|
|
17
|
+
// (canonical session layout per `src-services-session-canonical-workspace-resolver.md`).
|
|
18
|
+
// We look at the most-recent rd request to detect state. The full request-artifact
|
|
19
|
+
// service is the authoritative source; this is a lightweight check for the audit
|
|
20
|
+
// scanner.
|
|
21
|
+
const rdDir = join(input.projectRoot, '.peaks/_runtime', input.sessionId, 'rd/requests');
|
|
22
|
+
let requestState = null;
|
|
23
|
+
let requestStatePath = '';
|
|
24
|
+
if (existsSync(rdDir)) {
|
|
25
|
+
try {
|
|
26
|
+
const files = require('node:fs').readdirSync(rdDir);
|
|
27
|
+
for (const file of files) {
|
|
28
|
+
if (!file.endsWith('.md'))
|
|
29
|
+
continue;
|
|
30
|
+
const path = join(rdDir, file);
|
|
31
|
+
const content = readFileSync(path, 'utf8');
|
|
32
|
+
const match = /state:\s*([a-z0-9-]+)/i.exec(content);
|
|
33
|
+
if (match !== null) {
|
|
34
|
+
requestState = match[1] ?? null;
|
|
35
|
+
requestStatePath = path;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// ignore read errors
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const canResume = sessionBindingExists && requestState !== null && RESUMABLE_STATES.has(requestState);
|
|
45
|
+
return {
|
|
46
|
+
sessionBindingExists,
|
|
47
|
+
sessionBindingPath,
|
|
48
|
+
requestState,
|
|
49
|
+
requestStatePath,
|
|
50
|
+
canResume,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solo-code-ban enforcer — PreToolUse Bash guard.
|
|
3
|
+
*
|
|
4
|
+
* Per L2 redesign §5.4. Deny `git commit` or `git apply` invocations from
|
|
5
|
+
* a peaks-* skill. The Solo Code-Change Red Line says peaks-solo / peaks-rd
|
|
6
|
+
* are orchestrators, not implementers; the actual `git commit` step must
|
|
7
|
+
* go through `peaks request transition`, which itself enforces spec-locked
|
|
8
|
+
* + tech-doc-presence.
|
|
9
|
+
*
|
|
10
|
+
* Trust red line (per `gate-enforcement-hook.md`): if the registry or
|
|
11
|
+
* manifest read fails, the hook must fail-OPEN (warn + allow). The LLM is
|
|
12
|
+
* never bricked by a peaks bug.
|
|
13
|
+
*/
|
|
14
|
+
export interface SoloCodeBanInput {
|
|
15
|
+
readonly skill: string;
|
|
16
|
+
readonly command: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SoloCodeBanResult {
|
|
19
|
+
readonly denied: boolean;
|
|
20
|
+
readonly reason: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function isSoloCodeCommit(skill: string, command: string): boolean;
|
|
23
|
+
export declare function evaluateSoloCodeBan(input: SoloCodeBanInput): SoloCodeBanResult;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solo-code-ban enforcer — PreToolUse Bash guard.
|
|
3
|
+
*
|
|
4
|
+
* Per L2 redesign §5.4. Deny `git commit` or `git apply` invocations from
|
|
5
|
+
* a peaks-* skill. The Solo Code-Change Red Line says peaks-solo / peaks-rd
|
|
6
|
+
* are orchestrators, not implementers; the actual `git commit` step must
|
|
7
|
+
* go through `peaks request transition`, which itself enforces spec-locked
|
|
8
|
+
* + tech-doc-presence.
|
|
9
|
+
*
|
|
10
|
+
* Trust red line (per `gate-enforcement-hook.md`): if the registry or
|
|
11
|
+
* manifest read fails, the hook must fail-OPEN (warn + allow). The LLM is
|
|
12
|
+
* never bricked by a peaks bug.
|
|
13
|
+
*/
|
|
14
|
+
const COMMIT_APPLY_PATTERN = /^\s*git\s+(commit|apply)\b/;
|
|
15
|
+
const DENY_REASON = 'Solo Code-Change Red Line: peaks-* skills must go through peaks-solo / peaks-rd. ' +
|
|
16
|
+
'Use `peaks request transition` instead of `git commit` / `git apply` directly.';
|
|
17
|
+
export function isSoloCodeCommit(skill, command) {
|
|
18
|
+
if (!skill.startsWith('peaks-'))
|
|
19
|
+
return false;
|
|
20
|
+
return COMMIT_APPLY_PATTERN.test(command);
|
|
21
|
+
}
|
|
22
|
+
export function evaluateSoloCodeBan(input) {
|
|
23
|
+
if (isSoloCodeCommit(input.skill, input.command)) {
|
|
24
|
+
return { denied: true, reason: DENY_REASON };
|
|
25
|
+
}
|
|
26
|
+
return { denied: false, reason: '' };
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sub-agent-sid enforcer — dogfood of Slice 0.5 sid-naming-guard.
|
|
3
|
+
*
|
|
4
|
+
* Per L2 redesign §5.4, "sub-agent-sid" is one of the 5 P0 red lines.
|
|
5
|
+
* Slice 0.5 (Task 7) shipped `isValidSessionId` in
|
|
6
|
+
* `src/services/workspace/sid-naming-guard.ts`. This enforcer exposes the
|
|
7
|
+
* same check to the red-line audit framework, so any invalid sid under
|
|
8
|
+
* `.peaks/_sub_agents/` shows up as a backable red line in the audit.
|
|
9
|
+
*/
|
|
10
|
+
export interface SubAgentSidCheckResult {
|
|
11
|
+
readonly invalid: readonly string[];
|
|
12
|
+
readonly valid: readonly string[];
|
|
13
|
+
readonly scanned: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Find sids under `.peaks/_sub_agents/<sid>/` that fail `isValidSessionId`.
|
|
17
|
+
* Bare forms (sid-3, unknown-sid) and date-mismatched sids all fail.
|
|
18
|
+
*/
|
|
19
|
+
export declare function findInvalidSubAgentSids(projectRoot: string): SubAgentSidCheckResult;
|
|
20
|
+
/**
|
|
21
|
+
* Same check, for `.peaks/_runtime/<sid>/`. Slice 0.5's clean-service
|
|
22
|
+
* already handles the sub-agents dir; the audit framework also wants to
|
|
23
|
+
* know about invalid runtime sids (which would be a different failure mode).
|
|
24
|
+
*/
|
|
25
|
+
export declare function findInvalidRuntimeSids(projectRoot: string): SubAgentSidCheckResult;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sub-agent-sid enforcer — dogfood of Slice 0.5 sid-naming-guard.
|
|
3
|
+
*
|
|
4
|
+
* Per L2 redesign §5.4, "sub-agent-sid" is one of the 5 P0 red lines.
|
|
5
|
+
* Slice 0.5 (Task 7) shipped `isValidSessionId` in
|
|
6
|
+
* `src/services/workspace/sid-naming-guard.ts`. This enforcer exposes the
|
|
7
|
+
* same check to the red-line audit framework, so any invalid sid under
|
|
8
|
+
* `.peaks/_sub_agents/` shows up as a backable red line in the audit.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { isValidSessionId } from '../../workspace/sid-naming-guard.js';
|
|
13
|
+
const SUB_AGENTS_DIR = '.peaks/_sub_agents';
|
|
14
|
+
const RUNTIME_DIR = '.peaks/_runtime';
|
|
15
|
+
/**
|
|
16
|
+
* Find sids under `.peaks/_sub_agents/<sid>/` that fail `isValidSessionId`.
|
|
17
|
+
* Bare forms (sid-3, unknown-sid) and date-mismatched sids all fail.
|
|
18
|
+
*/
|
|
19
|
+
export function findInvalidSubAgentSids(projectRoot) {
|
|
20
|
+
const subAgentsRoot = join(projectRoot, SUB_AGENTS_DIR);
|
|
21
|
+
if (!existsSync(subAgentsRoot)) {
|
|
22
|
+
return { invalid: [], valid: [], scanned: false };
|
|
23
|
+
}
|
|
24
|
+
const entries = readdirSync(subAgentsRoot, { withFileTypes: true })
|
|
25
|
+
.filter((e) => e.isDirectory())
|
|
26
|
+
.map((e) => e.name);
|
|
27
|
+
const invalid = [];
|
|
28
|
+
const valid = [];
|
|
29
|
+
for (const name of entries) {
|
|
30
|
+
if (isValidSessionId(name)) {
|
|
31
|
+
valid.push(name);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
invalid.push(name);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { invalid, valid, scanned: true };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Same check, for `.peaks/_runtime/<sid>/`. Slice 0.5's clean-service
|
|
41
|
+
* already handles the sub-agents dir; the audit framework also wants to
|
|
42
|
+
* know about invalid runtime sids (which would be a different failure mode).
|
|
43
|
+
*/
|
|
44
|
+
export function findInvalidRuntimeSids(projectRoot) {
|
|
45
|
+
const runtimeRoot = join(projectRoot, RUNTIME_DIR);
|
|
46
|
+
if (!existsSync(runtimeRoot)) {
|
|
47
|
+
return { invalid: [], valid: [], scanned: false };
|
|
48
|
+
}
|
|
49
|
+
const entries = readdirSync(runtimeRoot, { withFileTypes: true })
|
|
50
|
+
.filter((e) => e.isDirectory())
|
|
51
|
+
.map((e) => e.name);
|
|
52
|
+
const invalid = [];
|
|
53
|
+
const valid = [];
|
|
54
|
+
for (const name of entries) {
|
|
55
|
+
if (isValidSessionId(name)) {
|
|
56
|
+
valid.push(name);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
invalid.push(name);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { invalid, valid, scanned: true };
|
|
63
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tech-doc-presence enforcer — refuses `peaks request transition <rid>
|
|
3
|
+
* spec-locked` if the slice's tech-doc.md is missing.
|
|
4
|
+
*
|
|
5
|
+
* Per L2 redesign §5.4. The tech-doc is the BLOCKING artifact for the
|
|
6
|
+
* spec-locked transition. This enforcer is called from
|
|
7
|
+
* `request-transition-service.ts` BEFORE the state machine runs.
|
|
8
|
+
*
|
|
9
|
+
* The session id is resolved from the current working directory using
|
|
10
|
+
* the canonical workspace resolver (per
|
|
11
|
+
* `src-services-session-canonical-workspace-resolver.md` memory).
|
|
12
|
+
*/
|
|
13
|
+
export interface TechDocPresenceInput {
|
|
14
|
+
readonly projectRoot: string;
|
|
15
|
+
readonly sessionId: string;
|
|
16
|
+
}
|
|
17
|
+
export interface TechDocPresenceResult {
|
|
18
|
+
readonly exists: boolean;
|
|
19
|
+
readonly path: string;
|
|
20
|
+
readonly isEmpty: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function checkTechDocPresence(input: TechDocPresenceInput): TechDocPresenceResult;
|
|
23
|
+
/**
|
|
24
|
+
* Hard-coded error message used by `request-transition-service.ts` when
|
|
25
|
+
* the spec-locked transition is refused.
|
|
26
|
+
*/
|
|
27
|
+
export declare const TECH_DOC_MISSING_MESSAGE: string;
|
|
28
|
+
export declare const TECH_DOC_MISSING_CODE = "TECH_DOC_MISSING";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tech-doc-presence enforcer — refuses `peaks request transition <rid>
|
|
3
|
+
* spec-locked` if the slice's tech-doc.md is missing.
|
|
4
|
+
*
|
|
5
|
+
* Per L2 redesign §5.4. The tech-doc is the BLOCKING artifact for the
|
|
6
|
+
* spec-locked transition. This enforcer is called from
|
|
7
|
+
* `request-transition-service.ts` BEFORE the state machine runs.
|
|
8
|
+
*
|
|
9
|
+
* The session id is resolved from the current working directory using
|
|
10
|
+
* the canonical workspace resolver (per
|
|
11
|
+
* `src-services-session-canonical-workspace-resolver.md` memory).
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, statSync } from 'node:fs';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
export function checkTechDocPresence(input) {
|
|
16
|
+
const docPath = join(input.projectRoot, '.peaks/_runtime', input.sessionId, 'rd/tech-doc.md');
|
|
17
|
+
if (!existsSync(docPath)) {
|
|
18
|
+
return { exists: false, path: docPath, isEmpty: false };
|
|
19
|
+
}
|
|
20
|
+
let stat;
|
|
21
|
+
try {
|
|
22
|
+
stat = statSync(docPath);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return { exists: false, path: docPath, isEmpty: false };
|
|
26
|
+
}
|
|
27
|
+
return { exists: true, path: docPath, isEmpty: stat.size === 0 };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Hard-coded error message used by `request-transition-service.ts` when
|
|
31
|
+
* the spec-locked transition is refused.
|
|
32
|
+
*/
|
|
33
|
+
export const TECH_DOC_MISSING_MESSAGE = 'spec-locked transition requires `rd/tech-doc.md` to exist and be non-empty. ' +
|
|
34
|
+
'Run `peaks-rd` to produce the tech-doc first, then retry the transition.';
|
|
35
|
+
export const TECH_DOC_MISSING_CODE = 'TECH_DOC_MISSING';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Red-line catalog — P2-a entries (Slice #6 L2.3).
|
|
3
|
+
*
|
|
4
|
+
* These 25 entries close the lint-style gap left by L2.1 (P0) and
|
|
5
|
+
* L2.2 (P1). Per spec §5.4, P2-a targets 25-40 lint-style red-lines
|
|
6
|
+
* for SKILL.md, references/, and openspec/. They are small,
|
|
7
|
+
* pattern-based, and reference the existing CLI surface (no new
|
|
8
|
+
* runtime dependencies).
|
|
9
|
+
*
|
|
10
|
+
* Enforcer functions live in `enforcers/lint-style-*.ts` and are
|
|
11
|
+
* wired into the audit framework via the same `enforcerRef`
|
|
12
|
+
* discovery path as the P0 / P1 entries.
|
|
13
|
+
*/
|
|
14
|
+
import type { RedLineCatalogEntry } from './red-line-catalog.js';
|
|
15
|
+
/**
|
|
16
|
+
* The 25 P2-a entries, in stable display order. Appending to a single
|
|
17
|
+
* readonly array keeps the catalog growable: future slices (L2.4, L3.x)
|
|
18
|
+
* can spread this list into RED_LINE_CATALOG and add their own without
|
|
19
|
+
* touching this file.
|
|
20
|
+
*/
|
|
21
|
+
export declare const RED_LINE_CATALOG_P2_A: readonly RedLineCatalogEntry[];
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/** Theme A — Section structure (5 enforcers). The section-shape and
|
|
2
|
+
* frontmatter-shape enforcers both live in lint-style.ts (a single
|
|
3
|
+
* file groups the small per-skill pattern scans). */
|
|
4
|
+
const SECTION_HARD_CONTRACTS = {
|
|
5
|
+
id: 'rl-section-hard-contracts-001',
|
|
6
|
+
rule: 'Section structure: Hard contracts for browser/IO surface',
|
|
7
|
+
markers: ['MANDATORY', 'BLOCKING'],
|
|
8
|
+
phrases: ['hard contract', 'hard contracts for browser', 'must be read before'],
|
|
9
|
+
enforcerRef: 'src/services/audit/enforcers/lint-style.ts',
|
|
10
|
+
};
|
|
11
|
+
const SECTION_MANDATORY_ARTIFACT = {
|
|
12
|
+
id: 'rl-section-mandatory-artifact-001',
|
|
13
|
+
rule: 'Section structure: Mandatory per-request artifact',
|
|
14
|
+
markers: ['MANDATORY', 'BLOCKING'],
|
|
15
|
+
phrases: ['mandatory per-request artifact', 'mandatory per-slice', 'mandatory .peaks/'],
|
|
16
|
+
enforcerRef: 'src/services/audit/enforcers/lint-style.ts',
|
|
17
|
+
};
|
|
18
|
+
const SECTION_DEFAULT_RUNBOOK = {
|
|
19
|
+
id: 'rl-section-default-runbook-001',
|
|
20
|
+
rule: 'Section structure: Default runbook pointer',
|
|
21
|
+
markers: ['MANDATORY'],
|
|
22
|
+
phrases: ['default runbook', 'runbook is in the references', 'full runbook', '## Default runbook'],
|
|
23
|
+
enforcerRef: 'src/services/audit/enforcers/lint-style.ts',
|
|
24
|
+
};
|
|
25
|
+
const SECTION_GATE_INDEX = {
|
|
26
|
+
id: 'rl-section-gate-index-001',
|
|
27
|
+
rule: 'Section structure: Gate index',
|
|
28
|
+
markers: ['MANDATORY'],
|
|
29
|
+
phrases: ['gate index', 'rd gate index', 'qa gate index', 'cli-backed gates'],
|
|
30
|
+
enforcerRef: 'src/services/audit/enforcers/lint-style.ts',
|
|
31
|
+
};
|
|
32
|
+
const SECTION_NAMING_AXIOM = {
|
|
33
|
+
id: 'rl-section-naming-axiom-001',
|
|
34
|
+
rule: 'Section structure: Two-axis naming axiom',
|
|
35
|
+
markers: ['MANDATORY'],
|
|
36
|
+
phrases: ['two-axis naming', 'change-id', 'session-id', 'two orthogonal axes'],
|
|
37
|
+
enforcerRef: 'src/services/audit/enforcers/lint-style.ts',
|
|
38
|
+
};
|
|
39
|
+
/** Theme A wireframe — the "ASCII wireframe" hint from spec §5.4
|
|
40
|
+
* line 647. The section-order enforcer in lint-style.ts checks
|
|
41
|
+
* that the canonical sections appear in the documented order. */
|
|
42
|
+
const SECTION_ORDER_WIREFRAME = {
|
|
43
|
+
id: 'rl-section-order-wireframe-001',
|
|
44
|
+
rule: 'Section structure: ASCII wireframe — sections in canonical order',
|
|
45
|
+
markers: ['MANDATORY'],
|
|
46
|
+
phrases: ['wireframe', 'section order', 'canonical order', 'ascii wireframe'],
|
|
47
|
+
enforcerRef: 'src/services/audit/enforcers/lint-style.ts',
|
|
48
|
+
};
|
|
49
|
+
/** Theme B — Frontmatter shape (3 enforcers). Grouped with Theme A
|
|
50
|
+
* in lint-style.ts; the loadStrategy check is a helper
|
|
51
|
+
* `lintReferenceLoadStrategy` that takes the references dir. */
|
|
52
|
+
const FRONTMATTER_PARSEABLE = {
|
|
53
|
+
id: 'rl-frontmatter-skills-md-001',
|
|
54
|
+
rule: 'Frontmatter shape: skills_md parseable frontmatter',
|
|
55
|
+
markers: ['MANDATORY'],
|
|
56
|
+
phrases: ['frontmatter', 'parseable', 'name: peaks-', 'description:'],
|
|
57
|
+
enforcerRef: 'src/services/audit/enforcers/lint-style.ts',
|
|
58
|
+
};
|
|
59
|
+
const FRONTMATTER_REFERENCES_LOAD_STRATEGY = {
|
|
60
|
+
id: 'rl-frontmatter-references-load-strategy-001',
|
|
61
|
+
rule: 'Frontmatter shape: references loadStrategy declared',
|
|
62
|
+
markers: ['MANDATORY'],
|
|
63
|
+
phrases: ['loadstrategy', 'load-strategy', 'always | on-demand'],
|
|
64
|
+
enforcerRef: 'src/services/audit/enforcers/lint-style.ts',
|
|
65
|
+
};
|
|
66
|
+
const FRONTMATTER_APPLICABLE_TASK_LEVELS = {
|
|
67
|
+
id: 'rl-frontmatter-applicable-task-levels-001',
|
|
68
|
+
rule: 'Frontmatter shape: skill applicable task levels',
|
|
69
|
+
markers: ['MANDATORY'],
|
|
70
|
+
phrases: ['applicabletasklevels', 'task levels invoke', 'applies to'],
|
|
71
|
+
enforcerRef: 'src/services/audit/enforcers/lint-style.ts',
|
|
72
|
+
};
|
|
73
|
+
/** Theme C — Output style (3 enforcers) */
|
|
74
|
+
const OUTPUT_STYLE_STATUS_HEADER = {
|
|
75
|
+
id: 'rl-output-style-status-header-001',
|
|
76
|
+
rule: 'Output style: Peaks-Cli status header on every response',
|
|
77
|
+
markers: ['MANDATORY'],
|
|
78
|
+
phrases: ['peaks-cli skill:', 'peaks-cli gate:', 'peaks-cli next:', 'status header'],
|
|
79
|
+
enforcerRef: 'src/services/audit/enforcers/lint-output-style.ts',
|
|
80
|
+
};
|
|
81
|
+
const OUTPUT_STYLE_NO_FLUFF = {
|
|
82
|
+
id: 'rl-output-style-no-fluff-001',
|
|
83
|
+
rule: 'Output style: no greeting / persona fluff in SKILL.md',
|
|
84
|
+
markers: ['MUST NOT'],
|
|
85
|
+
phrases: ['你好,', '你好!', 'hello, i am', 'i am a', '作为一个', '我是'],
|
|
86
|
+
enforcerRef: 'src/services/audit/enforcers/lint-output-style.ts',
|
|
87
|
+
};
|
|
88
|
+
const OUTPUT_STYLE_NO_CLOSING_PROMPT = {
|
|
89
|
+
id: 'rl-output-style-no-closing-prompt-001',
|
|
90
|
+
rule: 'Output style: no closing-prompt flattery',
|
|
91
|
+
markers: ['MUST NOT'],
|
|
92
|
+
phrases: ['let me know if', '如有任何需要', '如有需要', 'feel free to ask', 'do not hesitate'],
|
|
93
|
+
enforcerRef: 'src/services/audit/enforcers/lint-output-style.ts',
|
|
94
|
+
};
|
|
95
|
+
/** Theme D — CLI-back gaps (4 enforcers) */
|
|
96
|
+
const CLI_BACK_MANDATORY_TEXT = {
|
|
97
|
+
id: 'rl-cli-back-mandatory-text-001',
|
|
98
|
+
rule: 'CLI-back: MANDATORY text has peaks * enforcer in the surrounding ±2 lines',
|
|
99
|
+
markers: ['MANDATORY'],
|
|
100
|
+
phrases: ['mandatory', 'mandatory peaks', 'cli-enforced-by', 'enforced by peaks'],
|
|
101
|
+
enforcerRef: 'src/services/audit/enforcers/lint-cli-back.ts',
|
|
102
|
+
};
|
|
103
|
+
const CLI_BACK_NO_ORPHAN_BLOCKING = {
|
|
104
|
+
id: 'rl-cli-back-no-orphan-blocking-001',
|
|
105
|
+
rule: 'CLI-back: no orphan BLOCKING marker without a peaks * enforcer',
|
|
106
|
+
markers: ['BLOCKING'],
|
|
107
|
+
phrases: ['blocking', 'blocking peaks', 'blocking gate'],
|
|
108
|
+
enforcerRef: 'src/services/audit/enforcers/lint-cli-back.ts',
|
|
109
|
+
};
|
|
110
|
+
const CLI_BACK_NO_ORPHAN_MUST_NOT = {
|
|
111
|
+
id: 'rl-cli-back-no-orphan-must-not-001',
|
|
112
|
+
rule: 'CLI-back: no orphan MUST NOT marker without a peaks * enforcer',
|
|
113
|
+
markers: ['MUST NOT'],
|
|
114
|
+
phrases: ['must not', 'must not peaks', 'must not be'],
|
|
115
|
+
enforcerRef: 'src/services/audit/enforcers/lint-cli-back.ts',
|
|
116
|
+
};
|
|
117
|
+
const CLI_BACK_PROSE_ONLY_THRESHOLD = {
|
|
118
|
+
id: 'rl-cli-back-prose-only-threshold-001',
|
|
119
|
+
rule: 'CLI-back: prose-only ratio must stay ≤ 5%',
|
|
120
|
+
markers: ['MANDATORY'],
|
|
121
|
+
phrases: ['prose-only', 'prose only', 'prose-only ratio', 'prose-only threshold'],
|
|
122
|
+
enforcerRef: 'src/services/audit/enforcers/lint-cli-back.ts',
|
|
123
|
+
};
|
|
124
|
+
/** Theme E — Reference integrity (4 enforcers) */
|
|
125
|
+
const REF_PATH_RESOLVES = {
|
|
126
|
+
id: 'rl-ref-path-resolves-001',
|
|
127
|
+
rule: 'Reference integrity: every references/<file>.md link resolves',
|
|
128
|
+
markers: ['MANDATORY'],
|
|
129
|
+
phrases: ['see references/', 'see `references/', 'see the references file', '→ see'],
|
|
130
|
+
enforcerRef: 'src/services/audit/enforcers/lint-reference-integrity.ts',
|
|
131
|
+
};
|
|
132
|
+
const REF_NO_BROKEN_MKDIR = {
|
|
133
|
+
id: 'rl-ref-no-broken-mkdir-001',
|
|
134
|
+
rule: 'Reference integrity: no `mkdir -p` outside the project root',
|
|
135
|
+
markers: ['MUST NOT'],
|
|
136
|
+
phrases: ['mkdir -p', 'mkdir -p /', 'mkdir outside', 'mkdir the'],
|
|
137
|
+
enforcerRef: 'src/services/audit/enforcers/lint-reference-integrity.ts',
|
|
138
|
+
};
|
|
139
|
+
const REF_NO_PWD_SYMLINK_JUMPS = {
|
|
140
|
+
id: 'rl-ref-no-pwd-symlink-jumps-001',
|
|
141
|
+
rule: 'Reference integrity: no `cd ..` chain jumping outside the project',
|
|
142
|
+
markers: ['MUST NOT'],
|
|
143
|
+
phrases: ['cd ..', 'cd ../..', 'cd ../../..', 'cd outside the project'],
|
|
144
|
+
enforcerRef: 'src/services/audit/enforcers/lint-reference-integrity.ts',
|
|
145
|
+
};
|
|
146
|
+
const REF_NO_RELATIVE_ARCHIVE_PATHS = {
|
|
147
|
+
id: 'rl-ref-no-relative-archive-paths-001',
|
|
148
|
+
rule: 'Reference integrity: no `cp`/`mv`/`ln` to absolute /tmp paths',
|
|
149
|
+
markers: ['MUST NOT'],
|
|
150
|
+
phrases: ['cp /tmp', 'mv /tmp', 'ln /tmp', 'cp -r /tmp', 'do not use /tmp'],
|
|
151
|
+
enforcerRef: 'src/services/audit/enforcers/lint-reference-integrity.ts',
|
|
152
|
+
};
|
|
153
|
+
/** Theme F — Workflow-bound shape (4 enforcers) */
|
|
154
|
+
const OPENSPEC_PROPOSAL_HAS_AC_BULLETS = {
|
|
155
|
+
id: 'rl-openspec-proposal-has-acceptance-bullets-001',
|
|
156
|
+
rule: 'Workflow: openspec proposal has non-empty Acceptance Criteria bullets',
|
|
157
|
+
markers: ['MANDATORY'],
|
|
158
|
+
phrases: ['acceptance criteria', 'a1 —', 'a2 —', '## acceptance criteria'],
|
|
159
|
+
enforcerRef: 'src/services/audit/enforcers/lint-workflow-shape.ts',
|
|
160
|
+
};
|
|
161
|
+
const OPENSPEC_PROPOSAL_HAS_SPEC_CHANGES = {
|
|
162
|
+
id: 'rl-openspec-proposal-has-spec-changes-001',
|
|
163
|
+
rule: 'Workflow: openspec proposal has Spec reference (canonical) link',
|
|
164
|
+
markers: ['MANDATORY'],
|
|
165
|
+
phrases: ['spec reference (canonical)', 'spec reference', 'see the spec'],
|
|
166
|
+
enforcerRef: 'src/services/audit/enforcers/lint-workflow-shape.ts',
|
|
167
|
+
};
|
|
168
|
+
const TECH_DOC_PRESENCE_PRE_RD = {
|
|
169
|
+
id: 'rl-tech-doc-presence-pre-rd-001',
|
|
170
|
+
rule: 'Workflow: rd/tech-doc.md has Red-line scope + Implementation evidence',
|
|
171
|
+
markers: ['MANDATORY'],
|
|
172
|
+
phrases: ['red-line scope', 'implementation evidence', '## red-line scope', '## implementation evidence'],
|
|
173
|
+
enforcerRef: 'src/services/audit/enforcers/lint-workflow-shape.ts',
|
|
174
|
+
};
|
|
175
|
+
const PEAKS_DOCTOR_SKILL_ACKNOWLEDGED = {
|
|
176
|
+
id: 'rl-peaks-doctor-skill-acknowledged-001',
|
|
177
|
+
rule: 'Workflow: skill that writes a request artifact acknowledges peaks doctor',
|
|
178
|
+
markers: ['MANDATORY'],
|
|
179
|
+
phrases: ['peaks doctor', 'peaks-doctor', 'doctor scan', 'doctor route'],
|
|
180
|
+
enforcerRef: 'src/services/audit/enforcers/lint-workflow-shape.ts',
|
|
181
|
+
};
|
|
182
|
+
/** Theme G — Catalog governance (2 enforcers). The catalog-size
|
|
183
|
+
* enforcer was already planned; the prose-only-ratio enforcer is
|
|
184
|
+
* the partner check that flags when the catalog has too many
|
|
185
|
+
* prose-only entries (i.e. when CLI-back coverage is regressing). */
|
|
186
|
+
const CATALOG_TOTAL_LE_45 = {
|
|
187
|
+
id: 'rl-catalog-total-001',
|
|
188
|
+
rule: 'Catalog governance: catalog size must grow to ≥ 40 (L2.3 P2-a target)',
|
|
189
|
+
markers: ['MANDATORY'],
|
|
190
|
+
phrases: ['total red lines', 'totalredlines', 'catalog size', 'catalog grows'],
|
|
191
|
+
enforcerRef: 'src/services/audit/enforcers/lint-catalog-governance.ts',
|
|
192
|
+
};
|
|
193
|
+
const CATALOG_PROSE_ONLY_RATIO = {
|
|
194
|
+
id: 'rl-catalog-prose-only-ratio-001',
|
|
195
|
+
rule: 'Catalog governance: prose-only ratio must stay ≤ 5% (per §10.2 L2 acceptance)',
|
|
196
|
+
markers: ['MANDATORY'],
|
|
197
|
+
phrases: ['prose-only ratio', 'prose-only threshold', 'prose-only ≤ 5%', 'prose-only < 10%'],
|
|
198
|
+
enforcerRef: 'src/services/audit/enforcers/lint-catalog-governance.ts',
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* The 25 P2-a entries, in stable display order. Appending to a single
|
|
202
|
+
* readonly array keeps the catalog growable: future slices (L2.4, L3.x)
|
|
203
|
+
* can spread this list into RED_LINE_CATALOG and add their own without
|
|
204
|
+
* touching this file.
|
|
205
|
+
*/
|
|
206
|
+
export const RED_LINE_CATALOG_P2_A = [
|
|
207
|
+
SECTION_HARD_CONTRACTS,
|
|
208
|
+
SECTION_MANDATORY_ARTIFACT,
|
|
209
|
+
SECTION_DEFAULT_RUNBOOK,
|
|
210
|
+
SECTION_GATE_INDEX,
|
|
211
|
+
SECTION_NAMING_AXIOM,
|
|
212
|
+
SECTION_ORDER_WIREFRAME,
|
|
213
|
+
FRONTMATTER_PARSEABLE,
|
|
214
|
+
FRONTMATTER_REFERENCES_LOAD_STRATEGY,
|
|
215
|
+
FRONTMATTER_APPLICABLE_TASK_LEVELS,
|
|
216
|
+
OUTPUT_STYLE_STATUS_HEADER,
|
|
217
|
+
OUTPUT_STYLE_NO_FLUFF,
|
|
218
|
+
OUTPUT_STYLE_NO_CLOSING_PROMPT,
|
|
219
|
+
CLI_BACK_MANDATORY_TEXT,
|
|
220
|
+
CLI_BACK_NO_ORPHAN_BLOCKING,
|
|
221
|
+
CLI_BACK_NO_ORPHAN_MUST_NOT,
|
|
222
|
+
CLI_BACK_PROSE_ONLY_THRESHOLD,
|
|
223
|
+
REF_PATH_RESOLVES,
|
|
224
|
+
REF_NO_BROKEN_MKDIR,
|
|
225
|
+
REF_NO_PWD_SYMLINK_JUMPS,
|
|
226
|
+
REF_NO_RELATIVE_ARCHIVE_PATHS,
|
|
227
|
+
OPENSPEC_PROPOSAL_HAS_AC_BULLETS,
|
|
228
|
+
OPENSPEC_PROPOSAL_HAS_SPEC_CHANGES,
|
|
229
|
+
TECH_DOC_PRESENCE_PRE_RD,
|
|
230
|
+
PEAKS_DOCTOR_SKILL_ACKNOWLEDGED,
|
|
231
|
+
CATALOG_TOTAL_LE_45,
|
|
232
|
+
CATALOG_PROSE_ONLY_RATIO,
|
|
233
|
+
];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Red-line catalog — P2-b entries (Slice #7 L2.4).
|
|
3
|
+
*
|
|
4
|
+
* These 25 entries close the references/*.md + audit-regression
|
|
5
|
+
* gap left by L2.1 (P0), L2.2 (P1), and L2.3 (P2-a). Per spec
|
|
6
|
+
* §5.4, P2-b targets 25-40 lint-style red-lines for
|
|
7
|
+
* references/*.md and the audit regression stage.
|
|
8
|
+
*
|
|
9
|
+
* Enforcer functions live in:
|
|
10
|
+
* - enforcers/lint-reference-shape.ts (Themes H-K, M-P)
|
|
11
|
+
* - enforcers/lint-audit-regression.ts (Theme L)
|
|
12
|
+
*/
|
|
13
|
+
import type { RedLineCatalogEntry } from './red-line-catalog.js';
|
|
14
|
+
/**
|
|
15
|
+
* The 25 P2-b entries, in stable display order. Spread into
|
|
16
|
+
* RED_LINE_CATALOG (after P2-a's block) so future slices can
|
|
17
|
+
* append without touching this file.
|
|
18
|
+
*/
|
|
19
|
+
export declare const RED_LINE_CATALOG_P2_B: readonly RedLineCatalogEntry[];
|