docguard-cli 0.30.0 → 0.30.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/README.md +2 -0
- package/cli/commands/mcp.mjs +20 -0
- package/cli/commands/score.mjs +9 -4
- package/cli/commands/setup.mjs +0 -13
- package/cli/shared-git.mjs +8 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
[](https://nodejs.org)
|
|
14
14
|
[-green)](package.json)
|
|
15
15
|
[](https://github.com/github/spec-kit)
|
|
16
|
+
[](https://glama.ai/mcp/servers/raccioly/docguard)
|
|
17
|
+
[](https://registry.modelcontextprotocol.io/)
|
|
16
18
|
|
|
17
19
|
---
|
|
18
20
|
|
package/cli/commands/mcp.mjs
CHANGED
|
@@ -53,25 +53,40 @@ const PROJECT_DIR_PROP = {
|
|
|
53
53
|
},
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
+
// Every DocGuard MCP tool is READ-ONLY: it inspects local project files and
|
|
57
|
+
// never writes, mutates, or reaches the network. These MCP tool hints let
|
|
58
|
+
// clients (and directory scanners like Glama) surface that safety to users.
|
|
59
|
+
const READONLY_ANNOTATIONS = {
|
|
60
|
+
readOnlyHint: true,
|
|
61
|
+
destructiveHint: false,
|
|
62
|
+
idempotentHint: true,
|
|
63
|
+
openWorldHint: false,
|
|
64
|
+
};
|
|
65
|
+
|
|
56
66
|
const TOOLS = [
|
|
57
67
|
{
|
|
58
68
|
name: 'docguard_guard',
|
|
69
|
+
title: 'Guard docs against code',
|
|
59
70
|
description: 'Run every enabled DocGuard validator against the project\'s canonical docs. Returns the full guard JSON contract: status (PASS/WARN/FAIL), structured findings with stable codes and suggestions, nextStep, doc coverage map, semantic-claim count, and per-validator results.',
|
|
60
71
|
inputSchema: {
|
|
61
72
|
type: 'object',
|
|
62
73
|
properties: { ...PROJECT_DIR_PROP },
|
|
63
74
|
},
|
|
75
|
+
annotations: READONLY_ANNOTATIONS,
|
|
64
76
|
},
|
|
65
77
|
{
|
|
66
78
|
name: 'docguard_score',
|
|
79
|
+
title: 'CDD maturity score',
|
|
67
80
|
description: 'Compute the project\'s CDD maturity score (0-100) with letter grade and per-category breakdown.',
|
|
68
81
|
inputSchema: {
|
|
69
82
|
type: 'object',
|
|
70
83
|
properties: { ...PROJECT_DIR_PROP },
|
|
71
84
|
},
|
|
85
|
+
annotations: READONLY_ANNOTATIONS,
|
|
72
86
|
},
|
|
73
87
|
{
|
|
74
88
|
name: 'docguard_explain',
|
|
89
|
+
title: 'Explain a finding code',
|
|
75
90
|
description: 'Explain a stable DocGuard finding code (e.g. STR001, ENV003): what it means, which validator emits it, and the inline suppression to use if it\'s a confirmed false positive.',
|
|
76
91
|
inputSchema: {
|
|
77
92
|
type: 'object',
|
|
@@ -83,22 +98,27 @@ const TOOLS = [
|
|
|
83
98
|
},
|
|
84
99
|
required: ['code'],
|
|
85
100
|
},
|
|
101
|
+
annotations: READONLY_ANNOTATIONS,
|
|
86
102
|
},
|
|
87
103
|
{
|
|
88
104
|
name: 'docguard_verify_claims',
|
|
105
|
+
title: 'Extract claims to verify',
|
|
89
106
|
description: 'Extract the semantic claims in the project\'s canonical docs — documented numbers, limits, and enums — as a verification task list. Deterministic discovery, LLM judgment — the caller verifies each claim against the code.',
|
|
90
107
|
inputSchema: {
|
|
91
108
|
type: 'object',
|
|
92
109
|
properties: { ...PROJECT_DIR_PROP },
|
|
93
110
|
},
|
|
111
|
+
annotations: READONLY_ANNOTATIONS,
|
|
94
112
|
},
|
|
95
113
|
{
|
|
96
114
|
name: 'docguard_diagnose',
|
|
115
|
+
title: 'Diagnose what to fix',
|
|
97
116
|
description: 'Run guard and return only what needs fixing: failing/warning validators with their messages, structured findings, and suggested next actions — shaped for an agent to act on.',
|
|
98
117
|
inputSchema: {
|
|
99
118
|
type: 'object',
|
|
100
119
|
properties: { ...PROJECT_DIR_PROP },
|
|
101
120
|
},
|
|
121
|
+
annotations: READONLY_ANNOTATIONS,
|
|
102
122
|
},
|
|
103
123
|
];
|
|
104
124
|
|
package/cli/commands/score.mjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
7
7
|
import { resolve, join, extname } from 'node:path';
|
|
8
|
-
import {
|
|
8
|
+
import { execFileSync } from 'node:child_process';
|
|
9
9
|
import { c, docHasSection } from '../shared.mjs';
|
|
10
10
|
import { validateSecurity } from '../validators/security.mjs';
|
|
11
11
|
import { runGuardInternal } from './guard.mjs';
|
|
@@ -1039,11 +1039,16 @@ function estimateDocTax(projectDir, config, scores) {
|
|
|
1039
1039
|
// Estimate code churn (commits in last 30 days)
|
|
1040
1040
|
let recentCommits = 0;
|
|
1041
1041
|
try {
|
|
1042
|
-
|
|
1042
|
+
// execFileSync (argv array) + count in JS — avoids the shell `| wc -l` pipe,
|
|
1043
|
+
// which isn't portable to Windows (no `wc`) and needs a shell at all. Same
|
|
1044
|
+
// pattern freshness.mjs already uses for commit counting.
|
|
1045
|
+
const output = execFileSync('git', ['log', '--oneline', '--since=30 days ago'], {
|
|
1043
1046
|
cwd: projectDir,
|
|
1044
1047
|
encoding: 'utf-8',
|
|
1045
|
-
|
|
1046
|
-
|
|
1048
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
1049
|
+
maxBuffer: 1024 * 1024 * 5,
|
|
1050
|
+
});
|
|
1051
|
+
recentCommits = output.trim() ? output.trim().split('\n').length : 0;
|
|
1047
1052
|
} catch {
|
|
1048
1053
|
recentCommits = 10; // Default assumption
|
|
1049
1054
|
}
|
package/cli/commands/setup.mjs
CHANGED
|
@@ -21,7 +21,6 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from
|
|
|
21
21
|
import { resolve, dirname, basename } from 'node:path';
|
|
22
22
|
import { fileURLToPath } from 'node:url';
|
|
23
23
|
import { createInterface } from 'node:readline';
|
|
24
|
-
import { execSync } from 'node:child_process';
|
|
25
24
|
import { c, CURRENT_SCHEMA_VERSION } from '../shared.mjs';
|
|
26
25
|
import { ensureSkills, detectAgentMode, isSpecKitInitialized, getDetectedAgent } from '../ensure-skills.mjs';
|
|
27
26
|
|
|
@@ -70,18 +69,6 @@ function detectProjectType(dir) {
|
|
|
70
69
|
return 'unknown';
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
// ── CLI Detection ───────────────────────────────────────────────────────
|
|
74
|
-
|
|
75
|
-
function isCliAvailable(name) {
|
|
76
|
-
try {
|
|
77
|
-
const cmd = process.platform === 'win32' ? `where ${name}` : `which ${name}`;
|
|
78
|
-
execSync(`${cmd} 2>/dev/null`, { encoding: 'utf-8', timeout: 3000 });
|
|
79
|
-
return true;
|
|
80
|
-
} catch {
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
72
|
function detectAgentDirs(projectDir) {
|
|
86
73
|
const agentDirs = [
|
|
87
74
|
{ name: 'GitHub Copilot', dir: '.github', commandsPath: '.github/commands' },
|
package/cli/shared-git.mjs
CHANGED
|
@@ -167,7 +167,14 @@ export function getHooksDir(dir) {
|
|
|
167
167
|
).trim();
|
|
168
168
|
// --git-path returns a path relative to `dir` (cwd) or an absolute path;
|
|
169
169
|
// resolve() handles both.
|
|
170
|
-
|
|
170
|
+
//
|
|
171
|
+
// Guard `/dev/null`: when `core.hooksPath` is set to /dev/null (a common
|
|
172
|
+
// "disable all hooks" convention — and what Jules's sandbox VM does),
|
|
173
|
+
// git returns the literal `/dev/null`. resolve()-ing it and then writing
|
|
174
|
+
// `<hooksDir>/pre-commit` gives `ENOTDIR: /dev/null/pre-commit`. Treat it
|
|
175
|
+
// as "no usable hooks dir" and fall through to the `.git/hooks` check so
|
|
176
|
+
// hook install/list still works in that environment. (bug-200)
|
|
177
|
+
if (out && out !== '/dev/null') return resolve(dir, out);
|
|
171
178
|
} catch {
|
|
172
179
|
// git unavailable or not a repo — fall through to the literal-path check.
|
|
173
180
|
}
|
package/package.json
CHANGED