@doccov/cli 0.27.1 → 0.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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",
@@ -170,26 +87,75 @@ import {
170
87
  parseExamplesFlag,
171
88
  resolveTarget
172
89
  } from "@doccov/sdk";
173
- import chalk7 from "chalk";
90
+ import chalk6 from "chalk";
174
91
 
175
- // ../cli-utils/dist/index.js
92
+ // src/utils/filter-options.ts
93
+ import { mergeFilters, parseListFlag } from "@doccov/sdk";
176
94
  import chalk from "chalk";
95
+ var parseVisibilityFlag = (value) => {
96
+ if (!value)
97
+ return;
98
+ const validTags = ["public", "beta", "alpha", "internal"];
99
+ const parsed = parseListFlag(value);
100
+ if (!parsed)
101
+ return;
102
+ const result = [];
103
+ for (const tag of parsed) {
104
+ const lower = tag.toLowerCase();
105
+ if (validTags.includes(lower)) {
106
+ result.push(lower);
107
+ }
108
+ }
109
+ return result.length > 0 ? result : undefined;
110
+ };
111
+ var formatList = (label, values) => `${label}: ${values.map((value) => chalk.cyan(value)).join(", ")}`;
112
+ var mergeFilterOptions = (config, cliOptions) => {
113
+ const messages = [];
114
+ if (config?.include) {
115
+ messages.push(formatList("include filters from config", config.include));
116
+ }
117
+ if (config?.exclude) {
118
+ messages.push(formatList("exclude filters from config", config.exclude));
119
+ }
120
+ if (cliOptions.include) {
121
+ messages.push(formatList("apply include filters from CLI", cliOptions.include));
122
+ }
123
+ if (cliOptions.exclude) {
124
+ messages.push(formatList("apply exclude filters from CLI", cliOptions.exclude));
125
+ }
126
+ if (cliOptions.visibility) {
127
+ messages.push(formatList("apply visibility filter from CLI", cliOptions.visibility));
128
+ }
129
+ const resolved = mergeFilters(config, cliOptions);
130
+ if (!resolved.include && !resolved.exclude && !cliOptions.visibility) {
131
+ return { messages };
132
+ }
133
+ const source = resolved.source === "override" ? "cli" : resolved.source;
134
+ return {
135
+ include: resolved.include,
136
+ exclude: resolved.exclude,
137
+ visibility: cliOptions.visibility,
138
+ source,
139
+ messages
140
+ };
141
+ };
142
+
143
+ // src/utils/progress/colors.ts
177
144
  import chalk2 from "chalk";
178
- import { Worker } from "node:worker_threads";
179
145
  var colors = {
180
- success: chalk.green,
181
- error: chalk.red,
182
- warning: chalk.yellow,
183
- info: chalk.cyan,
184
- muted: chalk.gray,
185
- bold: chalk.bold,
186
- dim: chalk.dim,
187
- underline: chalk.underline,
188
- primary: chalk.cyan,
189
- secondary: chalk.magenta,
190
- path: chalk.cyan,
191
- number: chalk.yellow,
192
- code: chalk.gray
146
+ success: chalk2.green,
147
+ error: chalk2.red,
148
+ warning: chalk2.yellow,
149
+ info: chalk2.cyan,
150
+ muted: chalk2.gray,
151
+ bold: chalk2.bold,
152
+ dim: chalk2.dim,
153
+ underline: chalk2.underline,
154
+ primary: chalk2.cyan,
155
+ secondary: chalk2.magenta,
156
+ path: chalk2.cyan,
157
+ number: chalk2.yellow,
158
+ code: chalk2.gray
193
159
  };
194
160
  var symbols = {
195
161
  success: "✓",
@@ -228,6 +194,10 @@ var prefix = {
228
194
  warning: colors.warning(symbols.warning),
229
195
  info: colors.info(symbols.info)
230
196
  };
197
+ // src/utils/progress/spinner.ts
198
+ import chalk3 from "chalk";
199
+
200
+ // src/utils/progress/utils.ts
231
201
  function isTTY() {
232
202
  return Boolean(process.stdout.isTTY);
233
203
  }
@@ -249,18 +219,6 @@ function getTerminalWidth() {
249
219
  const width = process.stdout.columns || DEFAULT_TERMINAL_WIDTH;
250
220
  return Math.max(width, MIN_TERMINAL_WIDTH);
251
221
  }
252
- function formatDuration(ms) {
253
- if (ms < 1000) {
254
- return `${ms}ms`;
255
- }
256
- const seconds = ms / 1000;
257
- if (seconds < 60) {
258
- return `${seconds.toFixed(1)}s`;
259
- }
260
- const minutes = Math.floor(seconds / 60);
261
- const remainingSeconds = Math.floor(seconds % 60);
262
- return `${minutes}m ${remainingSeconds}s`;
263
- }
264
222
  var cursor = {
265
223
  hide: "\x1B[?25l",
266
224
  show: "\x1B[?25h",
@@ -279,11 +237,6 @@ function clearLine() {
279
237
  process.stdout.write(cursor.clearLine + cursor.left);
280
238
  }
281
239
  }
282
- function moveCursorUp(lines = 1) {
283
- if (isTTY()) {
284
- process.stdout.write(cursor.up(lines));
285
- }
286
- }
287
240
  function hideCursor() {
288
241
  if (isTTY()) {
289
242
  process.stdout.write(cursor.hide);
@@ -304,391 +257,15 @@ function stripAnsi(text) {
304
257
  return text.replace(ANSI_REGEX, "");
305
258
  }
306
259
 
307
- class MultiProgress {
308
- bars = new Map;
309
- barOrder = [];
310
- options;
311
- spinnerFrames;
312
- spinnerIndex = 0;
313
- timer = null;
314
- lastRenderedLines = 0;
315
- symbols = getSymbols(supportsUnicode());
316
- sigintHandler = null;
317
- filledChar;
318
- emptyChar;
319
- constructor(options = {}) {
320
- this.options = {
321
- barWidth: options.barWidth,
322
- showPercent: options.showPercent ?? true,
323
- showCount: options.showCount ?? true,
324
- spinnerInterval: options.spinnerInterval ?? 80
325
- };
326
- this.spinnerFrames = supportsUnicode() ? ["◐", "◓", "◑", "◒"] : ["-", "\\", "|", "/"];
327
- const unicode = supportsUnicode();
328
- this.filledChar = unicode ? "█" : "#";
329
- this.emptyChar = unicode ? "░" : "-";
330
- }
331
- start() {
332
- if (!isInteractive())
333
- return this;
334
- hideCursor();
335
- this.setupSignalHandler();
336
- this.timer = setInterval(() => {
337
- if (this.bars.size > 0 && [...this.bars.values()].some((b) => b.status === "active")) {
338
- this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
339
- this.render();
340
- }
341
- }, this.options.spinnerInterval);
342
- return this;
343
- }
344
- add(config) {
345
- const state = {
346
- id: config.id,
347
- label: config.label,
348
- total: config.total ?? 100,
349
- current: config.current ?? 0,
350
- status: "active",
351
- startTime: Date.now()
352
- };
353
- this.bars.set(config.id, state);
354
- if (!this.barOrder.includes(config.id)) {
355
- this.barOrder.push(config.id);
356
- }
357
- if (!isInteractive()) {
358
- console.log(`${this.symbols.bullet} ${config.label}`);
359
- } else {
360
- this.render();
361
- }
362
- return this;
363
- }
364
- update(id, current, label) {
365
- const bar = this.bars.get(id);
366
- if (!bar)
367
- return this;
368
- bar.current = Math.min(current, bar.total);
369
- if (label !== undefined)
370
- bar.label = label;
371
- if (isInteractive()) {
372
- this.render();
373
- }
374
- return this;
375
- }
376
- increment(id, amount = 1) {
377
- const bar = this.bars.get(id);
378
- if (!bar)
379
- return this;
380
- return this.update(id, bar.current + amount);
381
- }
382
- complete(id, label) {
383
- const bar = this.bars.get(id);
384
- if (!bar)
385
- return this;
386
- bar.status = "completed";
387
- bar.current = bar.total;
388
- if (label !== undefined)
389
- bar.label = label;
390
- if (!isInteractive()) {
391
- console.log(`${colors.success(this.symbols.success)} ${bar.label}`);
392
- } else {
393
- this.render();
394
- }
395
- return this;
396
- }
397
- fail(id, label) {
398
- const bar = this.bars.get(id);
399
- if (!bar)
400
- return this;
401
- bar.status = "failed";
402
- if (label !== undefined)
403
- bar.label = label;
404
- if (!isInteractive()) {
405
- console.log(`${colors.error(this.symbols.error)} ${bar.label}`);
406
- } else {
407
- this.render();
408
- }
409
- return this;
410
- }
411
- remove(id) {
412
- this.bars.delete(id);
413
- this.barOrder = this.barOrder.filter((i) => i !== id);
414
- if (isInteractive()) {
415
- this.render();
416
- }
417
- return this;
418
- }
419
- get(id) {
420
- return this.bars.get(id);
421
- }
422
- get allDone() {
423
- if (this.bars.size === 0)
424
- return true;
425
- return [...this.bars.values()].every((b) => b.status !== "active");
426
- }
427
- stop() {
428
- if (this.timer) {
429
- clearInterval(this.timer);
430
- this.timer = null;
431
- }
432
- this.cleanup();
433
- return this;
434
- }
435
- render() {
436
- if (!isTTY())
437
- return;
438
- this.clearOutput();
439
- const width = getTerminalWidth();
440
- const lines = [];
441
- for (const id of this.barOrder) {
442
- const bar = this.bars.get(id);
443
- if (!bar)
444
- continue;
445
- const line = this.renderBar(bar, width);
446
- lines.push(line);
447
- }
448
- if (lines.length > 0) {
449
- process.stdout.write(lines.join(`
450
- `));
451
- this.lastRenderedLines = lines.length;
452
- }
453
- }
454
- renderBar(bar, termWidth) {
455
- const parts = [];
456
- let symbol;
457
- switch (bar.status) {
458
- case "completed":
459
- symbol = colors.success(this.symbols.success);
460
- break;
461
- case "failed":
462
- symbol = colors.error(this.symbols.error);
463
- break;
464
- default:
465
- symbol = colors.primary(this.spinnerFrames[this.spinnerIndex]);
466
- }
467
- parts.push(symbol);
468
- parts.push(bar.label);
469
- const suffixParts = [];
470
- if (this.options.showPercent) {
471
- const pct = bar.total === 0 ? 0 : Math.round(bar.current / bar.total * 100);
472
- suffixParts.push(`${pct}%`);
473
- }
474
- if (this.options.showCount) {
475
- suffixParts.push(`${bar.current}/${bar.total}`);
476
- }
477
- const suffix = suffixParts.length > 0 ? ` ${suffixParts.join(" ")}` : "";
478
- const labelLen = stripAnsi(parts.join(" ")).length + 1;
479
- const bracketLen = 2;
480
- const suffixLen = stripAnsi(suffix).length;
481
- const minBarWidth = 10;
482
- const availableWidth = termWidth - labelLen - bracketLen - suffixLen - 1;
483
- const barWidth = this.options.barWidth ?? Math.max(minBarWidth, Math.min(30, availableWidth));
484
- const filledWidth = Math.round(bar.current / bar.total * barWidth);
485
- const emptyWidth = barWidth - filledWidth;
486
- const barViz = `[${this.filledChar.repeat(filledWidth)}${this.emptyChar.repeat(emptyWidth)}]`;
487
- parts.push(barViz);
488
- return truncate(parts.join(" ") + suffix, termWidth);
489
- }
490
- clearOutput() {
491
- if (!isTTY() || this.lastRenderedLines === 0)
492
- return;
493
- for (let i = 0;i < this.lastRenderedLines; i++) {
494
- if (i > 0)
495
- process.stdout.write(cursor.up(1));
496
- clearLine();
497
- }
498
- this.lastRenderedLines = 0;
499
- }
500
- setupSignalHandler() {
501
- this.sigintHandler = () => {
502
- this.cleanup();
503
- process.exit(130);
504
- };
505
- process.on("SIGINT", this.sigintHandler);
506
- }
507
- cleanup() {
508
- if (this.sigintHandler) {
509
- process.removeListener("SIGINT", this.sigintHandler);
510
- this.sigintHandler = null;
511
- }
512
- showCursor();
513
- if (isTTY() && this.lastRenderedLines > 0) {
514
- process.stdout.write(`
515
- `);
516
- }
517
- }
518
- }
519
- class ProgressBar {
520
- total;
521
- current;
522
- label;
523
- width;
524
- showPercent;
525
- showCount;
526
- showETA;
527
- filledChar;
528
- emptyChar;
529
- startTime = null;
530
- lastRender = "";
531
- symbols = getSymbols(supportsUnicode());
532
- sigintHandler = null;
533
- isComplete = false;
534
- constructor(options = {}) {
535
- this.total = options.total ?? 100;
536
- this.current = options.current ?? 0;
537
- this.label = options.label ?? "";
538
- this.width = options.width;
539
- this.showPercent = options.showPercent ?? true;
540
- this.showCount = options.showCount ?? true;
541
- this.showETA = options.showETA ?? true;
542
- const unicode = supportsUnicode();
543
- this.filledChar = options.chars?.filled ?? (unicode ? "█" : "#");
544
- this.emptyChar = options.chars?.empty ?? (unicode ? "░" : "-");
545
- }
546
- start(label) {
547
- if (label !== undefined)
548
- this.label = label;
549
- this.startTime = Date.now();
550
- this.current = 0;
551
- this.isComplete = false;
552
- if (!isInteractive()) {
553
- console.log(`${this.symbols.bullet} ${this.label}`);
554
- return this;
555
- }
556
- hideCursor();
557
- this.setupSignalHandler();
558
- this.render();
559
- return this;
560
- }
561
- update(current) {
562
- this.current = Math.min(current, this.total);
563
- if (isInteractive()) {
564
- this.render();
565
- }
566
- return this;
567
- }
568
- increment(amount = 1) {
569
- return this.update(this.current + amount);
570
- }
571
- setLabel(label) {
572
- this.label = label;
573
- if (isInteractive()) {
574
- this.render();
575
- }
576
- return this;
577
- }
578
- setTotal(total) {
579
- this.total = total;
580
- if (isInteractive()) {
581
- this.render();
582
- }
583
- return this;
584
- }
585
- complete(label) {
586
- if (label !== undefined)
587
- this.label = label;
588
- this.current = this.total;
589
- this.isComplete = true;
590
- if (!isInteractive()) {
591
- console.log(`${colors.success(this.symbols.success)} ${this.label}`);
592
- } else {
593
- clearLine();
594
- process.stdout.write(`${colors.success(this.symbols.success)} ${this.label}
595
- `);
596
- }
597
- this.cleanup();
598
- return this;
599
- }
600
- fail(label) {
601
- if (label !== undefined)
602
- this.label = label;
603
- this.isComplete = true;
604
- if (!isInteractive()) {
605
- console.log(`${colors.error(this.symbols.error)} ${this.label}`);
606
- } else {
607
- clearLine();
608
- process.stdout.write(`${colors.error(this.symbols.error)} ${this.label}
609
- `);
610
- }
611
- this.cleanup();
612
- return this;
613
- }
614
- get percentage() {
615
- return this.total === 0 ? 0 : Math.round(this.current / this.total * 100);
616
- }
617
- get isDone() {
618
- return this.isComplete || this.current >= this.total;
619
- }
620
- render() {
621
- if (!isTTY())
622
- return;
623
- const termWidth = getTerminalWidth();
624
- const parts = [];
625
- if (this.label) {
626
- parts.push(this.label);
627
- }
628
- const suffixParts = [];
629
- if (this.showPercent) {
630
- suffixParts.push(`${this.percentage}%`);
631
- }
632
- if (this.showCount) {
633
- suffixParts.push(`${this.current}/${this.total}`);
634
- }
635
- if (this.showETA && this.startTime) {
636
- const eta = this.calculateETA();
637
- if (eta)
638
- suffixParts.push(eta);
639
- }
640
- const suffix = suffixParts.length > 0 ? ` ${suffixParts.join(" ")}` : "";
641
- const labelLen = this.label ? stripAnsi(this.label).length + 1 : 0;
642
- const bracketLen = 2;
643
- const suffixLen = stripAnsi(suffix).length;
644
- const minBarWidth = 10;
645
- const availableWidth = termWidth - labelLen - bracketLen - suffixLen - 1;
646
- const barWidth = this.width ?? Math.max(minBarWidth, Math.min(40, availableWidth));
647
- const filledWidth = Math.round(this.current / this.total * barWidth);
648
- const emptyWidth = barWidth - filledWidth;
649
- const bar = `[${this.filledChar.repeat(filledWidth)}${this.emptyChar.repeat(emptyWidth)}]`;
650
- parts.push(bar);
651
- const line = truncate(parts.join(" ") + suffix, termWidth);
652
- if (line !== this.lastRender) {
653
- clearLine();
654
- process.stdout.write(line);
655
- this.lastRender = line;
656
- }
657
- }
658
- calculateETA() {
659
- if (!this.startTime || this.current === 0)
660
- return null;
661
- const elapsed = Date.now() - this.startTime;
662
- if (elapsed < 1000)
663
- return null;
664
- const rate = this.current / elapsed;
665
- const remaining = this.total - this.current;
666
- const etaMs = remaining / rate;
667
- return `ETA ${formatDuration(etaMs)}`;
668
- }
669
- setupSignalHandler() {
670
- this.sigintHandler = () => {
671
- this.cleanup();
672
- process.exit(130);
673
- };
674
- process.on("SIGINT", this.sigintHandler);
675
- }
676
- cleanup() {
677
- if (this.sigintHandler) {
678
- process.removeListener("SIGINT", this.sigintHandler);
679
- this.sigintHandler = null;
680
- }
681
- showCursor();
682
- }
683
- }
260
+ // src/utils/progress/spinner.ts
684
261
  var spinnerColors = {
685
- cyan: chalk2.cyan,
686
- yellow: chalk2.yellow,
687
- green: chalk2.green,
688
- red: chalk2.red,
689
- magenta: chalk2.magenta,
690
- blue: chalk2.blue,
691
- white: chalk2.white
262
+ cyan: chalk3.cyan,
263
+ yellow: chalk3.yellow,
264
+ green: chalk3.green,
265
+ red: chalk3.red,
266
+ magenta: chalk3.magenta,
267
+ blue: chalk3.blue,
268
+ white: chalk3.white
692
269
  };
693
270
  var FRAME_SETS = {
694
271
  dots: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
@@ -708,13 +285,11 @@ class Spinner {
708
285
  symbols = getSymbols(supportsUnicode());
709
286
  lastRenderedLines = 0;
710
287
  sigintHandler = null;
711
- animate;
712
288
  constructor(options = {}) {
713
289
  this.label = options.label ?? "";
714
290
  this.detail = options.detail;
715
291
  this.interval = options.interval ?? 80;
716
292
  this.colorFn = spinnerColors[options.color ?? "cyan"];
717
- this.animate = options.animate ?? true;
718
293
  const style = options.style ?? "circle";
719
294
  this.frames = supportsUnicode() ? FRAME_SETS[style] : ASCII_FRAME_SET;
720
295
  }
@@ -726,7 +301,7 @@ class Spinner {
726
301
  this.state = "spinning";
727
302
  this.frameIndex = 0;
728
303
  this.lastRenderedLines = 0;
729
- if (!isInteractive() || !this.animate) {
304
+ if (!isInteractive()) {
730
305
  console.log(`${this.symbols.bullet} ${this.label}`);
731
306
  return this;
732
307
  }
@@ -784,12 +359,14 @@ class Spinner {
784
359
  this.timer = null;
785
360
  }
786
361
  this.state = state;
787
- const symbol = state === "success" ? this.symbols.success : this.symbols.error;
788
- const colorFn = state === "success" ? colors.success : colors.error;
789
- if (!isInteractive() || !this.animate) {
362
+ if (!isInteractive()) {
363
+ const symbol = state === "success" ? this.symbols.success : this.symbols.error;
364
+ const colorFn = state === "success" ? colors.success : colors.error;
790
365
  console.log(`${colorFn(symbol)} ${this.label}`);
791
366
  } else {
792
367
  this.clearOutput();
368
+ const symbol = state === "success" ? this.symbols.success : this.symbols.error;
369
+ const colorFn = state === "success" ? colors.success : colors.error;
793
370
  process.stdout.write(`${colorFn(symbol)} ${this.label}
794
371
  `);
795
372
  }
@@ -839,206 +416,7 @@ ${detailLine}`);
839
416
  function spinner(label, options) {
840
417
  return new Spinner({ ...options, label }).start();
841
418
  }
842
-
843
- class StepProgress {
844
- steps = [];
845
- showNumbers;
846
- spinnerInterval;
847
- spinnerFrames;
848
- spinnerIndex = 0;
849
- timer = null;
850
- symbols = getSymbols(supportsUnicode());
851
- lastRenderedLines = 0;
852
- sigintHandler = null;
853
- constructor(options = {}) {
854
- this.showNumbers = options.showNumbers ?? true;
855
- this.spinnerInterval = options.spinnerInterval ?? 80;
856
- this.spinnerFrames = supportsUnicode() ? ["◐", "◓", "◑", "◒"] : ["-", "\\", "|", "/"];
857
- if (options.steps) {
858
- this.steps = options.steps.map((label) => ({ label, status: "pending" }));
859
- }
860
- }
861
- start() {
862
- if (!isInteractive())
863
- return this;
864
- hideCursor();
865
- this.setupSignalHandler();
866
- this.render();
867
- this.timer = setInterval(() => {
868
- if (this.steps.some((s) => s.status === "active")) {
869
- this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
870
- this.render();
871
- }
872
- }, this.spinnerInterval);
873
- return this;
874
- }
875
- addStep(label) {
876
- this.steps.push({ label, status: "pending" });
877
- if (isInteractive())
878
- this.render();
879
- return this;
880
- }
881
- startStep(index) {
882
- if (index >= 0 && index < this.steps.length) {
883
- this.steps[index].status = "active";
884
- this.steps[index].startTime = Date.now();
885
- if (isInteractive()) {
886
- this.render();
887
- } else {
888
- const step = this.steps[index];
889
- const prefix2 = this.showNumbers ? `[${index + 1}/${this.steps.length}] ` : "";
890
- console.log(`${this.symbols.bullet} ${prefix2}${step.label}...`);
891
- }
892
- }
893
- return this;
894
- }
895
- completeStep(index) {
896
- if (index >= 0 && index < this.steps.length) {
897
- this.steps[index].status = "completed";
898
- this.steps[index].endTime = Date.now();
899
- if (isInteractive()) {
900
- this.render();
901
- } else {
902
- const step = this.steps[index];
903
- const duration = this.getStepDuration(step);
904
- const prefix2 = this.showNumbers ? `[${index + 1}/${this.steps.length}] ` : "";
905
- console.log(`${colors.success(this.symbols.success)} ${prefix2}${step.label}${duration}`);
906
- }
907
- }
908
- return this;
909
- }
910
- failStep(index) {
911
- if (index >= 0 && index < this.steps.length) {
912
- this.steps[index].status = "failed";
913
- this.steps[index].endTime = Date.now();
914
- if (isInteractive()) {
915
- this.render();
916
- } else {
917
- const step = this.steps[index];
918
- const prefix2 = this.showNumbers ? `[${index + 1}/${this.steps.length}] ` : "";
919
- console.log(`${colors.error(this.symbols.error)} ${prefix2}${step.label}`);
920
- }
921
- }
922
- return this;
923
- }
924
- skipStep(index) {
925
- if (index >= 0 && index < this.steps.length) {
926
- this.steps[index].status = "skipped";
927
- if (isInteractive())
928
- this.render();
929
- }
930
- return this;
931
- }
932
- async run(tasks) {
933
- this.steps = tasks.map((t) => ({ label: t.label, status: "pending" }));
934
- this.start();
935
- const results = [];
936
- let failed = false;
937
- for (let i = 0;i < tasks.length; i++) {
938
- if (failed) {
939
- this.skipStep(i);
940
- continue;
941
- }
942
- this.startStep(i);
943
- try {
944
- results.push(await tasks[i].task());
945
- this.completeStep(i);
946
- } catch {
947
- this.failStep(i);
948
- failed = true;
949
- }
950
- }
951
- this.stop();
952
- return { results, failed };
953
- }
954
- stop() {
955
- if (this.timer) {
956
- clearInterval(this.timer);
957
- this.timer = null;
958
- }
959
- this.cleanup();
960
- return this;
961
- }
962
- get currentStepIndex() {
963
- const activeIdx = this.steps.findIndex((s) => s.status === "active");
964
- if (activeIdx >= 0)
965
- return activeIdx;
966
- return this.steps.findIndex((s) => s.status === "pending");
967
- }
968
- render() {
969
- if (!isTTY())
970
- return;
971
- if (this.lastRenderedLines > 0) {
972
- moveCursorUp(this.lastRenderedLines - 1);
973
- for (let i = 0;i < this.lastRenderedLines; i++) {
974
- clearLine();
975
- if (i < this.lastRenderedLines - 1) {
976
- process.stdout.write(cursor.down(1));
977
- }
978
- }
979
- moveCursorUp(this.lastRenderedLines - 1);
980
- }
981
- const width = getTerminalWidth();
982
- const lines = [];
983
- for (let i = 0;i < this.steps.length; i++) {
984
- const step = this.steps[i];
985
- const prefix2 = this.showNumbers ? `[${i + 1}/${this.steps.length}] ` : "";
986
- const duration = this.getStepDuration(step);
987
- let symbol;
988
- let text;
989
- switch (step.status) {
990
- case "completed":
991
- symbol = colors.success(this.symbols.success);
992
- text = `${prefix2}${step.label}${duration}`;
993
- break;
994
- case "failed":
995
- symbol = colors.error(this.symbols.error);
996
- text = `${prefix2}${step.label}`;
997
- break;
998
- case "active":
999
- symbol = colors.primary(this.spinnerFrames[this.spinnerIndex]);
1000
- text = `${prefix2}${step.label}`;
1001
- break;
1002
- case "skipped":
1003
- symbol = colors.muted(this.symbols.bullet);
1004
- text = colors.muted(`${prefix2}${step.label} (skipped)`);
1005
- break;
1006
- default:
1007
- symbol = colors.muted("○");
1008
- text = colors.muted(`${prefix2}${step.label}`);
1009
- }
1010
- lines.push(truncate(`${symbol} ${text}`, width));
1011
- }
1012
- process.stdout.write(lines.join(`
1013
- `));
1014
- this.lastRenderedLines = lines.length;
1015
- }
1016
- getStepDuration(step) {
1017
- if (step.startTime && step.endTime) {
1018
- const ms = step.endTime - step.startTime;
1019
- return colors.muted(` (${formatDuration(ms)})`);
1020
- }
1021
- return "";
1022
- }
1023
- setupSignalHandler() {
1024
- this.sigintHandler = () => {
1025
- this.cleanup();
1026
- process.exit(130);
1027
- };
1028
- process.on("SIGINT", this.sigintHandler);
1029
- }
1030
- cleanup() {
1031
- if (this.sigintHandler) {
1032
- process.removeListener("SIGINT", this.sigintHandler);
1033
- this.sigintHandler = null;
1034
- }
1035
- showCursor();
1036
- if (isTTY() && this.lastRenderedLines > 0) {
1037
- process.stdout.write(`
1038
- `);
1039
- }
1040
- }
1041
- }
419
+ // src/utils/progress/summary.ts
1042
420
  class Summary {
1043
421
  items = [];
1044
422
  title;
@@ -1149,70 +527,18 @@ class Summary {
1149
527
  switch (operator) {
1150
528
  case "<":
1151
529
  return value < thresh;
1152
- case ">":
1153
- return value > thresh;
1154
- case "<=":
1155
- return value <= thresh;
1156
- case ">=":
1157
- return value >= thresh;
1158
- }
1159
- }
1160
- }
1161
- function summary(options) {
1162
- return new Summary(options);
1163
- }
1164
-
1165
- // src/utils/filter-options.ts
1166
- import { mergeFilters, parseListFlag } from "@doccov/sdk";
1167
- import chalk3 from "chalk";
1168
- var parseVisibilityFlag = (value) => {
1169
- if (!value)
1170
- return;
1171
- const validTags = ["public", "beta", "alpha", "internal"];
1172
- const parsed = parseListFlag(value);
1173
- if (!parsed)
1174
- return;
1175
- const result = [];
1176
- for (const tag of parsed) {
1177
- const lower = tag.toLowerCase();
1178
- if (validTags.includes(lower)) {
1179
- result.push(lower);
1180
- }
1181
- }
1182
- return result.length > 0 ? result : undefined;
1183
- };
1184
- var formatList = (label, values) => `${label}: ${values.map((value) => chalk3.cyan(value)).join(", ")}`;
1185
- var mergeFilterOptions = (config, cliOptions) => {
1186
- const messages = [];
1187
- if (config?.include) {
1188
- messages.push(formatList("include filters from config", config.include));
1189
- }
1190
- if (config?.exclude) {
1191
- messages.push(formatList("exclude filters from config", config.exclude));
1192
- }
1193
- if (cliOptions.include) {
1194
- messages.push(formatList("apply include filters from CLI", cliOptions.include));
1195
- }
1196
- if (cliOptions.exclude) {
1197
- messages.push(formatList("apply exclude filters from CLI", cliOptions.exclude));
1198
- }
1199
- if (cliOptions.visibility) {
1200
- messages.push(formatList("apply visibility filter from CLI", cliOptions.visibility));
1201
- }
1202
- const resolved = mergeFilters(config, cliOptions);
1203
- if (!resolved.include && !resolved.exclude && !cliOptions.visibility) {
1204
- return { messages };
530
+ case ">":
531
+ return value > thresh;
532
+ case "<=":
533
+ return value <= thresh;
534
+ case ">=":
535
+ return value >= thresh;
536
+ }
1205
537
  }
1206
- const source = resolved.source === "override" ? "cli" : resolved.source;
1207
- return {
1208
- include: resolved.include,
1209
- exclude: resolved.exclude,
1210
- visibility: cliOptions.visibility,
1211
- source,
1212
- messages
1213
- };
1214
- };
1215
-
538
+ }
539
+ function summary(options) {
540
+ return new Summary(options);
541
+ }
1216
542
  // src/utils/validation.ts
1217
543
  function clampPercentage(value, fallback = 80) {
1218
544
  if (Number.isNaN(value))
@@ -1240,7 +566,7 @@ import {
1240
566
  previewForgottenExportFixes,
1241
567
  serializeJSDoc
1242
568
  } from "@doccov/sdk";
1243
- import chalk5 from "chalk";
569
+ import chalk4 from "chalk";
1244
570
 
1245
571
  // src/commands/check/utils.ts
1246
572
  import * as fs from "node:fs";
@@ -1314,13 +640,13 @@ async function handleFixes(openpkg, doccov, options, deps) {
1314
640
  }
1315
641
  const { fixable, nonFixable } = categorizeDrifts(allDrifts.map((d) => d.drift));
1316
642
  if (fixable.length === 0) {
1317
- log(chalk5.yellow(`Found ${nonFixable.length} drift issue(s), but none are auto-fixable.`));
643
+ log(chalk4.yellow(`Found ${nonFixable.length} drift issue(s), but none are auto-fixable.`));
1318
644
  return { fixedDriftKeys, editsApplied: 0, filesModified: 0, forgottenExportsFixed: 0 };
1319
645
  }
1320
646
  log("");
1321
- log(chalk5.bold(`Found ${fixable.length} fixable issue(s)`));
647
+ log(chalk4.bold(`Found ${fixable.length} fixable issue(s)`));
1322
648
  if (nonFixable.length > 0) {
1323
- log(chalk5.gray(`(${nonFixable.length} non-fixable issue(s) skipped)`));
649
+ log(chalk4.gray(`(${nonFixable.length} non-fixable issue(s) skipped)`));
1324
650
  }
1325
651
  log("");
1326
652
  const groupedDrifts = groupByExport(allDrifts.filter((d) => fixable.includes(d.drift)));
@@ -1353,20 +679,20 @@ async function handleFixes(openpkg, doccov, options, deps) {
1353
679
  const applyResult = await applyEdits(edits);
1354
680
  if (applyResult.errors.length > 0) {
1355
681
  for (const err of applyResult.errors) {
1356
- error(chalk5.red(` ${err.file}: ${err.error}`));
682
+ error(chalk4.red(` ${err.file}: ${err.error}`));
1357
683
  }
1358
684
  }
1359
685
  const totalFixes = Array.from(editsByFile.values()).reduce((sum, fileEdits) => sum + fileEdits.reduce((s, e) => s + e.fixes.length, 0), 0);
1360
686
  log("");
1361
- log(chalk5.green(`✓ Applied ${totalFixes} fix(es) to ${applyResult.filesModified} file(s)`));
687
+ log(chalk4.green(`✓ Applied ${totalFixes} fix(es) to ${applyResult.filesModified} file(s)`));
1362
688
  for (const [filePath, fileEdits] of editsByFile) {
1363
689
  const relativePath = path3.relative(targetDir, filePath);
1364
690
  const fixCount = fileEdits.reduce((s, e) => s + e.fixes.length, 0);
1365
- log(chalk5.dim(` ${relativePath} (${fixCount} fixes)`));
691
+ log(chalk4.dim(` ${relativePath} (${fixCount} fixes)`));
1366
692
  }
1367
693
  if (options.healthScore !== undefined) {
1368
694
  log("");
1369
- log(chalk5.cyan("Run doccov check again to see updated health score"));
695
+ log(chalk4.cyan("Run doccov check again to see updated health score"));
1370
696
  }
1371
697
  return {
1372
698
  fixedDriftKeys,
@@ -1393,7 +719,7 @@ async function handleForgottenExportFixes(doccov, options, deps) {
1393
719
  return { fixesApplied: 0, filesModified: 0 };
1394
720
  }
1395
721
  log("");
1396
- log(chalk5.bold(`Found ${fixes.length} forgotten export(s) to fix`));
722
+ log(chalk4.bold(`Found ${fixes.length} forgotten export(s) to fix`));
1397
723
  if (isPreview) {
1398
724
  displayForgottenExportPreview(fixes, targetDir, log);
1399
725
  return { fixesApplied: 0, filesModified: 0 };
@@ -1401,12 +727,12 @@ async function handleForgottenExportFixes(doccov, options, deps) {
1401
727
  const result = await applyForgottenExportFixes(fixes);
1402
728
  if (result.errors.length > 0) {
1403
729
  for (const err of result.errors) {
1404
- error(chalk5.red(` ${err.file}: ${err.error}`));
730
+ error(chalk4.red(` ${err.file}: ${err.error}`));
1405
731
  }
1406
732
  }
1407
733
  if (result.fixesApplied > 0) {
1408
734
  log("");
1409
- log(chalk5.green(`✓ Added ${result.fixesApplied} export(s) to ${result.filesModified} file(s)`));
735
+ log(chalk4.green(`✓ Added ${result.fixesApplied} export(s) to ${result.filesModified} file(s)`));
1410
736
  const grouped = new Map;
1411
737
  for (const fix of fixes) {
1412
738
  const relativePath = path3.relative(targetDir, fix.targetFile);
@@ -1415,45 +741,45 @@ async function handleForgottenExportFixes(doccov, options, deps) {
1415
741
  grouped.set(relativePath, types);
1416
742
  }
1417
743
  for (const [file, types] of grouped) {
1418
- log(chalk5.dim(` ${file}: ${types.join(", ")}`));
744
+ log(chalk4.dim(` ${file}: ${types.join(", ")}`));
1419
745
  }
1420
746
  }
1421
747
  return { fixesApplied: result.fixesApplied, filesModified: result.filesModified };
1422
748
  }
1423
749
  function displayForgottenExportPreview(fixes, targetDir, log) {
1424
- log(chalk5.bold("Preview - forgotten exports that would be added:"));
750
+ log(chalk4.bold("Preview - forgotten exports that would be added:"));
1425
751
  log("");
1426
752
  const previews = previewForgottenExportFixes(fixes);
1427
753
  for (const [filePath, preview] of previews) {
1428
754
  const relativePath = path3.relative(targetDir, filePath);
1429
- log(chalk5.cyan(`${relativePath}:${preview.insertLine + 1}`));
755
+ log(chalk4.cyan(`${relativePath}:${preview.insertLine + 1}`));
1430
756
  log("");
1431
757
  for (const stmt of preview.statements) {
1432
- log(chalk5.green(` + ${stmt}`));
758
+ log(chalk4.green(` + ${stmt}`));
1433
759
  }
1434
760
  log("");
1435
761
  }
1436
- log(chalk5.yellow(`${fixes.length} export(s) would be added.`));
1437
- log(chalk5.gray("Run with --fix to apply these changes."));
762
+ log(chalk4.yellow(`${fixes.length} export(s) would be added.`));
763
+ log(chalk4.gray("Run with --fix to apply these changes."));
1438
764
  }
1439
765
  function generateEditForExport(exp, drifts, targetDir, log) {
1440
766
  if (!exp.source?.file) {
1441
- log(chalk5.gray(` Skipping ${exp.name}: no source location`));
767
+ log(chalk4.gray(` Skipping ${exp.name}: no source location`));
1442
768
  return null;
1443
769
  }
1444
770
  if (exp.source.file.endsWith(".d.ts")) {
1445
- log(chalk5.gray(` Skipping ${exp.name}: declaration file`));
771
+ log(chalk4.gray(` Skipping ${exp.name}: declaration file`));
1446
772
  return null;
1447
773
  }
1448
774
  const filePath = path3.resolve(targetDir, exp.source.file);
1449
775
  if (!fs2.existsSync(filePath)) {
1450
- log(chalk5.gray(` Skipping ${exp.name}: file not found`));
776
+ log(chalk4.gray(` Skipping ${exp.name}: file not found`));
1451
777
  return null;
1452
778
  }
1453
779
  const sourceFile = createSourceFile(filePath);
1454
780
  const location = findJSDocLocation(sourceFile, exp.name, exp.source.line);
1455
781
  if (!location) {
1456
- log(chalk5.gray(` Skipping ${exp.name}: could not find declaration`));
782
+ log(chalk4.gray(` Skipping ${exp.name}: could not find declaration`));
1457
783
  return null;
1458
784
  }
1459
785
  let existingPatch = {};
@@ -1478,13 +804,13 @@ function generateEditForExport(exp, drifts, targetDir, log) {
1478
804
  return { filePath, edit, fixes, existingPatch };
1479
805
  }
1480
806
  function displayPreview(editsByFile, targetDir, log) {
1481
- log(chalk5.bold("Preview - changes that would be made:"));
807
+ log(chalk4.bold("Preview - changes that would be made:"));
1482
808
  log("");
1483
809
  for (const [filePath, fileEdits] of editsByFile) {
1484
810
  const relativePath = path3.relative(targetDir, filePath);
1485
811
  for (const { export: exp, edit, fixes } of fileEdits) {
1486
- log(chalk5.cyan(`${relativePath}:${edit.startLine + 1}`));
1487
- log(chalk5.bold(` ${exp.name}`));
812
+ log(chalk4.cyan(`${relativePath}:${edit.startLine + 1}`));
813
+ log(chalk4.bold(` ${exp.name}`));
1488
814
  log("");
1489
815
  if (edit.hasExisting && edit.existingJSDoc) {
1490
816
  const oldLines = edit.existingJSDoc.split(`
@@ -1492,98 +818,31 @@ function displayPreview(editsByFile, targetDir, log) {
1492
818
  const newLines = edit.newJSDoc.split(`
1493
819
  `);
1494
820
  for (const line of oldLines) {
1495
- log(chalk5.red(` - ${line}`));
821
+ log(chalk4.red(` - ${line}`));
1496
822
  }
1497
823
  for (const line of newLines) {
1498
- log(chalk5.green(` + ${line}`));
824
+ log(chalk4.green(` + ${line}`));
1499
825
  }
1500
826
  } else {
1501
827
  const newLines = edit.newJSDoc.split(`
1502
828
  `);
1503
829
  for (const line of newLines) {
1504
- log(chalk5.green(` + ${line}`));
830
+ log(chalk4.green(` + ${line}`));
1505
831
  }
1506
832
  }
1507
833
  log("");
1508
- log(chalk5.dim(` Fixes: ${fixes.map((f) => f.description).join(", ")}`));
834
+ log(chalk4.dim(` Fixes: ${fixes.map((f) => f.description).join(", ")}`));
1509
835
  log("");
1510
836
  }
1511
837
  }
1512
838
  const totalFixes = Array.from(editsByFile.values()).reduce((sum, fileEdits) => sum + fileEdits.reduce((s, e) => s + e.fixes.length, 0), 0);
1513
- log(chalk5.yellow(`${totalFixes} fix(es) across ${editsByFile.size} file(s) would be applied.`));
1514
- log(chalk5.gray("Run with --fix to apply these changes."));
839
+ log(chalk4.yellow(`${totalFixes} fix(es) across ${editsByFile.size} file(s) would be applied.`));
840
+ log(chalk4.gray("Run with --fix to apply these changes."));
1515
841
  }
1516
842
 
1517
843
  // src/commands/check/output.ts
1518
844
  import { generateReportFromDocCov } from "@doccov/sdk";
1519
845
 
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
846
  // src/reports/diff-markdown.ts
1588
847
  import * as path4 from "node:path";
1589
848
  function bar(pct, width = 10) {
@@ -1801,55 +1060,6 @@ function renderDiffHtml(data, options = {}) {
1801
1060
  </body>
1802
1061
  </html>`;
1803
1062
  }
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
1063
  // src/reports/markdown.ts
1854
1064
  import { DRIFT_CATEGORY_LABELS } from "@doccov/sdk";
1855
1065
  function bar2(pct, width = 10) {
@@ -1977,321 +1187,8 @@ function renderMarkdown(stats, options = {}) {
1977
1187
  return lines.join(`
1978
1188
  `);
1979
1189
  }
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
1190
  // src/reports/stats.ts
2294
- import { getExportAnalysis, getExportDrift as getExportDrift3, isFixableDrift } from "@doccov/sdk";
1191
+ import { getExportAnalysis, getExportDrift as getExportDrift2, isFixableDrift } from "@doccov/sdk";
2295
1192
  import {
2296
1193
  DRIFT_CATEGORIES as DRIFT_CATEGORIES2
2297
1194
  } from "@doccov/spec";
@@ -2332,7 +1229,7 @@ function computeStats(openpkg, doccov) {
2332
1229
  partiallyDocumented++;
2333
1230
  else
2334
1231
  undocumented++;
2335
- for (const d of getExportDrift3(exp, doccov)) {
1232
+ for (const d of getExportDrift2(exp, doccov)) {
2336
1233
  const item = {
2337
1234
  exportName: exp.name,
2338
1235
  type: d.type,
@@ -2397,7 +1294,7 @@ function computeStats(openpkg, doccov) {
2397
1294
  import * as fs3 from "node:fs";
2398
1295
  import * as path5 from "node:path";
2399
1296
  import { DEFAULT_REPORT_DIR, getReportPath } from "@doccov/sdk";
2400
- import chalk6 from "chalk";
1297
+ import chalk5 from "chalk";
2401
1298
  function writeReport(options) {
2402
1299
  const { format, content, outputPath, cwd = process.cwd(), silent = false } = options;
2403
1300
  const reportPath = outputPath ? path5.resolve(cwd, outputPath) : path5.resolve(cwd, getReportPath(format));
@@ -2408,7 +1305,7 @@ function writeReport(options) {
2408
1305
  fs3.writeFileSync(reportPath, content);
2409
1306
  const relativePath = path5.relative(cwd, reportPath);
2410
1307
  if (!silent) {
2411
- console.log(chalk6.green(`✓ Wrote ${format} report to ${relativePath}`));
1308
+ console.log(chalk5.green(`✓ Wrote ${format} report to ${relativePath}`));
2412
1309
  }
2413
1310
  return { path: reportPath, format, relativePath };
2414
1311
  }
@@ -2467,7 +1364,7 @@ function displayHealthTree(health, log) {
2467
1364
  }
2468
1365
  function displayHealthVerbose(health, log) {
2469
1366
  const tree = supportsUnicode() ? { branch: "├─", corner: "└─" } : { branch: "|-", corner: "\\-" };
2470
- log(colors.bold("COMPLETENESS") + ` ${health.completeness.score}%`);
1367
+ log(`${colors.bold("COMPLETENESS")} ${health.completeness.score}%`);
2471
1368
  const missingRules = Object.entries(health.completeness.missing);
2472
1369
  for (let i = 0;i < missingRules.length; i++) {
2473
1370
  const [rule, count] = missingRules[i];
@@ -2489,7 +1386,7 @@ function displayHealthVerbose(health, log) {
2489
1386
  }
2490
1387
  if (health.examples) {
2491
1388
  log("");
2492
- log(colors.bold("EXAMPLES") + ` ${health.examples.score}%`);
1389
+ log(`${colors.bold("EXAMPLES")} ${health.examples.score}%`);
2493
1390
  log(`${tree.branch} ${colors.muted("passed".padEnd(12))} ${health.examples.passed}`);
2494
1391
  log(`${tree.corner} ${colors.muted("failed".padEnd(12))} ${health.examples.failed}`);
2495
1392
  }
@@ -2505,7 +1402,6 @@ function displayTextOutput(options, deps) {
2505
1402
  driftExports,
2506
1403
  typecheckErrors,
2507
1404
  staleRefs,
2508
- exampleResult,
2509
1405
  specWarnings,
2510
1406
  specInfos,
2511
1407
  verbose
@@ -2657,10 +1553,8 @@ function handleNonTextOutput(options, deps) {
2657
1553
  format,
2658
1554
  openpkg,
2659
1555
  doccov,
2660
- coverageScore,
2661
1556
  minHealth,
2662
1557
  minApiSurface,
2663
- driftExports,
2664
1558
  typecheckErrors,
2665
1559
  limit,
2666
1560
  stdout,
@@ -2671,7 +1565,7 @@ function handleNonTextOutput(options, deps) {
2671
1565
  const stats = computeStats(openpkg, doccov);
2672
1566
  const report = generateReportFromDocCov(openpkg, doccov);
2673
1567
  const jsonContent = JSON.stringify(report, null, 2);
2674
- const healthScore = doccov.summary.health?.score ?? coverageScore;
1568
+ const healthScore = doccov.summary.health?.score ?? stats.coverageScore;
2675
1569
  let formatContent;
2676
1570
  switch (format) {
2677
1571
  case "json":
@@ -2680,15 +1574,6 @@ function handleNonTextOutput(options, deps) {
2680
1574
  case "markdown":
2681
1575
  formatContent = renderMarkdown(stats, { limit });
2682
1576
  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
1577
  default:
2693
1578
  throw new Error(`Unknown format: ${format}`);
2694
1579
  }
@@ -2838,12 +1723,12 @@ function registerCheckCommand(program, dependencies = {}) {
2838
1723
  ...defaultDependencies,
2839
1724
  ...dependencies
2840
1725
  };
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) => {
1726
+ 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
1727
  const n = parseInt(value, 10);
2843
1728
  if (Number.isNaN(n) || n < 1)
2844
1729
  throw new Error("--max-type-depth must be a positive integer");
2845
1730
  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) => {
1731
+ }).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
1732
  try {
2848
1733
  const spin = spinner("Analyzing...");
2849
1734
  let validations = parseExamplesFlag(options.examples);
@@ -2865,27 +1750,11 @@ function registerCheckCommand(program, dependencies = {}) {
2865
1750
  }
2866
1751
  hasExamples = validations.length > 0;
2867
1752
  }
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
1753
  const DEFAULT_MIN_HEALTH = 80;
2881
1754
  const minHealthRaw = options.minHealth ?? config?.check?.minHealth ?? DEFAULT_MIN_HEALTH;
2882
1755
  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
1756
  const apiSurfaceConfig = config?.check?.apiSurface;
2888
- const minApiSurfaceRaw = options.minApiSurface ?? apiSurfaceConfig?.minCompleteness ?? config?.check?.minApiSurface;
1757
+ const minApiSurfaceRaw = apiSurfaceConfig?.minCompleteness;
2889
1758
  const minApiSurface = minApiSurfaceRaw !== undefined ? clampPercentage(minApiSurfaceRaw) : undefined;
2890
1759
  const warnBelowApiSurface = apiSurfaceConfig?.warnBelow ? clampPercentage(apiSurfaceConfig.warnBelow) : undefined;
2891
1760
  const apiSurfaceIgnore = apiSurfaceConfig?.ignore ?? [];
@@ -2896,7 +1765,7 @@ function registerCheckCommand(program, dependencies = {}) {
2896
1765
  };
2897
1766
  const resolvedFilters = mergeFilterOptions(config, cliFilters);
2898
1767
  if (resolvedFilters.visibility) {
2899
- log(chalk7.dim(`Filtering by visibility: ${resolvedFilters.visibility.join(", ")}`));
1768
+ log(chalk6.dim(`Filtering by visibility: ${resolvedFilters.visibility.join(", ")}`));
2900
1769
  }
2901
1770
  const resolveExternalTypes = !options.skipResolve;
2902
1771
  const analyzer = createDocCov({
@@ -2924,7 +1793,6 @@ function registerCheckCommand(program, dependencies = {}) {
2924
1793
  const specInfos = specResult.diagnostics.filter((d) => d.severity === "info");
2925
1794
  const isPreview = options.preview;
2926
1795
  const shouldFix = options.fix || isPreview;
2927
- let exampleResult;
2928
1796
  let typecheckErrors = [];
2929
1797
  let runtimeDrifts = [];
2930
1798
  if (hasExamples) {
@@ -2932,7 +1800,6 @@ function registerCheckCommand(program, dependencies = {}) {
2932
1800
  validations,
2933
1801
  targetDir
2934
1802
  });
2935
- exampleResult = validation.result;
2936
1803
  typecheckErrors = validation.typecheckErrors;
2937
1804
  runtimeDrifts = validation.runtimeDrifts;
2938
1805
  }
@@ -2972,10 +1839,8 @@ function registerCheckCommand(program, dependencies = {}) {
2972
1839
  format,
2973
1840
  openpkg,
2974
1841
  doccov,
2975
- coverageScore,
2976
1842
  minHealth,
2977
1843
  minApiSurface,
2978
- driftExports,
2979
1844
  typecheckErrors,
2980
1845
  limit: parseInt(options.limit, 10) || 20,
2981
1846
  stdout: options.stdout,
@@ -2997,7 +1862,6 @@ function registerCheckCommand(program, dependencies = {}) {
2997
1862
  driftExports,
2998
1863
  typecheckErrors,
2999
1864
  staleRefs,
3000
- exampleResult,
3001
1865
  specWarnings,
3002
1866
  specInfos,
3003
1867
  verbose: options.verbose ?? false
@@ -3006,7 +1870,7 @@ function registerCheckCommand(program, dependencies = {}) {
3006
1870
  process.exit(1);
3007
1871
  }
3008
1872
  } catch (commandError) {
3009
- error(chalk7.red("Error:"), commandError instanceof Error ? commandError.message : commandError);
1873
+ error(chalk6.red("Error:"), commandError instanceof Error ? commandError.message : commandError);
3010
1874
  process.exit(1);
3011
1875
  }
3012
1876
  });
@@ -3024,7 +1888,7 @@ import {
3024
1888
  parseMarkdownFiles as parseMarkdownFiles2
3025
1889
  } from "@doccov/sdk";
3026
1890
  import { calculateNextVersion, recommendSemverBump } from "@openpkg-ts/spec";
3027
- import chalk8 from "chalk";
1891
+ import chalk7 from "chalk";
3028
1892
  import { glob as glob2 } from "glob";
3029
1893
  var defaultDependencies2 = {
3030
1894
  readFileSync: fs4.readFileSync,
@@ -3050,7 +1914,7 @@ function registerDiffCommand(program, dependencies = {}) {
3050
1914
  ...defaultDependencies2,
3051
1915
  ...dependencies
3052
1916
  };
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) => {
1917
+ 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
1918
  try {
3055
1919
  const baseFile = options.base ?? baseArg;
3056
1920
  const headFile = options.head ?? headArg;
@@ -3099,9 +1963,9 @@ function registerDiffCommand(program, dependencies = {}) {
3099
1963
  }, null, 2));
3100
1964
  } else {
3101
1965
  log("");
3102
- log(chalk8.bold("Semver Recommendation"));
1966
+ log(chalk7.bold("Semver Recommendation"));
3103
1967
  log(` Current version: ${currentVersion}`);
3104
- log(` Recommended: ${chalk8.cyan(nextVersion)} (${chalk8.yellow(recommendation.bump.toUpperCase())})`);
1968
+ log(` Recommended: ${chalk7.cyan(nextVersion)} (${chalk7.yellow(recommendation.bump.toUpperCase())})`);
3105
1969
  log(` Reason: ${recommendation.reason}`);
3106
1970
  }
3107
1971
  return;
@@ -3131,8 +1995,8 @@ function registerDiffCommand(program, dependencies = {}) {
3131
1995
  silent: true
3132
1996
  });
3133
1997
  }
3134
- const cacheNote = fromCache ? chalk8.cyan(" (cached)") : "";
3135
- log(chalk8.dim(`Report: ${jsonPath}`) + cacheNote);
1998
+ const cacheNote = fromCache ? chalk7.cyan(" (cached)") : "";
1999
+ log(chalk7.dim(`Report: ${jsonPath}`) + cacheNote);
3136
2000
  }
3137
2001
  break;
3138
2002
  case "json": {
@@ -3183,43 +2047,6 @@ function registerDiffCommand(program, dependencies = {}) {
3183
2047
  case "github":
3184
2048
  printGitHubAnnotations(diff, log);
3185
2049
  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
2050
  }
3224
2051
  const failures = validateDiff(diff, headSpec, {
3225
2052
  minCoverage,
@@ -3227,18 +2054,18 @@ function registerDiffCommand(program, dependencies = {}) {
3227
2054
  checks
3228
2055
  });
3229
2056
  if (failures.length > 0) {
3230
- log(chalk8.red(`
2057
+ log(chalk7.red(`
3231
2058
  ✗ Check failed`));
3232
2059
  for (const f of failures) {
3233
- log(chalk8.red(` - ${f}`));
2060
+ log(chalk7.red(` - ${f}`));
3234
2061
  }
3235
2062
  process.exitCode = 1;
3236
2063
  } else if (options.strict || minCoverage !== undefined || maxDrift !== undefined) {
3237
- log(chalk8.green(`
2064
+ log(chalk7.green(`
3238
2065
  ✓ All checks passed`));
3239
2066
  }
3240
2067
  } catch (commandError) {
3241
- error(chalk8.red("Error:"), commandError instanceof Error ? commandError.message : commandError);
2068
+ error(chalk7.red("Error:"), commandError instanceof Error ? commandError.message : commandError);
3242
2069
  process.exitCode = 1;
3243
2070
  }
3244
2071
  });
@@ -3265,7 +2092,7 @@ async function generateDiff(baseSpec, headSpec, options, config, log) {
3265
2092
  if (!docsPatterns || docsPatterns.length === 0) {
3266
2093
  if (config?.docs?.include) {
3267
2094
  docsPatterns = config.docs.include;
3268
- log(chalk8.gray(`Using docs patterns from config: ${docsPatterns.join(", ")}`));
2095
+ log(chalk7.gray(`Using docs patterns from config: ${docsPatterns.join(", ")}`));
3269
2096
  }
3270
2097
  }
3271
2098
  if (docsPatterns && docsPatterns.length > 0) {
@@ -3288,37 +2115,37 @@ function loadSpec(filePath, readFileSync3) {
3288
2115
  }
3289
2116
  function printSummary(diff, baseName, headName, fromCache, log) {
3290
2117
  log("");
3291
- const cacheIndicator = fromCache ? chalk8.cyan(" (cached)") : "";
3292
- log(chalk8.bold(`Comparing: ${baseName} → ${headName}`) + cacheIndicator);
2118
+ const cacheIndicator = fromCache ? chalk7.cyan(" (cached)") : "";
2119
+ log(chalk7.bold(`Comparing: ${baseName} → ${headName}`) + cacheIndicator);
3293
2120
  log("─".repeat(40));
3294
2121
  log("");
3295
- const coverageColor = diff.coverageDelta > 0 ? chalk8.green : diff.coverageDelta < 0 ? chalk8.red : chalk8.gray;
2122
+ const coverageColor = diff.coverageDelta > 0 ? chalk7.green : diff.coverageDelta < 0 ? chalk7.red : chalk7.gray;
3296
2123
  const coverageSign = diff.coverageDelta > 0 ? "+" : "";
3297
2124
  log(` Coverage: ${diff.oldCoverage}% → ${diff.newCoverage}% ${coverageColor(`(${coverageSign}${diff.coverageDelta}%)`)}`);
3298
2125
  const breakingCount = diff.breaking.length;
3299
2126
  const highSeverity = diff.categorizedBreaking?.filter((c) => c.severity === "high").length ?? 0;
3300
2127
  if (breakingCount > 0) {
3301
- const severityNote = highSeverity > 0 ? chalk8.red(` (${highSeverity} high severity)`) : "";
3302
- log(` Breaking: ${chalk8.red(breakingCount)} changes${severityNote}`);
2128
+ const severityNote = highSeverity > 0 ? chalk7.red(` (${highSeverity} high severity)`) : "";
2129
+ log(` Breaking: ${chalk7.red(breakingCount)} changes${severityNote}`);
3303
2130
  } else {
3304
- log(` Breaking: ${chalk8.green("0")} changes`);
2131
+ log(` Breaking: ${chalk7.green("0")} changes`);
3305
2132
  }
3306
2133
  const newCount = diff.nonBreaking.length;
3307
2134
  const undocCount = diff.newUndocumented.length;
3308
2135
  if (newCount > 0) {
3309
- const undocNote = undocCount > 0 ? chalk8.yellow(` (${undocCount} undocumented)`) : "";
3310
- log(` New: ${chalk8.green(newCount)} exports${undocNote}`);
2136
+ const undocNote = undocCount > 0 ? chalk7.yellow(` (${undocCount} undocumented)`) : "";
2137
+ log(` New: ${chalk7.green(newCount)} exports${undocNote}`);
3311
2138
  }
3312
2139
  if (diff.driftIntroduced > 0 || diff.driftResolved > 0) {
3313
2140
  const parts = [];
3314
2141
  if (diff.driftIntroduced > 0)
3315
- parts.push(chalk8.red(`+${diff.driftIntroduced}`));
2142
+ parts.push(chalk7.red(`+${diff.driftIntroduced}`));
3316
2143
  if (diff.driftResolved > 0)
3317
- parts.push(chalk8.green(`-${diff.driftResolved}`));
2144
+ parts.push(chalk7.green(`-${diff.driftResolved}`));
3318
2145
  log(` Drift: ${parts.join(", ")}`);
3319
2146
  }
3320
2147
  const recommendation = recommendSemverBump(diff);
3321
- const bumpColor = recommendation.bump === "major" ? chalk8.red : recommendation.bump === "minor" ? chalk8.yellow : chalk8.green;
2148
+ const bumpColor = recommendation.bump === "major" ? chalk7.red : recommendation.bump === "minor" ? chalk7.yellow : chalk7.green;
3322
2149
  log(` Semver: ${bumpColor(recommendation.bump.toUpperCase())} (${recommendation.reason})`);
3323
2150
  log("");
3324
2151
  }
@@ -3398,57 +2225,10 @@ function printGitHubAnnotations(diff, log) {
3398
2225
  }
3399
2226
  }
3400
2227
 
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
2228
  // src/commands/init.ts
3449
2229
  import * as fs5 from "node:fs";
3450
2230
  import * as path7 from "node:path";
3451
- import chalk10 from "chalk";
2231
+ import chalk8 from "chalk";
3452
2232
  var defaultDependencies3 = {
3453
2233
  fileExists: fs5.existsSync,
3454
2234
  writeFileSync: fs5.writeFileSync,
@@ -3466,7 +2246,7 @@ function registerInitCommand(program, dependencies = {}) {
3466
2246
  const cwd = path7.resolve(options.cwd);
3467
2247
  const existing = findExistingConfig(cwd, fileExists2);
3468
2248
  if (existing) {
3469
- error(chalk10.red(`A DocCov config already exists at ${path7.relative(cwd, existing) || "./doccov.config.*"}.`));
2249
+ error(chalk8.red(`A DocCov config already exists at ${path7.relative(cwd, existing) || "./doccov.config.*"}.`));
3470
2250
  process.exitCode = 1;
3471
2251
  return;
3472
2252
  }
@@ -3475,7 +2255,7 @@ function registerInitCommand(program, dependencies = {}) {
3475
2255
  const fileName = `doccov.config.${targetFormat}`;
3476
2256
  const outputPath = path7.join(cwd, fileName);
3477
2257
  if (fileExists2(outputPath)) {
3478
- error(chalk10.red(`Cannot create ${fileName}; file already exists.`));
2258
+ error(chalk8.red(`Cannot create ${fileName}; file already exists.`));
3479
2259
  process.exitCode = 1;
3480
2260
  return;
3481
2261
  }
@@ -3496,16 +2276,16 @@ function registerInitCommand(program, dependencies = {}) {
3496
2276
  }
3497
2277
  const repoInfo = detectRepoInfo(cwd, fileExists2, readFileSync4);
3498
2278
  log("");
3499
- log(chalk10.bold("Add this badge to your README:"));
2279
+ log(chalk8.bold("Add this badge to your README:"));
3500
2280
  log("");
3501
2281
  if (repoInfo) {
3502
- log(chalk10.cyan(`[![DocCov](https://doccov.dev/badge/${repoInfo.owner}/${repoInfo.repo})](https://doccov.dev/${repoInfo.owner}/${repoInfo.repo})`));
2282
+ log(chalk8.cyan(`[![DocCov](https://doccov.dev/badge/${repoInfo.owner}/${repoInfo.repo})](https://doccov.dev/${repoInfo.owner}/${repoInfo.repo})`));
3503
2283
  } 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"));
2284
+ log(chalk8.cyan(`[![DocCov](https://doccov.dev/badge/OWNER/REPO)](https://doccov.dev/OWNER/REPO)`));
2285
+ log(chalk8.dim(" Replace OWNER/REPO with your GitHub repo"));
3506
2286
  }
3507
2287
  log("");
3508
- log(chalk10.dim("Run `doccov check` to verify your documentation coverage"));
2288
+ log(chalk8.dim("Run `doccov check` to verify your documentation coverage"));
3509
2289
  });
3510
2290
  }
3511
2291
  var findExistingConfig = (cwd, fileExists2) => {
@@ -3632,21 +2412,21 @@ var detectRepoInfo = (cwd, fileExists2, readFileSync4) => {
3632
2412
  import * as fs6 from "node:fs";
3633
2413
  import * as path8 from "node:path";
3634
2414
  import {
3635
- buildDocCovSpec as buildDocCovSpec3,
3636
- DocCov as DocCov3,
2415
+ buildDocCovSpec as buildDocCovSpec2,
2416
+ DocCov as DocCov2,
3637
2417
  detectPackageManager,
3638
- NodeFileSystem as NodeFileSystem3,
2418
+ NodeFileSystem as NodeFileSystem2,
3639
2419
  renderApiSurface,
3640
- resolveTarget as resolveTarget3
2420
+ resolveTarget as resolveTarget2
3641
2421
  } from "@doccov/sdk";
3642
2422
  import { validateDocCovSpec } from "@doccov/spec";
3643
2423
  import {
3644
2424
  normalize,
3645
2425
  validateSpec
3646
2426
  } from "@openpkg-ts/spec";
3647
- import chalk11 from "chalk";
2427
+ import chalk9 from "chalk";
3648
2428
  var defaultDependencies4 = {
3649
- createDocCov: (options) => new DocCov3(options),
2429
+ createDocCov: (options) => new DocCov2(options),
3650
2430
  writeFileSync: fs6.writeFileSync,
3651
2431
  log: console.log,
3652
2432
  error: console.error
@@ -3657,7 +2437,7 @@ function getArrayLength(value) {
3657
2437
  function formatDiagnosticOutput(prefix2, diagnostic, baseDir) {
3658
2438
  const location = diagnostic.location;
3659
2439
  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;
2440
+ const locationText = location && relativePath ? chalk9.gray(`${relativePath}:${location.line ?? 1}:${location.column ?? 1}`) : null;
3661
2441
  const locationPrefix = locationText ? `${locationText} ` : "";
3662
2442
  return `${prefix2} ${locationPrefix}${diagnostic.message}`;
3663
2443
  }
@@ -3669,19 +2449,19 @@ function registerSpecCommand(program, dependencies = {}) {
3669
2449
  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
2450
  try {
3671
2451
  const spin = spinner("Generating spec...");
3672
- const fileSystem = new NodeFileSystem3(options.cwd);
3673
- const resolved = await resolveTarget3(fileSystem, {
2452
+ const fileSystem = new NodeFileSystem2(options.cwd);
2453
+ const resolved = await resolveTarget2(fileSystem, {
3674
2454
  cwd: options.cwd,
3675
2455
  package: options.package,
3676
2456
  entry
3677
2457
  });
3678
- const { targetDir, entryFile, packageInfo, entryPointInfo } = resolved;
2458
+ const { targetDir, entryFile } = resolved;
3679
2459
  let config = null;
3680
2460
  try {
3681
2461
  config = await loadDocCovConfig(targetDir);
3682
2462
  } catch (configError) {
3683
2463
  spin.fail("Failed to load config");
3684
- error(chalk11.red("Failed to load DocCov config:"), configError instanceof Error ? configError.message : configError);
2464
+ error(chalk9.red("Failed to load DocCov config:"), configError instanceof Error ? configError.message : configError);
3685
2465
  process.exit(1);
3686
2466
  }
3687
2467
  const cliFilters = {
@@ -3714,15 +2494,15 @@ function registerSpecCommand(program, dependencies = {}) {
3714
2494
  const validation = validateSpec(normalized);
3715
2495
  if (!validation.ok) {
3716
2496
  spin.fail("Validation failed");
3717
- error(chalk11.red("Spec failed schema validation"));
2497
+ error(chalk9.red("Spec failed schema validation"));
3718
2498
  for (const err of validation.errors) {
3719
- error(chalk11.red(`schema: ${err.instancePath || "/"} ${err.message}`));
2499
+ error(chalk9.red(`schema: ${err.instancePath || "/"} ${err.message}`));
3720
2500
  }
3721
2501
  process.exit(1);
3722
2502
  }
3723
2503
  let doccovSpec = null;
3724
2504
  if (!options.openpkgOnly) {
3725
- doccovSpec = buildDocCovSpec3({
2505
+ doccovSpec = buildDocCovSpec2({
3726
2506
  openpkgPath: "openpkg.json",
3727
2507
  openpkg: normalized,
3728
2508
  packagePath: targetDir,
@@ -3731,9 +2511,9 @@ function registerSpecCommand(program, dependencies = {}) {
3731
2511
  const doccovValidation = validateDocCovSpec(doccovSpec);
3732
2512
  if (!doccovValidation.ok) {
3733
2513
  spin.fail("DocCov validation failed");
3734
- error(chalk11.red("DocCov spec failed schema validation"));
2514
+ error(chalk9.red("DocCov spec failed schema validation"));
3735
2515
  for (const err of doccovValidation.errors) {
3736
- error(chalk11.red(`doccov: ${err.instancePath || "/"} ${err.message}`));
2516
+ error(chalk9.red(`doccov: ${err.instancePath || "/"} ${err.message}`));
3737
2517
  }
3738
2518
  process.exit(1);
3739
2519
  }
@@ -3753,12 +2533,12 @@ function registerSpecCommand(program, dependencies = {}) {
3753
2533
  const doccovPath = path8.join(outputDir, "doccov.json");
3754
2534
  writeFileSync4(doccovPath, JSON.stringify(doccovSpec, null, 2));
3755
2535
  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`));
2536
+ log(chalk9.gray(` openpkg.json: ${getArrayLength(normalized.exports)} exports`));
2537
+ log(chalk9.gray(` doccov.json: ${doccovSpec.summary.score}% coverage, ${doccovSpec.summary.drift.total} drift issues`));
3758
2538
  } else {
3759
2539
  spin.success(`Generated ${options.output}/openpkg.json`);
3760
- log(chalk11.gray(` ${getArrayLength(normalized.exports)} exports`));
3761
- log(chalk11.gray(` ${getArrayLength(normalized.types)} types`));
2540
+ log(chalk9.gray(` ${getArrayLength(normalized.exports)} exports`));
2541
+ log(chalk9.gray(` ${getArrayLength(normalized.types)} types`));
3762
2542
  }
3763
2543
  }
3764
2544
  const isFullGenerationInfo = (gen) => {
@@ -3770,62 +2550,62 @@ function registerSpecCommand(program, dependencies = {}) {
3770
2550
  const pm = await detectPackageManager(fileSystem);
3771
2551
  const buildCmd = pm.name === "npm" ? "npm run build" : `${pm.name} run build`;
3772
2552
  log("");
3773
- log(chalk11.yellow("⚠ Runtime extraction requested but no schemas extracted."));
3774
- log(chalk11.yellow(` Ensure project is built (${buildCmd}) and dist/ exists.`));
2553
+ log(chalk9.yellow("⚠ Runtime extraction requested but no schemas extracted."));
2554
+ log(chalk9.yellow(` Ensure project is built (${buildCmd}) and dist/ exists.`));
3775
2555
  }
3776
2556
  if (options.verbose && fullGen) {
3777
2557
  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"}`));
2558
+ log(chalk9.bold("Generation Info"));
2559
+ log(chalk9.gray(` Timestamp: ${fullGen.timestamp}`));
2560
+ log(chalk9.gray(` Generator: ${fullGen.generator.name}@${fullGen.generator.version}`));
2561
+ log(chalk9.gray(` Entry point: ${fullGen.analysis.entryPoint}`));
2562
+ log(chalk9.gray(` Detected via: ${fullGen.analysis.entryPointSource}`));
2563
+ log(chalk9.gray(` Declaration only: ${fullGen.analysis.isDeclarationOnly ? "yes" : "no"}`));
2564
+ log(chalk9.gray(` External types: ${fullGen.analysis.resolvedExternalTypes ? "resolved" : "skipped"}`));
3785
2565
  if (fullGen.analysis.maxTypeDepth) {
3786
- log(chalk11.gray(` Max type depth: ${fullGen.analysis.maxTypeDepth}`));
2566
+ log(chalk9.gray(` Max type depth: ${fullGen.analysis.maxTypeDepth}`));
3787
2567
  }
3788
2568
  if (fullGen.analysis.schemaExtraction) {
3789
2569
  const se = fullGen.analysis.schemaExtraction;
3790
- log(chalk11.gray(` Schema extraction: ${se.method}`));
2570
+ log(chalk9.gray(` Schema extraction: ${se.method}`));
3791
2571
  if (se.runtimeCount) {
3792
- log(chalk11.gray(` Runtime schemas: ${se.runtimeCount} (${se.vendors?.join(", ")})`));
2572
+ log(chalk9.gray(` Runtime schemas: ${se.runtimeCount} (${se.vendors?.join(", ")})`));
3793
2573
  }
3794
2574
  }
3795
2575
  log("");
3796
- log(chalk11.bold("Environment"));
3797
- log(chalk11.gray(` node_modules: ${fullGen.environment.hasNodeModules ? "found" : "not found"}`));
2576
+ log(chalk9.bold("Environment"));
2577
+ log(chalk9.gray(` node_modules: ${fullGen.environment.hasNodeModules ? "found" : "not found"}`));
3798
2578
  if (fullGen.environment.packageManager) {
3799
- log(chalk11.gray(` Package manager: ${fullGen.environment.packageManager}`));
2579
+ log(chalk9.gray(` Package manager: ${fullGen.environment.packageManager}`));
3800
2580
  }
3801
2581
  if (fullGen.environment.isMonorepo) {
3802
- log(chalk11.gray(` Monorepo: yes`));
2582
+ log(chalk9.gray(` Monorepo: yes`));
3803
2583
  }
3804
2584
  if (fullGen.environment.targetPackage) {
3805
- log(chalk11.gray(` Target package: ${fullGen.environment.targetPackage}`));
2585
+ log(chalk9.gray(` Target package: ${fullGen.environment.targetPackage}`));
3806
2586
  }
3807
2587
  if (fullGen.issues.length > 0) {
3808
2588
  log("");
3809
- log(chalk11.bold("Issues"));
2589
+ log(chalk9.bold("Issues"));
3810
2590
  for (const issue of fullGen.issues) {
3811
- const prefix2 = issue.severity === "error" ? chalk11.red(">") : issue.severity === "warning" ? chalk11.yellow(">") : chalk11.cyan(">");
2591
+ const prefix2 = issue.severity === "error" ? chalk9.red(">") : issue.severity === "warning" ? chalk9.yellow(">") : chalk9.cyan(">");
3812
2592
  log(`${prefix2} [${issue.code}] ${issue.message}`);
3813
2593
  if (issue.suggestion) {
3814
- log(chalk11.gray(` ${issue.suggestion}`));
2594
+ log(chalk9.gray(` ${issue.suggestion}`));
3815
2595
  }
3816
2596
  }
3817
2597
  }
3818
2598
  }
3819
2599
  if (options.showDiagnostics && result.diagnostics.length > 0) {
3820
2600
  log("");
3821
- log(chalk11.bold("Diagnostics"));
2601
+ log(chalk9.bold("Diagnostics"));
3822
2602
  for (const diagnostic of result.diagnostics) {
3823
- const prefix2 = diagnostic.severity === "error" ? chalk11.red(">") : diagnostic.severity === "warning" ? chalk11.yellow(">") : chalk11.cyan(">");
2603
+ const prefix2 = diagnostic.severity === "error" ? chalk9.red(">") : diagnostic.severity === "warning" ? chalk9.yellow(">") : chalk9.cyan(">");
3824
2604
  log(formatDiagnosticOutput(prefix2, diagnostic, targetDir));
3825
2605
  }
3826
2606
  }
3827
2607
  } catch (commandError) {
3828
- error(chalk11.red("Error:"), commandError instanceof Error ? commandError.message : commandError);
2608
+ error(chalk9.red("Error:"), commandError instanceof Error ? commandError.message : commandError);
3829
2609
  process.exit(1);
3830
2610
  }
3831
2611
  });
@@ -3839,13 +2619,11 @@ import {
3839
2619
  getExtendedTrend,
3840
2620
  getTrend,
3841
2621
  loadSnapshots,
3842
- pruneByTier,
3843
2622
  pruneHistory,
3844
- RETENTION_DAYS,
3845
2623
  renderSparkline,
3846
2624
  saveSnapshot
3847
2625
  } from "@doccov/sdk";
3848
- import chalk12 from "chalk";
2626
+ import chalk10 from "chalk";
3849
2627
  function formatDate(timestamp) {
3850
2628
  const date = new Date(timestamp);
3851
2629
  return date.toLocaleDateString("en-US", {
@@ -3858,19 +2636,19 @@ function formatDate(timestamp) {
3858
2636
  }
3859
2637
  function getColorForScore(score) {
3860
2638
  if (score >= 90)
3861
- return chalk12.green;
2639
+ return chalk10.green;
3862
2640
  if (score >= 70)
3863
- return chalk12.yellow;
2641
+ return chalk10.yellow;
3864
2642
  if (score >= 50)
3865
- return chalk12.hex("#FFA500");
3866
- return chalk12.red;
2643
+ return chalk10.hex("#FFA500");
2644
+ return chalk10.red;
3867
2645
  }
3868
2646
  function formatSnapshot(snapshot) {
3869
2647
  const color = getColorForScore(snapshot.coverageScore);
3870
2648
  const date = formatDate(snapshot.timestamp);
3871
2649
  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}`;
2650
+ const commit = snapshot.commit ? chalk10.gray(` (${snapshot.commit.slice(0, 7)})`) : "";
2651
+ return `${chalk10.gray(date)} ${color(`${snapshot.coverageScore}%`)} ${snapshot.documentedExports}/${snapshot.totalExports} exports${version}${commit}`;
3874
2652
  }
3875
2653
  function formatWeekDate(timestamp) {
3876
2654
  const date = new Date(timestamp);
@@ -3878,30 +2656,26 @@ function formatWeekDate(timestamp) {
3878
2656
  }
3879
2657
  function formatVelocity(velocity) {
3880
2658
  if (velocity > 0)
3881
- return chalk12.green(`+${velocity}%/day`);
2659
+ return chalk10.green(`+${velocity}%/day`);
3882
2660
  if (velocity < 0)
3883
- return chalk12.red(`${velocity}%/day`);
3884
- return chalk12.gray("0%/day");
2661
+ return chalk10.red(`${velocity}%/day`);
2662
+ return chalk10.gray("0%/day");
3885
2663
  }
3886
2664
  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) => {
2665
+ 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
2666
  const cwd = path9.resolve(options.cwd);
3889
- const tier = options.tier ?? "pro";
3890
2667
  if (options.prune) {
3891
2668
  const keepCount = parseInt(options.prune, 10);
3892
2669
  if (!Number.isNaN(keepCount)) {
3893
2670
  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`));
2671
+ console.log(chalk10.green(`Pruned ${deleted} old snapshots, kept ${keepCount} most recent`));
3898
2672
  }
3899
2673
  return;
3900
2674
  }
3901
2675
  if (options.record) {
3902
2676
  const specPath = path9.resolve(cwd, "openpkg.json");
3903
2677
  if (!fs7.existsSync(specPath)) {
3904
- console.error(chalk12.red("No openpkg.json found. Run `doccov spec` first to generate a spec."));
2678
+ console.error(chalk10.red("No openpkg.json found. Run `doccov spec` first to generate a spec."));
3905
2679
  process.exit(1);
3906
2680
  }
3907
2681
  const spin = spinner("Recording coverage snapshot");
@@ -3914,21 +2688,21 @@ function registerTrendsCommand(program) {
3914
2688
  console.log(formatSnapshot(trend.current));
3915
2689
  if (trend.delta !== undefined) {
3916
2690
  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));
2691
+ const deltaColor = trend.delta > 0 ? chalk10.green : trend.delta < 0 ? chalk10.red : chalk10.gray;
2692
+ console.log(chalk10.gray("Change from previous:"), deltaColor(deltaStr));
3919
2693
  }
3920
2694
  return;
3921
2695
  } catch (error) {
3922
2696
  spin.fail("Failed to record snapshot");
3923
- console.error(chalk12.red("Failed to read openpkg.json:"), error instanceof Error ? error.message : error);
2697
+ console.error(chalk10.red("Failed to read openpkg.json:"), error instanceof Error ? error.message : error);
3924
2698
  process.exit(1);
3925
2699
  }
3926
2700
  }
3927
2701
  const snapshots = loadSnapshots(cwd);
3928
2702
  const limit = parseInt(options.limit ?? "10", 10);
3929
2703
  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."));
2704
+ console.log(chalk10.yellow("No coverage history found."));
2705
+ console.log(chalk10.gray("Run `doccov trends --record` to save the current coverage."));
3932
2706
  return;
3933
2707
  }
3934
2708
  if (options.json) {
@@ -3943,17 +2717,17 @@ function registerTrendsCommand(program) {
3943
2717
  }
3944
2718
  const sparklineData = snapshots.slice(0, 10).map((s) => s.coverageScore).reverse();
3945
2719
  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}`));
2720
+ console.log(chalk10.bold("Coverage Trends"));
2721
+ console.log(chalk10.gray(`Package: ${snapshots[0].package}`));
2722
+ console.log(chalk10.gray(`Sparkline: ${sparkline}`));
3949
2723
  console.log("");
3950
2724
  if (snapshots.length >= 2) {
3951
2725
  const oldest = snapshots[snapshots.length - 1];
3952
2726
  const newest = snapshots[0];
3953
2727
  const overallDelta = newest.coverageScore - oldest.coverageScore;
3954
2728
  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)`));
2729
+ const deltaColor = overallDelta > 0 ? chalk10.green : overallDelta < 0 ? chalk10.red : chalk10.gray;
2730
+ console.log(chalk10.gray("Overall trend:"), deltaColor(deltaStr), chalk10.gray(`(${snapshots.length} snapshots)`));
3957
2731
  console.log("");
3958
2732
  }
3959
2733
  if (options.extended) {
@@ -3962,58 +2736,56 @@ function registerTrendsCommand(program) {
3962
2736
  try {
3963
2737
  const specContent = fs7.readFileSync(specPath, "utf-8");
3964
2738
  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)`));
2739
+ const extended = getExtendedTrend(spec, cwd);
2740
+ console.log(chalk10.bold("Extended Analysis"));
2741
+ console.log(chalk10.gray("90-day retention"));
3968
2742
  console.log("");
3969
2743
  console.log(" Velocity:");
3970
2744
  console.log(` 7-day: ${formatVelocity(extended.velocity7d)}`);
3971
2745
  console.log(` 30-day: ${formatVelocity(extended.velocity30d)}`);
3972
- if (extended.velocity90d !== undefined) {
3973
- console.log(` 90-day: ${formatVelocity(extended.velocity90d)}`);
3974
- }
2746
+ console.log(` 90-day: ${formatVelocity(extended.velocity90d)}`);
3975
2747
  console.log("");
3976
- const projColor = extended.projected30d >= extended.trend.current.coverageScore ? chalk12.green : chalk12.red;
2748
+ const projColor = extended.projected30d >= extended.trend.current.coverageScore ? chalk10.green : chalk10.red;
3977
2749
  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}%`)}`);
2750
+ console.log(` All-time high: ${chalk10.green(`${extended.allTimeHigh}%`)}`);
2751
+ console.log(` All-time low: ${chalk10.red(`${extended.allTimeLow}%`)}`);
3980
2752
  if (extended.dataRange) {
3981
2753
  const startDate = formatWeekDate(extended.dataRange.start);
3982
2754
  const endDate = formatWeekDate(extended.dataRange.end);
3983
- console.log(chalk12.gray(` Data range: ${startDate} - ${endDate}`));
2755
+ console.log(chalk10.gray(` Data range: ${startDate} - ${endDate}`));
3984
2756
  }
3985
2757
  console.log("");
3986
2758
  if (options.weekly && extended.weeklySummaries.length > 0) {
3987
- console.log(chalk12.bold("Weekly Summary"));
2759
+ console.log(chalk10.bold("Weekly Summary"));
3988
2760
  const weekLimit = Math.min(extended.weeklySummaries.length, 8);
3989
2761
  for (let i = 0;i < weekLimit; i++) {
3990
2762
  const week = extended.weeklySummaries[i];
3991
2763
  const weekStart = formatWeekDate(week.weekStart);
3992
2764
  const weekEnd = formatWeekDate(week.weekEnd);
3993
- const deltaColor = week.delta > 0 ? chalk12.green : week.delta < 0 ? chalk12.red : chalk12.gray;
2765
+ const deltaColor = week.delta > 0 ? chalk10.green : week.delta < 0 ? chalk10.red : chalk10.gray;
3994
2766
  const deltaStr = week.delta > 0 ? `+${week.delta}%` : `${week.delta}%`;
3995
2767
  console.log(` ${weekStart} - ${weekEnd}: ${week.avgCoverage}% avg ${deltaColor(deltaStr)} (${week.snapshotCount} snapshots)`);
3996
2768
  }
3997
2769
  if (extended.weeklySummaries.length > weekLimit) {
3998
- console.log(chalk12.gray(` ... and ${extended.weeklySummaries.length - weekLimit} more weeks`));
2770
+ console.log(chalk10.gray(` ... and ${extended.weeklySummaries.length - weekLimit} more weeks`));
3999
2771
  }
4000
2772
  console.log("");
4001
2773
  }
4002
2774
  } catch {
4003
- console.log(chalk12.yellow("Could not load openpkg.json for extended analysis"));
2775
+ console.log(chalk10.yellow("Could not load openpkg.json for extended analysis"));
4004
2776
  console.log("");
4005
2777
  }
4006
2778
  }
4007
2779
  }
4008
- console.log(chalk12.bold("History"));
2780
+ console.log(chalk10.bold("History"));
4009
2781
  const displaySnapshots = snapshots.slice(0, limit);
4010
2782
  for (let i = 0;i < displaySnapshots.length; i++) {
4011
2783
  const snapshot = displaySnapshots[i];
4012
- const prefix2 = i === 0 ? chalk12.cyan("→") : " ";
2784
+ const prefix2 = i === 0 ? chalk10.cyan("→") : " ";
4013
2785
  console.log(`${prefix2} ${formatSnapshot(snapshot)}`);
4014
2786
  }
4015
2787
  if (snapshots.length > limit) {
4016
- console.log(chalk12.gray(` ... and ${snapshots.length - limit} more`));
2788
+ console.log(chalk10.gray(` ... and ${snapshots.length - limit} more`));
4017
2789
  }
4018
2790
  });
4019
2791
  }
@@ -4025,7 +2797,6 @@ var packageJson = JSON.parse(readFileSync5(path10.join(__dirname2, "../package.j
4025
2797
  var program = new Command;
4026
2798
  program.name("doccov").description("DocCov - Documentation coverage and drift detection for TypeScript").version(packageJson.version);
4027
2799
  registerCheckCommand(program);
4028
- registerInfoCommand(program);
4029
2800
  registerSpecCommand(program);
4030
2801
  registerDiffCommand(program);
4031
2802
  registerInitCommand(program);