docguard-cli 0.5.2 → 0.7.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/PHILOSOPHY.md +22 -0
- package/README.md +13 -0
- package/cli/commands/diagnose.mjs +224 -33
- package/cli/commands/generate.mjs +501 -87
- package/cli/commands/guard.mjs +23 -6
- package/cli/commands/publish.mjs +246 -0
- package/cli/commands/score.mjs +31 -0
- package/cli/commands/trace.mjs +311 -0
- package/cli/docguard.mjs +31 -3
- package/cli/scanners/doc-tools.mjs +351 -0
- package/cli/scanners/routes.mjs +461 -0
- package/cli/scanners/schemas.mjs +567 -0
- package/package.json +1 -1
package/PHILOSOPHY.md
CHANGED
|
@@ -143,6 +143,28 @@ CDD is designed for progressive adoption:
|
|
|
143
143
|
|
|
144
144
|
---
|
|
145
145
|
|
|
146
|
+
## Academic Foundations
|
|
147
|
+
|
|
148
|
+
CDD is a practitioner methodology, but its core patterns align with peer-reviewed research in AI-driven documentation and quality evaluation:
|
|
149
|
+
|
|
150
|
+
### The Three-Stage Pipeline
|
|
151
|
+
|
|
152
|
+
DocGuard's architecture follows a **generate → validate → evaluate** pipeline inspired by the AITPG framework (Lopez et al., IEEE TSE 2026), which demonstrated that multi-agent debate over RAG-grounded standards produces 32% more comprehensive documentation while maintaining semantic alignment with expert references.
|
|
153
|
+
|
|
154
|
+
### Calibrated Quality Evaluation
|
|
155
|
+
|
|
156
|
+
DocGuard's quality scoring (HIGH/MEDIUM/LOW labels, multi-signal composite scores) adapts the Calibrated Judge Evaluation (CJE) framework from TRACE (Lopez et al., IEEE TMLCN 2026), which showed that weighted multi-signal scoring with confidence intervals provides actionable quality gating for enterprise deployment.
|
|
157
|
+
|
|
158
|
+
### Standards-Grounded Generation
|
|
159
|
+
|
|
160
|
+
Both AITPG and TRACE demonstrate that grounding AI-generated content in vectorized standards (ISO 29119, 3GPP) dramatically improves output quality. DocGuard applies this principle by mapping each canonical document to its relevant industry standard (arc42, C4, OWASP ASVS, ISO 29119, OpenAPI 3.1, 12-Factor App).
|
|
161
|
+
|
|
162
|
+
> **Full citations**: See [CONTRIBUTING.md — Research & Academic Credits](CONTRIBUTING.md#research--academic-credits)
|
|
163
|
+
>
|
|
164
|
+
> **Lead researcher**: [Martin Manuel Lopez](https://github.com/martinmanuel9) · [ORCID 0009-0002-7652-2385](https://orcid.org/0009-0002-7652-2385), University of Arizona
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
146
168
|
## License
|
|
147
169
|
|
|
148
170
|
This philosophy document and the CDD methodology are released under the [MIT License](https://opensource.org/licenses/MIT).
|
package/README.md
CHANGED
|
@@ -322,6 +322,19 @@ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
|
322
322
|
|
|
323
323
|
---
|
|
324
324
|
|
|
325
|
+
## Research Credits
|
|
326
|
+
|
|
327
|
+
DocGuard's quality evaluation and documentation generation patterns are informed by peer-reviewed research from the University of Arizona and the Joint Interoperability Test Command (JITC), U.S. Department of Defense:
|
|
328
|
+
|
|
329
|
+
- **AITPG** — AI-driven Test Plan Generator using Multi-Agent Debate and RAG ([Lopez et al., IEEE TSE 2026](Research/AITPG.pdf))
|
|
330
|
+
- **TRACE** — Telecom Root Cause Analysis through Calibrated Explainability ([Lopez et al., IEEE TMLCN 2026](Research/TRACE.pdf))
|
|
331
|
+
|
|
332
|
+
Lead researcher: **[Martin Manuel Lopez](https://github.com/martinmanuel9)** · [ORCID 0009-0002-7652-2385](https://orcid.org/0009-0002-7652-2385)
|
|
333
|
+
|
|
334
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md#research--academic-credits) for full citations and concept attributions.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
325
338
|
## License
|
|
326
339
|
|
|
327
340
|
[MIT](LICENSE) — Free to use, modify, and distribute.
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
import { c } from '../docguard.mjs';
|
|
17
17
|
import { runGuardInternal } from './guard.mjs';
|
|
18
18
|
import { runScoreInternal } from './score.mjs';
|
|
19
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
19
|
+
import { existsSync, readFileSync, mkdirSync } from 'node:fs';
|
|
20
20
|
import { resolve } from 'node:path';
|
|
21
|
+
import { execSync } from 'node:child_process';
|
|
21
22
|
|
|
22
23
|
// Map validator failures to the right fix --doc target
|
|
23
24
|
const VALIDATOR_TO_DOC = {
|
|
@@ -39,62 +40,141 @@ const FIX_INSTRUCTIONS = {
|
|
|
39
40
|
action: 'Create missing files',
|
|
40
41
|
command: 'docguard init',
|
|
41
42
|
description: 'Run init to create missing documentation templates.',
|
|
43
|
+
autoFixable: true,
|
|
42
44
|
},
|
|
43
45
|
'Doc Sections': {
|
|
44
46
|
action: 'Fill document sections',
|
|
45
47
|
command: 'docguard fix --doc',
|
|
46
48
|
description: 'Documents exist but have missing or placeholder sections. Use fix --doc to generate AI content prompts.',
|
|
49
|
+
autoFixable: false,
|
|
47
50
|
},
|
|
48
51
|
'Docs-Sync': {
|
|
49
52
|
action: 'Sync documentation references',
|
|
50
53
|
command: 'docguard fix --doc architecture',
|
|
51
54
|
description: 'Documentation references are out of sync with code. Review and update component maps.',
|
|
55
|
+
autoFixable: false,
|
|
52
56
|
},
|
|
53
57
|
'Drift': {
|
|
54
58
|
action: 'Update DRIFT-LOG.md',
|
|
55
59
|
description: 'Code deviates from canonical docs without logged reasons. Add DRIFT entries or update the canonical docs.',
|
|
60
|
+
autoFixable: false,
|
|
56
61
|
},
|
|
57
62
|
'Changelog': {
|
|
58
63
|
action: 'Update CHANGELOG.md',
|
|
59
64
|
description: 'CHANGELOG.md is missing or has no [Unreleased] section. Add recent changes.',
|
|
65
|
+
autoFixable: false,
|
|
60
66
|
},
|
|
61
67
|
'Test-Spec': {
|
|
62
68
|
action: 'Update TEST-SPEC.md',
|
|
63
69
|
command: 'docguard fix --doc test-spec',
|
|
64
70
|
description: 'Test documentation needs updating to match actual test structure.',
|
|
71
|
+
autoFixable: false,
|
|
65
72
|
},
|
|
66
73
|
'Environment': {
|
|
67
74
|
action: 'Update ENVIRONMENT.md',
|
|
68
75
|
command: 'docguard fix --doc environment',
|
|
69
76
|
description: 'Environment documentation is missing or incomplete.',
|
|
77
|
+
autoFixable: false,
|
|
70
78
|
},
|
|
71
79
|
'Security': {
|
|
72
80
|
action: 'Update SECURITY.md',
|
|
73
81
|
command: 'docguard fix --doc security',
|
|
74
82
|
description: 'Security documentation needs updating.',
|
|
83
|
+
autoFixable: false,
|
|
75
84
|
},
|
|
76
85
|
'Architecture': {
|
|
77
86
|
action: 'Update ARCHITECTURE.md',
|
|
78
87
|
command: 'docguard fix --doc architecture',
|
|
79
88
|
description: 'Architecture documentation doesn\'t match the codebase.',
|
|
89
|
+
autoFixable: false,
|
|
80
90
|
},
|
|
81
91
|
'Freshness': {
|
|
82
92
|
action: 'Review stale documents',
|
|
83
93
|
description: 'Documents haven\'t been reviewed since recent code changes. Re-run fix --doc for each stale doc.',
|
|
94
|
+
autoFixable: false,
|
|
84
95
|
},
|
|
85
96
|
};
|
|
86
97
|
|
|
87
98
|
export function runDiagnose(projectDir, config, flags) {
|
|
88
99
|
// ── Step 1: Run guard internally ──
|
|
89
|
-
|
|
100
|
+
let guardData = runGuardInternal(projectDir, config);
|
|
90
101
|
const scoreData = runScoreInternal(projectDir, config);
|
|
91
102
|
|
|
92
103
|
// ── Step 2: Collect issues ──
|
|
104
|
+
let issues = collectIssues(guardData);
|
|
105
|
+
|
|
106
|
+
// ── Step 3: Auto-fix what we can (unless --no-fix) ──
|
|
107
|
+
const shouldAutoFix = !flags.noFix && flags.format !== 'json';
|
|
108
|
+
if (shouldAutoFix && issues.length > 0) {
|
|
109
|
+
const autoFixable = issues.filter(i => i.autoFixable);
|
|
110
|
+
const hasStructural = issues.some(i => i.validator === 'Structure');
|
|
111
|
+
|
|
112
|
+
if (hasStructural || autoFixable.length > 0) {
|
|
113
|
+
// Run init to create missing files
|
|
114
|
+
try {
|
|
115
|
+
const cliPath = resolve(import.meta.dirname, '..', 'docguard.mjs');
|
|
116
|
+
execSync(`node "${cliPath}" init --dir "${projectDir}"`, {
|
|
117
|
+
encoding: 'utf-8',
|
|
118
|
+
stdio: 'pipe',
|
|
119
|
+
});
|
|
120
|
+
} catch { /* init may partially succeed */ }
|
|
121
|
+
|
|
122
|
+
// Run generate to fill in content
|
|
123
|
+
try {
|
|
124
|
+
const cliPath = resolve(import.meta.dirname, '..', 'docguard.mjs');
|
|
125
|
+
execSync(`node "${cliPath}" generate --dir "${projectDir}" --force`, {
|
|
126
|
+
encoding: 'utf-8',
|
|
127
|
+
stdio: 'pipe',
|
|
128
|
+
});
|
|
129
|
+
} catch { /* generate may partially succeed */ }
|
|
130
|
+
|
|
131
|
+
// Re-run guard to see what's still broken
|
|
132
|
+
guardData = runGuardInternal(projectDir, config);
|
|
133
|
+
issues = collectIssues(guardData);
|
|
134
|
+
|
|
135
|
+
if (!flags.format || flags.format === 'text') {
|
|
136
|
+
const fixedCount = autoFixable.length - issues.filter(i => i.autoFixable).length;
|
|
137
|
+
if (fixedCount > 0) {
|
|
138
|
+
console.log(` ${c.green}⚡ Auto-fixed ${fixedCount} issue(s)${c.reset} (created/regenerated docs)\n`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Detect stale docs from freshness and map to specific fix --doc targets
|
|
145
|
+
for (const issue of issues) {
|
|
146
|
+
if (issue.validator === 'Freshness' && !issue.docTarget) {
|
|
147
|
+
const match = issue.message.match(/([\w-]+\.md)/i);
|
|
148
|
+
if (match) {
|
|
149
|
+
const docName = match[1].toLowerCase().replace('.md', '');
|
|
150
|
+
const docMap = { 'architecture': 'architecture', 'data-model': 'data-model', 'security': 'security', 'test-spec': 'test-spec', 'environment': 'environment' };
|
|
151
|
+
issue.docTarget = docMap[docName] || null;
|
|
152
|
+
if (issue.docTarget) {
|
|
153
|
+
issue.command = `docguard fix --doc ${issue.docTarget}`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ── Step 4: Output ──
|
|
160
|
+
if (flags.format === 'json') {
|
|
161
|
+
outputJSON(guardData, scoreData, issues);
|
|
162
|
+
} else if (flags.format === 'prompt') {
|
|
163
|
+
outputPrompt(projectDir, guardData, scoreData, issues, flags);
|
|
164
|
+
} else {
|
|
165
|
+
outputText(projectDir, guardData, scoreData, issues, flags);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Collect issues from guard results with fix metadata.
|
|
171
|
+
*/
|
|
172
|
+
function collectIssues(guardData) {
|
|
93
173
|
const issues = [];
|
|
94
174
|
for (const v of guardData.validators) {
|
|
95
175
|
if (v.status === 'skipped' || v.status === 'pass') continue;
|
|
96
176
|
|
|
97
|
-
const fixInfo = FIX_INSTRUCTIONS[v.name] || { action: `Review ${v.name}`, description: 'Manual review needed.' };
|
|
177
|
+
const fixInfo = FIX_INSTRUCTIONS[v.name] || { action: `Review ${v.name}`, description: 'Manual review needed.', autoFixable: false };
|
|
98
178
|
const docTarget = VALIDATOR_TO_DOC[v.name];
|
|
99
179
|
|
|
100
180
|
for (const err of v.errors) {
|
|
@@ -105,6 +185,7 @@ export function runDiagnose(projectDir, config, flags) {
|
|
|
105
185
|
action: fixInfo.action,
|
|
106
186
|
command: fixInfo.command || null,
|
|
107
187
|
docTarget,
|
|
188
|
+
autoFixable: fixInfo.autoFixable || false,
|
|
108
189
|
});
|
|
109
190
|
}
|
|
110
191
|
for (const warn of v.warnings) {
|
|
@@ -115,34 +196,11 @@ export function runDiagnose(projectDir, config, flags) {
|
|
|
115
196
|
action: fixInfo.action,
|
|
116
197
|
command: fixInfo.command || null,
|
|
117
198
|
docTarget,
|
|
199
|
+
autoFixable: fixInfo.autoFixable || false,
|
|
118
200
|
});
|
|
119
201
|
}
|
|
120
202
|
}
|
|
121
|
-
|
|
122
|
-
// Detect stale docs from freshness and map to specific fix --doc targets
|
|
123
|
-
for (const issue of issues) {
|
|
124
|
-
if (issue.validator === 'Freshness' && !issue.docTarget) {
|
|
125
|
-
// Try to extract doc name from warning message
|
|
126
|
-
const match = issue.message.match(/([\w-]+\.md)/i);
|
|
127
|
-
if (match) {
|
|
128
|
-
const docName = match[1].toLowerCase().replace('.md', '');
|
|
129
|
-
const docMap = { 'architecture': 'architecture', 'data-model': 'data-model', 'security': 'security', 'test-spec': 'test-spec', 'environment': 'environment' };
|
|
130
|
-
issue.docTarget = docMap[docName] || null;
|
|
131
|
-
if (issue.docTarget) {
|
|
132
|
-
issue.command = `docguard fix --doc ${issue.docTarget}`;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// ── Step 3: Output ──
|
|
139
|
-
if (flags.format === 'json') {
|
|
140
|
-
outputJSON(guardData, scoreData, issues);
|
|
141
|
-
} else if (flags.format === 'prompt') {
|
|
142
|
-
outputPrompt(projectDir, guardData, scoreData, issues);
|
|
143
|
-
} else {
|
|
144
|
-
outputText(projectDir, guardData, scoreData, issues);
|
|
145
|
-
}
|
|
203
|
+
return issues;
|
|
146
204
|
}
|
|
147
205
|
|
|
148
206
|
function outputJSON(guardData, scoreData, issues) {
|
|
@@ -168,7 +226,7 @@ function outputJSON(guardData, scoreData, issues) {
|
|
|
168
226
|
console.log(JSON.stringify(result, null, 2));
|
|
169
227
|
}
|
|
170
228
|
|
|
171
|
-
function outputText(projectDir, guardData, scoreData, issues) {
|
|
229
|
+
function outputText(projectDir, guardData, scoreData, issues, flags) {
|
|
172
230
|
console.log(`${c.bold}🔍 DocGuard Diagnose — ${guardData.project}${c.reset}`);
|
|
173
231
|
console.log(`${c.dim} Profile: ${guardData.profile} | Score: ${scoreData.score}/100 (${scoreData.grade})${c.reset}`);
|
|
174
232
|
console.log(`${c.dim} Guard: ${guardData.passed}/${guardData.total} passed | Status: ${guardData.status}${c.reset}\n`);
|
|
@@ -213,17 +271,27 @@ function outputText(projectDir, guardData, scoreData, issues) {
|
|
|
213
271
|
}
|
|
214
272
|
|
|
215
273
|
// ── AI Prompt (always shown in text mode for easy copy) ──
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
274
|
+
if (flags && flags.debate) {
|
|
275
|
+
// Multi-perspective debate prompts (AITPG/TRACE-inspired)
|
|
276
|
+
console.log(` ${c.bold}🤖 Multi-Perspective AI Debate Prompt:${c.reset}`);
|
|
277
|
+
console.log(` ${c.dim}Copy everything below and paste to your AI agent:${c.reset}\n`);
|
|
278
|
+
outputDebatePrompt(projectDir, guardData, scoreData, issues);
|
|
279
|
+
} else {
|
|
280
|
+
console.log(` ${c.bold}🤖 AI-Ready Prompt:${c.reset}`);
|
|
281
|
+
console.log(` ${c.dim}Copy everything below and paste to your AI agent:${c.reset}\n`);
|
|
282
|
+
outputPrompt(undefined, guardData, scoreData, issues, flags);
|
|
283
|
+
}
|
|
219
284
|
}
|
|
220
285
|
|
|
221
|
-
function outputPrompt(projectDir, guardData, scoreData, issues) {
|
|
286
|
+
function outputPrompt(projectDir, guardData, scoreData, issues, flags) {
|
|
222
287
|
if (issues.length === 0) {
|
|
223
288
|
console.log('No issues to fix. Documentation is healthy.');
|
|
224
289
|
return;
|
|
225
290
|
}
|
|
226
291
|
|
|
292
|
+
// Detect agent capability for prompt complexity (inspired by CJE equalizer effect, TRACE 2026)
|
|
293
|
+
const agentTier = detectAgentTier(projectDir || '.');
|
|
294
|
+
|
|
227
295
|
const lines = [];
|
|
228
296
|
lines.push(`TASK: Fix ${issues.length} documentation issue(s) in project "${guardData.project}"`);
|
|
229
297
|
lines.push(`Profile: ${guardData.profile} | Score: ${scoreData.score}/100 | Guard: ${guardData.status}`);
|
|
@@ -257,6 +325,11 @@ function outputPrompt(projectDir, guardData, scoreData, issues) {
|
|
|
257
325
|
if (group.docTarget) {
|
|
258
326
|
lines.push(` Then research the codebase and write real content for this document.`);
|
|
259
327
|
}
|
|
328
|
+
// Agent-aware: add extra detail for smaller models
|
|
329
|
+
if (agentTier === 'basic') {
|
|
330
|
+
lines.push(` NOTE: Review the codebase file by file. Look for patterns matching this issue.`);
|
|
331
|
+
lines.push(` Check docs-canonical/ for the expected format. Compare against existing docs.`);
|
|
332
|
+
}
|
|
260
333
|
for (const msg of group.issues) {
|
|
261
334
|
lines.push(` - ${msg}`);
|
|
262
335
|
}
|
|
@@ -269,5 +342,123 @@ function outputPrompt(projectDir, guardData, scoreData, issues) {
|
|
|
269
342
|
lines.push('Expected result: All checks pass (0 errors, 0 warnings)');
|
|
270
343
|
lines.push(`Target score: ≥${scoreData.score + 5}/100`);
|
|
271
344
|
|
|
345
|
+
// Agent-aware: add explicit checklist for basic-tier agents
|
|
346
|
+
if (agentTier === 'basic') {
|
|
347
|
+
lines.push('');
|
|
348
|
+
lines.push('VERIFICATION CHECKLIST (complete each step):');
|
|
349
|
+
lines.push('□ Read each file in docs-canonical/ before editing');
|
|
350
|
+
lines.push('□ Run `docguard guard` after each file change');
|
|
351
|
+
lines.push('□ Confirm 0 errors before moving to next issue');
|
|
352
|
+
lines.push('□ Run `docguard score` to confirm improvement');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
console.log(lines.join('\n'));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Generate multi-perspective debate prompts.
|
|
360
|
+
* Inspired by AITPG multi-agent role specialization (Positive/Negative/Edge + Critic)
|
|
361
|
+
* and TRACE adversarial debate (Advocate/Challenger/Mediator/Explainer).
|
|
362
|
+
* Lopez et al., IEEE TSE/TMLCN 2026.
|
|
363
|
+
*/
|
|
364
|
+
function outputDebatePrompt(projectDir, guardData, scoreData, issues) {
|
|
365
|
+
const lines = [];
|
|
366
|
+
|
|
367
|
+
lines.push('═══════════════════════════════════════════════════════');
|
|
368
|
+
lines.push('MULTI-PERSPECTIVE DOCUMENTATION ANALYSIS');
|
|
369
|
+
lines.push(`Project: "${guardData.project}" | Score: ${scoreData.score}/100 | Issues: ${issues.length}`);
|
|
370
|
+
lines.push('Methodology: Multi-agent debate (Lopez et al., AITPG/TRACE, IEEE 2026)');
|
|
371
|
+
lines.push('═══════════════════════════════════════════════════════');
|
|
372
|
+
lines.push('');
|
|
373
|
+
|
|
374
|
+
// Issue context
|
|
375
|
+
lines.push('CONTEXT — Current Issues:');
|
|
376
|
+
for (let i = 0; i < issues.length; i++) {
|
|
377
|
+
lines.push(` ${i + 1}. [${issues[i].severity.toUpperCase()}] [${issues[i].validator}] ${issues[i].message}`);
|
|
378
|
+
}
|
|
379
|
+
lines.push('');
|
|
380
|
+
|
|
381
|
+
// ── Agent 1: Advocate ──
|
|
382
|
+
lines.push('───────────────────────────────────────────────────────');
|
|
383
|
+
lines.push('PERSPECTIVE 1: ADVOCATE (What is working well)');
|
|
384
|
+
lines.push('───────────────────────────────────────────────────────');
|
|
385
|
+
lines.push('Role: You are the Advocate agent. Your job is to identify what the project');
|
|
386
|
+
lines.push('documentation is doing RIGHT and which patterns should be PRESERVED.');
|
|
387
|
+
lines.push('');
|
|
388
|
+
lines.push('Instructions:');
|
|
389
|
+
lines.push('1. Read all files in docs-canonical/');
|
|
390
|
+
lines.push('2. Identify which documents are well-structured and complete');
|
|
391
|
+
lines.push('3. Note which naming conventions, section formats, and patterns are consistent');
|
|
392
|
+
lines.push('4. List 3-5 strengths that must be preserved during remediation');
|
|
393
|
+
lines.push('');
|
|
394
|
+
|
|
395
|
+
// ── Agent 2: Challenger ──
|
|
396
|
+
lines.push('───────────────────────────────────────────────────────');
|
|
397
|
+
lines.push('PERSPECTIVE 2: CHALLENGER (What is broken or risky)');
|
|
398
|
+
lines.push('───────────────────────────────────────────────────────');
|
|
399
|
+
lines.push('Role: You are the Challenger agent. Your job is to STRESS-TEST the documentation');
|
|
400
|
+
lines.push('and identify gaps, inconsistencies, and risks that the issues list might miss.');
|
|
401
|
+
lines.push('');
|
|
402
|
+
lines.push('Instructions:');
|
|
403
|
+
lines.push('1. For each issue listed above, explain WHY it matters and what the root cause is');
|
|
404
|
+
lines.push('2. Identify any ADDITIONAL issues not caught by docguard guard');
|
|
405
|
+
lines.push('3. Check: Are there undocumented API routes? Missing env vars? Stale references?');
|
|
406
|
+
lines.push('4. Rank all issues by business impact (P0 = blocks deployment, P1 = degrades quality, P2 = cosmetic)');
|
|
407
|
+
lines.push('');
|
|
408
|
+
|
|
409
|
+
// ── Agent 3: Synthesizer ──
|
|
410
|
+
lines.push('───────────────────────────────────────────────────────');
|
|
411
|
+
lines.push('PERSPECTIVE 3: SYNTHESIZER (Prioritized remediation plan)');
|
|
412
|
+
lines.push('───────────────────────────────────────────────────────');
|
|
413
|
+
lines.push('Role: You are the Synthesizer agent. Given the Advocate\'s strengths and the');
|
|
414
|
+
lines.push('Challenger\'s gaps, produce a PRIORITIZED and ACTIONABLE remediation plan.');
|
|
415
|
+
lines.push('');
|
|
416
|
+
lines.push('Instructions:');
|
|
417
|
+
lines.push('1. Preserve the patterns the Advocate identified as strengths');
|
|
418
|
+
lines.push('2. Address the Challenger\'s issues in priority order (P0 → P1 → P2)');
|
|
419
|
+
lines.push('3. For each fix, specify:');
|
|
420
|
+
lines.push(' a. Which file to edit');
|
|
421
|
+
lines.push(' b. What section to add or modify');
|
|
422
|
+
lines.push(' c. What content to write (be specific, not vague)');
|
|
423
|
+
lines.push('4. After all fixes, verify with: docguard guard');
|
|
424
|
+
lines.push(`5. Target score: ≥${Math.min(scoreData.score + 10, 100)}/100`);
|
|
425
|
+
lines.push('');
|
|
426
|
+
lines.push('═══════════════════════════════════════════════════════');
|
|
427
|
+
lines.push('Execute all three perspectives in sequence, then implement the Synthesizer\'s plan.');
|
|
428
|
+
lines.push('═══════════════════════════════════════════════════════');
|
|
429
|
+
|
|
272
430
|
console.log(lines.join('\n'));
|
|
273
431
|
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Detect the AI agent tier from AGENTS.md or .docguard.json.
|
|
435
|
+
* Returns 'advanced' (concise prompts) or 'basic' (verbose step-by-step).
|
|
436
|
+
* Inspired by CJE equalizer effect (Lopez et al., TRACE, IEEE TMLCN 2026).
|
|
437
|
+
*/
|
|
438
|
+
function detectAgentTier(projectDir) {
|
|
439
|
+
// Check .docguard.json for explicit agent config
|
|
440
|
+
const configPath = resolve(projectDir, '.docguard.json');
|
|
441
|
+
if (existsSync(configPath)) {
|
|
442
|
+
try {
|
|
443
|
+
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
444
|
+
if (config.agentTier) return config.agentTier;
|
|
445
|
+
} catch { /* ignore */ }
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Check AGENTS.md for known agent names
|
|
449
|
+
const agentFiles = ['AGENTS.md', 'CLAUDE.md', '.github/copilot-instructions.md'];
|
|
450
|
+
for (const file of agentFiles) {
|
|
451
|
+
const agentPath = resolve(projectDir, file);
|
|
452
|
+
if (existsSync(agentPath)) {
|
|
453
|
+
const content = readFileSync(agentPath, 'utf-8').toLowerCase();
|
|
454
|
+
// Advanced agents: Claude, GPT-4, Gemini Pro
|
|
455
|
+
const advancedMarkers = ['claude', 'gpt-4', 'gemini pro', 'gemini 2', 'opus', 'sonnet'];
|
|
456
|
+
if (advancedMarkers.some(m => content.includes(m))) {
|
|
457
|
+
return 'advanced';
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Default to advanced (most users run modern models)
|
|
463
|
+
return 'advanced';
|
|
464
|
+
}
|