@doccov/cli 0.27.0 → 0.28.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/dist/cli.js CHANGED
@@ -4,90 +4,7 @@
4
4
  import { access } from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
-
8
- // src/config/schema.ts
9
- import { z } from "zod";
10
- var stringList = z.union([
11
- z.string(),
12
- z.array(z.string())
13
- ]);
14
- var docsConfigSchema = z.object({
15
- include: stringList.optional(),
16
- exclude: stringList.optional()
17
- });
18
- var exampleModeSchema = z.enum([
19
- "presence",
20
- "typecheck",
21
- "run"
22
- ]);
23
- var exampleModesSchema = z.union([
24
- exampleModeSchema,
25
- z.array(exampleModeSchema),
26
- z.string()
27
- ]);
28
- var apiSurfaceConfigSchema = z.object({
29
- minCompleteness: z.number().min(0).max(100).optional(),
30
- warnBelow: z.number().min(0).max(100).optional(),
31
- ignore: z.array(z.string()).optional()
32
- });
33
- var checkConfigSchema = z.object({
34
- examples: exampleModesSchema.optional(),
35
- minHealth: z.number().min(0).max(100).optional(),
36
- minCoverage: z.number().min(0).max(100).optional(),
37
- maxDrift: z.number().min(0).max(100).optional(),
38
- minApiSurface: z.number().min(0).max(100).optional(),
39
- apiSurface: apiSurfaceConfigSchema.optional()
40
- });
41
- var docCovConfigSchema = z.object({
42
- include: stringList.optional(),
43
- exclude: stringList.optional(),
44
- plugins: z.array(z.unknown()).optional(),
45
- docs: docsConfigSchema.optional(),
46
- check: checkConfigSchema.optional()
47
- });
48
- var normalizeList = (value) => {
49
- if (!value) {
50
- return;
51
- }
52
- const list = Array.isArray(value) ? value : [value];
53
- const normalized = list.map((item) => item.trim()).filter(Boolean);
54
- return normalized.length > 0 ? normalized : undefined;
55
- };
56
- var normalizeConfig = (input) => {
57
- const include = normalizeList(input.include);
58
- const exclude = normalizeList(input.exclude);
59
- let docs;
60
- if (input.docs) {
61
- const docsInclude = normalizeList(input.docs.include);
62
- const docsExclude = normalizeList(input.docs.exclude);
63
- if (docsInclude || docsExclude) {
64
- docs = {
65
- include: docsInclude,
66
- exclude: docsExclude
67
- };
68
- }
69
- }
70
- let check;
71
- if (input.check) {
72
- check = {
73
- examples: input.check.examples,
74
- minHealth: input.check.minHealth,
75
- minCoverage: input.check.minCoverage,
76
- maxDrift: input.check.maxDrift,
77
- minApiSurface: input.check.minApiSurface,
78
- apiSurface: input.check.apiSurface
79
- };
80
- }
81
- return {
82
- include,
83
- exclude,
84
- plugins: input.plugins,
85
- docs,
86
- check
87
- };
88
- };
89
-
90
- // src/config/doccov-config.ts
7
+ import { docCovConfigSchema, normalizeConfig } from "@doccov/sdk";
91
8
  var DOCCOV_CONFIG_FILENAMES = [
92
9
  "doccov.config.ts",
93
10
  "doccov.config.mts",
@@ -1517,73 +1434,6 @@ function displayPreview(editsByFile, targetDir, log) {
1517
1434
  // src/commands/check/output.ts
1518
1435
  import { generateReportFromDocCov } from "@doccov/sdk";
1519
1436
 
1520
- // src/reports/changelog-renderer.ts
1521
- function renderChangelog(data, options = {}) {
1522
- const { diff, categorizedBreaking } = data;
1523
- const lines = [];
1524
- const version = options.version ?? data.version ?? "Unreleased";
1525
- const date = options.date instanceof Date ? options.date.toISOString().split("T")[0] : options.date ?? new Date().toISOString().split("T")[0];
1526
- lines.push(`## [${version}] - ${date}`);
1527
- lines.push("");
1528
- if (diff.breaking.length > 0) {
1529
- lines.push("### ⚠️ BREAKING CHANGES");
1530
- lines.push("");
1531
- if (categorizedBreaking && categorizedBreaking.length > 0) {
1532
- for (const breaking of categorizedBreaking) {
1533
- const severity = breaking.severity === "high" ? "**" : "";
1534
- lines.push(`- ${severity}${breaking.name}${severity}: ${breaking.reason}`);
1535
- }
1536
- } else {
1537
- for (const id of diff.breaking) {
1538
- lines.push(`- \`${id}\` removed or changed`);
1539
- }
1540
- }
1541
- lines.push("");
1542
- }
1543
- if (diff.nonBreaking.length > 0) {
1544
- lines.push("### Added");
1545
- lines.push("");
1546
- for (const id of diff.nonBreaking) {
1547
- lines.push(`- \`${id}\``);
1548
- }
1549
- lines.push("");
1550
- }
1551
- if (diff.docsOnly.length > 0) {
1552
- lines.push("### Documentation");
1553
- lines.push("");
1554
- for (const id of diff.docsOnly) {
1555
- lines.push(`- Updated documentation for \`${id}\``);
1556
- }
1557
- lines.push("");
1558
- }
1559
- if (diff.coverageDelta !== 0) {
1560
- lines.push("### Coverage");
1561
- lines.push("");
1562
- const arrow = diff.coverageDelta > 0 ? "↑" : "↓";
1563
- const sign = diff.coverageDelta > 0 ? "+" : "";
1564
- lines.push(`- Documentation coverage: ${diff.oldCoverage}% → ${diff.newCoverage}% (${arrow} ${sign}${diff.coverageDelta}%)`);
1565
- lines.push("");
1566
- }
1567
- if (diff.driftIntroduced > 0 || diff.driftResolved > 0) {
1568
- if (!lines.some((l) => l.startsWith("### Coverage"))) {
1569
- lines.push("### Coverage");
1570
- lines.push("");
1571
- }
1572
- if (diff.driftResolved > 0) {
1573
- lines.push(`- Fixed ${diff.driftResolved} drift issue${diff.driftResolved === 1 ? "" : "s"}`);
1574
- }
1575
- if (diff.driftIntroduced > 0) {
1576
- lines.push(`- ${diff.driftIntroduced} new drift issue${diff.driftIntroduced === 1 ? "" : "s"} detected`);
1577
- }
1578
- lines.push("");
1579
- }
1580
- if (options.compareUrl) {
1581
- lines.push(`**Full Changelog**: ${options.compareUrl}`);
1582
- lines.push("");
1583
- }
1584
- return lines.join(`
1585
- `);
1586
- }
1587
1437
  // src/reports/diff-markdown.ts
1588
1438
  import * as path4 from "node:path";
1589
1439
  function bar(pct, width = 10) {
@@ -1801,55 +1651,6 @@ function renderDiffHtml(data, options = {}) {
1801
1651
  </body>
1802
1652
  </html>`;
1803
1653
  }
1804
- // src/reports/github.ts
1805
- function renderGithubSummary(stats, options = {}) {
1806
- const coverageScore = options.coverageScore ?? stats.coverageScore;
1807
- const driftCount = options.driftCount ?? stats.driftCount;
1808
- const qualityIssues = options.qualityIssues ?? 0;
1809
- let output = "";
1810
- if (stats.health) {
1811
- const h = stats.health;
1812
- const status = h.score >= 80 ? "✅" : h.score >= 50 ? "⚠️" : "❌";
1813
- output += `## ${status} Documentation Health: ${h.score}%
1814
-
1815
- `;
1816
- output += `| Metric | Score | Details |
1817
- |--------|-------|---------|
1818
- `;
1819
- output += `| Completeness | ${h.completeness.score}% | ${h.completeness.total - h.completeness.documented} missing docs |
1820
- `;
1821
- output += `| Accuracy | ${h.accuracy.score}% | ${h.accuracy.issues} drift issues |
1822
- `;
1823
- if (h.examples) {
1824
- output += `| Examples | ${h.examples.score}% | ${h.examples.passed}/${h.examples.total} passed |
1825
- `;
1826
- }
1827
- output += `
1828
- `;
1829
- } else {
1830
- output += `## Documentation Coverage: ${coverageScore}%
1831
-
1832
- `;
1833
- }
1834
- output += `| Metric | Value |
1835
- |--------|-------|
1836
- `;
1837
- output += `| Coverage Score | ${coverageScore}% |
1838
- `;
1839
- output += `| Total Exports | ${stats.totalExports} |
1840
- `;
1841
- output += `| Drift Issues | ${driftCount} |
1842
- `;
1843
- output += `| Quality Issues | ${qualityIssues} |
1844
- `;
1845
- if (!stats.health) {
1846
- const status = coverageScore >= 80 ? "✅" : coverageScore >= 50 ? "⚠️" : "❌";
1847
- output += `
1848
- ${status} Coverage ${coverageScore >= 80 ? "passing" : coverageScore >= 50 ? "needs improvement" : "failing"}
1849
- `;
1850
- }
1851
- return output;
1852
- }
1853
1654
  // src/reports/markdown.ts
1854
1655
  import { DRIFT_CATEGORY_LABELS } from "@doccov/sdk";
1855
1656
  function bar2(pct, width = 10) {
@@ -1977,321 +1778,8 @@ function renderMarkdown(stats, options = {}) {
1977
1778
  return lines.join(`
1978
1779
  `);
1979
1780
  }
1980
-
1981
- // src/reports/html.ts
1982
- function escapeHtml2(s) {
1983
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1984
- }
1985
- function renderHtml(stats, options = {}) {
1986
- const md = renderMarkdown(stats, options);
1987
- return `<!DOCTYPE html>
1988
- <html lang="en">
1989
- <head>
1990
- <meta charset="UTF-8">
1991
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1992
- <title>DocCov Report: ${escapeHtml2(stats.packageName)}</title>
1993
- <style>
1994
- :root { --bg: #0d1117; --fg: #c9d1d9; --border: #30363d; --accent: #58a6ff; }
1995
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--fg); max-width: 900px; margin: 0 auto; padding: 2rem; line-height: 1.6; }
1996
- h1, h2 { border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; }
1997
- table { border-collapse: collapse; width: 100%; margin: 1rem 0; }
1998
- th, td { border: 1px solid var(--border); padding: 0.5rem 1rem; text-align: left; }
1999
- th { background: #161b22; }
2000
- code { background: #161b22; padding: 0.2rem 0.4rem; border-radius: 4px; font-size: 0.9em; }
2001
- a { color: var(--accent); }
2002
- </style>
2003
- </head>
2004
- <body>
2005
- <pre style="white-space: pre-wrap; font-family: inherit;">${escapeHtml2(md)}</pre>
2006
- </body>
2007
- </html>`;
2008
- }
2009
- // src/reports/pr-comment.ts
2010
- import { getExportDrift as getExportDrift2 } from "@doccov/sdk";
2011
- function extractReturnType(schema) {
2012
- if (!schema)
2013
- return "void";
2014
- if (typeof schema === "string")
2015
- return schema;
2016
- if (typeof schema === "object") {
2017
- const s = schema;
2018
- if (typeof s.type === "string")
2019
- return s.type;
2020
- if (typeof s.$ref === "string") {
2021
- const ref = s.$ref;
2022
- return ref.startsWith("#/types/") ? ref.slice("#/types/".length) : ref;
2023
- }
2024
- }
2025
- return "unknown";
2026
- }
2027
- function renderPRComment(data, opts = {}) {
2028
- const { diff, headSpec, doccov } = data;
2029
- const limit = opts.limit ?? 10;
2030
- const lines = [];
2031
- const hasStaleRefs = (opts.staleDocsRefs?.length ?? 0) > 0;
2032
- const hasIssues = diff.newUndocumented.length > 0 || diff.driftIntroduced > 0 || diff.breaking.length > 0 || hasStaleRefs || opts.minCoverage !== undefined && diff.newCoverage < opts.minCoverage;
2033
- const statusIcon = hasIssues ? diff.coverageDelta < 0 ? "❌" : "⚠️" : "✅";
2034
- lines.push(`## ${statusIcon} DocCov — Documentation Coverage`);
2035
- lines.push("");
2036
- const targetStr = opts.minCoverage !== undefined ? ` (target: ${opts.minCoverage}%) ${diff.newCoverage >= opts.minCoverage ? "✅" : "❌"}` : "";
2037
- lines.push(`**Patch coverage:** ${diff.newCoverage}%${targetStr}`);
2038
- if (diff.newUndocumented.length > 0) {
2039
- lines.push(`**New undocumented exports:** ${diff.newUndocumented.length}`);
2040
- }
2041
- if (diff.driftIntroduced > 0) {
2042
- lines.push(`**Doc drift issues:** ${diff.driftIntroduced}`);
2043
- }
2044
- if (opts.staleDocsRefs && opts.staleDocsRefs.length > 0) {
2045
- lines.push(`**Stale doc references:** ${opts.staleDocsRefs.length}`);
2046
- }
2047
- if (opts.semverBump) {
2048
- const emoji = opts.semverBump.bump === "major" ? "\uD83D\uDD34" : opts.semverBump.bump === "minor" ? "\uD83D\uDFE1" : "\uD83D\uDFE2";
2049
- lines.push(`**Semver:** ${emoji} ${opts.semverBump.bump.toUpperCase()} (${opts.semverBump.reason})`);
2050
- }
2051
- if (diff.newUndocumented.length > 0) {
2052
- lines.push("");
2053
- lines.push("### Undocumented exports in this PR");
2054
- lines.push("");
2055
- renderUndocumentedExports(lines, diff.newUndocumented, headSpec, opts, limit);
2056
- }
2057
- if (diff.driftIntroduced > 0 && headSpec) {
2058
- lines.push("");
2059
- lines.push("### Doc drift detected");
2060
- lines.push("");
2061
- renderDriftIssues(lines, diff.newUndocumented, headSpec, doccov, opts, limit);
2062
- }
2063
- if (opts.staleDocsRefs && opts.staleDocsRefs.length > 0) {
2064
- lines.push("");
2065
- lines.push("### \uD83D\uDCDD Stale documentation references");
2066
- lines.push("");
2067
- lines.push("These markdown files reference exports that no longer exist:");
2068
- lines.push("");
2069
- renderStaleDocsRefs(lines, opts.staleDocsRefs, opts, limit);
2070
- }
2071
- const fixGuidance = renderFixGuidance(diff, opts);
2072
- if (fixGuidance) {
2073
- lines.push("");
2074
- lines.push("### How to fix");
2075
- lines.push("");
2076
- lines.push(fixGuidance);
2077
- }
2078
- lines.push("");
2079
- lines.push("<details>");
2080
- lines.push("<summary>View full report</summary>");
2081
- lines.push("");
2082
- renderDetailsTable(lines, diff);
2083
- lines.push("");
2084
- lines.push("</details>");
2085
- if (opts.includeBadge !== false && opts.repoUrl) {
2086
- const repoMatch = opts.repoUrl.match(/github\.com\/([^/]+)\/([^/]+)/);
2087
- if (repoMatch) {
2088
- const [, owner, repo] = repoMatch;
2089
- lines.push("");
2090
- lines.push("---");
2091
- lines.push("");
2092
- lines.push(`[![DocCov](https://doccov.dev/badge/${owner}/${repo})](https://doccov.dev/${owner}/${repo})`);
2093
- }
2094
- }
2095
- return lines.join(`
2096
- `);
2097
- }
2098
- function renderUndocumentedExports(lines, undocumented, headSpec, opts, limit) {
2099
- if (!headSpec) {
2100
- for (const name of undocumented.slice(0, limit)) {
2101
- lines.push(`- \`${name}\``);
2102
- }
2103
- if (undocumented.length > limit) {
2104
- lines.push(`- _...and ${undocumented.length - limit} more_`);
2105
- }
2106
- return;
2107
- }
2108
- const byFile = new Map;
2109
- const undocSet = new Set(undocumented);
2110
- for (const exp of headSpec.exports) {
2111
- if (undocSet.has(exp.name)) {
2112
- const file = exp.source?.file ?? "unknown";
2113
- const list = byFile.get(file) ?? [];
2114
- list.push(exp);
2115
- byFile.set(file, list);
2116
- }
2117
- }
2118
- let count = 0;
2119
- for (const [file, exports] of byFile) {
2120
- if (count >= limit)
2121
- break;
2122
- const fileLink = buildFileLink(file, opts);
2123
- lines.push(`\uD83D\uDCC1 ${fileLink}`);
2124
- for (const exp of exports) {
2125
- if (count >= limit) {
2126
- lines.push(`- _...and more_`);
2127
- break;
2128
- }
2129
- const sig = formatExportSignature(exp);
2130
- lines.push(`- \`${sig}\``);
2131
- const missing = getMissingSignals(exp);
2132
- if (missing.length > 0) {
2133
- lines.push(` - Missing: ${missing.join(", ")}`);
2134
- }
2135
- count++;
2136
- }
2137
- lines.push("");
2138
- }
2139
- if (undocumented.length > count) {
2140
- lines.push(`_...and ${undocumented.length - count} more undocumented exports_`);
2141
- }
2142
- }
2143
- function renderDriftIssues(lines, _undocumented, headSpec, doccov, opts, limit) {
2144
- const driftIssues = [];
2145
- for (const exp of headSpec.exports) {
2146
- const drifts = doccov ? getExportDrift2(exp, doccov) : [];
2147
- for (const d of drifts) {
2148
- driftIssues.push({
2149
- exportName: exp.name,
2150
- file: exp.source?.file,
2151
- drift: d
2152
- });
2153
- }
2154
- }
2155
- if (driftIssues.length === 0) {
2156
- lines.push("_No specific drift details available_");
2157
- return;
2158
- }
2159
- for (const issue of driftIssues.slice(0, limit)) {
2160
- const fileRef = issue.file ? `\`${issue.file}\`` : "unknown file";
2161
- const fileLink = issue.file ? buildFileLink(issue.file, opts) : fileRef;
2162
- lines.push(`⚠️ ${fileLink}: \`${issue.exportName}\``);
2163
- lines.push(`- ${issue.drift.issue}`);
2164
- if (issue.drift.suggestion) {
2165
- lines.push(`- Fix: ${issue.drift.suggestion}`);
2166
- }
2167
- lines.push("");
2168
- }
2169
- if (driftIssues.length > limit) {
2170
- lines.push(`_...and ${driftIssues.length - limit} more drift issues_`);
2171
- }
2172
- }
2173
- function buildFileLink(file, opts) {
2174
- if (opts.repoUrl && opts.sha) {
2175
- const url = `${opts.repoUrl}/blob/${opts.sha}/${file}`;
2176
- return `[\`${file}\`](${url})`;
2177
- }
2178
- return `\`${file}\``;
2179
- }
2180
- function getExportKeyword(kind) {
2181
- switch (kind) {
2182
- case "type":
2183
- return "type";
2184
- case "interface":
2185
- return "interface";
2186
- case "class":
2187
- return "class";
2188
- default:
2189
- return "function";
2190
- }
2191
- }
2192
- function formatExportSignature(exp) {
2193
- const prefix2 = `export ${getExportKeyword(exp.kind)}`;
2194
- if (exp.kind === "function" && exp.signatures?.[0]) {
2195
- const sig = exp.signatures[0];
2196
- const params = sig.parameters?.map((p) => `${p.name}${p.required === false ? "?" : ""}`).join(", ") ?? "";
2197
- const ret = extractReturnType(sig.returns?.schema);
2198
- return `${prefix2} ${exp.name}(${params}): ${ret}`;
2199
- }
2200
- if (exp.kind === "type" || exp.kind === "interface") {
2201
- return `${prefix2} ${exp.name}`;
2202
- }
2203
- if (exp.kind === "class") {
2204
- return `${prefix2} ${exp.name}`;
2205
- }
2206
- return `export ${exp.kind} ${exp.name}`;
2207
- }
2208
- function getMissingSignals(exp) {
2209
- const missing = [];
2210
- if (!exp.description) {
2211
- missing.push("description");
2212
- }
2213
- if (exp.kind === "function" && exp.signatures?.[0]) {
2214
- const sig = exp.signatures[0];
2215
- const undocParams = sig.parameters?.filter((p) => !p.description) ?? [];
2216
- if (undocParams.length > 0) {
2217
- missing.push(`\`@param ${undocParams.map((p) => p.name).join(", ")}\``);
2218
- }
2219
- if (!sig.returns?.description && extractReturnType(sig.returns?.schema) !== "void") {
2220
- missing.push("`@returns`");
2221
- }
2222
- }
2223
- return missing;
2224
- }
2225
- function renderStaleDocsRefs(lines, refs, opts, limit) {
2226
- const byFile = new Map;
2227
- for (const ref of refs) {
2228
- const list = byFile.get(ref.file) ?? [];
2229
- list.push({ line: ref.line, exportName: ref.exportName });
2230
- byFile.set(ref.file, list);
2231
- }
2232
- let count = 0;
2233
- for (const [file, fileRefs] of byFile) {
2234
- if (count >= limit)
2235
- break;
2236
- const fileLink = buildFileLink(file, opts);
2237
- lines.push(`\uD83D\uDCC1 ${fileLink}`);
2238
- for (const ref of fileRefs) {
2239
- if (count >= limit)
2240
- break;
2241
- lines.push(`- Line ${ref.line}: \`${ref.exportName}\` does not exist`);
2242
- count++;
2243
- }
2244
- lines.push("");
2245
- }
2246
- if (refs.length > count) {
2247
- lines.push(`_...and ${refs.length - count} more stale references_`);
2248
- }
2249
- }
2250
- function renderFixGuidance(diff, opts) {
2251
- const sections = [];
2252
- if (diff.newUndocumented.length > 0) {
2253
- sections.push(`**For undocumented exports:**
2254
- ` + "Add JSDoc/TSDoc blocks with description, `@param`, and `@returns` tags.");
2255
- }
2256
- if (diff.driftIntroduced > 0) {
2257
- const fixableNote = opts.fixableDriftCount && opts.fixableDriftCount > 0 ? `
2258
-
2259
- **Quick fix:** Run \`npx doccov check --fix\` to auto-fix ${opts.fixableDriftCount} issue(s).` : "";
2260
- sections.push(`**For doc drift:**
2261
- Update JSDoc to match current code signatures.${fixableNote}`);
2262
- }
2263
- if (opts.staleDocsRefs && opts.staleDocsRefs.length > 0) {
2264
- sections.push(`**For stale docs:**
2265
- ` + "Update or remove code examples that reference deleted exports.");
2266
- }
2267
- if (diff.breaking.length > 0) {
2268
- sections.push(`**For breaking changes:**
2269
- ` + "Consider adding a migration guide or updating changelog.");
2270
- }
2271
- if (sections.length === 0) {
2272
- return "";
2273
- }
2274
- sections.push(`
2275
- Push your changes — DocCov re-checks automatically.`);
2276
- return sections.join(`
2277
-
2278
- `);
2279
- }
2280
- function renderDetailsTable(lines, diff) {
2281
- const delta = (n) => n > 0 ? `+${n}` : n === 0 ? "0" : String(n);
2282
- lines.push("| Metric | Before | After | Delta |");
2283
- lines.push("|--------|--------|-------|-------|");
2284
- lines.push(`| Coverage | ${diff.oldCoverage}% | ${diff.newCoverage}% | ${delta(diff.coverageDelta)}% |`);
2285
- lines.push(`| Breaking changes | - | ${diff.breaking.length} | - |`);
2286
- lines.push(`| New exports | - | ${diff.nonBreaking.length} | - |`);
2287
- lines.push(`| Undocumented | - | ${diff.newUndocumented.length} | - |`);
2288
- if (diff.driftIntroduced > 0 || diff.driftResolved > 0) {
2289
- const driftDelta = diff.driftIntroduced - diff.driftResolved;
2290
- lines.push(`| Drift | - | - | ${delta(driftDelta)} |`);
2291
- }
2292
- }
2293
1781
  // src/reports/stats.ts
2294
- import { getExportAnalysis, getExportDrift as getExportDrift3, isFixableDrift } from "@doccov/sdk";
1782
+ import { getExportAnalysis, getExportDrift as getExportDrift2, isFixableDrift } from "@doccov/sdk";
2295
1783
  import {
2296
1784
  DRIFT_CATEGORIES as DRIFT_CATEGORIES2
2297
1785
  } from "@doccov/spec";
@@ -2332,7 +1820,7 @@ function computeStats(openpkg, doccov) {
2332
1820
  partiallyDocumented++;
2333
1821
  else
2334
1822
  undocumented++;
2335
- for (const d of getExportDrift3(exp, doccov)) {
1823
+ for (const d of getExportDrift2(exp, doccov)) {
2336
1824
  const item = {
2337
1825
  exportName: exp.name,
2338
1826
  type: d.type,
@@ -2467,7 +1955,7 @@ function displayHealthTree(health, log) {
2467
1955
  }
2468
1956
  function displayHealthVerbose(health, log) {
2469
1957
  const tree = supportsUnicode() ? { branch: "├─", corner: "└─" } : { branch: "|-", corner: "\\-" };
2470
- log(colors.bold("COMPLETENESS") + ` ${health.completeness.score}%`);
1958
+ log(`${colors.bold("COMPLETENESS")} ${health.completeness.score}%`);
2471
1959
  const missingRules = Object.entries(health.completeness.missing);
2472
1960
  for (let i = 0;i < missingRules.length; i++) {
2473
1961
  const [rule, count] = missingRules[i];
@@ -2489,7 +1977,7 @@ function displayHealthVerbose(health, log) {
2489
1977
  }
2490
1978
  if (health.examples) {
2491
1979
  log("");
2492
- log(colors.bold("EXAMPLES") + ` ${health.examples.score}%`);
1980
+ log(`${colors.bold("EXAMPLES")} ${health.examples.score}%`);
2493
1981
  log(`${tree.branch} ${colors.muted("passed".padEnd(12))} ${health.examples.passed}`);
2494
1982
  log(`${tree.corner} ${colors.muted("failed".padEnd(12))} ${health.examples.failed}`);
2495
1983
  }
@@ -2505,7 +1993,6 @@ function displayTextOutput(options, deps) {
2505
1993
  driftExports,
2506
1994
  typecheckErrors,
2507
1995
  staleRefs,
2508
- exampleResult,
2509
1996
  specWarnings,
2510
1997
  specInfos,
2511
1998
  verbose
@@ -2657,10 +2144,8 @@ function handleNonTextOutput(options, deps) {
2657
2144
  format,
2658
2145
  openpkg,
2659
2146
  doccov,
2660
- coverageScore,
2661
2147
  minHealth,
2662
2148
  minApiSurface,
2663
- driftExports,
2664
2149
  typecheckErrors,
2665
2150
  limit,
2666
2151
  stdout,
@@ -2671,7 +2156,7 @@ function handleNonTextOutput(options, deps) {
2671
2156
  const stats = computeStats(openpkg, doccov);
2672
2157
  const report = generateReportFromDocCov(openpkg, doccov);
2673
2158
  const jsonContent = JSON.stringify(report, null, 2);
2674
- const healthScore = doccov.summary.health?.score ?? coverageScore;
2159
+ const healthScore = doccov.summary.health?.score ?? stats.coverageScore;
2675
2160
  let formatContent;
2676
2161
  switch (format) {
2677
2162
  case "json":
@@ -2680,15 +2165,6 @@ function handleNonTextOutput(options, deps) {
2680
2165
  case "markdown":
2681
2166
  formatContent = renderMarkdown(stats, { limit });
2682
2167
  break;
2683
- case "html":
2684
- formatContent = renderHtml(stats, { limit });
2685
- break;
2686
- case "github":
2687
- formatContent = renderGithubSummary(stats, {
2688
- coverageScore,
2689
- driftCount: driftExports.length
2690
- });
2691
- break;
2692
2168
  default:
2693
2169
  throw new Error(`Unknown format: ${format}`);
2694
2170
  }
@@ -2838,12 +2314,12 @@ function registerCheckCommand(program, dependencies = {}) {
2838
2314
  ...defaultDependencies,
2839
2315
  ...dependencies
2840
2316
  };
2841
- program.command("check [entry]").description("Check documentation coverage and output reports").option("--cwd <dir>", "Working directory", process.cwd()).option("--package <name>", "Target package name (for monorepos)").option("--min-health <percentage>", "Minimum health score (0-100)", (value) => Number(value)).option("--min-coverage <percentage>", "[deprecated] Use --min-health instead", (value) => Number(value)).option("--max-drift <percentage>", "[deprecated] Use --min-health instead", (value) => Number(value)).option("--examples [mode]", "Example validation: presence, typecheck, run (comma-separated). Bare flag runs all.").option("--skip-resolve", "Skip external type resolution from node_modules").option("--docs <glob>", "Glob pattern for markdown docs to check for stale refs", collect, []).option("--fix", "Auto-fix drift issues").option("--preview", "Preview fixes with diff output (implies --fix)").option("--format <format>", "Output format: text, json, markdown, html, github", "text").option("-o, --output <file>", "Custom output path (overrides default .doccov/ path)").option("--stdout", "Output to stdout instead of writing to .doccov/").option("--update-snapshot", "Force regenerate .doccov/report.json").option("--limit <n>", "Max exports to show in report tables", "20").option("--max-type-depth <number>", "Maximum depth for type conversion (default: 20)", (value) => {
2317
+ program.command("check [entry]").description("Check documentation coverage and output reports").option("--cwd <dir>", "Working directory", process.cwd()).option("--package <name>", "Target package name (for monorepos)").option("--min-health <percentage>", "Minimum health score (0-100)", (value) => Number(value)).option("--examples [mode]", "Example validation: presence, typecheck, run (comma-separated). Bare flag runs all.").option("--skip-resolve", "Skip external type resolution from node_modules").option("--docs <glob>", "Glob pattern for markdown docs to check for stale refs", collect, []).option("--fix", "Auto-fix drift issues").option("--preview", "Preview fixes with diff output (implies --fix)").option("--format <format>", "Output format: text, json, markdown", "text").option("-o, --output <file>", "Custom output path (overrides default .doccov/ path)").option("--stdout", "Output to stdout instead of writing to .doccov/").option("--limit <n>", "Max exports to show in report tables", "20").option("--max-type-depth <number>", "Maximum depth for type conversion (default: 20)", (value) => {
2842
2318
  const n = parseInt(value, 10);
2843
2319
  if (Number.isNaN(n) || n < 1)
2844
2320
  throw new Error("--max-type-depth must be a positive integer");
2845
2321
  return n;
2846
- }).option("--no-cache", "Bypass spec cache and force regeneration").option("--visibility <tags>", "Filter by release stage: public,beta,alpha,internal (comma-separated)").option("--min-api-surface <percentage>", "Minimum API surface completeness percentage (0-100)", (value) => Number(value)).option("--api-surface", "Show only API surface / forgotten exports info").option("-v, --verbose", "Show detailed output including forgotten exports").action(async (entry, options) => {
2322
+ }).option("--no-cache", "Bypass spec cache and force regeneration").option("--visibility <tags>", "Filter by release stage: public,beta,alpha,internal (comma-separated)").option("--api-surface", "Show only API surface / forgotten exports info").option("-v, --verbose", "Show detailed output including forgotten exports").action(async (entry, options) => {
2847
2323
  try {
2848
2324
  const spin = spinner("Analyzing...");
2849
2325
  let validations = parseExamplesFlag(options.examples);
@@ -2865,27 +2341,11 @@ function registerCheckCommand(program, dependencies = {}) {
2865
2341
  }
2866
2342
  hasExamples = validations.length > 0;
2867
2343
  }
2868
- if (options.minCoverage !== undefined) {
2869
- log(chalk7.yellow("Warning: --min-coverage is deprecated. Use --min-health instead."));
2870
- }
2871
- if (options.maxDrift !== undefined) {
2872
- log(chalk7.yellow("Warning: --max-drift is deprecated. Use --min-health instead."));
2873
- }
2874
- if (config?.check?.minCoverage !== undefined) {
2875
- log(chalk7.yellow("Warning: config.check.minCoverage is deprecated. Use minHealth."));
2876
- }
2877
- if (config?.check?.maxDrift !== undefined) {
2878
- log(chalk7.yellow("Warning: config.check.maxDrift is deprecated. Use minHealth."));
2879
- }
2880
2344
  const DEFAULT_MIN_HEALTH = 80;
2881
2345
  const minHealthRaw = options.minHealth ?? config?.check?.minHealth ?? DEFAULT_MIN_HEALTH;
2882
2346
  const minHealth = clampPercentage(minHealthRaw);
2883
- const minCoverageRaw = options.minCoverage ?? config?.check?.minCoverage ?? DEFAULT_MIN_HEALTH;
2884
- const minCoverage = clampPercentage(minCoverageRaw);
2885
- const maxDriftRaw = options.maxDrift ?? config?.check?.maxDrift;
2886
- const maxDrift = maxDriftRaw !== undefined ? clampPercentage(maxDriftRaw) : undefined;
2887
2347
  const apiSurfaceConfig = config?.check?.apiSurface;
2888
- const minApiSurfaceRaw = options.minApiSurface ?? apiSurfaceConfig?.minCompleteness ?? config?.check?.minApiSurface;
2348
+ const minApiSurfaceRaw = apiSurfaceConfig?.minCompleteness;
2889
2349
  const minApiSurface = minApiSurfaceRaw !== undefined ? clampPercentage(minApiSurfaceRaw) : undefined;
2890
2350
  const warnBelowApiSurface = apiSurfaceConfig?.warnBelow ? clampPercentage(apiSurfaceConfig.warnBelow) : undefined;
2891
2351
  const apiSurfaceIgnore = apiSurfaceConfig?.ignore ?? [];
@@ -2903,7 +2363,7 @@ function registerCheckCommand(program, dependencies = {}) {
2903
2363
  resolveExternalTypes,
2904
2364
  maxDepth: options.maxTypeDepth,
2905
2365
  useCache: options.cache !== false,
2906
- cwd: options.cwd
2366
+ cwd: targetDir
2907
2367
  });
2908
2368
  const analyzeOptions = resolvedFilters.visibility ? { filters: { visibility: resolvedFilters.visibility } } : {};
2909
2369
  const specResult = await analyzer.analyzeFileWithDiagnostics(entryFile, analyzeOptions);
@@ -2924,7 +2384,6 @@ function registerCheckCommand(program, dependencies = {}) {
2924
2384
  const specInfos = specResult.diagnostics.filter((d) => d.severity === "info");
2925
2385
  const isPreview = options.preview;
2926
2386
  const shouldFix = options.fix || isPreview;
2927
- let exampleResult;
2928
2387
  let typecheckErrors = [];
2929
2388
  let runtimeDrifts = [];
2930
2389
  if (hasExamples) {
@@ -2932,7 +2391,6 @@ function registerCheckCommand(program, dependencies = {}) {
2932
2391
  validations,
2933
2392
  targetDir
2934
2393
  });
2935
- exampleResult = validation.result;
2936
2394
  typecheckErrors = validation.typecheckErrors;
2937
2395
  runtimeDrifts = validation.runtimeDrifts;
2938
2396
  }
@@ -2972,15 +2430,13 @@ function registerCheckCommand(program, dependencies = {}) {
2972
2430
  format,
2973
2431
  openpkg,
2974
2432
  doccov,
2975
- coverageScore,
2976
2433
  minHealth,
2977
2434
  minApiSurface,
2978
- driftExports,
2979
2435
  typecheckErrors,
2980
2436
  limit: parseInt(options.limit, 10) || 20,
2981
2437
  stdout: options.stdout,
2982
2438
  outputPath: options.output,
2983
- cwd: options.cwd
2439
+ cwd: targetDir
2984
2440
  }, { log });
2985
2441
  if (!passed2) {
2986
2442
  process.exit(1);
@@ -2997,7 +2453,6 @@ function registerCheckCommand(program, dependencies = {}) {
2997
2453
  driftExports,
2998
2454
  typecheckErrors,
2999
2455
  staleRefs,
3000
- exampleResult,
3001
2456
  specWarnings,
3002
2457
  specInfos,
3003
2458
  verbose: options.verbose ?? false
@@ -3050,7 +2505,7 @@ function registerDiffCommand(program, dependencies = {}) {
3050
2505
  ...defaultDependencies2,
3051
2506
  ...dependencies
3052
2507
  };
3053
- program.command("diff [base] [head]").description("Compare two OpenPkg specs and detect breaking changes").option("--base <file>", 'Base spec file (the "before" state)').option("--head <file>", 'Head spec file (the "after" state)').option("--format <format>", "Output format: text, json, markdown, html, github, pr-comment, changelog", "text").option("--stdout", "Output to stdout instead of writing to .doccov/").option("-o, --output <file>", "Custom output path").option("--cwd <dir>", "Working directory", process.cwd()).option("--limit <n>", "Max items to show in terminal/reports", "10").option("--repo-url <url>", "GitHub repo URL for file links (pr-comment format)").option("--sha <sha>", "Commit SHA for file links (pr-comment format)").option("--min-coverage <n>", "Minimum coverage % for HEAD spec (0-100)").option("--max-drift <n>", "Maximum drift % for HEAD spec (0-100)").option("--strict <preset>", "Fail on conditions: ci, release, quality").option("--docs <glob>", "Glob pattern for markdown docs to check for impact", collect2, []).option("--no-cache", "Bypass cache and force regeneration").option("--recommend-version", "Output recommended semver version bump").action(async (baseArg, headArg, options) => {
2508
+ program.command("diff [base] [head]").description("Compare two OpenPkg specs and detect breaking changes").option("--base <file>", 'Base spec file (the "before" state)').option("--head <file>", 'Head spec file (the "after" state)').option("--format <format>", "Output format: text, json, markdown, html, github", "text").option("--stdout", "Output to stdout instead of writing to .doccov/").option("-o, --output <file>", "Custom output path").option("--cwd <dir>", "Working directory", process.cwd()).option("--limit <n>", "Max items to show in terminal/reports", "10").option("--min-coverage <n>", "Minimum coverage % for HEAD spec (0-100)").option("--max-drift <n>", "Maximum drift % for HEAD spec (0-100)").option("--strict <preset>", "Fail on conditions: ci, release, quality").option("--docs <glob>", "Glob pattern for markdown docs to check for impact", collect2, []).option("--no-cache", "Bypass cache and force regeneration").option("--recommend-version", "Output recommended semver version bump").action(async (baseArg, headArg, options) => {
3054
2509
  try {
3055
2510
  const baseFile = options.base ?? baseArg;
3056
2511
  const headFile = options.head ?? headArg;
@@ -3183,43 +2638,6 @@ function registerDiffCommand(program, dependencies = {}) {
3183
2638
  case "github":
3184
2639
  printGitHubAnnotations(diff, log);
3185
2640
  break;
3186
- case "pr-comment": {
3187
- const semverRecommendation = recommendSemverBump(diff);
3188
- const content = renderPRComment({ diff, baseName, headName, headSpec }, {
3189
- repoUrl: options.repoUrl,
3190
- sha: options.sha,
3191
- minCoverage,
3192
- limit,
3193
- semverBump: {
3194
- bump: semverRecommendation.bump,
3195
- reason: semverRecommendation.reason
3196
- }
3197
- });
3198
- log(content);
3199
- break;
3200
- }
3201
- case "changelog": {
3202
- const content = renderChangelog({
3203
- diff,
3204
- categorizedBreaking: diff.categorizedBreaking,
3205
- version: headSpec.meta?.version
3206
- }, {
3207
- version: headSpec.meta?.version,
3208
- compareUrl: options.repoUrl ? `${options.repoUrl}/compare/${baseSpec.meta?.version ?? "v0"}...${headSpec.meta?.version ?? "HEAD"}` : undefined
3209
- });
3210
- if (options.stdout) {
3211
- log(content);
3212
- } else {
3213
- const outputPath = options.output ?? getDiffReportPath(baseHash, headHash, "md");
3214
- writeReport({
3215
- format: "markdown",
3216
- content,
3217
- outputPath: outputPath.replace(/\.(json|html)$/, ".changelog.md"),
3218
- cwd: options.cwd
3219
- });
3220
- }
3221
- break;
3222
- }
3223
2641
  }
3224
2642
  const failures = validateDiff(diff, headSpec, {
3225
2643
  minCoverage,
@@ -3398,57 +2816,10 @@ function printGitHubAnnotations(diff, log) {
3398
2816
  }
3399
2817
  }
3400
2818
 
3401
- // src/commands/info.ts
3402
- import { buildDocCovSpec as buildDocCovSpec2, DocCov as DocCov2, NodeFileSystem as NodeFileSystem2, resolveTarget as resolveTarget2 } from "@doccov/sdk";
3403
- import chalk9 from "chalk";
3404
- function registerInfoCommand(program) {
3405
- program.command("info [entry]").description("Show brief documentation coverage summary").option("--cwd <dir>", "Working directory", process.cwd()).option("--package <name>", "Target package name (for monorepos)").option("--skip-resolve", "Skip external type resolution from node_modules").action(async (entry, options) => {
3406
- const spin = spinner("Analyzing documentation coverage");
3407
- try {
3408
- const fileSystem = new NodeFileSystem2(options.cwd);
3409
- const resolved = await resolveTarget2(fileSystem, {
3410
- cwd: options.cwd,
3411
- package: options.package,
3412
- entry
3413
- });
3414
- const { entryFile, targetDir } = resolved;
3415
- const resolveExternalTypes = !options.skipResolve;
3416
- const analyzer = new DocCov2({
3417
- resolveExternalTypes
3418
- });
3419
- const specResult = await analyzer.analyzeFileWithDiagnostics(entryFile);
3420
- if (!specResult) {
3421
- spin.fail("Failed to analyze");
3422
- throw new Error("Failed to analyze documentation coverage.");
3423
- }
3424
- const openpkg = specResult.spec;
3425
- const doccov = buildDocCovSpec2({
3426
- openpkg,
3427
- openpkgPath: entryFile,
3428
- packagePath: targetDir,
3429
- forgottenExports: specResult.forgottenExports
3430
- });
3431
- const stats = computeStats(openpkg, doccov);
3432
- spin.success("Analysis complete");
3433
- console.log("");
3434
- console.log(chalk9.bold(`${stats.packageName}@${stats.version}`));
3435
- console.log("");
3436
- console.log(` Exports: ${chalk9.bold(stats.totalExports.toString())}`);
3437
- console.log(` Coverage: ${chalk9.bold(`${stats.coverageScore}%`)}`);
3438
- console.log(` Drift: ${chalk9.bold(`${stats.driftScore}%`)}`);
3439
- console.log("");
3440
- } catch (err) {
3441
- spin.fail("Analysis failed");
3442
- console.error(chalk9.red("Error:"), err instanceof Error ? err.message : err);
3443
- process.exit(1);
3444
- }
3445
- });
3446
- }
3447
-
3448
2819
  // src/commands/init.ts
3449
2820
  import * as fs5 from "node:fs";
3450
2821
  import * as path7 from "node:path";
3451
- import chalk10 from "chalk";
2822
+ import chalk9 from "chalk";
3452
2823
  var defaultDependencies3 = {
3453
2824
  fileExists: fs5.existsSync,
3454
2825
  writeFileSync: fs5.writeFileSync,
@@ -3466,7 +2837,7 @@ function registerInitCommand(program, dependencies = {}) {
3466
2837
  const cwd = path7.resolve(options.cwd);
3467
2838
  const existing = findExistingConfig(cwd, fileExists2);
3468
2839
  if (existing) {
3469
- error(chalk10.red(`A DocCov config already exists at ${path7.relative(cwd, existing) || "./doccov.config.*"}.`));
2840
+ error(chalk9.red(`A DocCov config already exists at ${path7.relative(cwd, existing) || "./doccov.config.*"}.`));
3470
2841
  process.exitCode = 1;
3471
2842
  return;
3472
2843
  }
@@ -3475,7 +2846,7 @@ function registerInitCommand(program, dependencies = {}) {
3475
2846
  const fileName = `doccov.config.${targetFormat}`;
3476
2847
  const outputPath = path7.join(cwd, fileName);
3477
2848
  if (fileExists2(outputPath)) {
3478
- error(chalk10.red(`Cannot create ${fileName}; file already exists.`));
2849
+ error(chalk9.red(`Cannot create ${fileName}; file already exists.`));
3479
2850
  process.exitCode = 1;
3480
2851
  return;
3481
2852
  }
@@ -3496,16 +2867,16 @@ function registerInitCommand(program, dependencies = {}) {
3496
2867
  }
3497
2868
  const repoInfo = detectRepoInfo(cwd, fileExists2, readFileSync4);
3498
2869
  log("");
3499
- log(chalk10.bold("Add this badge to your README:"));
2870
+ log(chalk9.bold("Add this badge to your README:"));
3500
2871
  log("");
3501
2872
  if (repoInfo) {
3502
- log(chalk10.cyan(`[![DocCov](https://doccov.dev/badge/${repoInfo.owner}/${repoInfo.repo})](https://doccov.dev/${repoInfo.owner}/${repoInfo.repo})`));
2873
+ log(chalk9.cyan(`[![DocCov](https://doccov.dev/badge/${repoInfo.owner}/${repoInfo.repo})](https://doccov.dev/${repoInfo.owner}/${repoInfo.repo})`));
3503
2874
  } else {
3504
- log(chalk10.cyan(`[![DocCov](https://doccov.dev/badge/OWNER/REPO)](https://doccov.dev/OWNER/REPO)`));
3505
- log(chalk10.dim(" Replace OWNER/REPO with your GitHub repo"));
2875
+ log(chalk9.cyan(`[![DocCov](https://doccov.dev/badge/OWNER/REPO)](https://doccov.dev/OWNER/REPO)`));
2876
+ log(chalk9.dim(" Replace OWNER/REPO with your GitHub repo"));
3506
2877
  }
3507
2878
  log("");
3508
- log(chalk10.dim("Run `doccov check` to verify your documentation coverage"));
2879
+ log(chalk9.dim("Run `doccov check` to verify your documentation coverage"));
3509
2880
  });
3510
2881
  }
3511
2882
  var findExistingConfig = (cwd, fileExists2) => {
@@ -3632,21 +3003,21 @@ var detectRepoInfo = (cwd, fileExists2, readFileSync4) => {
3632
3003
  import * as fs6 from "node:fs";
3633
3004
  import * as path8 from "node:path";
3634
3005
  import {
3635
- buildDocCovSpec as buildDocCovSpec3,
3636
- DocCov as DocCov3,
3006
+ buildDocCovSpec as buildDocCovSpec2,
3007
+ DocCov as DocCov2,
3637
3008
  detectPackageManager,
3638
- NodeFileSystem as NodeFileSystem3,
3009
+ NodeFileSystem as NodeFileSystem2,
3639
3010
  renderApiSurface,
3640
- resolveTarget as resolveTarget3
3011
+ resolveTarget as resolveTarget2
3641
3012
  } from "@doccov/sdk";
3642
3013
  import { validateDocCovSpec } from "@doccov/spec";
3643
3014
  import {
3644
3015
  normalize,
3645
3016
  validateSpec
3646
3017
  } from "@openpkg-ts/spec";
3647
- import chalk11 from "chalk";
3018
+ import chalk10 from "chalk";
3648
3019
  var defaultDependencies4 = {
3649
- createDocCov: (options) => new DocCov3(options),
3020
+ createDocCov: (options) => new DocCov2(options),
3650
3021
  writeFileSync: fs6.writeFileSync,
3651
3022
  log: console.log,
3652
3023
  error: console.error
@@ -3657,7 +3028,7 @@ function getArrayLength(value) {
3657
3028
  function formatDiagnosticOutput(prefix2, diagnostic, baseDir) {
3658
3029
  const location = diagnostic.location;
3659
3030
  const relativePath = location?.file ? path8.relative(baseDir, location.file) || location.file : undefined;
3660
- const locationText = location && relativePath ? chalk11.gray(`${relativePath}:${location.line ?? 1}:${location.column ?? 1}`) : null;
3031
+ const locationText = location && relativePath ? chalk10.gray(`${relativePath}:${location.line ?? 1}:${location.column ?? 1}`) : null;
3661
3032
  const locationPrefix = locationText ? `${locationText} ` : "";
3662
3033
  return `${prefix2} ${locationPrefix}${diagnostic.message}`;
3663
3034
  }
@@ -3669,19 +3040,19 @@ function registerSpecCommand(program, dependencies = {}) {
3669
3040
  program.command("spec [entry]").description("Generate OpenPkg + DocCov specifications").option("--cwd <dir>", "Working directory", process.cwd()).option("-p, --package <name>", "Target package name (for monorepos)").option("-o, --output <dir>", "Output directory", ".doccov").option("-f, --format <format>", "Output format: json (default) or api-surface", "json").option("--openpkg-only", "Only generate openpkg.json (skip coverage analysis)").option("--include <patterns>", "Include exports matching pattern (comma-separated)").option("--exclude <patterns>", "Exclude exports matching pattern (comma-separated)").option("--visibility <tags>", "Filter by release stage: public,beta,alpha,internal (comma-separated)").option("--skip-resolve", "Skip external type resolution from node_modules").option("--max-type-depth <n>", "Maximum depth for type conversion", "20").option("--runtime", "Enable Standard Schema runtime extraction (richer output for Zod, Valibot, etc.)").option("--no-cache", "Bypass spec cache and force regeneration").option("--show-diagnostics", "Show TypeScript compiler diagnostics").option("--verbose", "Show detailed generation metadata").action(async (entry, options) => {
3670
3041
  try {
3671
3042
  const spin = spinner("Generating spec...");
3672
- const fileSystem = new NodeFileSystem3(options.cwd);
3673
- const resolved = await resolveTarget3(fileSystem, {
3043
+ const fileSystem = new NodeFileSystem2(options.cwd);
3044
+ const resolved = await resolveTarget2(fileSystem, {
3674
3045
  cwd: options.cwd,
3675
3046
  package: options.package,
3676
3047
  entry
3677
3048
  });
3678
- const { targetDir, entryFile, packageInfo, entryPointInfo } = resolved;
3049
+ const { targetDir, entryFile } = resolved;
3679
3050
  let config = null;
3680
3051
  try {
3681
3052
  config = await loadDocCovConfig(targetDir);
3682
3053
  } catch (configError) {
3683
3054
  spin.fail("Failed to load config");
3684
- error(chalk11.red("Failed to load DocCov config:"), configError instanceof Error ? configError.message : configError);
3055
+ error(chalk10.red("Failed to load DocCov config:"), configError instanceof Error ? configError.message : configError);
3685
3056
  process.exit(1);
3686
3057
  }
3687
3058
  const cliFilters = {
@@ -3714,15 +3085,15 @@ function registerSpecCommand(program, dependencies = {}) {
3714
3085
  const validation = validateSpec(normalized);
3715
3086
  if (!validation.ok) {
3716
3087
  spin.fail("Validation failed");
3717
- error(chalk11.red("Spec failed schema validation"));
3088
+ error(chalk10.red("Spec failed schema validation"));
3718
3089
  for (const err of validation.errors) {
3719
- error(chalk11.red(`schema: ${err.instancePath || "/"} ${err.message}`));
3090
+ error(chalk10.red(`schema: ${err.instancePath || "/"} ${err.message}`));
3720
3091
  }
3721
3092
  process.exit(1);
3722
3093
  }
3723
3094
  let doccovSpec = null;
3724
3095
  if (!options.openpkgOnly) {
3725
- doccovSpec = buildDocCovSpec3({
3096
+ doccovSpec = buildDocCovSpec2({
3726
3097
  openpkgPath: "openpkg.json",
3727
3098
  openpkg: normalized,
3728
3099
  packagePath: targetDir,
@@ -3731,9 +3102,9 @@ function registerSpecCommand(program, dependencies = {}) {
3731
3102
  const doccovValidation = validateDocCovSpec(doccovSpec);
3732
3103
  if (!doccovValidation.ok) {
3733
3104
  spin.fail("DocCov validation failed");
3734
- error(chalk11.red("DocCov spec failed schema validation"));
3105
+ error(chalk10.red("DocCov spec failed schema validation"));
3735
3106
  for (const err of doccovValidation.errors) {
3736
- error(chalk11.red(`doccov: ${err.instancePath || "/"} ${err.message}`));
3107
+ error(chalk10.red(`doccov: ${err.instancePath || "/"} ${err.message}`));
3737
3108
  }
3738
3109
  process.exit(1);
3739
3110
  }
@@ -3753,12 +3124,12 @@ function registerSpecCommand(program, dependencies = {}) {
3753
3124
  const doccovPath = path8.join(outputDir, "doccov.json");
3754
3125
  writeFileSync4(doccovPath, JSON.stringify(doccovSpec, null, 2));
3755
3126
  spin.success(`Generated ${options.output}/`);
3756
- log(chalk11.gray(` openpkg.json: ${getArrayLength(normalized.exports)} exports`));
3757
- log(chalk11.gray(` doccov.json: ${doccovSpec.summary.score}% coverage, ${doccovSpec.summary.drift.total} drift issues`));
3127
+ log(chalk10.gray(` openpkg.json: ${getArrayLength(normalized.exports)} exports`));
3128
+ log(chalk10.gray(` doccov.json: ${doccovSpec.summary.score}% coverage, ${doccovSpec.summary.drift.total} drift issues`));
3758
3129
  } else {
3759
3130
  spin.success(`Generated ${options.output}/openpkg.json`);
3760
- log(chalk11.gray(` ${getArrayLength(normalized.exports)} exports`));
3761
- log(chalk11.gray(` ${getArrayLength(normalized.types)} types`));
3131
+ log(chalk10.gray(` ${getArrayLength(normalized.exports)} exports`));
3132
+ log(chalk10.gray(` ${getArrayLength(normalized.types)} types`));
3762
3133
  }
3763
3134
  }
3764
3135
  const isFullGenerationInfo = (gen) => {
@@ -3770,62 +3141,62 @@ function registerSpecCommand(program, dependencies = {}) {
3770
3141
  const pm = await detectPackageManager(fileSystem);
3771
3142
  const buildCmd = pm.name === "npm" ? "npm run build" : `${pm.name} run build`;
3772
3143
  log("");
3773
- log(chalk11.yellow("⚠ Runtime extraction requested but no schemas extracted."));
3774
- log(chalk11.yellow(` Ensure project is built (${buildCmd}) and dist/ exists.`));
3144
+ log(chalk10.yellow("⚠ Runtime extraction requested but no schemas extracted."));
3145
+ log(chalk10.yellow(` Ensure project is built (${buildCmd}) and dist/ exists.`));
3775
3146
  }
3776
3147
  if (options.verbose && fullGen) {
3777
3148
  log("");
3778
- log(chalk11.bold("Generation Info"));
3779
- log(chalk11.gray(` Timestamp: ${fullGen.timestamp}`));
3780
- log(chalk11.gray(` Generator: ${fullGen.generator.name}@${fullGen.generator.version}`));
3781
- log(chalk11.gray(` Entry point: ${fullGen.analysis.entryPoint}`));
3782
- log(chalk11.gray(` Detected via: ${fullGen.analysis.entryPointSource}`));
3783
- log(chalk11.gray(` Declaration only: ${fullGen.analysis.isDeclarationOnly ? "yes" : "no"}`));
3784
- log(chalk11.gray(` External types: ${fullGen.analysis.resolvedExternalTypes ? "resolved" : "skipped"}`));
3149
+ log(chalk10.bold("Generation Info"));
3150
+ log(chalk10.gray(` Timestamp: ${fullGen.timestamp}`));
3151
+ log(chalk10.gray(` Generator: ${fullGen.generator.name}@${fullGen.generator.version}`));
3152
+ log(chalk10.gray(` Entry point: ${fullGen.analysis.entryPoint}`));
3153
+ log(chalk10.gray(` Detected via: ${fullGen.analysis.entryPointSource}`));
3154
+ log(chalk10.gray(` Declaration only: ${fullGen.analysis.isDeclarationOnly ? "yes" : "no"}`));
3155
+ log(chalk10.gray(` External types: ${fullGen.analysis.resolvedExternalTypes ? "resolved" : "skipped"}`));
3785
3156
  if (fullGen.analysis.maxTypeDepth) {
3786
- log(chalk11.gray(` Max type depth: ${fullGen.analysis.maxTypeDepth}`));
3157
+ log(chalk10.gray(` Max type depth: ${fullGen.analysis.maxTypeDepth}`));
3787
3158
  }
3788
3159
  if (fullGen.analysis.schemaExtraction) {
3789
3160
  const se = fullGen.analysis.schemaExtraction;
3790
- log(chalk11.gray(` Schema extraction: ${se.method}`));
3161
+ log(chalk10.gray(` Schema extraction: ${se.method}`));
3791
3162
  if (se.runtimeCount) {
3792
- log(chalk11.gray(` Runtime schemas: ${se.runtimeCount} (${se.vendors?.join(", ")})`));
3163
+ log(chalk10.gray(` Runtime schemas: ${se.runtimeCount} (${se.vendors?.join(", ")})`));
3793
3164
  }
3794
3165
  }
3795
3166
  log("");
3796
- log(chalk11.bold("Environment"));
3797
- log(chalk11.gray(` node_modules: ${fullGen.environment.hasNodeModules ? "found" : "not found"}`));
3167
+ log(chalk10.bold("Environment"));
3168
+ log(chalk10.gray(` node_modules: ${fullGen.environment.hasNodeModules ? "found" : "not found"}`));
3798
3169
  if (fullGen.environment.packageManager) {
3799
- log(chalk11.gray(` Package manager: ${fullGen.environment.packageManager}`));
3170
+ log(chalk10.gray(` Package manager: ${fullGen.environment.packageManager}`));
3800
3171
  }
3801
3172
  if (fullGen.environment.isMonorepo) {
3802
- log(chalk11.gray(` Monorepo: yes`));
3173
+ log(chalk10.gray(` Monorepo: yes`));
3803
3174
  }
3804
3175
  if (fullGen.environment.targetPackage) {
3805
- log(chalk11.gray(` Target package: ${fullGen.environment.targetPackage}`));
3176
+ log(chalk10.gray(` Target package: ${fullGen.environment.targetPackage}`));
3806
3177
  }
3807
3178
  if (fullGen.issues.length > 0) {
3808
3179
  log("");
3809
- log(chalk11.bold("Issues"));
3180
+ log(chalk10.bold("Issues"));
3810
3181
  for (const issue of fullGen.issues) {
3811
- const prefix2 = issue.severity === "error" ? chalk11.red(">") : issue.severity === "warning" ? chalk11.yellow(">") : chalk11.cyan(">");
3182
+ const prefix2 = issue.severity === "error" ? chalk10.red(">") : issue.severity === "warning" ? chalk10.yellow(">") : chalk10.cyan(">");
3812
3183
  log(`${prefix2} [${issue.code}] ${issue.message}`);
3813
3184
  if (issue.suggestion) {
3814
- log(chalk11.gray(` ${issue.suggestion}`));
3185
+ log(chalk10.gray(` ${issue.suggestion}`));
3815
3186
  }
3816
3187
  }
3817
3188
  }
3818
3189
  }
3819
3190
  if (options.showDiagnostics && result.diagnostics.length > 0) {
3820
3191
  log("");
3821
- log(chalk11.bold("Diagnostics"));
3192
+ log(chalk10.bold("Diagnostics"));
3822
3193
  for (const diagnostic of result.diagnostics) {
3823
- const prefix2 = diagnostic.severity === "error" ? chalk11.red(">") : diagnostic.severity === "warning" ? chalk11.yellow(">") : chalk11.cyan(">");
3194
+ const prefix2 = diagnostic.severity === "error" ? chalk10.red(">") : diagnostic.severity === "warning" ? chalk10.yellow(">") : chalk10.cyan(">");
3824
3195
  log(formatDiagnosticOutput(prefix2, diagnostic, targetDir));
3825
3196
  }
3826
3197
  }
3827
3198
  } catch (commandError) {
3828
- error(chalk11.red("Error:"), commandError instanceof Error ? commandError.message : commandError);
3199
+ error(chalk10.red("Error:"), commandError instanceof Error ? commandError.message : commandError);
3829
3200
  process.exit(1);
3830
3201
  }
3831
3202
  });
@@ -3839,13 +3210,11 @@ import {
3839
3210
  getExtendedTrend,
3840
3211
  getTrend,
3841
3212
  loadSnapshots,
3842
- pruneByTier,
3843
3213
  pruneHistory,
3844
- RETENTION_DAYS,
3845
3214
  renderSparkline,
3846
3215
  saveSnapshot
3847
3216
  } from "@doccov/sdk";
3848
- import chalk12 from "chalk";
3217
+ import chalk11 from "chalk";
3849
3218
  function formatDate(timestamp) {
3850
3219
  const date = new Date(timestamp);
3851
3220
  return date.toLocaleDateString("en-US", {
@@ -3858,19 +3227,19 @@ function formatDate(timestamp) {
3858
3227
  }
3859
3228
  function getColorForScore(score) {
3860
3229
  if (score >= 90)
3861
- return chalk12.green;
3230
+ return chalk11.green;
3862
3231
  if (score >= 70)
3863
- return chalk12.yellow;
3232
+ return chalk11.yellow;
3864
3233
  if (score >= 50)
3865
- return chalk12.hex("#FFA500");
3866
- return chalk12.red;
3234
+ return chalk11.hex("#FFA500");
3235
+ return chalk11.red;
3867
3236
  }
3868
3237
  function formatSnapshot(snapshot) {
3869
3238
  const color = getColorForScore(snapshot.coverageScore);
3870
3239
  const date = formatDate(snapshot.timestamp);
3871
3240
  const version = snapshot.version ? ` v${snapshot.version}` : "";
3872
- const commit = snapshot.commit ? chalk12.gray(` (${snapshot.commit.slice(0, 7)})`) : "";
3873
- return `${chalk12.gray(date)} ${color(`${snapshot.coverageScore}%`)} ${snapshot.documentedExports}/${snapshot.totalExports} exports${version}${commit}`;
3241
+ const commit = snapshot.commit ? chalk11.gray(` (${snapshot.commit.slice(0, 7)})`) : "";
3242
+ return `${chalk11.gray(date)} ${color(`${snapshot.coverageScore}%`)} ${snapshot.documentedExports}/${snapshot.totalExports} exports${version}${commit}`;
3874
3243
  }
3875
3244
  function formatWeekDate(timestamp) {
3876
3245
  const date = new Date(timestamp);
@@ -3878,30 +3247,26 @@ function formatWeekDate(timestamp) {
3878
3247
  }
3879
3248
  function formatVelocity(velocity) {
3880
3249
  if (velocity > 0)
3881
- return chalk12.green(`+${velocity}%/day`);
3250
+ return chalk11.green(`+${velocity}%/day`);
3882
3251
  if (velocity < 0)
3883
- return chalk12.red(`${velocity}%/day`);
3884
- return chalk12.gray("0%/day");
3252
+ return chalk11.red(`${velocity}%/day`);
3253
+ return chalk11.gray("0%/day");
3885
3254
  }
3886
3255
  function registerTrendsCommand(program) {
3887
- program.command("trends").description("Show coverage trends over time").option("--cwd <dir>", "Working directory", process.cwd()).option("-n, --limit <count>", "Number of snapshots to show", "10").option("--prune <count>", "Prune history to keep only N snapshots").option("--record", "Record current coverage to history").option("--json", "Output as JSON").option("--extended", "Show extended trend analysis (velocity, projections)").option("--tier <tier>", "Retention tier: free (7d), team (30d), pro (90d)", "pro").option("--weekly", "Show weekly summary breakdown").action(async (options) => {
3256
+ program.command("trends").description("Show coverage trends over time").option("--cwd <dir>", "Working directory", process.cwd()).option("-n, --limit <count>", "Number of snapshots to show", "10").option("--prune <count>", "Prune history to keep only N snapshots").option("--record", "Record current coverage to history").option("--json", "Output as JSON").option("--extended", "Show extended trend analysis (velocity, projections)").option("--weekly", "Show weekly summary breakdown").action(async (options) => {
3888
3257
  const cwd = path9.resolve(options.cwd);
3889
- const tier = options.tier ?? "pro";
3890
3258
  if (options.prune) {
3891
3259
  const keepCount = parseInt(options.prune, 10);
3892
3260
  if (!Number.isNaN(keepCount)) {
3893
3261
  const deleted = pruneHistory(cwd, keepCount);
3894
- console.log(chalk12.green(`Pruned ${deleted} old snapshots, kept ${keepCount} most recent`));
3895
- } else {
3896
- const deleted = pruneByTier(cwd, tier);
3897
- console.log(chalk12.green(`Pruned ${deleted} snapshots older than ${RETENTION_DAYS[tier]} days`));
3262
+ console.log(chalk11.green(`Pruned ${deleted} old snapshots, kept ${keepCount} most recent`));
3898
3263
  }
3899
3264
  return;
3900
3265
  }
3901
3266
  if (options.record) {
3902
3267
  const specPath = path9.resolve(cwd, "openpkg.json");
3903
3268
  if (!fs7.existsSync(specPath)) {
3904
- console.error(chalk12.red("No openpkg.json found. Run `doccov spec` first to generate a spec."));
3269
+ console.error(chalk11.red("No openpkg.json found. Run `doccov spec` first to generate a spec."));
3905
3270
  process.exit(1);
3906
3271
  }
3907
3272
  const spin = spinner("Recording coverage snapshot");
@@ -3914,21 +3279,21 @@ function registerTrendsCommand(program) {
3914
3279
  console.log(formatSnapshot(trend.current));
3915
3280
  if (trend.delta !== undefined) {
3916
3281
  const deltaStr = formatDelta2(trend.delta);
3917
- const deltaColor = trend.delta > 0 ? chalk12.green : trend.delta < 0 ? chalk12.red : chalk12.gray;
3918
- console.log(chalk12.gray("Change from previous:"), deltaColor(deltaStr));
3282
+ const deltaColor = trend.delta > 0 ? chalk11.green : trend.delta < 0 ? chalk11.red : chalk11.gray;
3283
+ console.log(chalk11.gray("Change from previous:"), deltaColor(deltaStr));
3919
3284
  }
3920
3285
  return;
3921
3286
  } catch (error) {
3922
3287
  spin.fail("Failed to record snapshot");
3923
- console.error(chalk12.red("Failed to read openpkg.json:"), error instanceof Error ? error.message : error);
3288
+ console.error(chalk11.red("Failed to read openpkg.json:"), error instanceof Error ? error.message : error);
3924
3289
  process.exit(1);
3925
3290
  }
3926
3291
  }
3927
3292
  const snapshots = loadSnapshots(cwd);
3928
3293
  const limit = parseInt(options.limit ?? "10", 10);
3929
3294
  if (snapshots.length === 0) {
3930
- console.log(chalk12.yellow("No coverage history found."));
3931
- console.log(chalk12.gray("Run `doccov trends --record` to save the current coverage."));
3295
+ console.log(chalk11.yellow("No coverage history found."));
3296
+ console.log(chalk11.gray("Run `doccov trends --record` to save the current coverage."));
3932
3297
  return;
3933
3298
  }
3934
3299
  if (options.json) {
@@ -3943,17 +3308,17 @@ function registerTrendsCommand(program) {
3943
3308
  }
3944
3309
  const sparklineData = snapshots.slice(0, 10).map((s) => s.coverageScore).reverse();
3945
3310
  const sparkline = renderSparkline(sparklineData);
3946
- console.log(chalk12.bold("Coverage Trends"));
3947
- console.log(chalk12.gray(`Package: ${snapshots[0].package}`));
3948
- console.log(chalk12.gray(`Sparkline: ${sparkline}`));
3311
+ console.log(chalk11.bold("Coverage Trends"));
3312
+ console.log(chalk11.gray(`Package: ${snapshots[0].package}`));
3313
+ console.log(chalk11.gray(`Sparkline: ${sparkline}`));
3949
3314
  console.log("");
3950
3315
  if (snapshots.length >= 2) {
3951
3316
  const oldest = snapshots[snapshots.length - 1];
3952
3317
  const newest = snapshots[0];
3953
3318
  const overallDelta = newest.coverageScore - oldest.coverageScore;
3954
3319
  const deltaStr = formatDelta2(overallDelta);
3955
- const deltaColor = overallDelta > 0 ? chalk12.green : overallDelta < 0 ? chalk12.red : chalk12.gray;
3956
- console.log(chalk12.gray("Overall trend:"), deltaColor(deltaStr), chalk12.gray(`(${snapshots.length} snapshots)`));
3320
+ const deltaColor = overallDelta > 0 ? chalk11.green : overallDelta < 0 ? chalk11.red : chalk11.gray;
3321
+ console.log(chalk11.gray("Overall trend:"), deltaColor(deltaStr), chalk11.gray(`(${snapshots.length} snapshots)`));
3957
3322
  console.log("");
3958
3323
  }
3959
3324
  if (options.extended) {
@@ -3962,58 +3327,56 @@ function registerTrendsCommand(program) {
3962
3327
  try {
3963
3328
  const specContent = fs7.readFileSync(specPath, "utf-8");
3964
3329
  const spec = JSON.parse(specContent);
3965
- const extended = getExtendedTrend(spec, cwd, { tier });
3966
- console.log(chalk12.bold("Extended Analysis"));
3967
- console.log(chalk12.gray(`Tier: ${tier} (${RETENTION_DAYS[tier]}-day retention)`));
3330
+ const extended = getExtendedTrend(spec, cwd);
3331
+ console.log(chalk11.bold("Extended Analysis"));
3332
+ console.log(chalk11.gray("90-day retention"));
3968
3333
  console.log("");
3969
3334
  console.log(" Velocity:");
3970
3335
  console.log(` 7-day: ${formatVelocity(extended.velocity7d)}`);
3971
3336
  console.log(` 30-day: ${formatVelocity(extended.velocity30d)}`);
3972
- if (extended.velocity90d !== undefined) {
3973
- console.log(` 90-day: ${formatVelocity(extended.velocity90d)}`);
3974
- }
3337
+ console.log(` 90-day: ${formatVelocity(extended.velocity90d)}`);
3975
3338
  console.log("");
3976
- const projColor = extended.projected30d >= extended.trend.current.coverageScore ? chalk12.green : chalk12.red;
3339
+ const projColor = extended.projected30d >= extended.trend.current.coverageScore ? chalk11.green : chalk11.red;
3977
3340
  console.log(` Projected (30d): ${projColor(`${extended.projected30d}%`)}`);
3978
- console.log(` All-time high: ${chalk12.green(`${extended.allTimeHigh}%`)}`);
3979
- console.log(` All-time low: ${chalk12.red(`${extended.allTimeLow}%`)}`);
3341
+ console.log(` All-time high: ${chalk11.green(`${extended.allTimeHigh}%`)}`);
3342
+ console.log(` All-time low: ${chalk11.red(`${extended.allTimeLow}%`)}`);
3980
3343
  if (extended.dataRange) {
3981
3344
  const startDate = formatWeekDate(extended.dataRange.start);
3982
3345
  const endDate = formatWeekDate(extended.dataRange.end);
3983
- console.log(chalk12.gray(` Data range: ${startDate} - ${endDate}`));
3346
+ console.log(chalk11.gray(` Data range: ${startDate} - ${endDate}`));
3984
3347
  }
3985
3348
  console.log("");
3986
3349
  if (options.weekly && extended.weeklySummaries.length > 0) {
3987
- console.log(chalk12.bold("Weekly Summary"));
3350
+ console.log(chalk11.bold("Weekly Summary"));
3988
3351
  const weekLimit = Math.min(extended.weeklySummaries.length, 8);
3989
3352
  for (let i = 0;i < weekLimit; i++) {
3990
3353
  const week = extended.weeklySummaries[i];
3991
3354
  const weekStart = formatWeekDate(week.weekStart);
3992
3355
  const weekEnd = formatWeekDate(week.weekEnd);
3993
- const deltaColor = week.delta > 0 ? chalk12.green : week.delta < 0 ? chalk12.red : chalk12.gray;
3356
+ const deltaColor = week.delta > 0 ? chalk11.green : week.delta < 0 ? chalk11.red : chalk11.gray;
3994
3357
  const deltaStr = week.delta > 0 ? `+${week.delta}%` : `${week.delta}%`;
3995
3358
  console.log(` ${weekStart} - ${weekEnd}: ${week.avgCoverage}% avg ${deltaColor(deltaStr)} (${week.snapshotCount} snapshots)`);
3996
3359
  }
3997
3360
  if (extended.weeklySummaries.length > weekLimit) {
3998
- console.log(chalk12.gray(` ... and ${extended.weeklySummaries.length - weekLimit} more weeks`));
3361
+ console.log(chalk11.gray(` ... and ${extended.weeklySummaries.length - weekLimit} more weeks`));
3999
3362
  }
4000
3363
  console.log("");
4001
3364
  }
4002
3365
  } catch {
4003
- console.log(chalk12.yellow("Could not load openpkg.json for extended analysis"));
3366
+ console.log(chalk11.yellow("Could not load openpkg.json for extended analysis"));
4004
3367
  console.log("");
4005
3368
  }
4006
3369
  }
4007
3370
  }
4008
- console.log(chalk12.bold("History"));
3371
+ console.log(chalk11.bold("History"));
4009
3372
  const displaySnapshots = snapshots.slice(0, limit);
4010
3373
  for (let i = 0;i < displaySnapshots.length; i++) {
4011
3374
  const snapshot = displaySnapshots[i];
4012
- const prefix2 = i === 0 ? chalk12.cyan("→") : " ";
3375
+ const prefix2 = i === 0 ? chalk11.cyan("→") : " ";
4013
3376
  console.log(`${prefix2} ${formatSnapshot(snapshot)}`);
4014
3377
  }
4015
3378
  if (snapshots.length > limit) {
4016
- console.log(chalk12.gray(` ... and ${snapshots.length - limit} more`));
3379
+ console.log(chalk11.gray(` ... and ${snapshots.length - limit} more`));
4017
3380
  }
4018
3381
  });
4019
3382
  }
@@ -4025,7 +3388,6 @@ var packageJson = JSON.parse(readFileSync5(path10.join(__dirname2, "../package.j
4025
3388
  var program = new Command;
4026
3389
  program.name("doccov").description("DocCov - Documentation coverage and drift detection for TypeScript").version(packageJson.version);
4027
3390
  registerCheckCommand(program);
4028
- registerInfoCommand(program);
4029
3391
  registerSpecCommand(program);
4030
3392
  registerDiffCommand(program);
4031
3393
  registerInitCommand(program);