@driftdev/cli 0.36.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/drift.js +449 -25
  2. package/package.json +1 -1
package/dist/drift.js CHANGED
@@ -175286,6 +175286,25 @@ function validateConfig(raw) {
175286
175286
  if (docs.exclude !== undefined && (!Array.isArray(docs.exclude) || !docs.exclude.every((i) => typeof i === "string"))) {
175287
175287
  errors.push('"docs.exclude" must be an array of strings');
175288
175288
  }
175289
+ if (docs.remote !== undefined) {
175290
+ if (!Array.isArray(docs.remote)) {
175291
+ errors.push('"docs.remote" must be an array');
175292
+ } else {
175293
+ for (let i = 0;i < docs.remote.length; i++) {
175294
+ const target = docs.remote[i];
175295
+ if (typeof target !== "object" || target === null) {
175296
+ errors.push(`"docs.remote[${i}]" must be an object`);
175297
+ continue;
175298
+ }
175299
+ if (typeof target.repo !== "string" || !/^[^/]+\/[^/]+$/.test(target.repo)) {
175300
+ errors.push(`"docs.remote[${i}].repo" must be in "owner/repo" format`);
175301
+ }
175302
+ if (target.branch !== undefined && typeof target.branch !== "string") {
175303
+ errors.push(`"docs.remote[${i}].branch" must be a string`);
175304
+ }
175305
+ }
175306
+ }
175307
+ }
175289
175308
  }
175290
175309
  }
175291
175310
  if (errors.length > 0)
@@ -175651,14 +175670,17 @@ function renderBatchLint(data) {
175651
175670
  function renderBatchList(data) {
175652
175671
  const lines = [""];
175653
175672
  const rows = data.packages;
175673
+ const columnLabel = data.filter === "undocumented" ? "UNDOCUMENTED" : "EXPORTS";
175654
175674
  const nameW = Math.max(7, ...rows.map((r) => r.name.length));
175655
- lines.push(indent(`${c.gray(pad("PACKAGE", nameW))} ${c.gray("EXPORTS")}`));
175675
+ lines.push(indent(`${c.gray(pad("PACKAGE", nameW))} ${c.gray(columnLabel)}`));
175656
175676
  for (const r of rows) {
175657
- lines.push(indent(`${pad(r.name, nameW)} ${r.count}`));
175677
+ const countStr = data.filter === "undocumented" ? r.count === 0 ? c.green("0") : c.yellow(String(r.count)) : String(r.count);
175678
+ lines.push(indent(`${pad(r.name, nameW)} ${countStr}`));
175658
175679
  }
175659
175680
  const total = rows.reduce((s, r) => s + r.count, 0);
175660
175681
  lines.push("");
175661
- lines.push(indent(`${c.bold("Total")}: ${total} exports across ${rows.length} packages`));
175682
+ const label = data.filter === "undocumented" ? "undocumented exports" : "exports";
175683
+ lines.push(indent(`${c.bold("Total")}: ${total} ${label} across ${rows.length} packages`));
175662
175684
  lines.push("");
175663
175685
  return lines.join(`
175664
175686
  `);
@@ -176013,7 +176035,7 @@ function getPackageInfo(cwd) {
176013
176035
  }
176014
176036
  }
176015
176037
  function registerHealthCommand(program) {
176016
- program.command("health [entry]", { isDefault: true }).description("Show documentation health score (default command)").option("--min <n>", "Minimum health threshold (exit 1 if below)").option("--all", "Run across all workspace packages").option("--private", "Include private packages in --all mode").action(async (entry, options) => {
176038
+ program.command("health [entry]").description("Show documentation health score (default command)").option("--min <n>", "Minimum health threshold (exit 1 if below)").option("--all", "Run across all workspace packages").option("--private", "Include private packages in --all mode").action(async (entry, options) => {
176017
176039
  const startTime = Date.now();
176018
176040
  const version = getVersion();
176019
176041
  try {
@@ -176517,6 +176539,7 @@ import { existsSync as existsSync17, readFileSync as readFileSync20 } from "node
176517
176539
  import * as path24 from "node:path";
176518
176540
  import { fileURLToPath as fileURLToPath5 } from "node:url";
176519
176541
  import { computeDrift as computeDrift2 } from "@driftdev/sdk";
176542
+ import { diffSpec as diffSpec6, categorizeBreakingChanges as categorizeBreakingChanges4 } from "@openpkg-ts/spec";
176520
176543
 
176521
176544
  // src/formatters/ci.ts
176522
176545
  function renderCi(data) {
@@ -176771,20 +176794,104 @@ function filterChangedPackages(allDirs, changedFiles) {
176771
176794
  return changedFiles.some((f) => prefix === "" || f.startsWith(prefix));
176772
176795
  });
176773
176796
  }
176774
- function buildMarkdownTable(results, pass) {
176797
+ function buildPRComment(results, pass, commit) {
176775
176798
  const lines = [];
176776
- lines.push(`## Drift CI Results
176799
+ const multi = results.length > 1;
176800
+ lines.push(`## Drift CI
176777
176801
  `);
176778
176802
  lines.push("| Package | Exports | Coverage | Lint | Status |");
176779
176803
  lines.push("|---------|---------|----------|------|--------|");
176780
176804
  for (const r of results) {
176781
- const cov = r.coveragePass ? `${r.coverage}%` : `${r.coverage}% ❌`;
176782
- const lint = r.lintPass ? `${r.lintIssues} issues` : `${r.lintIssues} issues ❌`;
176783
- const status = r.pass ? "" : "";
176805
+ const cov = r.coveragePass ? `${r.coverage}%` : `${r.coverage}% :x:`;
176806
+ const lint = r.lintPass ? `${r.lintIssues}` : `${r.lintIssues} :x:`;
176807
+ const status = r.pass ? ":white_check_mark:" : ":x:";
176784
176808
  lines.push(`| ${r.name} | ${r.exports} | ${cov} | ${lint} | ${status} |`);
176785
176809
  }
176810
+ const apiEntries = [];
176811
+ for (const r of results) {
176812
+ if (!r.diff)
176813
+ continue;
176814
+ const { breaking, added, changed } = r.diff;
176815
+ if (breaking.length === 0 && added.length === 0 && changed.length === 0)
176816
+ continue;
176817
+ const pkgLines = [];
176818
+ if (multi)
176819
+ pkgLines.push(`
176820
+ **${r.name}**`);
176821
+ for (const name of added)
176822
+ pkgLines.push(`- :heavy_plus_sign: Added: \`${name}\``);
176823
+ for (const name of changed)
176824
+ pkgLines.push(`- :pencil2: Changed: \`${name}\``);
176825
+ for (const b of breaking)
176826
+ pkgLines.push(`- :x: Removed: \`${b.name}\``);
176827
+ apiEntries.push(pkgLines.join(`
176828
+ `));
176829
+ }
176830
+ if (apiEntries.length > 0) {
176831
+ const total = results.reduce((s, r) => s + (r.diff ? r.diff.breaking.length + r.diff.added.length + r.diff.changed.length : 0), 0);
176832
+ lines.push("");
176833
+ lines.push(`<details>
176834
+ <summary>API Changes (${total})</summary>
176835
+ `);
176836
+ lines.push(apiEntries.join(`
176837
+ `));
176838
+ lines.push(`
176839
+ </details>`);
176840
+ }
176841
+ const breakingEntries = [];
176842
+ for (const r of results) {
176843
+ if (!r.diff?.breaking.length)
176844
+ continue;
176845
+ const pkgLines = [];
176846
+ if (multi)
176847
+ pkgLines.push(`
176848
+ **${r.name}**`);
176849
+ for (const b of r.diff.breaking) {
176850
+ pkgLines.push(`- \`${b.name}\`${b.reason ? `: ${b.reason}` : ""}`);
176851
+ }
176852
+ breakingEntries.push(pkgLines.join(`
176853
+ `));
176854
+ }
176855
+ if (breakingEntries.length > 0) {
176856
+ const total = results.reduce((s, r) => s + (r.diff?.breaking.length ?? 0), 0);
176857
+ lines.push("");
176858
+ lines.push(`<details>
176859
+ <summary>Breaking Changes (${total})</summary>
176860
+ `);
176861
+ lines.push(breakingEntries.join(`
176862
+ `));
176863
+ lines.push(`
176864
+ </details>`);
176865
+ }
176866
+ const undocEntries = [];
176867
+ for (const r of results) {
176868
+ if (!r.undocumented?.length)
176869
+ continue;
176870
+ const pkgLines = [];
176871
+ if (multi)
176872
+ pkgLines.push(`
176873
+ **${r.name}**`);
176874
+ for (const name of r.undocumented)
176875
+ pkgLines.push(`- \`${name}\``);
176876
+ undocEntries.push(pkgLines.join(`
176877
+ `));
176878
+ }
176879
+ if (undocEntries.length > 0) {
176880
+ const total = results.reduce((s, r) => s + (r.undocumented?.length ?? 0), 0);
176881
+ lines.push("");
176882
+ lines.push(`<details>
176883
+ <summary>Undocumented Exports (${total})</summary>
176884
+ `);
176885
+ lines.push(undocEntries.join(`
176886
+ `));
176887
+ lines.push(`
176888
+ </details>`);
176889
+ }
176786
176890
  lines.push("");
176787
- lines.push(pass ? "**All checks passed.**" : "**Some checks failed.**");
176891
+ lines.push("---");
176892
+ const ts18 = new Date().toISOString();
176893
+ const sha = commit ?? "";
176894
+ lines.push(`*[Drift](https://github.com/driftdev/drift) · ${ts18}${sha ? ` · ${sha}` : ""}*`);
176788
176895
  return lines.join(`
176789
176896
  `);
176790
176897
  }
@@ -176852,6 +176959,24 @@ function registerCiCommand(program) {
176852
176959
  lintIssues += drifts.length;
176853
176960
  }
176854
176961
  const lintPass = config.lint === false || lintIssues === 0;
176962
+ let diff;
176963
+ let undocumented;
176964
+ if (gh.isPR && gh.baseRef) {
176965
+ try {
176966
+ const relEntry = path24.relative(cwd, detectEntry(absDir));
176967
+ const oldSpec = await extractSpecFromRef(`origin/${gh.baseRef}`, relEntry, cwd);
176968
+ const diffResult = diffSpec6(oldSpec, spec);
176969
+ const breaking = categorizeBreakingChanges4(diffResult.breaking, oldSpec, spec);
176970
+ diff = {
176971
+ breaking: breaking.map((b) => ({ name: b.name, reason: b.reason })),
176972
+ added: diffResult.nonBreaking,
176973
+ changed: diffResult.docsOnly
176974
+ };
176975
+ } catch {}
176976
+ const undoc = exports.filter((e) => !e.description?.trim()).map((e) => e.name);
176977
+ if (undoc.length > 0)
176978
+ undocumented = undoc;
176979
+ }
176855
176980
  results.push({
176856
176981
  name,
176857
176982
  coverage,
@@ -176859,7 +176984,9 @@ function registerCiCommand(program) {
176859
176984
  lintIssues,
176860
176985
  lintPass,
176861
176986
  exports: total,
176862
- pass: coveragePass && lintPass
176987
+ pass: coveragePass && lintPass,
176988
+ diff,
176989
+ undocumented
176863
176990
  });
176864
176991
  } catch {
176865
176992
  results.push({
@@ -176897,7 +177024,7 @@ function registerCiCommand(program) {
176897
177024
  });
176898
177025
  } catch {}
176899
177026
  if (gh.isPR && gh.token && gh.repository) {
176900
- const md = buildMarkdownTable(results, allPass);
177027
+ const md = buildPRComment(results, allPass, commit);
176901
177028
  writeStepSummary(md);
176902
177029
  const prNumber = getPRNumber(gh.eventPath);
176903
177030
  if (prNumber) {
@@ -177244,7 +177371,7 @@ function registerExamplesCommand(program) {
177244
177371
  import { readFileSync as readFileSync23 } from "node:fs";
177245
177372
  import * as path27 from "node:path";
177246
177373
  import { fileURLToPath as fileURLToPath8 } from "node:url";
177247
- import { diffSpec as diffSpec6, categorizeBreakingChanges as categorizeBreakingChanges4 } from "@openpkg-ts/spec";
177374
+ import { diffSpec as diffSpec7, categorizeBreakingChanges as categorizeBreakingChanges5 } from "@openpkg-ts/spec";
177248
177375
 
177249
177376
  // src/formatters/diff.ts
177250
177377
  function renderDiff(data) {
@@ -177310,8 +177437,8 @@ function registerDiffCommand(program) {
177310
177437
  try {
177311
177438
  const args = [oldPath, newPath].filter(Boolean);
177312
177439
  const { oldSpec, newSpec } = await resolveSpecs({ args, ...options });
177313
- const diff = diffSpec6(oldSpec, newSpec);
177314
- const breaking = categorizeBreakingChanges4(diff.breaking, oldSpec, newSpec);
177440
+ const diff = diffSpec7(oldSpec, newSpec);
177441
+ const breaking = categorizeBreakingChanges5(diff.breaking, oldSpec, newSpec);
177315
177442
  const data = {
177316
177443
  breaking,
177317
177444
  added: diff.nonBreaking,
@@ -177831,7 +177958,7 @@ function flattenConfig(obj, prefix = "") {
177831
177958
  }
177832
177959
  function registerConfigCommand(program) {
177833
177960
  const cmd = program.command("config").description("Manage drift configuration");
177834
- cmd.command("list").description("Show all config values").action(() => {
177961
+ cmd.command("list").alias("show").description("Show all config values").action(() => {
177835
177962
  const startTime = Date.now();
177836
177963
  const version = getVersion12();
177837
177964
  try {
@@ -178032,10 +178159,11 @@ function renderInit(data) {
178032
178159
  const lines = [""];
178033
178160
  lines.push(indent(`${data.isMonorepo ? "Monorepo" : "Project"} scan ${c.gray(`${data.packages.length} package${data.packages.length === 1 ? "" : "s"}`)}`));
178034
178161
  lines.push("");
178035
- const header = ["PACKAGE", "ENTRY", "EXPORTS", "COVERAGE"];
178162
+ const header = ["Package", "Exports", "Coverage", "Health"];
178036
178163
  const rows = data.packages.map((pkg) => {
178037
- const color = coverageColor(pkg.coverage);
178038
- return [pkg.name, pkg.entry, String(pkg.exports), color(`${pkg.coverage}%`)];
178164
+ const covColor = coverageColor(pkg.coverage);
178165
+ const healthColor = coverageColor(pkg.health);
178166
+ return [pkg.name, String(pkg.exports), covColor(`${pkg.coverage}%`), healthColor(`${pkg.health}%`)];
178039
178167
  });
178040
178168
  lines.push(indent(table([header, ...rows])));
178041
178169
  lines.push("");
@@ -178050,6 +178178,277 @@ function renderInit(data) {
178050
178178
  `);
178051
178179
  }
178052
178180
 
178181
+ // src/utils/progress/spinner.ts
178182
+ import chalk3 from "chalk";
178183
+
178184
+ // src/utils/progress/colors.ts
178185
+ import chalk2 from "chalk";
178186
+ var colors = {
178187
+ success: chalk2.green,
178188
+ error: chalk2.red,
178189
+ warning: chalk2.yellow,
178190
+ info: chalk2.cyan,
178191
+ muted: chalk2.gray,
178192
+ bold: chalk2.bold,
178193
+ dim: chalk2.dim,
178194
+ underline: chalk2.underline,
178195
+ primary: chalk2.cyan,
178196
+ secondary: chalk2.magenta,
178197
+ path: chalk2.cyan,
178198
+ number: chalk2.yellow,
178199
+ code: chalk2.gray
178200
+ };
178201
+ var symbols = {
178202
+ success: "✓",
178203
+ error: "✗",
178204
+ warning: "⚠",
178205
+ info: "ℹ",
178206
+ spinner: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
178207
+ bullet: "•",
178208
+ arrow: "→",
178209
+ arrowRight: "›",
178210
+ line: "─",
178211
+ corner: "└",
178212
+ vertical: "│",
178213
+ horizontalLine: "─"
178214
+ };
178215
+ var asciiSymbols = {
178216
+ success: "+",
178217
+ error: "x",
178218
+ warning: "!",
178219
+ info: "i",
178220
+ spinner: ["-", "\\", "|", "/"],
178221
+ bullet: "*",
178222
+ arrow: "->",
178223
+ arrowRight: ">",
178224
+ line: "-",
178225
+ corner: "\\",
178226
+ vertical: "|",
178227
+ horizontalLine: "-"
178228
+ };
178229
+ function getSymbols(unicodeSupport = true) {
178230
+ return unicodeSupport ? symbols : asciiSymbols;
178231
+ }
178232
+ var prefix = {
178233
+ success: colors.success(symbols.success),
178234
+ error: colors.error(symbols.error),
178235
+ warning: colors.warning(symbols.warning),
178236
+ info: colors.info(symbols.info)
178237
+ };
178238
+
178239
+ // src/utils/progress/utils.ts
178240
+ function isTTY2() {
178241
+ return Boolean(process.stdout.isTTY);
178242
+ }
178243
+ function isCI() {
178244
+ return Boolean(process.env.CI || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.CIRCLECI || process.env.TRAVIS || process.env.JENKINS_URL || process.env.BUILDKITE || process.env.TEAMCITY_VERSION || process.env.TF_BUILD || process.env.CODEBUILD_BUILD_ID || process.env.BITBUCKET_BUILD_NUMBER);
178245
+ }
178246
+ function isInteractive() {
178247
+ return isTTY2() && !isCI();
178248
+ }
178249
+ function supportsUnicode() {
178250
+ if (process.platform === "win32") {
178251
+ return Boolean(process.env.WT_SESSION) || process.env.TERM_PROGRAM === "vscode";
178252
+ }
178253
+ return process.env.TERM !== "linux";
178254
+ }
178255
+ var MIN_TERMINAL_WIDTH = 40;
178256
+ var DEFAULT_TERMINAL_WIDTH = 80;
178257
+ function getTerminalWidth() {
178258
+ const width = process.stdout.columns || DEFAULT_TERMINAL_WIDTH;
178259
+ return Math.max(width, MIN_TERMINAL_WIDTH);
178260
+ }
178261
+ var cursor = {
178262
+ hide: "\x1B[?25l",
178263
+ show: "\x1B[?25h",
178264
+ up: (n = 1) => `\x1B[${n}A`,
178265
+ down: (n = 1) => `\x1B[${n}B`,
178266
+ forward: (n = 1) => `\x1B[${n}C`,
178267
+ back: (n = 1) => `\x1B[${n}D`,
178268
+ left: "\x1B[G",
178269
+ clearLine: "\x1B[2K",
178270
+ clearDown: "\x1B[J",
178271
+ save: "\x1B[s",
178272
+ restore: "\x1B[u"
178273
+ };
178274
+ function clearLine() {
178275
+ if (isTTY2()) {
178276
+ process.stdout.write(cursor.clearLine + cursor.left);
178277
+ }
178278
+ }
178279
+ function hideCursor() {
178280
+ if (isTTY2()) {
178281
+ process.stdout.write(cursor.hide);
178282
+ }
178283
+ }
178284
+ function showCursor() {
178285
+ if (isTTY2()) {
178286
+ process.stdout.write(cursor.show);
178287
+ }
178288
+ }
178289
+ function truncate(text, maxLength) {
178290
+ if (text.length <= maxLength)
178291
+ return text;
178292
+ return `${text.slice(0, maxLength - 1)}…`;
178293
+ }
178294
+
178295
+ // src/utils/progress/spinner.ts
178296
+ var spinnerColors = {
178297
+ cyan: chalk3.cyan,
178298
+ yellow: chalk3.yellow,
178299
+ green: chalk3.green,
178300
+ red: chalk3.red,
178301
+ magenta: chalk3.magenta,
178302
+ blue: chalk3.blue,
178303
+ white: chalk3.white
178304
+ };
178305
+ var FRAME_SETS = {
178306
+ dots: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
178307
+ circle: ["◐", "◓", "◑", "◒"]
178308
+ };
178309
+ var ASCII_FRAME_SET = ["-", "\\", "|", "/"];
178310
+
178311
+ class Spinner {
178312
+ label;
178313
+ detail;
178314
+ frames;
178315
+ interval;
178316
+ colorFn;
178317
+ frameIndex = 0;
178318
+ timer = null;
178319
+ state = "stopped";
178320
+ symbols = getSymbols(supportsUnicode());
178321
+ lastRenderedLines = 0;
178322
+ sigintHandler = null;
178323
+ constructor(options = {}) {
178324
+ this.label = options.label ?? "";
178325
+ this.detail = options.detail;
178326
+ this.interval = options.interval ?? 80;
178327
+ this.colorFn = spinnerColors[options.color ?? "cyan"];
178328
+ const style = options.style ?? "circle";
178329
+ this.frames = supportsUnicode() ? FRAME_SETS[style] : ASCII_FRAME_SET;
178330
+ }
178331
+ start(label) {
178332
+ if (label !== undefined)
178333
+ this.label = label;
178334
+ if (this.state === "spinning")
178335
+ return this;
178336
+ this.state = "spinning";
178337
+ this.frameIndex = 0;
178338
+ this.lastRenderedLines = 0;
178339
+ if (!isInteractive()) {
178340
+ console.log(`${this.symbols.bullet} ${this.label}`);
178341
+ return this;
178342
+ }
178343
+ hideCursor();
178344
+ this.setupSignalHandler();
178345
+ this.render();
178346
+ this.timer = setInterval(() => {
178347
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
178348
+ this.render();
178349
+ }, this.interval);
178350
+ return this;
178351
+ }
178352
+ stop() {
178353
+ if (this.timer) {
178354
+ clearInterval(this.timer);
178355
+ this.timer = null;
178356
+ }
178357
+ this.state = "stopped";
178358
+ this.clearOutput();
178359
+ this.cleanup();
178360
+ return this;
178361
+ }
178362
+ success(label) {
178363
+ if (label !== undefined)
178364
+ this.label = label;
178365
+ this.finish("success");
178366
+ return this;
178367
+ }
178368
+ fail(label) {
178369
+ if (label !== undefined)
178370
+ this.label = label;
178371
+ this.finish("error");
178372
+ return this;
178373
+ }
178374
+ update(label) {
178375
+ this.label = label;
178376
+ if (this.state === "spinning" && isInteractive()) {
178377
+ this.render();
178378
+ }
178379
+ return this;
178380
+ }
178381
+ setDetail(detail) {
178382
+ this.detail = detail;
178383
+ if (this.state === "spinning" && isInteractive()) {
178384
+ this.render();
178385
+ }
178386
+ return this;
178387
+ }
178388
+ get isSpinning() {
178389
+ return this.state === "spinning";
178390
+ }
178391
+ finish(state) {
178392
+ if (this.timer) {
178393
+ clearInterval(this.timer);
178394
+ this.timer = null;
178395
+ }
178396
+ this.state = state;
178397
+ if (!isInteractive()) {
178398
+ const symbol = state === "success" ? this.symbols.success : this.symbols.error;
178399
+ const colorFn = state === "success" ? colors.success : colors.error;
178400
+ console.log(`${colorFn(symbol)} ${this.label}`);
178401
+ } else {
178402
+ this.clearOutput();
178403
+ const symbol = state === "success" ? this.symbols.success : this.symbols.error;
178404
+ const colorFn = state === "success" ? colors.success : colors.error;
178405
+ process.stdout.write(`${colorFn(symbol)} ${this.label}
178406
+ `);
178407
+ }
178408
+ this.cleanup();
178409
+ }
178410
+ render() {
178411
+ if (!isTTY2())
178412
+ return;
178413
+ this.clearOutput();
178414
+ const frame = this.colorFn(this.frames[this.frameIndex]);
178415
+ const width = getTerminalWidth();
178416
+ const mainLine = truncate(`${frame} ${this.label}`, width);
178417
+ process.stdout.write(mainLine);
178418
+ let lines = 1;
178419
+ if (this.detail) {
178420
+ const detailLine = truncate(` ${colors.muted(this.detail)}`, width);
178421
+ process.stdout.write(`
178422
+ ${detailLine}`);
178423
+ lines = 2;
178424
+ }
178425
+ this.lastRenderedLines = lines;
178426
+ }
178427
+ clearOutput() {
178428
+ if (!isTTY2())
178429
+ return;
178430
+ for (let i = 0;i < this.lastRenderedLines; i++) {
178431
+ if (i > 0)
178432
+ process.stdout.write(cursor.up(1));
178433
+ clearLine();
178434
+ }
178435
+ }
178436
+ setupSignalHandler() {
178437
+ this.sigintHandler = () => {
178438
+ this.cleanup();
178439
+ process.exit(130);
178440
+ };
178441
+ process.on("SIGINT", this.sigintHandler);
178442
+ }
178443
+ cleanup() {
178444
+ if (this.sigintHandler) {
178445
+ process.removeListener("SIGINT", this.sigintHandler);
178446
+ this.sigintHandler = null;
178447
+ }
178448
+ showCursor();
178449
+ }
178450
+ }
178451
+
178053
178452
  // src/commands/init.ts
178054
178453
  var __dirname15 = path33.dirname(fileURLToPath14(import.meta.url));
178055
178454
  function getVersion14() {
@@ -178084,7 +178483,8 @@ async function scanPackage(cwd, pkgDir) {
178084
178483
  documented++;
178085
178484
  }
178086
178485
  const coverage = total > 0 ? Math.round(documented / total * 100) : 100;
178087
- return { name, entry: path33.relative(cwd, entryFile), exports: total, coverage };
178486
+ const health = Math.round(coverage * 0.5 + 100 * 0.5);
178487
+ return { name, entry: path33.relative(cwd, entryFile), exports: total, coverage, health };
178088
178488
  } catch {
178089
178489
  return null;
178090
178490
  }
@@ -178105,12 +178505,16 @@ function registerInitCommand(program) {
178105
178505
  const workspaces = detectWorkspaces(cwd);
178106
178506
  const isMonorepo = workspaces !== null;
178107
178507
  const packageDirs = isMonorepo ? resolveGlobs(cwd, workspaces) : ["."];
178508
+ const spin = new Spinner({ style: "dots" });
178509
+ spin.start("Scanning packages…");
178108
178510
  const packages = [];
178109
178511
  for (const dir of packageDirs) {
178512
+ spin.update(`Scanning ${dir}…`);
178110
178513
  const result = await scanPackage(cwd, dir);
178111
178514
  if (result)
178112
178515
  packages.push(result);
178113
178516
  }
178517
+ spin.success(`Scanned ${packages.length} package${packages.length === 1 ? "" : "s"}`);
178114
178518
  if (packages.length === 0) {
178115
178519
  formatError("init", "No TypeScript packages found", startTime, version);
178116
178520
  return;
@@ -178523,6 +178927,13 @@ function renderList(data) {
178523
178927
  lines.push(` ${c.bold(`${total} exports`)}`);
178524
178928
  }
178525
178929
  lines.push("");
178930
+ if (total === 0 && data.filter) {
178931
+ const msg = data.filter === "undocumented" ? `${c.green(sym.ok)} All exports are documented` : `${c.green(sym.ok)} No drifted exports found`;
178932
+ lines.push(indent(msg));
178933
+ lines.push("");
178934
+ return lines.join(`
178935
+ `);
178936
+ }
178526
178937
  if (!data.search) {
178527
178938
  const kindCounts = new Map;
178528
178939
  for (const exp of exports) {
@@ -178579,9 +178990,14 @@ function registerListCommand(program) {
178579
178990
  const rows = [];
178580
178991
  for (const pkg of packages) {
178581
178992
  const res = await listExports({ entryFile: pkg.entry });
178582
- rows.push({ name: pkg.name, count: res.exports.length });
178993
+ let filtered = res.exports;
178994
+ if (options.undocumented) {
178995
+ filtered = filtered.filter((e) => !e.description || e.description.trim().length === 0);
178996
+ }
178997
+ rows.push({ name: pkg.name, count: filtered.length });
178583
178998
  }
178584
- formatOutput("list", { packages: rows }, startTime, version, renderBatchList);
178999
+ const filter2 = options.undocumented ? "undocumented" : undefined;
179000
+ formatOutput("list", { packages: rows, filter: filter2 }, startTime, version, renderBatchList);
178585
179001
  return;
178586
179002
  }
178587
179003
  let entryFile;
@@ -178618,6 +179034,7 @@ function registerListCommand(program) {
178618
179034
  const matches = fuzzySearch(searchTerm, exports);
178619
179035
  exports = matches.map((m) => exports.find((e) => e.name === m.name));
178620
179036
  }
179037
+ const filter = options.undocumented ? "undocumented" : options.drifted ? "drifted" : undefined;
178621
179038
  const data = {
178622
179039
  exports: exports.map((e) => ({
178623
179040
  name: e.name,
@@ -178626,7 +179043,8 @@ function registerListCommand(program) {
178626
179043
  ...e.deprecated ? { deprecated: true } : {}
178627
179044
  })),
178628
179045
  ...searchTerm ? { search: searchTerm } : {},
178629
- showAll: !!options.full
179046
+ showAll: !!options.full,
179047
+ ...filter ? { filter } : {}
178630
179048
  };
178631
179049
  formatOutput("list", data, startTime, version, renderList);
178632
179050
  } catch (err) {
@@ -178968,7 +179386,7 @@ function registerReportCommand(program) {
178968
179386
  import { readFileSync as readFileSync36 } from "node:fs";
178969
179387
  import * as path40 from "node:path";
178970
179388
  import { fileURLToPath as fileURLToPath20 } from "node:url";
178971
- import { diffSpec as diffSpec7, recommendSemverBump as recommendSemverBump3 } from "@openpkg-ts/spec";
179389
+ import { diffSpec as diffSpec8, recommendSemverBump as recommendSemverBump3 } from "@openpkg-ts/spec";
178972
179390
 
178973
179391
  // src/formatters/semver.ts
178974
179392
  function renderSemver(data) {
@@ -178997,7 +179415,7 @@ function registerSemverCommand(program) {
178997
179415
  try {
178998
179416
  const args = [oldPath, newPath].filter(Boolean);
178999
179417
  const { oldSpec, newSpec } = await resolveSpecs({ args, ...options });
179000
- const diff = diffSpec7(oldSpec, newSpec);
179418
+ const diff = diffSpec8(oldSpec, newSpec);
179001
179419
  const recommendation = recommendSemverBump3(diff);
179002
179420
  const data = {
179003
179421
  bump: recommendation.bump,
@@ -179158,6 +179576,12 @@ if (process.argv.includes("--capabilities")) {
179158
179576
  `);
179159
179577
  process.exit(0);
179160
179578
  }
179579
+ var userArgs = process.argv.slice(2).filter((a) => !a.startsWith("-"));
179580
+ if (userArgs.length === 0) {
179581
+ const { configPath } = loadConfig();
179582
+ const subcommand = configPath ? "health" : "init";
179583
+ process.argv.splice(2, 0, subcommand);
179584
+ }
179161
179585
  program.parseAsync().catch(() => {
179162
179586
  process.exit(1);
179163
179587
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@driftdev/cli",
3
- "version": "0.36.0",
3
+ "version": "0.37.0",
4
4
  "description": "Drift CLI - Documentation coverage and drift detection for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",