@kiwidata/grimoire 0.1.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.
Files changed (215) hide show
  1. package/.claude-plugin/plugin.json +8 -0
  2. package/AGENTS.md +217 -0
  3. package/README.md +748 -0
  4. package/bin/grimoire.js +2 -0
  5. package/dist/cli/index.d.ts +2 -0
  6. package/dist/cli/index.d.ts.map +1 -0
  7. package/dist/cli/index.js +42 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/commands/archive.d.ts +3 -0
  10. package/dist/commands/archive.d.ts.map +1 -0
  11. package/dist/commands/archive.js +22 -0
  12. package/dist/commands/archive.js.map +1 -0
  13. package/dist/commands/branch-check.d.ts +3 -0
  14. package/dist/commands/branch-check.d.ts.map +1 -0
  15. package/dist/commands/branch-check.js +16 -0
  16. package/dist/commands/branch-check.js.map +1 -0
  17. package/dist/commands/check.d.ts +3 -0
  18. package/dist/commands/check.d.ts.map +1 -0
  19. package/dist/commands/check.js +22 -0
  20. package/dist/commands/check.js.map +1 -0
  21. package/dist/commands/ci.d.ts +3 -0
  22. package/dist/commands/ci.d.ts.map +1 -0
  23. package/dist/commands/ci.js +18 -0
  24. package/dist/commands/ci.js.map +1 -0
  25. package/dist/commands/diff.d.ts +3 -0
  26. package/dist/commands/diff.d.ts.map +1 -0
  27. package/dist/commands/diff.js +10 -0
  28. package/dist/commands/diff.js.map +1 -0
  29. package/dist/commands/docs.d.ts +3 -0
  30. package/dist/commands/docs.d.ts.map +1 -0
  31. package/dist/commands/docs.js +11 -0
  32. package/dist/commands/docs.js.map +1 -0
  33. package/dist/commands/health.d.ts +3 -0
  34. package/dist/commands/health.d.ts.map +1 -0
  35. package/dist/commands/health.js +13 -0
  36. package/dist/commands/health.js.map +1 -0
  37. package/dist/commands/init.d.ts +3 -0
  38. package/dist/commands/init.d.ts.map +1 -0
  39. package/dist/commands/init.js +21 -0
  40. package/dist/commands/init.js.map +1 -0
  41. package/dist/commands/list.d.ts +3 -0
  42. package/dist/commands/list.d.ts.map +1 -0
  43. package/dist/commands/list.js +22 -0
  44. package/dist/commands/list.js.map +1 -0
  45. package/dist/commands/log.d.ts +3 -0
  46. package/dist/commands/log.d.ts.map +1 -0
  47. package/dist/commands/log.js +15 -0
  48. package/dist/commands/log.js.map +1 -0
  49. package/dist/commands/map.d.ts +3 -0
  50. package/dist/commands/map.d.ts.map +1 -0
  51. package/dist/commands/map.js +17 -0
  52. package/dist/commands/map.js.map +1 -0
  53. package/dist/commands/pr.d.ts +3 -0
  54. package/dist/commands/pr.d.ts.map +1 -0
  55. package/dist/commands/pr.js +17 -0
  56. package/dist/commands/pr.js.map +1 -0
  57. package/dist/commands/status.d.ts +3 -0
  58. package/dist/commands/status.d.ts.map +1 -0
  59. package/dist/commands/status.js +12 -0
  60. package/dist/commands/status.js.map +1 -0
  61. package/dist/commands/test-quality.d.ts +3 -0
  62. package/dist/commands/test-quality.d.ts.map +1 -0
  63. package/dist/commands/test-quality.js +37 -0
  64. package/dist/commands/test-quality.js.map +1 -0
  65. package/dist/commands/trace.d.ts +3 -0
  66. package/dist/commands/trace.d.ts.map +1 -0
  67. package/dist/commands/trace.js +12 -0
  68. package/dist/commands/trace.js.map +1 -0
  69. package/dist/commands/update.d.ts +3 -0
  70. package/dist/commands/update.d.ts.map +1 -0
  71. package/dist/commands/update.js +22 -0
  72. package/dist/commands/update.js.map +1 -0
  73. package/dist/commands/validate.d.ts +3 -0
  74. package/dist/commands/validate.d.ts.map +1 -0
  75. package/dist/commands/validate.js +17 -0
  76. package/dist/commands/validate.js.map +1 -0
  77. package/dist/core/archive.d.ts +9 -0
  78. package/dist/core/archive.d.ts.map +1 -0
  79. package/dist/core/archive.js +92 -0
  80. package/dist/core/archive.js.map +1 -0
  81. package/dist/core/branch-check.d.ts +27 -0
  82. package/dist/core/branch-check.d.ts.map +1 -0
  83. package/dist/core/branch-check.js +205 -0
  84. package/dist/core/branch-check.js.map +1 -0
  85. package/dist/core/check.d.ts +24 -0
  86. package/dist/core/check.d.ts.map +1 -0
  87. package/dist/core/check.js +372 -0
  88. package/dist/core/check.js.map +1 -0
  89. package/dist/core/ci.d.ts +24 -0
  90. package/dist/core/ci.d.ts.map +1 -0
  91. package/dist/core/ci.js +162 -0
  92. package/dist/core/ci.js.map +1 -0
  93. package/dist/core/detect.d.ts +10 -0
  94. package/dist/core/detect.d.ts.map +1 -0
  95. package/dist/core/detect.js +368 -0
  96. package/dist/core/detect.js.map +1 -0
  97. package/dist/core/diff.d.ts +29 -0
  98. package/dist/core/diff.d.ts.map +1 -0
  99. package/dist/core/diff.js +197 -0
  100. package/dist/core/diff.js.map +1 -0
  101. package/dist/core/doc-style.d.ts +16 -0
  102. package/dist/core/doc-style.d.ts.map +1 -0
  103. package/dist/core/doc-style.js +192 -0
  104. package/dist/core/doc-style.js.map +1 -0
  105. package/dist/core/docs.d.ts +6 -0
  106. package/dist/core/docs.d.ts.map +1 -0
  107. package/dist/core/docs.js +478 -0
  108. package/dist/core/docs.js.map +1 -0
  109. package/dist/core/health.d.ts +7 -0
  110. package/dist/core/health.d.ts.map +1 -0
  111. package/dist/core/health.js +489 -0
  112. package/dist/core/health.js.map +1 -0
  113. package/dist/core/hooks.d.ts +5 -0
  114. package/dist/core/hooks.d.ts.map +1 -0
  115. package/dist/core/hooks.js +168 -0
  116. package/dist/core/hooks.js.map +1 -0
  117. package/dist/core/init.d.ts +9 -0
  118. package/dist/core/init.d.ts.map +1 -0
  119. package/dist/core/init.js +563 -0
  120. package/dist/core/init.js.map +1 -0
  121. package/dist/core/list.d.ts +4 -0
  122. package/dist/core/list.d.ts.map +1 -0
  123. package/dist/core/list.js +170 -0
  124. package/dist/core/list.js.map +1 -0
  125. package/dist/core/log.d.ts +8 -0
  126. package/dist/core/log.d.ts.map +1 -0
  127. package/dist/core/log.js +150 -0
  128. package/dist/core/log.js.map +1 -0
  129. package/dist/core/map.d.ts +9 -0
  130. package/dist/core/map.d.ts.map +1 -0
  131. package/dist/core/map.js +302 -0
  132. package/dist/core/map.js.map +1 -0
  133. package/dist/core/pr.d.ts +9 -0
  134. package/dist/core/pr.d.ts.map +1 -0
  135. package/dist/core/pr.js +273 -0
  136. package/dist/core/pr.js.map +1 -0
  137. package/dist/core/shared-setup.d.ts +52 -0
  138. package/dist/core/shared-setup.d.ts.map +1 -0
  139. package/dist/core/shared-setup.js +221 -0
  140. package/dist/core/shared-setup.js.map +1 -0
  141. package/dist/core/status.d.ts +6 -0
  142. package/dist/core/status.d.ts.map +1 -0
  143. package/dist/core/status.js +114 -0
  144. package/dist/core/status.js.map +1 -0
  145. package/dist/core/test-quality.d.ts +33 -0
  146. package/dist/core/test-quality.d.ts.map +1 -0
  147. package/dist/core/test-quality.js +378 -0
  148. package/dist/core/test-quality.js.map +1 -0
  149. package/dist/core/trace.d.ts +6 -0
  150. package/dist/core/trace.d.ts.map +1 -0
  151. package/dist/core/trace.js +211 -0
  152. package/dist/core/trace.js.map +1 -0
  153. package/dist/core/update.d.ts +10 -0
  154. package/dist/core/update.d.ts.map +1 -0
  155. package/dist/core/update.js +149 -0
  156. package/dist/core/update.js.map +1 -0
  157. package/dist/core/validate.d.ts +20 -0
  158. package/dist/core/validate.d.ts.map +1 -0
  159. package/dist/core/validate.js +275 -0
  160. package/dist/core/validate.js.map +1 -0
  161. package/dist/index.d.ts +19 -0
  162. package/dist/index.d.ts.map +1 -0
  163. package/dist/index.js +20 -0
  164. package/dist/index.js.map +1 -0
  165. package/dist/utils/config.d.ts +61 -0
  166. package/dist/utils/config.d.ts.map +1 -0
  167. package/dist/utils/config.js +172 -0
  168. package/dist/utils/config.js.map +1 -0
  169. package/dist/utils/fs.d.ts +17 -0
  170. package/dist/utils/fs.d.ts.map +1 -0
  171. package/dist/utils/fs.js +38 -0
  172. package/dist/utils/fs.js.map +1 -0
  173. package/dist/utils/paths.d.ts +10 -0
  174. package/dist/utils/paths.d.ts.map +1 -0
  175. package/dist/utils/paths.js +35 -0
  176. package/dist/utils/paths.js.map +1 -0
  177. package/dist/utils/spawn.d.ts +5 -0
  178. package/dist/utils/spawn.d.ts.map +1 -0
  179. package/dist/utils/spawn.js +34 -0
  180. package/dist/utils/spawn.js.map +1 -0
  181. package/package.json +68 -0
  182. package/skills/grimoire-apply/SKILL.md +274 -0
  183. package/skills/grimoire-audit/SKILL.md +129 -0
  184. package/skills/grimoire-branch-guard/SKILL.md +111 -0
  185. package/skills/grimoire-bug/SKILL.md +160 -0
  186. package/skills/grimoire-bug-explore/SKILL.md +242 -0
  187. package/skills/grimoire-bug-report/SKILL.md +237 -0
  188. package/skills/grimoire-bug-session/SKILL.md +222 -0
  189. package/skills/grimoire-bug-triage/SKILL.md +274 -0
  190. package/skills/grimoire-commit/SKILL.md +150 -0
  191. package/skills/grimoire-discover/SKILL.md +297 -0
  192. package/skills/grimoire-draft/SKILL.md +202 -0
  193. package/skills/grimoire-plan/SKILL.md +329 -0
  194. package/skills/grimoire-pr/SKILL.md +134 -0
  195. package/skills/grimoire-pr-review/SKILL.md +240 -0
  196. package/skills/grimoire-refactor/SKILL.md +251 -0
  197. package/skills/grimoire-remove/SKILL.md +112 -0
  198. package/skills/grimoire-review/SKILL.md +247 -0
  199. package/skills/grimoire-verify/SKILL.md +223 -0
  200. package/skills/references/bug-classification.md +154 -0
  201. package/skills/references/build-vs-buy.md +77 -0
  202. package/skills/references/elicitation-personas.md +118 -0
  203. package/skills/references/refactor-register-format.md +88 -0
  204. package/skills/references/refactor-scan-categories.md +102 -0
  205. package/skills/references/schema-format.md +68 -0
  206. package/skills/references/security-compliance.md +110 -0
  207. package/skills/references/testing-contracts.md +93 -0
  208. package/templates/context.yml +110 -0
  209. package/templates/debt-exceptions.yml +61 -0
  210. package/templates/decision.md +50 -0
  211. package/templates/dupignore +93 -0
  212. package/templates/example.feature +24 -0
  213. package/templates/manifest.md +29 -0
  214. package/templates/mapignore +58 -0
  215. package/templates/mapkeys +65 -0
@@ -0,0 +1,489 @@
1
+ import { readdir, readFile, writeFile } from "node:fs/promises";
2
+ import { join, relative } from "node:path";
3
+ import { execFile } from "node:child_process";
4
+ import { promisify } from "node:util";
5
+ import chalk from "chalk";
6
+ import { parse as parseYaml } from "yaml";
7
+ import matter from "gray-matter";
8
+ import { findProjectRoot, safePath } from "../utils/paths.js";
9
+ import { loadConfig } from "../utils/config.js";
10
+ import { readFileOrNull, escapeRegex, findFiles } from "../utils/fs.js";
11
+ const execFileAsync = promisify(execFile);
12
+ export async function runHealth(options) {
13
+ const root = await findProjectRoot();
14
+ const config = await loadConfig(root);
15
+ const metrics = [];
16
+ // Run all checks in parallel where possible
17
+ const [features, decisions, areaDocs, dataSchema, testCoverage, unitCoverage, duplicates, complexity] = await Promise.all([
18
+ checkFeatures(root),
19
+ checkDecisions(root),
20
+ checkAreaDocs(root),
21
+ checkDataSchema(root),
22
+ checkTestCoverage(root),
23
+ checkUnitTestCoverage(root, config),
24
+ checkDuplicates(root, config),
25
+ checkComplexity(root, config),
26
+ ]);
27
+ metrics.push(features, decisions, areaDocs, dataSchema, testCoverage, unitCoverage, duplicates, complexity);
28
+ // Calculate overall (average of scored metrics)
29
+ const scored = metrics.filter((m) => m.score !== null);
30
+ const overall = scored.length > 0
31
+ ? Math.round(scored.reduce((sum, m) => sum + m.score, 0) / scored.length)
32
+ : 0;
33
+ const result = { metrics, overall };
34
+ if (options.json) {
35
+ console.log(JSON.stringify(result, null, 2));
36
+ }
37
+ else {
38
+ printHealth(result);
39
+ }
40
+ if (options.badges) {
41
+ await writeBadges(root, options.badges, result);
42
+ }
43
+ }
44
+ // --- Metrics ---
45
+ async function checkFeatures(root) {
46
+ const featuresDir = join(root, "features");
47
+ let featureFiles;
48
+ try {
49
+ featureFiles = await findFiles(featuresDir, ".feature");
50
+ }
51
+ catch {
52
+ return { name: "features", score: null, label: "no features/" };
53
+ }
54
+ if (featureFiles.length === 0) {
55
+ return { name: "features", score: null, label: "no features found" };
56
+ }
57
+ let totalScenarios = 0;
58
+ for (const file of featureFiles) {
59
+ const content = await readFileOrNull(file);
60
+ if (!content)
61
+ continue;
62
+ const scenarios = content.match(/^\s*Scenario(?: Outline)?:/gm);
63
+ totalScenarios += scenarios?.length ?? 0;
64
+ }
65
+ // We can't run tests here (that's what grimoire check does),
66
+ // so we report scenario count. Score based on having scenarios at all.
67
+ const hasScenarios = totalScenarios > 0;
68
+ return {
69
+ name: "features",
70
+ score: hasScenarios ? 100 : 0,
71
+ label: `${totalScenarios} scenario${totalScenarios !== 1 ? "s" : ""} in ${featureFiles.length} file${featureFiles.length !== 1 ? "s" : ""}`,
72
+ };
73
+ }
74
+ async function checkDecisions(root) {
75
+ const decisionsDir = join(root, ".grimoire", "decisions");
76
+ let files;
77
+ try {
78
+ const entries = await readdir(decisionsDir);
79
+ files = entries.filter((f) => f.endsWith(".md") && f !== "template.md");
80
+ }
81
+ catch {
82
+ return { name: "decisions", score: null, label: "no decisions/" };
83
+ }
84
+ if (files.length === 0) {
85
+ return { name: "decisions", score: null, label: "no decisions found" };
86
+ }
87
+ let current = 0;
88
+ let total = 0;
89
+ for (const file of files) {
90
+ const content = await readFileOrNull(join(decisionsDir, file));
91
+ if (!content)
92
+ continue;
93
+ total++;
94
+ const { data: fm } = matter(content);
95
+ const status = fm.status ? String(fm.status).trim() : "";
96
+ if (!status.includes("superseded")) {
97
+ current++;
98
+ }
99
+ }
100
+ const score = total > 0 ? Math.round((current / total) * 100) : 0;
101
+ return {
102
+ name: "decisions",
103
+ score,
104
+ label: `${current}/${total} current`,
105
+ };
106
+ }
107
+ async function checkAreaDocs(root) {
108
+ const indexPath = join(root, ".grimoire", "docs", "index.yml");
109
+ const snapshotPath = join(root, ".grimoire", "docs", ".snapshot.json");
110
+ let documented = 0;
111
+ try {
112
+ const indexContent = await readFile(indexPath, "utf-8");
113
+ const index = parseYaml(indexContent);
114
+ documented = index?.areas?.length ?? 0;
115
+ }
116
+ catch {
117
+ return {
118
+ name: "area_docs",
119
+ score: 0,
120
+ label: "no area docs (run grimoire map + discover)",
121
+ };
122
+ }
123
+ // Count total areas from snapshot
124
+ let totalAreas = documented;
125
+ try {
126
+ const snapshotContent = await readFile(snapshotPath, "utf-8");
127
+ const snapshot = JSON.parse(snapshotContent);
128
+ if (snapshot.directories) {
129
+ // Count top-level directories as areas
130
+ totalAreas = Math.max(Object.keys(snapshot.directories).length, documented);
131
+ }
132
+ }
133
+ catch {
134
+ // No snapshot — use documented count as total
135
+ }
136
+ const score = totalAreas > 0 ? Math.round((documented / totalAreas) * 100) : 0;
137
+ return {
138
+ name: "area_docs",
139
+ score,
140
+ label: `${documented}/${totalAreas} areas documented`,
141
+ };
142
+ }
143
+ async function checkDataSchema(root) {
144
+ const schemaPath = join(root, ".grimoire", "docs", "data", "schema.yml");
145
+ let schemaContent;
146
+ try {
147
+ schemaContent = await readFile(schemaPath, "utf-8");
148
+ }
149
+ catch {
150
+ return {
151
+ name: "data_schema",
152
+ score: null,
153
+ label: "no schema.yml",
154
+ };
155
+ }
156
+ const schema = parseYaml(schemaContent);
157
+ if (!schema) {
158
+ return { name: "data_schema", score: null, label: "empty schema" };
159
+ }
160
+ const modelCount = Object.keys(schema).length;
161
+ // If schema exists and has models, it's documented
162
+ return {
163
+ name: "data_schema",
164
+ score: modelCount > 0 ? 100 : 0,
165
+ label: `${modelCount} model${modelCount !== 1 ? "s" : ""} documented`,
166
+ };
167
+ }
168
+ async function checkTestCoverage(root) {
169
+ const featuresDir = join(root, "features");
170
+ let featureFiles;
171
+ try {
172
+ featureFiles = await findFiles(featuresDir, ".feature");
173
+ }
174
+ catch {
175
+ return { name: "test_coverage", score: null, label: "no features/" };
176
+ }
177
+ if (featureFiles.length === 0) {
178
+ return { name: "test_coverage", score: null, label: "no features" };
179
+ }
180
+ // For each feature file, check if step definitions exist somewhere
181
+ // Look for step_defs/, steps/, step_definitions/ directories
182
+ let withSteps = 0;
183
+ const stepDirs = await findStepDirectories(root);
184
+ if (stepDirs.length === 0) {
185
+ return {
186
+ name: "test_coverage",
187
+ score: 0,
188
+ label: `0/${featureFiles.length} features have step definitions`,
189
+ detail: "No step definition directories found",
190
+ };
191
+ }
192
+ // Read all step definition content for matching
193
+ const allStepContent = await readAllFiles(stepDirs);
194
+ for (const file of featureFiles) {
195
+ const content = await readFileOrNull(file);
196
+ if (!content)
197
+ continue;
198
+ // Extract scenario names and step text
199
+ const steps = content.match(/^\s+(?:Given|When|Then|And|But)\s+(.+)$/gm);
200
+ if (!steps || steps.length === 0)
201
+ continue;
202
+ // Check if any step text appears in step definitions (loose match)
203
+ const hasSteps = steps.some((step) => {
204
+ const text = step.replace(/^\s+(?:Given|When|Then|And|But)\s+/, "");
205
+ // Check for step text or key words from it in step defs
206
+ const keywords = text
207
+ .split(/\s+/)
208
+ .filter((w) => w.length > 4)
209
+ .slice(0, 3);
210
+ return keywords.some((kw) => allStepContent.some((sc) => sc.includes(kw)));
211
+ });
212
+ if (hasSteps)
213
+ withSteps++;
214
+ }
215
+ const score = featureFiles.length > 0
216
+ ? Math.round((withSteps / featureFiles.length) * 100)
217
+ : 0;
218
+ return {
219
+ name: "test_coverage",
220
+ score,
221
+ label: `${withSteps}/${featureFiles.length} features have step definitions`,
222
+ };
223
+ }
224
+ async function checkUnitTestCoverage(root, config) {
225
+ // Try to get coverage from common coverage report locations
226
+ const coveragePaths = [
227
+ join(root, "coverage", "coverage-summary.json"), // jest/vitest
228
+ join(root, "htmlcov", "status.json"), // pytest-cov
229
+ join(root, ".coverage.json"), // custom
230
+ join(root, "coverage.json"),
231
+ ];
232
+ for (const coveragePath of coveragePaths) {
233
+ try {
234
+ const content = await readFile(coveragePath, "utf-8");
235
+ const data = JSON.parse(content);
236
+ // jest/vitest format
237
+ if (data.total?.lines?.pct !== undefined) {
238
+ const pct = Math.round(data.total.lines.pct);
239
+ return {
240
+ name: "unit_coverage",
241
+ score: pct,
242
+ label: `${pct}% line coverage`,
243
+ detail: relative(root, coveragePath),
244
+ };
245
+ }
246
+ // pytest-cov JSON format
247
+ if (data.totals?.percent_covered !== undefined) {
248
+ const pct = Math.round(data.totals.percent_covered);
249
+ return {
250
+ name: "unit_coverage",
251
+ score: pct,
252
+ label: `${pct}% line coverage`,
253
+ detail: relative(root, coveragePath),
254
+ };
255
+ }
256
+ }
257
+ catch {
258
+ continue;
259
+ }
260
+ }
261
+ // Try running coverage command if configured
262
+ const unitTool = config.tools.unit_test;
263
+ if (unitTool?.command) {
264
+ // Try common coverage flags
265
+ const coverageCommands = detectCoverageCommand(unitTool, config);
266
+ if (coverageCommands) {
267
+ try {
268
+ const { stdout } = await execFileAsync("sh", ["-c", coverageCommands], { cwd: root, timeout: 120_000 });
269
+ // Parse percentage from output (most tools print "XX%" or "XX.X%")
270
+ const pctMatch = stdout.match(/(?:total|overall|TOTAL)[^\d]*(\d+(?:\.\d+)?)\s*%/i);
271
+ if (pctMatch) {
272
+ const pct = Math.round(parseFloat(pctMatch[1]));
273
+ return {
274
+ name: "unit_coverage",
275
+ score: pct,
276
+ label: `${pct}% line coverage`,
277
+ };
278
+ }
279
+ }
280
+ catch {
281
+ // Coverage command failed
282
+ }
283
+ }
284
+ }
285
+ return {
286
+ name: "unit_coverage",
287
+ score: null,
288
+ label: "no coverage data (run tests with --coverage)",
289
+ };
290
+ }
291
+ function detectCoverageCommand(unitTool, config) {
292
+ const name = unitTool.name.toLowerCase();
293
+ const lang = config.project.language?.toLowerCase() ?? "";
294
+ if (name === "pytest" || lang === "python") {
295
+ return `${unitTool.command ?? "pytest"} --cov --cov-report=term 2>/dev/null || true`;
296
+ }
297
+ if (name === "vitest") {
298
+ return `npx vitest run --coverage --reporter=default 2>/dev/null || true`;
299
+ }
300
+ if (name === "jest") {
301
+ return `npx jest --coverage --coverageReporters=text 2>/dev/null || true`;
302
+ }
303
+ if (name === "go" || lang === "go") {
304
+ return `go test ./... -coverprofile=/dev/null -covermode=atomic 2>&1 | grep total || true`;
305
+ }
306
+ return null;
307
+ }
308
+ async function checkDuplicates(root, config) {
309
+ const tool = config.tools.duplicates;
310
+ if (!tool?.command) {
311
+ return {
312
+ name: "duplicates",
313
+ score: null,
314
+ label: "not configured",
315
+ };
316
+ }
317
+ try {
318
+ const { stdout } = await execFileAsync("sh", ["-c", tool.command], { cwd: root, timeout: 60_000 });
319
+ // jscpd typically reports "Found X clones"
320
+ const cloneMatch = stdout.match(/Found\s+(\d+)\s+clone/i);
321
+ const clones = cloneMatch ? parseInt(cloneMatch[1], 10) : 0;
322
+ return {
323
+ name: "duplicates",
324
+ score: null, // informational
325
+ label: clones === 0
326
+ ? "no clones detected"
327
+ : `${clones} clone${clones !== 1 ? "s" : ""} detected`,
328
+ };
329
+ }
330
+ catch {
331
+ return {
332
+ name: "duplicates",
333
+ score: null,
334
+ label: "jscpd not available",
335
+ };
336
+ }
337
+ }
338
+ async function checkComplexity(root, config) {
339
+ const tool = config.tools.complexity;
340
+ if (!tool?.command) {
341
+ return {
342
+ name: "complexity",
343
+ score: null,
344
+ label: "not configured",
345
+ };
346
+ }
347
+ try {
348
+ const { stdout } = await execFileAsync("sh", ["-c", tool.command], { cwd: root, timeout: 60_000 });
349
+ // radon typically shows grade letters (A-F)
350
+ const highComplexity = (stdout.match(/\b[D-F]\b/g) || []).length;
351
+ return {
352
+ name: "complexity",
353
+ score: null, // informational
354
+ label: highComplexity === 0
355
+ ? "no high-complexity functions"
356
+ : `${highComplexity} function${highComplexity !== 1 ? "s" : ""} above threshold`,
357
+ };
358
+ }
359
+ catch {
360
+ return {
361
+ name: "complexity",
362
+ score: null,
363
+ label: "tool not available",
364
+ };
365
+ }
366
+ }
367
+ // --- Output ---
368
+ function printHealth(result) {
369
+ console.log(chalk.bold("\ngrimoire health\n"));
370
+ for (const m of result.metrics) {
371
+ const name = m.name.replace(/_/g, " ").padEnd(16);
372
+ const bar = m.score !== null ? renderBar(m.score) : " ";
373
+ const scoreText = m.score !== null ? `${String(m.score).padStart(3)}%` : " —";
374
+ const color = m.score !== null ? scoreColor(m.score) : chalk.dim;
375
+ console.log(` ${name} ${color(scoreText)} ${bar} ${m.label}`);
376
+ }
377
+ console.log();
378
+ const overallColor = scoreColor(result.overall);
379
+ console.log(` ${chalk.bold("Overall")} ${overallColor(chalk.bold(`${result.overall}%`))} ${renderBar(result.overall)}`);
380
+ console.log();
381
+ }
382
+ function renderBar(score) {
383
+ const filled = Math.round(score / 10);
384
+ const empty = 10 - filled;
385
+ const color = scoreColor(score);
386
+ return color("█".repeat(filled)) + chalk.dim("░".repeat(empty));
387
+ }
388
+ function scoreColor(score) {
389
+ if (score >= 80)
390
+ return chalk.green;
391
+ if (score >= 60)
392
+ return chalk.yellow;
393
+ return chalk.red;
394
+ }
395
+ // --- Badges ---
396
+ async function writeBadges(root, filePath, result) {
397
+ const target = safePath(root, filePath);
398
+ const marker = "<!-- GRIMOIRE:HEALTH:START -->";
399
+ const endMarker = "<!-- GRIMOIRE:HEALTH:END -->";
400
+ const badges = [];
401
+ for (const m of result.metrics) {
402
+ if (m.score === null)
403
+ continue;
404
+ const color = m.score >= 80 ? "green" : m.score >= 60 ? "yellow" : "red";
405
+ const label = m.name.replace(/_/g, "%20");
406
+ const value = encodeURIComponent(`${m.score}%`);
407
+ badges.push(`![${m.name}](https://img.shields.io/badge/${label}-${value}-${color})`);
408
+ }
409
+ // Add informational badges
410
+ for (const m of result.metrics) {
411
+ if (m.score !== null)
412
+ continue;
413
+ if (m.label === "not configured" || m.label.includes("not available"))
414
+ continue;
415
+ const label = m.name.replace(/_/g, "%20");
416
+ const value = encodeURIComponent(m.label);
417
+ badges.push(`![${m.name}](https://img.shields.io/badge/${label}-${value}-blue)`);
418
+ }
419
+ // Overall
420
+ const overallColor = result.overall >= 80
421
+ ? "green"
422
+ : result.overall >= 60
423
+ ? "yellow"
424
+ : "red";
425
+ badges.push(`![health](https://img.shields.io/badge/grimoire%20health-${result.overall}%25-${overallColor})`);
426
+ const badgeBlock = `${marker}\n${badges.join("\n")}\n${endMarker}`;
427
+ let content;
428
+ try {
429
+ content = await readFile(target, "utf-8");
430
+ }
431
+ catch {
432
+ // File doesn't exist, create with just badges
433
+ await writeFile(target, badgeBlock + "\n");
434
+ console.log(chalk.green("Created") + ` ${filePath} with health badges`);
435
+ return;
436
+ }
437
+ if (content.includes(marker)) {
438
+ const updated = content.replace(new RegExp(`${escapeRegex(marker)}[\\s\\S]*?${escapeRegex(endMarker)}`), badgeBlock);
439
+ await writeFile(target, updated);
440
+ console.log(chalk.blue("Updated") + ` ${filePath} health badges`);
441
+ }
442
+ else {
443
+ // Prepend badges to file
444
+ await writeFile(target, badgeBlock + "\n\n" + content);
445
+ console.log(chalk.blue("Added") + ` health badges to ${filePath}`);
446
+ }
447
+ }
448
+ // --- Helpers ---
449
+ async function findStepDirectories(root) {
450
+ const candidates = [
451
+ "features/steps",
452
+ "features/step_definitions",
453
+ "tests/step_defs",
454
+ "tests/steps",
455
+ "test/step_definitions",
456
+ "test/steps",
457
+ "e2e/steps",
458
+ "e2e/step_definitions",
459
+ ];
460
+ const found = [];
461
+ for (const candidate of candidates) {
462
+ try {
463
+ await readdir(join(root, candidate));
464
+ found.push(join(root, candidate));
465
+ }
466
+ catch {
467
+ // doesn't exist
468
+ }
469
+ }
470
+ return found;
471
+ }
472
+ async function readAllFiles(dirs) {
473
+ const contents = [];
474
+ for (const dir of dirs) {
475
+ try {
476
+ const files = await findFiles(dir, "");
477
+ for (const f of files) {
478
+ const content = await readFileOrNull(f);
479
+ if (content)
480
+ contents.push(content);
481
+ }
482
+ }
483
+ catch {
484
+ // skip
485
+ }
486
+ }
487
+ return contents;
488
+ }
489
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/core/health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generate Claude Code hooks and git hooks for grimoire enforcement.
3
+ */
4
+ export declare function setupHooks(root: string): Promise<void>;
5
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/core/hooks.ts"],"names":[],"mappings":"AAgBA;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5D"}