agentic-sdd-framework 1.4.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.
Files changed (57) hide show
  1. package/.agents/AGENTS.template.md +59 -0
  2. package/.agents/CONTEXT.template.md +41 -0
  3. package/.agents/ENTRYPOINT.template.md +31 -0
  4. package/.agents/skills/ast-navigator/SKILL.md +31 -0
  5. package/.agents/skills/ast-navigator/adapters/ast-grep.md +18 -0
  6. package/.agents/skills/ast-navigator/adapters/graphify.md +19 -0
  7. package/.agents/skills/ast-navigator/adapters/lsp.md +16 -0
  8. package/.agents/skills/ast-navigator/adapters/ripgrep.md +19 -0
  9. package/.agents/skills/auditor-executor-protocol/SKILL.md +410 -0
  10. package/.agents/skills/auditor-executor-protocol/references/autonomous-mode.md +144 -0
  11. package/.agents/skills/auditor-executor-protocol/references/failure-modes-and-example.md +103 -0
  12. package/.agents/skills/auditor-executor-protocol/references/handoffs.md +133 -0
  13. package/.agents/skills/auditor-executor-protocol/references/tasks-and-gates.md +81 -0
  14. package/.agents/skills/no-ai-slop/LICENSE +21 -0
  15. package/.agents/skills/no-ai-slop/SKILL.md +52 -0
  16. package/.agents/skills/strategic-cto/SKILL.md +54 -0
  17. package/CHANGELOG.md +117 -0
  18. package/LICENSE +21 -0
  19. package/README.md +244 -0
  20. package/docs/SPEC_TEMPLATE.md +78 -0
  21. package/docs/decisions/ADR_TEMPLATE.md +49 -0
  22. package/docs/guidelines/AST_NAVIGATION.md +51 -0
  23. package/docs/guides/AGENT_CREDENTIALS.md +75 -0
  24. package/docs/guides/GITHUB_CLI_SETUP.md +74 -0
  25. package/docs/incidents/0000-00-00-incident-template.md +35 -0
  26. package/docs/roadmap/templates/compliance-log.md +37 -0
  27. package/docs/roadmap/templates/execution-guide.md +75 -0
  28. package/docs/roadmap/templates/plan-of-record.md +49 -0
  29. package/package.json +49 -0
  30. package/scripts/check-copy-slop.js +120 -0
  31. package/scripts/check-file-size.js +66 -0
  32. package/scripts/check-spec.js +201 -0
  33. package/scripts/check-system-prerequisites.js +133 -0
  34. package/scripts/check-versions.js +50 -0
  35. package/scripts/dev/fuzz-spec-markup.js +123 -0
  36. package/scripts/dev/set-npm-publish-token.sh +40 -0
  37. package/scripts/dev/sync-vendored.js +94 -0
  38. package/scripts/install-git-hooks.js +103 -0
  39. package/scripts/lib/cli.js +60 -0
  40. package/scripts/lib/config.js +111 -0
  41. package/scripts/lib/git.js +211 -0
  42. package/scripts/lib/markdown.js +46 -0
  43. package/scripts/lib/provision.js +323 -0
  44. package/scripts/lib/runner.js +70 -0
  45. package/scripts/lib/sdd.config.schema.json +213 -0
  46. package/scripts/lib/slop-patterns.js +57 -0
  47. package/scripts/lib/spec-markup.js +346 -0
  48. package/scripts/lib/spec.js +226 -0
  49. package/scripts/lib/state.js +107 -0
  50. package/scripts/lib/vendor/README.md +11 -0
  51. package/scripts/lib/vendor/markdown-it.LICENSE +22 -0
  52. package/scripts/lib/vendor/markdown-it.min.js +3 -0
  53. package/scripts/quality-gate.js +151 -0
  54. package/scripts/sdd-init.js +245 -0
  55. package/scripts/sdd-verify.js +176 -0
  56. package/scripts/verify-no-secrets.js +216 -0
  57. package/sdd.config.json +33 -0
@@ -0,0 +1,74 @@
1
+ # 🐙 GitHub CLI Setup & Zero-Trust Provisioning Guide
2
+
3
+ This guide establishes the standard Day-0 provisioning procedure for repositories built with the **Agentic SDD Framework**.
4
+
5
+ ---
6
+
7
+ ## 1. Why GitHub CLI (`gh`) over the Web UI?
8
+
9
+ Using the command-line interface (`gh`) instead of clicking through github.com provides three fundamental engineering advantages:
10
+
11
+ 1. **Deterministic & Scriptable:** Ensures every repository is provisioned with identical security flags (private by default, clean `.gitignore`, standard branch).
12
+ 2. **Eliminates URL Credential Leaks:** Cloning through `gh` uses authenticated keychain tokens or SSH agent keys, preventing hardcoded credentials in `.git/config` remote URLs.
13
+ 3. **Automated Branch Governance:** Enables setting up branch protection rules and CI/CD secret environments directly from terminal scripts.
14
+
15
+ ---
16
+
17
+ ## 2. Authentication & Least-Privilege Scopes
18
+
19
+ Before running provisioning commands, verify your local authentication state:
20
+
21
+ ```bash
22
+ gh auth status
23
+ ```
24
+
25
+ ### 🔒 Security Risk: Over-Privileged Personal Access Tokens (PAT)
26
+ When running `gh auth login`:
27
+ * **Recommended Protocol:** Choose `SSH` or `HTTPS` with web-browser verification.
28
+ * **Minimum Scopes Required:** `'repo'`, `'read:org'`, `'workflow'`.
29
+ * **FORBIDDEN:** Never grant `'admin:org'` or full account administration scopes to everyday CLI development machines.
30
+
31
+ ---
32
+
33
+ ## 3. Provisioning a New SDD Repository
34
+
35
+ To create and clone a clean, private repository from scratch:
36
+
37
+ ```bash
38
+ # 1. Create remote private repo and clone to local disk
39
+ gh repo create <project-name> --private --description "Spec-Driven Development Project" --clone
40
+
41
+ # 2. Navigate into the project
42
+ cd <project-name>
43
+ ```
44
+
45
+ ---
46
+
47
+ ## 4. Branch Protection Rules (The First Defense)
48
+
49
+ Autonomous AI agents must **never** be permitted to execute blind force-pushes (`git push --force`) to your production branch.
50
+
51
+ ### Setting up Branch Protection via CLI:
52
+ Protect the `main` (or `master`) branch by requiring pull requests and status checks:
53
+
54
+ ```bash
55
+ # Verify the default branch name
56
+ git branch -M main
57
+
58
+ # Enforce branch protection (requires GitHub Pro/Team for private repos or public repo)
59
+ gh api \
60
+ --method PUT \
61
+ "repos/:owner/:repo/branches/main/protection" \
62
+ -f required_status_checks='{"strict":true,"contexts":["quality-gate"]}' \
63
+ -f enforce_admins=true \
64
+ -f required_pull_request_reviews=null \
65
+ -f restrictions=null
66
+ ```
67
+
68
+ ---
69
+
70
+ ## 5. Security Checklist Before First Commit
71
+
72
+ - [ ] Repository is set to **Private** (unless explicitly intended as open-source).
73
+ - [ ] `.gitignore` contains rules for `.env`, `.vault`, `scratch/`, and private keys.
74
+ - [ ] No personal access tokens or credentials are typed into terminal arguments that persist in shell history (`~/.zsh_history` or `~/.bash_history`).
@@ -0,0 +1,35 @@
1
+ # Incident Post-Mortem: [YYYY-MM-DD] [Incident Title]
2
+
3
+ **Date:** [YYYY-MM-DD]
4
+ **Author / Investigator:** [Name]
5
+ **Severity:** P1 (Critical) | P2 (Major) | P3 (Minor)
6
+ **Status:** Resolved
7
+
8
+ ---
9
+
10
+ ## 1. Summary and Impact
11
+ Briefly describe what failed, which services were affected, and how the issue was detected (e.g. automated alert, customer report, test suite).
12
+
13
+ ---
14
+
15
+ ## 2. Timeline
16
+ * **[Time UTC]:** Initial symptom observed.
17
+ * **[Time UTC]:** Investigation started; root cause identified.
18
+ * **[Time UTC]:** Remediation deployed.
19
+ * **[Time UTC]:** Verification completed; service restored.
20
+
21
+ ---
22
+
23
+ ## 3. Root Cause Analysis
24
+ Explain the underlying mechanical, configuration, or architectural failure without speculation. State what code path or environment variable triggered the failure.
25
+
26
+ ---
27
+
28
+ ## 4. Remediation and Verification
29
+ * **Fix Applied:** [Link to commit or description of change]
30
+ * **Verification Command:** [Terminal command used to reproduce and verify the fix]
31
+
32
+ ---
33
+
34
+ ## 5. Inviolable Rule Created
35
+ Document the permanent rule added to `.agents/AGENTS.md` to ensure AI agents and engineers cannot repeat this error.
@@ -0,0 +1,37 @@
1
+ # {{PROJECT_NAME}} — Compliance Log
2
+
3
+ > **Evidence of record.** One report and one verdict per task/gate ID. Pre-generate an
4
+ > empty row per ID from the execution guide so nothing gets skipped silently.
5
+ >
6
+ > Maintained by the Auditor after every verdict. Compact repeated open conditions
7
+ > periodically instead of only appending — see the protocol's note on log maintenance.
8
+
9
+ ---
10
+
11
+ ## Status board
12
+
13
+ | ID | Delivery | Verdict | Notes |
14
+ |---|---|---|---|
15
+ | P0-T1 | | `PENDING` | |
16
+ | P0-G1 | | `PENDING` | |
17
+
18
+ ---
19
+
20
+ ## Open conditions
21
+
22
+ None yet.
23
+
24
+ ---
25
+
26
+ ## Reports
27
+
28
+ ### P0-T1 — PENDING
29
+ **Changed:**
30
+ **Verify output:**
31
+ **Observations:**
32
+ **Decisions made without stopping:**
33
+
34
+ ### P0-G1 — PENDING
35
+ **Verify output:**
36
+ **Observations:**
37
+
@@ -0,0 +1,75 @@
1
+ # {{PROJECT_NAME}} — Execution Guide
2
+
3
+ > **You are the Executor.** The Auditor wrote this file and will re-run every gate
4
+ > independently. Read `plan-of-record.md` once for context, then work only from here.
5
+ > Report every task in `compliance-log.md`.
6
+
7
+ ---
8
+
9
+ ## Rules of engagement
10
+
11
+ 1. **One task at a time, in order.** No batching. Do not start a phase whose
12
+ predecessor is not marked `APPROVED` in the compliance log.
13
+ 2. **Never invent a value the codebase declares.** Read it. Needing to ask for one
14
+ means a file was skipped.
15
+ 3. **Never guess a cause. Observe it.** Read the log, run the query, print the value.
16
+ 4. **Verification is running the thing, not reading the code.** "I reviewed it and it
17
+ looks correct" is reported as `FAILED`.
18
+ 5. **Scope is the task text.** Unrelated problems go in *Observations*. Do not fix
19
+ them.
20
+ 6. **Stop and ask** when this document contradicts the code, when a task needs a
21
+ decision this document does not make, or when a previously passing check starts
22
+ failing for reasons unrelated to your change. If you resolve an ambiguity without
23
+ stopping, log the decision. A decision in the plan of record is settled; a factual
24
+ claim never is — if this document states something the code contradicts, the
25
+ evidence outranks the order.
26
+ 7. **When the system cannot do what a task asks, that is the deliverable.** Report it
27
+ and stop. A task that ends in a well-argued finding is a success.
28
+ 8. Project-specific rules that apply to every task — list them here, cited from their
29
+ source rather than restated:
30
+ -
31
+ -
32
+
33
+ ## Reporting format
34
+
35
+ For each task, append to `compliance-log.md`:
36
+
37
+ ```
38
+ ### <TASK-ID> — DONE | BLOCKED | FAILED
39
+ **Changed:** <paths>
40
+ **Verify output:**
41
+ <pasted, literal, unedited command output>
42
+ **Observations:** <or "none">
43
+ **Decisions made without stopping:** <or "none">
44
+ ```
45
+
46
+ A `DONE` with no pasted output is recorded as `FAILED`.
47
+
48
+ ---
49
+
50
+ # Phase 0 — <name>
51
+
52
+ ### P0-T1 — <imperative, one line>
53
+
54
+ **Goal:**
55
+ **Files:**
56
+ **Steps:**
57
+ 1.
58
+
59
+ **Expected failure to avoid:**
60
+
61
+ **Verify:**
62
+ ```bash
63
+ ```
64
+
65
+ **Report:** `P0-T1`
66
+
67
+ ---
68
+
69
+ ### P0-G1 — Gate: <claim under test>
70
+
71
+ **Proven by:** <the check that proves the claim>
72
+
73
+ **Negative control:** <how you remove the protection, which check fails, and that it passes again once restored>
74
+
75
+ **Report:** `P0-G1`
@@ -0,0 +1,49 @@
1
+ # {{PROJECT_NAME}} — Plan of Record
2
+
3
+ > **Status:** draft. This document holds the *what* and the *why*. Nobody implements
4
+ > from this file. The executable instructions live in `execution-guide.md`; evidence
5
+ > goes in `compliance-log.md`.
6
+
7
+ **Target version / milestone:**
8
+
9
+ ---
10
+
11
+ ## 1. Why this exists
12
+
13
+ What problem is this solving, and why now. If several requests trace back to one
14
+ underlying gap, name the gap here rather than listing the requests as unrelated.
15
+
16
+ ## 2. What the audit of the current system found
17
+
18
+ | Finding | Evidence |
19
+ |---|---|
20
+ | | |
21
+
22
+ State each finding with the command or artifact that established it, not from memory.
23
+
24
+ ## 3. The decisions (settled — reopening one is a stop, not a choice)
25
+
26
+ ### D1 — <decision name>
27
+
28
+ What was decided, what alternative was rejected and why, what failure this prevents.
29
+
30
+ ## 4. What this deliberately does not do
31
+
32
+ Scope boundaries the Auditor is holding, so an Executor (or a future Auditor) doesn't
33
+ drift into rebuilding something that was cut on purpose.
34
+
35
+ ## 5. Phases
36
+
37
+ | Phase | Delivers | Risk |
38
+ |---|---|---|
39
+ | | | |
40
+
41
+ ## 6. Request traceability
42
+
43
+ | Origin request | Where it lands |
44
+ |---|---|
45
+ | | |
46
+
47
+ ## 7. Standards this work is held to
48
+
49
+ Cite the project's own conventions rather than restating them here.
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "agentic-sdd-framework",
3
+ "version": "1.4.0",
4
+ "description": "Spec-Driven Development governance for AI coding agents: auto-loaded agent rules, specifications with recorded evidence, and a pre-push quality gate",
5
+ "bin": {
6
+ "sdd-init": "scripts/sdd-init.js"
7
+ },
8
+ "files": [
9
+ "scripts/",
10
+ ".agents/",
11
+ "docs/",
12
+ "sdd.config.json",
13
+ "README.md",
14
+ "LICENSE",
15
+ "CHANGELOG.md"
16
+ ],
17
+ "engines": {
18
+ "node": ">=22"
19
+ },
20
+ "scripts": {
21
+ "test": "node --test",
22
+ "init": "node scripts/sdd-init.js",
23
+ "verify": "node scripts/sdd-verify.js",
24
+ "check:prereqs": "node scripts/check-system-prerequisites.js",
25
+ "check:secrets": "node scripts/verify-no-secrets.js",
26
+ "check:slop": "node scripts/check-copy-slop.js",
27
+ "check:size": "node scripts/check-file-size.js",
28
+ "check:spec": "node scripts/check-spec.js",
29
+ "check:versions": "node scripts/check-versions.js",
30
+ "install-hooks": "node scripts/install-git-hooks.js",
31
+ "quality-gate": "node scripts/quality-gate.js"
32
+ },
33
+ "keywords": [
34
+ "sdd",
35
+ "spec-driven-development",
36
+ "ai-agents",
37
+ "claude-code",
38
+ "antigravity",
39
+ "cursor",
40
+ "governance",
41
+ "auditor-executor"
42
+ ],
43
+ "author": "tBeltty",
44
+ "license": "MIT",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/tBeltty/agentic-sdd-framework.git"
48
+ }
49
+ }
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * scripts/check-copy-slop.js
5
+ *
6
+ * Linter for AI-generated writing cliches, buzzwords, and banned patterns in prose
7
+ * (.md, .mdx, .txt). Code blocks, inline code and table rows are not checked.
8
+ * Inspired by https://github.com/petergyang/no-ai-slop (MIT License).
9
+ *
10
+ * Config (sdd.config.json -> capabilities.noAiSlop):
11
+ * enabled false skips the check (default true)
12
+ * exclude path prefixes to skip
13
+ * maxEmDashes em dashes allowed per file, counted individually (default 1)
14
+ */
15
+
16
+ const { listFiles, readFiles, isBinary, WORKTREE } = require('./lib/git');
17
+ const { loadConfig, getIn } = require('./lib/config');
18
+ const { runCheckCli } = require('./lib/cli');
19
+ const { normalizeEol, createFenceTracker } = require('./lib/markdown');
20
+ const { BANNED_PATTERNS } = require('./lib/slop-patterns');
21
+
22
+ const PROSE_EXTENSIONS = ['.md', '.mdx', '.txt'];
23
+
24
+ // The skill that defines the banned patterns must quote them; vendored skills and the
25
+ // Rigor templates are synced from their upstream repositories and linted there. Rigor
26
+ // documents (specification.roadmapDir) are records in the protocol's format and hold
27
+ // pasted command output.
28
+ // sdd-init copies the skills into .claude/skills/ where symlinks are unavailable (Windows
29
+ // without Developer Mode), so those copies are excluded too.
30
+ const DEFAULT_EXCLUDE = [
31
+ '.agents/skills/no-ai-slop/',
32
+ '.agents/skills/auditor-executor-protocol/',
33
+ '.claude/skills/no-ai-slop/',
34
+ '.claude/skills/auditor-executor-protocol/',
35
+ 'docs/roadmap/templates/'
36
+ ];
37
+
38
+ function lintContent(content, { maxEmDashes = 1 } = {}) {
39
+ const violations = [];
40
+ const emDashLines = [];
41
+ let emDashes = 0;
42
+ const fence = createFenceTracker();
43
+
44
+ normalizeEol(content).split('\n').forEach((rawLine, index) => {
45
+ const trimmed = rawLine.trim();
46
+ if (fence.update(rawLine) || fence.inside) return;
47
+ if (trimmed.startsWith('|') || /^-{3,}$/.test(trimmed)) return;
48
+
49
+ const line = rawLine.replace(/`[^`]*`/g, '``');
50
+ const dashes = (line.match(/—/g) || []).length;
51
+ if (dashes > 0) {
52
+ emDashes += dashes;
53
+ emDashLines.push(index + 1);
54
+ }
55
+
56
+ for (const pattern of BANNED_PATTERNS) {
57
+ const match = line.match(pattern.regex);
58
+ if (match) {
59
+ violations.push({
60
+ line: index + 1,
61
+ pattern: pattern.name,
62
+ matchedText: match[0].trim(),
63
+ lineText: trimmed.slice(0, 100)
64
+ });
65
+ break;
66
+ }
67
+ }
68
+ });
69
+
70
+ if (emDashes > maxEmDashes) {
71
+ violations.push({
72
+ line: emDashLines[0],
73
+ pattern: `Em Dash Overuse (${emDashes} found, max ${maxEmDashes} per file)`,
74
+ matchedText: '—',
75
+ lineText: `lines ${emDashLines.join(', ')}`
76
+ });
77
+ }
78
+ return violations;
79
+ }
80
+
81
+ function run({ root, source = WORKTREE } = {}) {
82
+ const config = loadConfig(root, source);
83
+ if (getIn(config, 'capabilities.noAiSlop.enabled', true) === false) {
84
+ return { ok: true, report: '⏭️ No-AI-Slop linter disabled in sdd.config.json.' };
85
+ }
86
+ const roadmapDir = `${getIn(config, 'specification.roadmapDir', 'docs/roadmap').replace(/\/+$/, '')}/`;
87
+ const exclude = [...DEFAULT_EXCLUDE, roadmapDir, ...getIn(config, 'capabilities.noAiSlop.exclude', [])];
88
+ const maxEmDashes = getIn(config, 'capabilities.noAiSlop.maxEmDashes', 1);
89
+
90
+ const files = listFiles(root, source)
91
+ .filter(f => PROSE_EXTENSIONS.some(ext => f.endsWith(ext)))
92
+ .filter(f => !exclude.some(prefix => f.startsWith(prefix)));
93
+
94
+ const violations = [];
95
+ for (const [file, buffer] of readFiles(root, files, source)) {
96
+ if (!buffer || isBinary(buffer)) continue;
97
+ for (const v of lintContent(buffer.toString('utf8'), { maxEmDashes })) {
98
+ violations.push({ file, ...v });
99
+ }
100
+ }
101
+
102
+ if (violations.length === 0) {
103
+ return { ok: true, report: `✅ Scanned ${files.length} file(s). Zero AI slop patterns detected.` };
104
+ }
105
+ const lines = [`❌ Found ${violations.length} AI writing pattern violation(s):\n`];
106
+ for (const v of violations) {
107
+ lines.push(` - File: ${v.file}:${v.line}`);
108
+ lines.push(` Pattern: ${v.pattern}`);
109
+ lines.push(` Matched: "${v.matchedText}"`);
110
+ lines.push(` Context: ${v.lineText}\n`);
111
+ }
112
+ lines.push('Action: Rewrite directly without empty filler or binary contrasts.');
113
+ return { ok: false, report: lines.join('\n') };
114
+ }
115
+
116
+ if (require.main === module) {
117
+ runCheckCli('✍️ Agentic SDD Framework: No-AI-Slop Copy Linter', run);
118
+ }
119
+
120
+ module.exports = { lintContent, run };
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * scripts/check-file-size.js
5
+ *
6
+ * Enforces architecture.maxLocPerFile from sdd.config.json on tracked source files.
7
+ * Documentation, data and lockfiles are not counted.
8
+ *
9
+ * Config (sdd.config.json -> architecture):
10
+ * maxLocPerFile line limit per source file (default 400; 0 disables the check)
11
+ * maxLocExclude path prefixes to skip (for example generated code)
12
+ */
13
+
14
+ const path = require('path');
15
+ const { listFiles, readFiles, isBinary, WORKTREE } = require('./lib/git');
16
+ const { loadConfig, getIn } = require('./lib/config');
17
+ const { runCheckCli } = require('./lib/cli');
18
+
19
+ const SOURCE_EXTENSIONS = new Set([
20
+ '.js', '.mjs', '.cjs', '.jsx', '.ts', '.mts', '.cts', '.tsx', '.vue', '.svelte',
21
+ '.py', '.go', '.rs', '.java', '.kt', '.kts', '.scala', '.rb', '.php', '.cs',
22
+ '.c', '.h', '.cc', '.cpp', '.hpp', '.m', '.swift', '.dart', '.ex', '.exs',
23
+ '.sh', '.bash', '.zsh', '.lua', '.sql'
24
+ ]);
25
+
26
+ function countLines(text) {
27
+ if (text.length === 0) return 0;
28
+ const normalized = text.replace(/\r\n?/g, '\n');
29
+ return normalized.split('\n').length - (normalized.endsWith('\n') ? 1 : 0);
30
+ }
31
+
32
+ function run({ root, source = WORKTREE } = {}) {
33
+ const config = loadConfig(root, source);
34
+ const limit = getIn(config, 'architecture.maxLocPerFile', 400);
35
+ if (!limit) {
36
+ return { ok: true, report: '⏭️ File size limit disabled (architecture.maxLocPerFile is 0).' };
37
+ }
38
+ const exclude = getIn(config, 'architecture.maxLocExclude', []);
39
+
40
+ const files = listFiles(root, source)
41
+ .filter(f => SOURCE_EXTENSIONS.has(path.extname(f).toLowerCase()))
42
+ .filter(f => !exclude.some(prefix => f.startsWith(prefix)));
43
+
44
+ const oversized = [];
45
+ for (const [file, buffer] of readFiles(root, files, source)) {
46
+ if (!buffer || isBinary(buffer)) continue;
47
+ const lines = countLines(buffer.toString('utf8'));
48
+ if (lines > limit) oversized.push({ file, lines });
49
+ }
50
+
51
+ if (oversized.length === 0) {
52
+ return { ok: true, report: `✅ ${files.length} source file(s) within ${limit} lines.` };
53
+ }
54
+ const report = [`❌ ${oversized.length} source file(s) exceed architecture.maxLocPerFile (${limit}):\n`];
55
+ for (const { file, lines } of oversized.sort((a, b) => b.lines - a.lines)) {
56
+ report.push(` - ${file}: ${lines} lines`);
57
+ }
58
+ report.push('\nAction: Split the file by responsibility, or add generated paths to architecture.maxLocExclude.');
59
+ return { ok: false, report: report.join('\n') };
60
+ }
61
+
62
+ if (require.main === module) {
63
+ runCheckCli('📏 Agentic SDD Framework: File Size Limit', run);
64
+ }
65
+
66
+ module.exports = { countLines, run };