@vibgrate/cli 2026.617.1 → 2026.618.2

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
@@ -6,7 +6,7 @@ import {
6
6
  pathExists,
7
7
  readJsonFile,
8
8
  writeTextFile
9
- } from "./chunk-LWB7JBWP.js";
9
+ } from "./chunk-34KD4UJ3.js";
10
10
  import {
11
11
  computeRepoFingerprint,
12
12
  detectVcs,
@@ -16,7 +16,7 @@ import {
16
16
  resolveRepositoryName,
17
17
  runScan,
18
18
  writeDefaultConfig
19
- } from "./chunk-BMLE722B.js";
19
+ } from "./chunk-XKZBEQYY.js";
20
20
  import {
21
21
  require_semver
22
22
  } from "./chunk-5IXVOEZN.js";
@@ -30,7 +30,7 @@ import {
30
30
 
31
31
  // src/cli.ts
32
32
  import { Command as Command13 } from "commander";
33
- import chalk14 from "chalk";
33
+ import chalk15 from "chalk";
34
34
 
35
35
  // src/commands/init.ts
36
36
  import * as path from "path";
@@ -49,7 +49,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
49
49
  console.log(chalk.green("\u2714") + ` Created ${chalk.bold("vibgrate.config.ts")}`);
50
50
  }
51
51
  if (opts.baseline) {
52
- const { runBaseline } = await import("./baseline-K2GQA6G5.js");
52
+ const { runBaseline } = await import("./baseline-6CJI5Z45.js");
53
53
  await runBaseline(rootDir);
54
54
  }
55
55
  console.log("");
@@ -62,7 +62,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
62
62
  // src/commands/scan.ts
63
63
  import * as path4 from "path";
64
64
  import { Command as Command3 } from "commander";
65
- import chalk3 from "chalk";
65
+ import chalk4 from "chalk";
66
66
 
67
67
  // src/version.ts
68
68
  import { createRequire } from "module";
@@ -129,6 +129,9 @@ function dashHostForIngestHost(ingestHost) {
129
129
  const match = REGIONS.find((r) => r.ingestHost === ingestHost);
130
130
  return match?.dashHost ?? "dash.vibgrate.com";
131
131
  }
132
+ function ingestHostForRegionId(region) {
133
+ return findRegion(region.toLowerCase())?.ingestHost;
134
+ }
132
135
 
133
136
  // src/commands/dsn.ts
134
137
  async function provisionDsn(keyId, secret, workspaceId, ingestHost, region) {
@@ -261,18 +264,62 @@ function emitIngestIdLine(ingestId, options) {
261
264
  }
262
265
  }
263
266
 
267
+ // src/utils/upload.ts
268
+ import chalk3 from "chalk";
269
+ function postOnce(input, host) {
270
+ const url = `${input.scheme}://${host}/v1/ingest/scan`;
271
+ return fetch(url, {
272
+ method: "POST",
273
+ headers: {
274
+ "Content-Type": "application/json",
275
+ "Content-Encoding": input.contentEncoding,
276
+ "X-Vibgrate-Timestamp": input.timestamp,
277
+ "Authorization": `VibgrateDSN ${input.keyId}:${input.secret}`,
278
+ "Connection": "close"
279
+ // Prevent keep-alive delays on exit
280
+ },
281
+ body: input.body
282
+ });
283
+ }
284
+ async function regionRedirectHost(response) {
285
+ try {
286
+ const payload = await response.clone().json();
287
+ if (payload?.code !== "REGION_MISMATCH" || !payload.region) return void 0;
288
+ return ingestHostForRegionId(payload.region);
289
+ } catch {
290
+ return void 0;
291
+ }
292
+ }
293
+ async function uploadScanArtifact(input) {
294
+ let host = input.host;
295
+ let response = await postOnce(input, host);
296
+ if (response.status === 409) {
297
+ const target = await regionRedirectHost(response);
298
+ if (target && target !== host) {
299
+ console.log(
300
+ chalk3.yellow(
301
+ `\u21BB Workspace is pinned to a different region \u2014 retrying upload to ${target}...`
302
+ )
303
+ );
304
+ host = target;
305
+ response = await postOnce(input, host);
306
+ }
307
+ }
308
+ return { response, host };
309
+ }
310
+
264
311
  // src/commands/scan.ts
265
312
  async function autoPush(artifact, rootDir, opts) {
266
313
  const dsn = resolveDsn(opts.dsn);
267
314
  if (!dsn) {
268
- console.error(chalk3.red("No DSN provided for push."));
269
- console.error(chalk3.dim('Run "vibgrate login", set VIBGRATE_DSN, or use the --dsn flag.'));
315
+ console.error(chalk4.red("No DSN provided for push."));
316
+ console.error(chalk4.dim('Run "vibgrate login", set VIBGRATE_DSN, or use the --dsn flag.'));
270
317
  if (opts.strict) process.exit(1);
271
318
  return;
272
319
  }
273
320
  const parsed = parseDsn(dsn);
274
321
  if (!parsed) {
275
- console.error(chalk3.red("Invalid DSN format."));
322
+ console.error(chalk4.red("Invalid DSN format."));
276
323
  if (opts.strict) process.exit(1);
277
324
  return;
278
325
  }
@@ -283,29 +330,26 @@ async function autoPush(artifact, rootDir, opts) {
283
330
  try {
284
331
  host = resolveIngestHost(opts.region);
285
332
  } catch (e) {
286
- console.error(chalk3.red(e instanceof Error ? e.message : String(e)));
333
+ console.error(chalk4.red(e instanceof Error ? e.message : String(e)));
287
334
  if (opts.strict) process.exit(1);
288
335
  return;
289
336
  }
290
337
  }
291
- const url = `${parsed.scheme}://${host}/v1/ingest/scan`;
292
338
  const originalSize = JSON.stringify(artifact).length;
293
339
  const compressedSize = body.length;
294
340
  const ratio = ((1 - compressedSize / originalSize) * 100).toFixed(0);
295
- console.log(chalk3.dim(`Uploading to ${host}... (${(compressedSize / 1024).toFixed(0)} KB, ${ratio}% smaller)`));
341
+ console.log(chalk4.dim(`Uploading to ${host}... (${(compressedSize / 1024).toFixed(0)} KB, ${ratio}% smaller)`));
296
342
  try {
297
- const response = await fetch(url, {
298
- method: "POST",
299
- headers: {
300
- "Content-Type": "application/json",
301
- "Content-Encoding": contentEncoding,
302
- "X-Vibgrate-Timestamp": timestamp,
303
- "Authorization": `VibgrateDSN ${parsed.keyId}:${parsed.secret}`,
304
- "Connection": "close"
305
- // Prevent keep-alive delays on exit
306
- },
307
- body
343
+ const { response, host: uploadedHost } = await uploadScanArtifact({
344
+ scheme: parsed.scheme,
345
+ host,
346
+ keyId: parsed.keyId,
347
+ secret: parsed.secret,
348
+ body,
349
+ contentEncoding,
350
+ timestamp
308
351
  });
352
+ host = uploadedHost;
309
353
  if (!response.ok) {
310
354
  const text = await response.text();
311
355
  throw new Error(`HTTP ${response.status}: ${text}`);
@@ -313,36 +357,36 @@ async function autoPush(artifact, rootDir, opts) {
313
357
  const result = await response.json();
314
358
  if (result.unchanged) {
315
359
  console.log(
316
- chalk3.green("\u2714") + ` Repository unchanged since ${result.lastScannedAt ?? "last scan"} \u2014 skipped upload (no credit used).`
360
+ chalk4.green("\u2714") + ` Repository unchanged since ${result.lastScannedAt ?? "last scan"} \u2014 skipped upload (no credit used).`
317
361
  );
318
362
  if (result.previousIngestId) {
319
363
  emitIngestIdLine(result.previousIngestId, { unchanged: true });
320
- const dashUrl = `https://dash.vibgrate.com/${parsed.workspaceId}/scan/${result.previousIngestId}`;
321
- console.log(chalk3.dim(` Previous report: ${dashUrl}`));
364
+ const dashUrl = `https://${dashHostForIngestHost(host)}/${parsed.workspaceId}/scan/${result.previousIngestId}`;
365
+ console.log(chalk4.dim(` Previous report: ${dashUrl}`));
322
366
  } else if (opts.strict) {
323
- console.error(chalk3.red("Repository unchanged but no previous ingest id returned."));
367
+ console.error(chalk4.red("Repository unchanged but no previous ingest id returned."));
324
368
  process.exit(1);
325
369
  }
326
370
  return;
327
371
  }
328
- console.log(chalk3.green("\u2714") + ` Scan queued for processing (${result.ingestId ?? "ok"})`);
372
+ console.log(chalk4.green("\u2714") + ` Scan queued for processing (${result.ingestId ?? "ok"})`);
329
373
  if (result.ingestId) {
330
374
  emitIngestIdLine(result.ingestId);
331
- const dashUrl = `https://dash.vibgrate.com/${parsed.workspaceId}/scan/${result.ingestId}`;
375
+ const dashUrl = `https://${dashHostForIngestHost(host)}/${parsed.workspaceId}/scan/${result.ingestId}`;
332
376
  const CLEAR_LINE = process.platform === "win32" ? "\x1B[0G\x1B[2K" : "";
333
377
  console.log("");
334
- console.log(CLEAR_LINE + chalk3.dim(" Processing continues in the background. Results available shortly."));
378
+ console.log(CLEAR_LINE + chalk4.dim(" Processing continues in the background. Results available shortly."));
335
379
  console.log("");
336
- console.log(CLEAR_LINE + chalk3.cyan("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
337
- console.log(CLEAR_LINE + chalk3.bold(" \u{1F4CA} View Scan Report"));
338
- console.log(CLEAR_LINE + " " + chalk3.underline.cyan(dashUrl));
339
- console.log(CLEAR_LINE + chalk3.cyan("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
380
+ console.log(CLEAR_LINE + chalk4.cyan("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
381
+ console.log(CLEAR_LINE + chalk4.bold(" \u{1F4CA} View Scan Report"));
382
+ console.log(CLEAR_LINE + " " + chalk4.underline.cyan(dashUrl));
383
+ console.log(CLEAR_LINE + chalk4.cyan("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
340
384
  console.log("");
341
385
  console.log("");
342
386
  }
343
387
  } catch (e) {
344
388
  const msg = e instanceof Error ? e.message : String(e);
345
- console.error(chalk3.red(`Upload failed: ${msg}`));
389
+ console.error(chalk4.red(`Upload failed: ${msg}`));
346
390
  if (opts.strict) process.exit(1);
347
391
  }
348
392
  }
@@ -362,14 +406,15 @@ var scanCommand = new Command3("scan").description("Scan a project for upgrade d
362
406
  'Exclude paths matching a glob pattern. Repeatable, and a single value may list several patterns separated by commas or semicolons (e.g. --exclude "legacy/**,vendor/**"). Merged with excludes from the config file.',
363
407
  collectExcludes,
364
408
  []
365
- ).option("--concurrency <n>", "Max concurrent npm calls", "8").option("--push", "Auto-push results to Vibgrate API after scan").option("--dsn <dsn>", "DSN token for push (or use VIBGRATE_DSN env)").option("--region <region>", "Override data residency region for push (us, eu)").option("--strict", "Fail on push errors").option("--ui-purpose", "Enable optional UI purpose evidence extraction (slower)").option("--no-local-artifacts", "Do not write .vibgrate JSON artifacts to disk").option("--max-privacy", "Enable strongest privacy mode (minimal scanners, no local artifacts)").option("--offline", "Run without network calls; do not upload results").option("--package-manifest <file>", "Use local package-version manifest JSON/ZIP (for offline mode)").option("--project-scan-timeout <seconds>", "Per-project scan timeout in seconds (default: 180)").option("--drift-budget <score>", "Fail if drift score is above budget (0-100)").option("--drift-worsening <percent>", "Fail if drift worsens by more than % since baseline").action(async (targetPath, opts) => {
409
+ ).option("--concurrency <n>", "Max concurrent npm calls", "8").option("--push", "Auto-push results to Vibgrate API after scan").option("--dsn <dsn>", "DSN token for push (or use VIBGRATE_DSN env)").option("--region <region>", "Override data residency region for push (us, eu)").option("--strict", "Fail on push errors").option("--ui-purpose", "Enable optional UI purpose evidence extraction (slower)").option("--no-local-artifacts", "Do not write .vibgrate JSON artifacts to disk").option("--max-privacy", "Enable strongest privacy mode (minimal scanners, no local artifacts)").option("--offline", "Run without network calls; do not upload results").option("--package-manifest <file>", "Use local package-version manifest JSON/ZIP (for offline mode)").option("--project-scan-timeout <seconds>", "Per-project scan timeout in seconds (default: 180)").option("--drift-budget <score>", "Fail if drift score is above budget (0-100)").option("--drift-worsening <percent>", "Fail if drift worsens by more than % since baseline").option("--repository-name <name>", "Override the repository name recorded for this scan (defaults to the directory or package.json name)").action(async (targetPath, opts) => {
366
410
  const rootDir = path4.resolve(targetPath);
367
411
  if (!await pathExists2(rootDir)) {
368
- console.error(chalk3.red(`Path does not exist: ${rootDir}`));
412
+ console.error(chalk4.red(`Path does not exist: ${rootDir}`));
369
413
  process.exit(1);
370
414
  }
371
415
  const hasDsn = !!resolveDsn(opts.dsn);
372
416
  const willPush = !opts.offline && (opts.push || hasDsn);
417
+ let pinnedRegion;
373
418
  if (willPush && hasDsn) {
374
419
  const dsn = resolveDsn(opts.dsn);
375
420
  const parsed = parseDsn(dsn);
@@ -377,25 +422,26 @@ var scanCommand = new Command3("scan").description("Scan a project for upgrade d
377
422
  const ingestHost = opts.region ? resolveIngestHost(opts.region) : parsed.host;
378
423
  const vcs = await detectVcs(rootDir);
379
424
  const fingerprint = await computeRepoFingerprint(rootDir, vcs);
380
- const repositoryName = await resolveRepositoryName(rootDir);
425
+ const repositoryName = opts.repositoryName?.trim() || await resolveRepositoryName(rootDir);
381
426
  try {
382
427
  const preflight = await fetchScanPreflight(parsed, ingestHost, {
383
428
  repositoryName,
384
429
  vcsSha: fingerprint.vcsSha
385
430
  });
431
+ pinnedRegion = preflight.region;
386
432
  if (preflight.vm && !preflight.vm.allowed) {
387
- console.error(chalk3.red(preflight.error ?? "VM meter usage exhausted"));
433
+ console.error(chalk4.red(preflight.error ?? "VM meter usage exhausted"));
388
434
  console.error(
389
- chalk3.dim(
435
+ chalk4.dim(
390
436
  `VM minutes: ${preflight.vm.used}/${preflight.vm.limit} (${preflight.plan.label} plan) \u2014 enable overages or upgrade your plan.`
391
437
  )
392
438
  );
393
439
  process.exit(1);
394
440
  }
395
441
  if (preflight.status === "error" || !preflight.scans.allowed) {
396
- console.error(chalk3.red(preflight.error ?? "Scan ingestion not allowed for this workspace."));
442
+ console.error(chalk4.red(preflight.error ?? "Scan ingestion not allowed for this workspace."));
397
443
  console.error(
398
- chalk3.dim(
444
+ chalk4.dim(
399
445
  `Credits: ${preflight.scans.used}/${preflight.scans.limit} (${preflight.plan.label} plan)`
400
446
  )
401
447
  );
@@ -403,27 +449,27 @@ var scanCommand = new Command3("scan").description("Scan a project for upgrade d
403
449
  process.exit(1);
404
450
  }
405
451
  console.log(
406
- chalk3.dim(
452
+ chalk4.dim(
407
453
  `Plan: ${preflight.plan.label} \u2014 scan credits ${preflight.scans.used}/${preflight.scans.limit} this month`
408
454
  )
409
455
  );
410
456
  if (preflight.repository?.unchanged) {
411
457
  console.log(
412
- chalk3.green("\u2714") + ` Repository unchanged at ${preflight.repository.lastVcsSha?.slice(0, 7) ?? "same revision"} \u2014 skipping scan.`
458
+ chalk4.green("\u2714") + ` Repository unchanged at ${preflight.repository.lastVcsSha?.slice(0, 7) ?? "same revision"} \u2014 skipping scan.`
413
459
  );
414
460
  if (preflight.repository.lastIngestId) {
415
461
  emitIngestIdLine(preflight.repository.lastIngestId, { unchanged: true });
416
- const dashUrl = `https://dash.vibgrate.com/${parsed.workspaceId}/scan/${preflight.repository.lastIngestId}`;
417
- console.log(chalk3.dim(` Latest report: ${dashUrl}`));
462
+ const dashUrl = `https://${dashHostForIngestHost(ingestHost)}/${parsed.workspaceId}/scan/${preflight.repository.lastIngestId}`;
463
+ console.log(chalk4.dim(` Latest report: ${dashUrl}`));
418
464
  } else if (opts.strict) {
419
- console.error(chalk3.red("Repository unchanged but no previous ingest id available."));
465
+ console.error(chalk4.red("Repository unchanged but no previous ingest id available."));
420
466
  process.exit(1);
421
467
  }
422
468
  return;
423
469
  }
424
470
  } catch (e) {
425
471
  const msg = e instanceof Error ? e.message : String(e);
426
- console.error(chalk3.yellow(`Preflight check failed: ${msg}`));
472
+ console.error(chalk4.yellow(`Preflight check failed: ${msg}`));
427
473
  if (opts.strict) process.exit(1);
428
474
  }
429
475
  }
@@ -439,7 +485,9 @@ var scanCommand = new Command3("scan").description("Scan a project for upgrade d
439
485
  concurrency: parseInt(opts.concurrency, 10) || 8,
440
486
  push: opts.push,
441
487
  dsn: opts.dsn,
442
- region: opts.region,
488
+ // An explicit --region wins; otherwise route to the workspace's pinned
489
+ // region as reported by preflight.
490
+ region: opts.region ?? pinnedRegion,
443
491
  strict: opts.strict,
444
492
  uiPurpose: opts.uiPurpose,
445
493
  noLocalArtifacts: opts.noLocalArtifacts,
@@ -448,31 +496,32 @@ var scanCommand = new Command3("scan").description("Scan a project for upgrade d
448
496
  packageManifest: opts.packageManifest,
449
497
  driftBudget: parseNonNegativeNumber(opts.driftBudget, "--drift-budget"),
450
498
  driftWorseningPercent: parseNonNegativeNumber(opts.driftWorsening, "--drift-worsening"),
451
- projectScanTimeout: opts.projectScanTimeout ? parseInt(opts.projectScanTimeout, 10) || void 0 : void 0
499
+ projectScanTimeout: opts.projectScanTimeout ? parseInt(opts.projectScanTimeout, 10) || void 0 : void 0,
500
+ repositoryName: opts.repositoryName?.trim() || void 0
452
501
  };
453
502
  const artifact = await runScan(rootDir, scanOpts);
454
503
  if (opts.failOn) {
455
504
  const hasErrors = artifact.findings.some((f) => f.level === "error");
456
505
  const hasWarnings = artifact.findings.some((f) => f.level === "warning");
457
506
  if (opts.failOn === "error" && hasErrors) {
458
- console.error(chalk3.red(`
507
+ console.error(chalk4.red(`
459
508
  Failing: ${artifact.findings.filter((f) => f.level === "error").length} error finding(s) detected.`));
460
509
  process.exit(2);
461
510
  }
462
511
  if (opts.failOn === "warn" && (hasErrors || hasWarnings)) {
463
- console.error(chalk3.red(`
512
+ console.error(chalk4.red(`
464
513
  Failing: findings detected at warn level or above.`));
465
514
  process.exit(2);
466
515
  }
467
516
  }
468
517
  if (scanOpts.driftBudget !== void 0 && artifact.drift.score > scanOpts.driftBudget) {
469
- console.error(chalk3.red(`
518
+ console.error(chalk4.red(`
470
519
  Failing fitness function: drift score ${artifact.drift.score}/100 exceeds budget ${scanOpts.driftBudget}.`));
471
520
  process.exit(2);
472
521
  }
473
522
  if (scanOpts.driftWorseningPercent !== void 0) {
474
523
  if (artifact.delta === void 0) {
475
- console.error(chalk3.red("\nFailing fitness function: --drift-worsening requires --baseline to compare against previous drift."));
524
+ console.error(chalk4.red("\nFailing fitness function: --drift-worsening requires --baseline to compare against previous drift."));
476
525
  process.exit(2);
477
526
  }
478
527
  if (artifact.delta > 0) {
@@ -480,7 +529,7 @@ Failing fitness function: drift score ${artifact.drift.score}/100 exceeds budget
480
529
  const denominator = Math.max(Math.abs(baselineScore), 1e-4);
481
530
  const worseningPercent = artifact.delta / denominator * 100;
482
531
  if (worseningPercent > scanOpts.driftWorseningPercent) {
483
- console.error(chalk3.red(`
532
+ console.error(chalk4.red(`
484
533
  Failing fitness function: drift worsened by ${worseningPercent.toFixed(2)}% (threshold ${scanOpts.driftWorseningPercent}%).`));
485
534
  process.exit(2);
486
535
  }
@@ -494,28 +543,28 @@ Failing fitness function: drift worsened by ${worseningPercent.toFixed(2)}% (thr
494
543
  // src/commands/report.ts
495
544
  import * as path5 from "path";
496
545
  import { Command as Command4 } from "commander";
497
- import chalk5 from "chalk";
546
+ import chalk6 from "chalk";
498
547
 
499
548
  // src/formatters/text.ts
500
- import chalk4 from "chalk";
549
+ import chalk5 from "chalk";
501
550
  function formatText(artifact) {
502
551
  const lines = [];
503
- const teal = chalk4.hex("#3FB0A4");
504
- const mint = chalk4.hex("#4FE3C1");
552
+ const teal = chalk5.hex("#3FB0A4");
553
+ const mint = chalk5.hex("#4FE3C1");
505
554
  lines.push("");
506
555
  lines.push(" " + teal("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u256E") + mint("\u279C"));
507
- lines.push(" " + chalk4.dim("\u2524") + teal("\u2502") + " " + mint("\u25FC") + " " + mint("\u25FC") + " " + teal("\u2502") + chalk4.dim("\u251C") + " " + chalk4.bold.white("vibgrate"));
508
- lines.push(" " + chalk4.dim("\u2524") + teal("\u2502") + " " + chalk4.dim("\u2581\u2581") + " " + teal("\u2502") + chalk4.dim("\u251C") + " " + chalk4.dim(`Drift Intelligence Engine v${VERSION}`));
556
+ lines.push(" " + chalk5.dim("\u2524") + teal("\u2502") + " " + mint("\u25FC") + " " + mint("\u25FC") + " " + teal("\u2502") + chalk5.dim("\u251C") + " " + chalk5.bold.white("vibgrate"));
557
+ lines.push(" " + chalk5.dim("\u2524") + teal("\u2502") + " " + chalk5.dim("\u2581\u2581") + " " + teal("\u2502") + chalk5.dim("\u251C") + " " + chalk5.dim(`Drift Intelligence Engine v${VERSION}`));
509
558
  lines.push(" " + teal("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
510
559
  lines.push("");
511
560
  lines.push(teal("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
512
- lines.push(teal("\u2551 ") + chalk4.bold.white("Vibgrate Drift Report") + teal(" \u2551"));
561
+ lines.push(teal("\u2551 ") + chalk5.bold.white("Vibgrate Drift Report") + teal(" \u2551"));
513
562
  lines.push(teal("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
514
563
  lines.push("");
515
564
  for (const project of artifact.projects) {
516
- lines.push(chalk4.bold(` \u2500\u2500 ${project.name} `) + chalk4.dim(`(${project.type}) ${project.path}`));
565
+ lines.push(chalk5.bold(` \u2500\u2500 ${project.name} `) + chalk5.dim(`(${project.type}) ${project.path}`));
517
566
  if (project.runtime) {
518
- const behindStr = project.runtimeMajorsBehind !== void 0 && project.runtimeMajorsBehind > 0 ? chalk4.yellow(` (${project.runtimeMajorsBehind} major${project.runtimeMajorsBehind > 1 ? "s" : ""} behind)`) : chalk4.green(" (current)");
567
+ const behindStr = project.runtimeMajorsBehind !== void 0 && project.runtimeMajorsBehind > 0 ? chalk5.yellow(` (${project.runtimeMajorsBehind} major${project.runtimeMajorsBehind > 1 ? "s" : ""} behind)`) : chalk5.green(" (current)");
519
568
  lines.push(` Runtime: ${project.runtime}${behindStr}`);
520
569
  }
521
570
  if (project.targetFramework) {
@@ -524,7 +573,7 @@ function formatText(artifact) {
524
573
  if (project.frameworks.length > 0) {
525
574
  lines.push(" Frameworks:");
526
575
  for (const fw of project.frameworks) {
527
- const lag = fw.majorsBehind !== null ? fw.majorsBehind === 0 ? chalk4.green("current") : chalk4.yellow(`${fw.majorsBehind} behind`) : chalk4.dim("unknown");
576
+ const lag = fw.majorsBehind !== null ? fw.majorsBehind === 0 ? chalk5.green("current") : chalk5.yellow(`${fw.majorsBehind} behind`) : chalk5.dim("unknown");
528
577
  lines.push(` ${fw.name}: ${fw.currentVersion ?? "?"} \u2192 ${fw.latestVersion ?? "?"} (${lag})`);
529
578
  }
530
579
  }
@@ -532,13 +581,13 @@ function formatText(artifact) {
532
581
  const total = b.current + b.oneBehind + b.twoPlusBehind + b.unknown;
533
582
  if (total > 0) {
534
583
  lines.push(" Dependencies:");
535
- lines.push(` ${chalk4.green(`${b.current} current`)} ${chalk4.yellow(`${b.oneBehind} 1-behind`)} ${chalk4.red(`${b.twoPlusBehind} 2+ behind`)} ${chalk4.dim(`${b.unknown} unknown`)}`);
584
+ lines.push(` ${chalk5.green(`${b.current} current`)} ${chalk5.yellow(`${b.oneBehind} 1-behind`)} ${chalk5.red(`${b.twoPlusBehind} 2+ behind`)} ${chalk5.dim(`${b.unknown} unknown`)}`);
536
585
  }
537
586
  lines.push("");
538
587
  }
539
588
  if (artifact.delta !== void 0) {
540
- const deltaStr = artifact.delta > 0 ? chalk4.green(`+${artifact.delta}`) : artifact.delta < 0 ? chalk4.red(`${artifact.delta}`) : chalk4.dim("0");
541
- lines.push(chalk4.bold(" Drift Delta: ") + deltaStr + " (vs baseline)");
589
+ const deltaStr = artifact.delta > 0 ? chalk5.green(`+${artifact.delta}`) : artifact.delta < 0 ? chalk5.red(`${artifact.delta}`) : chalk5.dim("0");
590
+ lines.push(chalk5.bold(" Drift Delta: ") + deltaStr + " (vs baseline)");
542
591
  lines.push("");
543
592
  }
544
593
  if (artifact.extended) {
@@ -549,30 +598,30 @@ function formatText(artifact) {
549
598
  const warnings = artifact.findings.filter((f) => f.level === "warning");
550
599
  const notes = artifact.findings.filter((f) => f.level === "note");
551
600
  const summary = [
552
- errors.length > 0 ? chalk4.red(`${errors.length} error${errors.length !== 1 ? "s" : ""}`) : "",
553
- warnings.length > 0 ? chalk4.yellow(`${warnings.length} warning${warnings.length !== 1 ? "s" : ""}`) : "",
554
- notes.length > 0 ? chalk4.blue(`${notes.length} note${notes.length !== 1 ? "s" : ""}`) : ""
555
- ].filter(Boolean).join(chalk4.dim(", "));
556
- lines.push(chalk4.bold.underline(` Findings`) + chalk4.dim(` (${summary})`));
601
+ errors.length > 0 ? chalk5.red(`${errors.length} error${errors.length !== 1 ? "s" : ""}`) : "",
602
+ warnings.length > 0 ? chalk5.yellow(`${warnings.length} warning${warnings.length !== 1 ? "s" : ""}`) : "",
603
+ notes.length > 0 ? chalk5.blue(`${notes.length} note${notes.length !== 1 ? "s" : ""}`) : ""
604
+ ].filter(Boolean).join(chalk5.dim(", "));
605
+ lines.push(chalk5.bold.underline(` Findings`) + chalk5.dim(` (${summary})`));
557
606
  for (const f of artifact.findings) {
558
- const icon = f.level === "error" ? chalk4.red("\u2716") : f.level === "warning" ? chalk4.yellow("\u26A0") : chalk4.blue("\u2139");
607
+ const icon = f.level === "error" ? chalk5.red("\u2716") : f.level === "warning" ? chalk5.yellow("\u26A0") : chalk5.blue("\u2139");
559
608
  lines.push(` ${icon} ${f.message}`);
560
- lines.push(chalk4.dim(` ${f.ruleId} in ${f.location}`));
609
+ lines.push(chalk5.dim(` ${f.ruleId} in ${f.location}`));
561
610
  }
562
611
  lines.push("");
563
612
  }
564
613
  const actions = generatePriorityActions(artifact);
565
614
  if (actions.length > 0) {
566
- lines.push(chalk4.bold.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
567
- lines.push(chalk4.bold.cyan("\u2551 Top Priority Actions \u2551"));
568
- lines.push(chalk4.bold.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
615
+ lines.push(chalk5.bold.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
616
+ lines.push(chalk5.bold.cyan("\u2551 Top Priority Actions \u2551"));
617
+ lines.push(chalk5.bold.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
569
618
  lines.push("");
570
619
  for (let i = 0; i < actions.length; i++) {
571
620
  const a = actions[i];
572
- const num = chalk4.bold.cyan(` ${i + 1}.`);
573
- lines.push(`${num} ${chalk4.bold(a.title)}`);
574
- lines.push(chalk4.dim(` ${a.explanation}`));
575
- if (a.impact) lines.push(` Impact: ${chalk4.green(a.impact)}`);
621
+ const num = chalk5.bold.cyan(` ${i + 1}.`);
622
+ lines.push(`${num} ${chalk5.bold(a.title)}`);
623
+ lines.push(chalk5.dim(` ${a.explanation}`));
624
+ if (a.impact) lines.push(` Impact: ${chalk5.green(a.impact)}`);
576
625
  lines.push("");
577
626
  }
578
627
  }
@@ -580,38 +629,38 @@ function formatText(artifact) {
580
629
  lines.push(...formatArchitectureDiagram(artifact.extended.architecture));
581
630
  }
582
631
  if (artifact.solutions && artifact.solutions.length > 0) {
583
- lines.push(chalk4.bold.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
584
- lines.push(chalk4.bold.cyan("\u2551 Solution Drift Summary \u2551"));
585
- lines.push(chalk4.bold.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
632
+ lines.push(chalk5.bold.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
633
+ lines.push(chalk5.bold.cyan("\u2551 Solution Drift Summary \u2551"));
634
+ lines.push(chalk5.bold.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
586
635
  lines.push("");
587
636
  for (const solution of artifact.solutions) {
588
637
  const solScore = solution.drift?.score;
589
- const color = typeof solScore === "number" ? solScore >= 70 ? chalk4.green : solScore >= 40 ? chalk4.yellow : chalk4.red : chalk4.dim;
590
- lines.push(` \u2022 ${solution.name} (${solution.projectPaths.length} projects) \u2014 ${typeof solScore === "number" ? color(`${solScore}/100`) : chalk4.dim("n/a")}`);
638
+ const color = typeof solScore === "number" ? solScore >= 70 ? chalk5.green : solScore >= 40 ? chalk5.yellow : chalk5.red : chalk5.dim;
639
+ lines.push(` \u2022 ${solution.name} (${solution.projectPaths.length} projects) \u2014 ${typeof solScore === "number" ? color(`${solScore}/100`) : chalk5.dim("n/a")}`);
591
640
  }
592
641
  lines.push("");
593
642
  }
594
- const scoreColor = artifact.drift.score >= 70 ? chalk4.green : artifact.drift.score >= 40 ? chalk4.yellow : chalk4.red;
595
- lines.push(chalk4.bold.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
596
- lines.push(chalk4.bold.cyan("\u2551 Drift Score Summary \u2551"));
597
- lines.push(chalk4.bold.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
643
+ const scoreColor = artifact.drift.score >= 70 ? chalk5.green : artifact.drift.score >= 40 ? chalk5.yellow : chalk5.red;
644
+ lines.push(chalk5.bold.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
645
+ lines.push(chalk5.bold.cyan("\u2551 Drift Score Summary \u2551"));
646
+ lines.push(chalk5.bold.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
598
647
  lines.push("");
599
- lines.push(chalk4.bold(" Drift Score: ") + scoreColor.bold(`${artifact.drift.score}/100`));
600
- lines.push(chalk4.bold(" Risk Level: ") + riskBadge(artifact.drift.riskLevel));
601
- lines.push(chalk4.bold(" Projects: ") + `${artifact.projects.length}`);
648
+ lines.push(chalk5.bold(" Drift Score: ") + scoreColor.bold(`${artifact.drift.score}/100`));
649
+ lines.push(chalk5.bold(" Risk Level: ") + riskBadge(artifact.drift.riskLevel));
650
+ lines.push(chalk5.bold(" Projects: ") + `${artifact.projects.length}`);
602
651
  if (artifact.vcs) {
603
652
  const vcsParts = [artifact.vcs.type];
604
653
  if (artifact.vcs.branch) vcsParts.push(artifact.vcs.branch);
605
- if (artifact.vcs.shortSha) vcsParts.push(chalk4.dim(artifact.vcs.shortSha));
606
- lines.push(chalk4.bold(" VCS: ") + vcsParts.join(" "));
654
+ if (artifact.vcs.shortSha) vcsParts.push(chalk5.dim(artifact.vcs.shortSha));
655
+ lines.push(chalk5.bold(" VCS: ") + vcsParts.join(" "));
607
656
  }
608
657
  lines.push("");
609
658
  const m = new Set(artifact.drift.measured ?? ["runtime", "framework", "dependency", "eol"]);
610
- lines.push(" " + chalk4.bold.underline("Score Breakdown"));
611
- lines.push(` Runtime: ${m.has("runtime") ? scoreBar(artifact.drift.components.runtimeScore) : chalk4.dim("n/a")}`);
612
- lines.push(` Frameworks: ${m.has("framework") ? scoreBar(artifact.drift.components.frameworkScore) : chalk4.dim("n/a")}`);
613
- lines.push(` Dependencies: ${m.has("dependency") ? scoreBar(artifact.drift.components.dependencyScore) : chalk4.dim("n/a")}`);
614
- lines.push(` EOL Risk: ${m.has("eol") ? scoreBar(artifact.drift.components.eolScore) : chalk4.dim("n/a")}`);
659
+ lines.push(" " + chalk5.bold.underline("Score Breakdown"));
660
+ lines.push(` Runtime: ${m.has("runtime") ? scoreBar(artifact.drift.components.runtimeScore) : chalk5.dim("n/a")}`);
661
+ lines.push(` Frameworks: ${m.has("framework") ? scoreBar(artifact.drift.components.frameworkScore) : chalk5.dim("n/a")}`);
662
+ lines.push(` Dependencies: ${m.has("dependency") ? scoreBar(artifact.drift.components.dependencyScore) : chalk5.dim("n/a")}`);
663
+ lines.push(` EOL Risk: ${m.has("eol") ? scoreBar(artifact.drift.components.eolScore) : chalk5.dim("n/a")}`);
615
664
  lines.push("");
616
665
  const scannedParts = [`Scanned at ${artifact.timestamp}`];
617
666
  if (artifact.durationMs !== void 0) {
@@ -625,18 +674,18 @@ function formatText(artifact) {
625
674
  scannedParts.push(`${artifact.treeSummary.totalFiles.toLocaleString()} workspace files`);
626
675
  scannedParts.push(`${artifact.treeSummary.totalDirs.toLocaleString()} dirs`);
627
676
  }
628
- lines.push(chalk4.dim(` ${scannedParts.join(" \xB7 ")}`));
677
+ lines.push(chalk5.dim(` ${scannedParts.join(" \xB7 ")}`));
629
678
  lines.push("");
630
679
  return lines.join("\n");
631
680
  }
632
681
  function riskBadge(level) {
633
682
  switch (level) {
634
683
  case "low":
635
- return chalk4.bgGreen.black(" LOW ");
684
+ return chalk5.bgGreen.black(" LOW ");
636
685
  case "moderate":
637
- return chalk4.bgYellow.black(" MODERATE ");
686
+ return chalk5.bgYellow.black(" MODERATE ");
638
687
  case "high":
639
- return chalk4.bgRed.white(" HIGH ");
688
+ return chalk5.bgRed.white(" HIGH ");
640
689
  default:
641
690
  return level;
642
691
  }
@@ -645,8 +694,8 @@ function scoreBar(score) {
645
694
  const width = 20;
646
695
  const filled = Math.round(score / 100 * width);
647
696
  const empty = width - filled;
648
- const color = score >= 70 ? chalk4.green : score >= 40 ? chalk4.yellow : chalk4.red;
649
- return color("\u2588".repeat(filled)) + chalk4.dim("\u2591".repeat(empty)) + ` ${Math.round(score)}`;
697
+ const color = score >= 70 ? chalk5.green : score >= 40 ? chalk5.yellow : chalk5.red;
698
+ return color("\u2588".repeat(filled)) + chalk5.dim("\u2591".repeat(empty)) + ` ${Math.round(score)}`;
650
699
  }
651
700
  var CATEGORY_LABELS = {
652
701
  frontend: "Frontend",
@@ -675,11 +724,11 @@ function formatExtended(ext) {
675
724
  const inv = ext.toolingInventory;
676
725
  const categories = Object.entries(inv).filter(([, items]) => items.length > 0);
677
726
  if (categories.length > 0) {
678
- lines.push(chalk4.bold.underline(" Tech Stack"));
727
+ lines.push(chalk5.bold.underline(" Tech Stack"));
679
728
  for (const [cat, items] of categories) {
680
729
  const label = CATEGORY_LABELS[cat] ?? cat;
681
- const names = items.map((i) => chalk4.white(i.name)).join(chalk4.dim(", "));
682
- lines.push(` ${chalk4.cyan(label)}: ${names}`);
730
+ const names = items.map((i) => chalk5.white(i.name)).join(chalk5.dim(", "));
731
+ lines.push(` ${chalk5.cyan(label)}: ${names}`);
683
732
  }
684
733
  lines.push("");
685
734
  }
@@ -688,14 +737,14 @@ function formatExtended(ext) {
688
737
  const svc = ext.serviceDependencies;
689
738
  const categories = Object.entries(svc).filter(([, items]) => items.length > 0);
690
739
  if (categories.length > 0) {
691
- lines.push(chalk4.bold.underline(" Services & Integrations"));
740
+ lines.push(chalk5.bold.underline(" Services & Integrations"));
692
741
  for (const [cat, items] of categories) {
693
742
  const label = CATEGORY_LABELS[cat] ?? cat;
694
743
  const names = items.map((i) => {
695
- const ver = i.version ? chalk4.dim(` ${i.version}`) : "";
696
- return chalk4.white(i.name) + ver;
697
- }).join(chalk4.dim(", "));
698
- lines.push(` ${chalk4.cyan(label)}: ${names}`);
744
+ const ver = i.version ? chalk5.dim(` ${i.version}`) : "";
745
+ return chalk5.white(i.name) + ver;
746
+ }).join(chalk5.dim(", "));
747
+ lines.push(` ${chalk5.cyan(label)}: ${names}`);
699
748
  }
700
749
  lines.push("");
701
750
  }
@@ -703,19 +752,19 @@ function formatExtended(ext) {
703
752
  if (ext.breakingChangeExposure) {
704
753
  const bc = ext.breakingChangeExposure;
705
754
  if (bc.deprecatedPackages.length > 0 || bc.legacyPolyfills.length > 0) {
706
- lines.push(chalk4.bold.underline(" Breaking Change Exposure"));
707
- const exposureColor = bc.exposureScore >= 40 ? chalk4.red : bc.exposureScore >= 20 ? chalk4.yellow : chalk4.green;
755
+ lines.push(chalk5.bold.underline(" Breaking Change Exposure"));
756
+ const exposureColor = bc.exposureScore >= 40 ? chalk5.red : bc.exposureScore >= 20 ? chalk5.yellow : chalk5.green;
708
757
  lines.push(` Exposure Score: ${exposureColor.bold(`${bc.exposureScore}/100`)}`);
709
758
  if (bc.deprecatedPackages.length > 0) {
710
- lines.push(` ${chalk4.red("Deprecated")}: ${bc.deprecatedPackages.map((p) => chalk4.dim(p)).join(", ")}`);
759
+ lines.push(` ${chalk5.red("Deprecated")}: ${bc.deprecatedPackages.map((p) => chalk5.dim(p)).join(", ")}`);
711
760
  }
712
761
  if (bc.legacyPolyfills.length > 0) {
713
- lines.push(` ${chalk4.yellow("Polyfills")}: ${bc.legacyPolyfills.map((p) => chalk4.dim(p)).join(", ")}`);
762
+ lines.push(` ${chalk5.yellow("Polyfills")}: ${bc.legacyPolyfills.map((p) => chalk5.dim(p)).join(", ")}`);
714
763
  }
715
764
  if (bc.peerConflictsDetected) {
716
- lines.push(` ${chalk4.red("\u26A0")} Peer dependency conflicts detected`);
765
+ lines.push(` ${chalk5.red("\u26A0")} Peer dependency conflicts detected`);
717
766
  }
718
- lines.push(` Recommendation: ${chalk4.bold(bc.overallRecommendation)}`);
767
+ lines.push(` Recommendation: ${chalk5.bold(bc.overallRecommendation)}`);
719
768
  const projectsWithPlans = bc.projectIntelligence.filter((p) => p.packages.length > 0).slice(0, 3);
720
769
  if (projectsWithPlans.length > 0) {
721
770
  lines.push(" Major Upgrade Intelligence:");
@@ -731,21 +780,21 @@ function formatExtended(ext) {
731
780
  }
732
781
  if (ext.tsModernity && ext.tsModernity.typescriptVersion) {
733
782
  const ts = ext.tsModernity;
734
- lines.push(chalk4.bold.underline(" TypeScript"));
783
+ lines.push(chalk5.bold.underline(" TypeScript"));
735
784
  const parts = [];
736
785
  parts.push(`v${ts.typescriptVersion}`);
737
- if (ts.strict === true) parts.push(chalk4.green("strict \u2714"));
738
- else if (ts.strict === false) parts.push(chalk4.yellow("strict \u2716"));
786
+ if (ts.strict === true) parts.push(chalk5.green("strict \u2714"));
787
+ else if (ts.strict === false) parts.push(chalk5.yellow("strict \u2716"));
739
788
  if (ts.moduleType) parts.push(ts.moduleType.toUpperCase());
740
789
  if (ts.target) parts.push(`target: ${ts.target}`);
741
- lines.push(` ${parts.join(chalk4.dim(" \xB7 "))}`);
790
+ lines.push(` ${parts.join(chalk5.dim(" \xB7 "))}`);
742
791
  lines.push("");
743
792
  }
744
793
  if (ext.buildDeploy) {
745
794
  const bd = ext.buildDeploy;
746
795
  const hasSomething = bd.ci.length > 0 || bd.docker.dockerfileCount > 0 || bd.packageManagers.length > 0;
747
796
  if (hasSomething) {
748
- lines.push(chalk4.bold.underline(" Build & Deploy"));
797
+ lines.push(chalk5.bold.underline(" Build & Deploy"));
749
798
  if (bd.ci.length > 0) lines.push(` CI: ${bd.ci.join(", ")}`);
750
799
  if (bd.docker.dockerfileCount > 0) {
751
800
  lines.push(` Docker: ${bd.docker.dockerfileCount} Dockerfile${bd.docker.dockerfileCount !== 1 ? "s" : ""} (${bd.docker.baseImages.join(", ")})`);
@@ -758,42 +807,42 @@ function formatExtended(ext) {
758
807
  }
759
808
  if (ext.uiPurpose) {
760
809
  const up = ext.uiPurpose;
761
- lines.push(chalk4.bold.underline(" Product Purpose Signals"));
762
- lines.push(` Frameworks: ${up.detectedFrameworks.length > 0 ? up.detectedFrameworks.join(", ") : chalk4.dim("unknown")}`);
763
- lines.push(` Evidence: ${up.topEvidence.length}${up.capped ? chalk4.dim(` of ${up.evidenceCount} (capped)`) : ""}`);
810
+ lines.push(chalk5.bold.underline(" Product Purpose Signals"));
811
+ lines.push(` Frameworks: ${up.detectedFrameworks.length > 0 ? up.detectedFrameworks.join(", ") : chalk5.dim("unknown")}`);
812
+ lines.push(` Evidence: ${up.topEvidence.length}${up.capped ? chalk5.dim(` of ${up.evidenceCount} (capped)`) : ""}`);
764
813
  const top = up.topEvidence.slice(0, 8);
765
814
  if (top.length > 0) {
766
815
  lines.push(" Top Signals:");
767
816
  for (const item of top) {
768
- lines.push(` - [${item.kind}] ${item.value} ${chalk4.dim(`(${item.file})`)}`);
817
+ lines.push(` - [${item.kind}] ${item.value} ${chalk5.dim(`(${item.file})`)}`);
769
818
  }
770
819
  }
771
820
  if (up.unknownSignals.length > 0) {
772
821
  lines.push(" Unknowns:");
773
822
  for (const u of up.unknownSignals.slice(0, 4)) {
774
- lines.push(` - ${chalk4.yellow(u)}`);
823
+ lines.push(` - ${chalk5.yellow(u)}`);
775
824
  }
776
825
  }
777
826
  lines.push("");
778
827
  }
779
828
  if (ext.securityPosture) {
780
829
  const sec = ext.securityPosture;
781
- lines.push(chalk4.bold.underline(" Security Posture"));
830
+ lines.push(chalk5.bold.underline(" Security Posture"));
782
831
  const checks = [];
783
- checks.push(sec.lockfilePresent ? chalk4.green("Lockfile \u2714") : chalk4.red("Lockfile \u2716"));
784
- checks.push(sec.gitignoreCoversEnv ? chalk4.green(".env \u2714") : chalk4.red(".env \u2716"));
785
- checks.push(sec.gitignoreCoversNodeModules ? chalk4.green("node_modules \u2714") : chalk4.yellow("node_modules \u2716"));
786
- if (sec.multipleLockfileTypes) checks.push(chalk4.yellow("Multiple lockfiles \u26A0"));
787
- if (sec.envFilesTracked) checks.push(chalk4.red("Env files tracked \u2716"));
788
- lines.push(` ${checks.join(chalk4.dim(" \xB7 "))}`);
832
+ checks.push(sec.lockfilePresent ? chalk5.green("Lockfile \u2714") : chalk5.red("Lockfile \u2716"));
833
+ checks.push(sec.gitignoreCoversEnv ? chalk5.green(".env \u2714") : chalk5.red(".env \u2716"));
834
+ checks.push(sec.gitignoreCoversNodeModules ? chalk5.green("node_modules \u2714") : chalk5.yellow("node_modules \u2716"));
835
+ if (sec.multipleLockfileTypes) checks.push(chalk5.yellow("Multiple lockfiles \u26A0"));
836
+ if (sec.envFilesTracked) checks.push(chalk5.red("Env files tracked \u2716"));
837
+ lines.push(` ${checks.join(chalk5.dim(" \xB7 "))}`);
789
838
  lines.push("");
790
839
  }
791
840
  if (ext.platformMatrix) {
792
841
  const pm = ext.platformMatrix;
793
842
  if (pm.nativeModules.length > 0 || pm.dockerBaseImages.length > 0) {
794
- lines.push(chalk4.bold.underline(" Platform"));
843
+ lines.push(chalk5.bold.underline(" Platform"));
795
844
  if (pm.nativeModules.length > 0) {
796
- lines.push(` Native modules: ${pm.nativeModules.map((m) => chalk4.dim(m)).join(", ")}`);
845
+ lines.push(` Native modules: ${pm.nativeModules.map((m) => chalk5.dim(m)).join(", ")}`);
797
846
  }
798
847
  if (pm.osAssumptions.length > 0) {
799
848
  lines.push(` OS assumptions: ${pm.osAssumptions.join(", ")}`);
@@ -803,25 +852,25 @@ function formatExtended(ext) {
803
852
  }
804
853
  if (ext.codeQuality) {
805
854
  const cq = ext.codeQuality;
806
- lines.push(chalk4.bold.underline(" Code Quality"));
807
- lines.push(` Files: ${chalk4.white(`${cq.filesAnalyzed}`)} \xB7 Functions: ${chalk4.white(`${cq.functionsAnalyzed}`)} \xB7 Avg complexity: ${chalk4.white(`${cq.avgCyclomaticComplexity}`)} \xB7 Avg length: ${chalk4.white(`${cq.avgFunctionLength}`)} lines`);
855
+ lines.push(chalk5.bold.underline(" Code Quality"));
856
+ lines.push(` Files: ${chalk5.white(`${cq.filesAnalyzed}`)} \xB7 Functions: ${chalk5.white(`${cq.functionsAnalyzed}`)} \xB7 Avg complexity: ${chalk5.white(`${cq.avgCyclomaticComplexity}`)} \xB7 Avg length: ${chalk5.white(`${cq.avgFunctionLength}`)} lines`);
808
857
  lines.push(` Max nesting: ${cq.maxNestingDepth} \xB7 Circular deps: ${cq.circularDependencies} \xB7 Dead code: ${cq.deadCodePercent}%`);
809
858
  if (cq.godFiles.length > 0) {
810
859
  const preview = cq.godFiles.slice(0, 3).map((f) => `${f.path} (${f.lines} lines)`).join(", ");
811
- lines.push(` ${chalk4.yellow("God files")}: ${preview}`);
860
+ lines.push(` ${chalk5.yellow("God files")}: ${preview}`);
812
861
  }
813
862
  lines.push("");
814
863
  }
815
864
  if (ext.dependencyGraph) {
816
865
  const dg = ext.dependencyGraph;
817
866
  if (dg.lockfileType) {
818
- lines.push(chalk4.bold.underline(" Dependency Graph"));
819
- lines.push(` ${dg.lockfileType}: ${chalk4.white(`${dg.totalUnique}`)} unique, ${chalk4.white(`${dg.totalInstalled}`)} installed`);
867
+ lines.push(chalk5.bold.underline(" Dependency Graph"));
868
+ lines.push(` ${dg.lockfileType}: ${chalk5.white(`${dg.totalUnique}`)} unique, ${chalk5.white(`${dg.totalInstalled}`)} installed`);
820
869
  if (dg.duplicatedPackages.length > 0) {
821
- lines.push(` ${chalk4.yellow(`${dg.duplicatedPackages.length} duplicated`)} packages`);
870
+ lines.push(` ${chalk5.yellow(`${dg.duplicatedPackages.length} duplicated`)} packages`);
822
871
  }
823
872
  if (dg.phantomDependencies.length > 0) {
824
- lines.push(` ${chalk4.red(`${dg.phantomDependencies.length} phantom`)} dependencies`);
873
+ lines.push(` ${chalk5.red(`${dg.phantomDependencies.length} phantom`)} dependencies`);
825
874
  }
826
875
  lines.push("");
827
876
  }
@@ -830,17 +879,17 @@ function formatExtended(ext) {
830
879
  }
831
880
  function formatArchitectureDiagram(arch) {
832
881
  const lines = [];
833
- lines.push(chalk4.bold.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
834
- lines.push(chalk4.bold.cyan("\u2551 Architecture Layers \u2551"));
835
- lines.push(chalk4.bold.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
882
+ lines.push(chalk5.bold.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
883
+ lines.push(chalk5.bold.cyan("\u2551 Architecture Layers \u2551"));
884
+ lines.push(chalk5.bold.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
836
885
  lines.push("");
837
- lines.push(chalk4.bold(" Archetype: ") + `${arch.archetype}` + chalk4.dim(` (${Math.round(arch.archetypeConfidence * 100)}% confidence)`));
838
- lines.push(` Files classified: ${arch.totalClassified}` + (arch.unclassified > 0 ? chalk4.dim(` (${arch.unclassified} unclassified)`) : ""));
886
+ lines.push(chalk5.bold(" Archetype: ") + `${arch.archetype}` + chalk5.dim(` (${Math.round(arch.archetypeConfidence * 100)}% confidence)`));
887
+ lines.push(` Files classified: ${arch.totalClassified}` + (arch.unclassified > 0 ? chalk5.dim(` (${arch.unclassified} unclassified)`) : ""));
839
888
  lines.push("");
840
889
  if (arch.layers.length > 0) {
841
890
  for (const layer of arch.layers) {
842
- const risk = layer.riskLevel === "none" ? chalk4.dim("none") : layer.riskLevel === "low" ? chalk4.green("low") : layer.riskLevel === "moderate" ? chalk4.yellow("moderate") : chalk4.red("high");
843
- lines.push(` ${chalk4.bold(layer.layer)} ${layer.fileCount} file${layer.fileCount !== 1 ? "s" : ""} drift ${scoreBar(layer.driftScore)} risk ${risk}`);
891
+ const risk = layer.riskLevel === "none" ? chalk5.dim("none") : layer.riskLevel === "low" ? chalk5.green("low") : layer.riskLevel === "moderate" ? chalk5.yellow("moderate") : chalk5.red("high");
892
+ lines.push(` ${chalk5.bold(layer.layer)} ${layer.fileCount} file${layer.fileCount !== 1 ? "s" : ""} drift ${scoreBar(layer.driftScore)} risk ${risk}`);
844
893
  }
845
894
  lines.push("");
846
895
  }
@@ -1211,8 +1260,8 @@ function formatMarkdown(artifact) {
1211
1260
  var reportCommand = new Command4("report").description("Generate a drift report from a scan artifact").option("--in <file>", "Input artifact file", ".vibgrate/scan_result.json").option("--format <format>", "Output format (md|text|json)", "text").action(async (opts) => {
1212
1261
  const artifactPath = path5.resolve(opts.in);
1213
1262
  if (!await pathExists(artifactPath)) {
1214
- console.error(chalk5.red(`Artifact not found: ${artifactPath}`));
1215
- console.error(chalk5.dim('Run "vibgrate scan" first to generate a scan artifact.'));
1263
+ console.error(chalk6.red(`Artifact not found: ${artifactPath}`));
1264
+ console.error(chalk6.dim('Run "vibgrate scan" first to generate a scan artifact.'));
1216
1265
  process.exit(1);
1217
1266
  }
1218
1267
  const artifact = await readJsonFile(artifactPath);
@@ -1232,7 +1281,7 @@ var reportCommand = new Command4("report").description("Generate a drift report
1232
1281
 
1233
1282
  // src/commands/login.ts
1234
1283
  import { Command as Command5 } from "commander";
1235
- import chalk6 from "chalk";
1284
+ import chalk7 from "chalk";
1236
1285
 
1237
1286
  // src/utils/open-url.ts
1238
1287
  import { spawn } from "child_process";
@@ -1268,7 +1317,7 @@ var loginCommand = new Command5("login").description("Authenticate the CLI with
1268
1317
  try {
1269
1318
  ingestHost = resolveIngestHost(opts.region, opts.ingest);
1270
1319
  } catch (e) {
1271
- console.error(chalk6.red(e instanceof Error ? e.message : String(e)));
1320
+ console.error(chalk7.red(e instanceof Error ? e.message : String(e)));
1272
1321
  process.exit(1);
1273
1322
  }
1274
1323
  const base = `https://${ingestHost}/v1/auth/device`;
@@ -1280,28 +1329,28 @@ var loginCommand = new Command5("login").description("Authenticate the CLI with
1280
1329
  body: "{}"
1281
1330
  });
1282
1331
  if (!res.ok) {
1283
- console.error(chalk6.red(`Failed to start login (HTTP ${res.status}).`));
1332
+ console.error(chalk7.red(`Failed to start login (HTTP ${res.status}).`));
1284
1333
  process.exit(1);
1285
1334
  }
1286
1335
  start = await res.json();
1287
1336
  } catch (e) {
1288
- console.error(chalk6.red(`Could not reach ${ingestHost}: ${e instanceof Error ? e.message : String(e)}`));
1337
+ console.error(chalk7.red(`Could not reach ${ingestHost}: ${e instanceof Error ? e.message : String(e)}`));
1289
1338
  process.exit(1);
1290
1339
  }
1291
1340
  console.log("");
1292
1341
  console.log("To finish signing in, open this URL and approve the request:");
1293
1342
  console.log("");
1294
- console.log(" " + chalk6.cyan(start.verificationUri));
1343
+ console.log(" " + chalk7.cyan(start.verificationUri));
1295
1344
  console.log("");
1296
- console.log(" Your code: " + chalk6.bold(start.userCode));
1345
+ console.log(" Your code: " + chalk7.bold(start.userCode));
1297
1346
  console.log("");
1298
1347
  if (opts.browser) {
1299
1348
  const opened = openUrl(start.verificationUriComplete);
1300
1349
  if (opened) {
1301
- console.log(chalk6.dim("Opening your browser\u2026 (if it does not open, use the URL above)"));
1350
+ console.log(chalk7.dim("Opening your browser\u2026 (if it does not open, use the URL above)"));
1302
1351
  }
1303
1352
  }
1304
- console.log(chalk6.dim("Waiting for approval\u2026"));
1353
+ console.log(chalk7.dim("Waiting for approval\u2026"));
1305
1354
  const intervalMs = Math.max(2, start.interval || 5) * 1e3;
1306
1355
  const deadline = Date.now() + (start.expiresIn || 900) * 1e3;
1307
1356
  while (Date.now() < deadline) {
@@ -1327,40 +1376,40 @@ var loginCommand = new Command5("login").description("Authenticate the CLI with
1327
1376
  savedAt: (/* @__PURE__ */ new Date()).toISOString()
1328
1377
  });
1329
1378
  console.log("");
1330
- console.log(chalk6.green("\u2714") + " Logged in.");
1379
+ console.log(chalk7.green("\u2714") + " Logged in.");
1331
1380
  if (token.workspaceId) {
1332
- console.log(" Workspace: " + chalk6.bold(token.workspaceId));
1381
+ console.log(" Workspace: " + chalk7.bold(token.workspaceId));
1333
1382
  }
1334
- console.log(chalk6.dim(` Credentials saved to ${credentialsPath()}`));
1335
- console.log(chalk6.dim(' You can now run "vibgrate scan --push".'));
1383
+ console.log(chalk7.dim(` Credentials saved to ${credentialsPath()}`));
1384
+ console.log(chalk7.dim(' You can now run "vibgrate scan --push".'));
1336
1385
  return;
1337
1386
  }
1338
1387
  if (token.status === "access_denied") {
1339
- console.error(chalk6.red("\u2716 Login was denied in the browser."));
1388
+ console.error(chalk7.red("\u2716 Login was denied in the browser."));
1340
1389
  process.exit(1);
1341
1390
  }
1342
1391
  if (token.status === "expired" || token.status === "invalid") {
1343
- console.error(chalk6.red('\u2716 Login request expired. Run "vibgrate login" again.'));
1392
+ console.error(chalk7.red('\u2716 Login request expired. Run "vibgrate login" again.'));
1344
1393
  process.exit(1);
1345
1394
  }
1346
1395
  if (token.status === "error") {
1347
- console.error(chalk6.red(`\u2716 ${token.error ?? "Login failed."}`));
1396
+ console.error(chalk7.red(`\u2716 ${token.error ?? "Login failed."}`));
1348
1397
  process.exit(1);
1349
1398
  }
1350
1399
  }
1351
- console.error(chalk6.red('\u2716 Timed out waiting for approval. Run "vibgrate login" again.'));
1400
+ console.error(chalk7.red('\u2716 Timed out waiting for approval. Run "vibgrate login" again.'));
1352
1401
  process.exit(1);
1353
1402
  });
1354
1403
 
1355
1404
  // src/commands/logout.ts
1356
1405
  import { Command as Command6 } from "commander";
1357
- import chalk7 from "chalk";
1406
+ import chalk8 from "chalk";
1358
1407
  var logoutCommand = new Command6("logout").description("Clear stored Vibgrate login credentials").action(() => {
1359
1408
  const cleared = clearStoredCredentials();
1360
1409
  if (cleared) {
1361
- console.log(chalk7.green("\u2714") + " Logged out. Stored credentials removed.");
1410
+ console.log(chalk8.green("\u2714") + " Logged out. Stored credentials removed.");
1362
1411
  } else {
1363
- console.log(chalk7.dim(`No stored credentials found at ${credentialsPath()}.`));
1412
+ console.log(chalk8.dim(`No stored credentials found at ${credentialsPath()}.`));
1364
1413
  }
1365
1414
  });
1366
1415
 
@@ -1368,7 +1417,7 @@ var logoutCommand = new Command6("logout").description("Clear stored Vibgrate lo
1368
1417
  import * as crypto2 from "crypto";
1369
1418
  import * as path6 from "path";
1370
1419
  import { Command as Command7 } from "commander";
1371
- import chalk8 from "chalk";
1420
+ import chalk9 from "chalk";
1372
1421
 
1373
1422
  // src/utils/compact-artifact.ts
1374
1423
  import * as zlib from "zlib";
@@ -1643,22 +1692,22 @@ function computeHmac(body, secret) {
1643
1692
  var pushCommand = new Command7("push").description("Push scan results to Vibgrate API").option("--dsn <dsn>", "DSN token (or use VIBGRATE_DSN env)").option("--region <region>", `Override data residency region (${availableRegionIds().join(", ")})`).option("--file <file>", "Scan artifact file", ".vibgrate/scan_result.json").option("--strict", "Fail on upload errors").action(async (opts) => {
1644
1693
  const dsn = resolveDsn(opts.dsn);
1645
1694
  if (!dsn) {
1646
- console.error(chalk8.red("No DSN provided."));
1647
- console.error(chalk8.dim('Run "vibgrate login", set VIBGRATE_DSN, or use the --dsn flag.'));
1695
+ console.error(chalk9.red("No DSN provided."));
1696
+ console.error(chalk9.dim('Run "vibgrate login", set VIBGRATE_DSN, or use the --dsn flag.'));
1648
1697
  if (opts.strict) process.exit(1);
1649
1698
  return;
1650
1699
  }
1651
1700
  const parsed = parseDsn2(dsn);
1652
1701
  if (!parsed) {
1653
- console.error(chalk8.red("Invalid DSN format."));
1654
- console.error(chalk8.dim("Expected: vibgrate+https://<key_id>:<secret>@<host>/<workspace_id>"));
1702
+ console.error(chalk9.red("Invalid DSN format."));
1703
+ console.error(chalk9.dim("Expected: vibgrate+https://<key_id>:<secret>@<host>/<workspace_id>"));
1655
1704
  if (opts.strict) process.exit(1);
1656
1705
  return;
1657
1706
  }
1658
1707
  const filePath = path6.resolve(opts.file);
1659
1708
  if (!await pathExists(filePath)) {
1660
- console.error(chalk8.red(`Scan artifact not found: ${filePath}`));
1661
- console.error(chalk8.dim('Run "vibgrate scan" first.'));
1709
+ console.error(chalk9.red(`Scan artifact not found: ${filePath}`));
1710
+ console.error(chalk9.dim('Run "vibgrate scan" first.'));
1662
1711
  if (opts.strict) process.exit(1);
1663
1712
  return;
1664
1713
  }
@@ -1670,46 +1719,43 @@ var pushCommand = new Command7("push").description("Push scan results to Vibgrat
1670
1719
  try {
1671
1720
  host = resolveIngestHost(opts.region);
1672
1721
  } catch (e) {
1673
- console.error(chalk8.red(e instanceof Error ? e.message : String(e)));
1722
+ console.error(chalk9.red(e instanceof Error ? e.message : String(e)));
1674
1723
  if (opts.strict) process.exit(1);
1675
1724
  return;
1676
1725
  }
1677
1726
  }
1678
- const url = `${parsed.scheme}://${host}/v1/ingest/scan`;
1679
1727
  const originalSize = JSON.stringify(artifact).length;
1680
1728
  const compressedSize = body.length;
1681
1729
  const ratio = ((1 - compressedSize / originalSize) * 100).toFixed(0);
1682
- console.log(chalk8.dim(`Uploading to ${host}... (${(compressedSize / 1024).toFixed(0)} KB, ${ratio}% smaller)`));
1730
+ console.log(chalk9.dim(`Uploading to ${host}... (${(compressedSize / 1024).toFixed(0)} KB, ${ratio}% smaller)`));
1683
1731
  try {
1684
- const response = await fetch(url, {
1685
- method: "POST",
1686
- headers: {
1687
- "Content-Type": "application/json",
1688
- "Content-Encoding": contentEncoding,
1689
- "X-Vibgrate-Timestamp": timestamp,
1690
- "Authorization": `VibgrateDSN ${parsed.keyId}:${parsed.secret}`,
1691
- "Connection": "close"
1692
- // Prevent keep-alive delays on exit
1693
- },
1694
- body
1732
+ const { response, host: uploadedHost } = await uploadScanArtifact({
1733
+ scheme: parsed.scheme,
1734
+ host,
1735
+ keyId: parsed.keyId,
1736
+ secret: parsed.secret,
1737
+ body,
1738
+ contentEncoding,
1739
+ timestamp
1695
1740
  });
1741
+ host = uploadedHost;
1696
1742
  if (!response.ok) {
1697
1743
  const text = await response.text();
1698
1744
  throw new Error(`HTTP ${response.status}: ${text}`);
1699
1745
  }
1700
1746
  const result = await response.json();
1701
- console.log(chalk8.green("\u2714") + ` Scan queued for processing (${result.ingestId ?? "ok"})`);
1747
+ console.log(chalk9.green("\u2714") + ` Scan queued for processing (${result.ingestId ?? "ok"})`);
1702
1748
  console.log();
1703
- console.log(chalk8.dim("Processing continues in the background. Results available shortly."));
1749
+ console.log(chalk9.dim("Processing continues in the background. Results available shortly."));
1704
1750
  console.log();
1705
1751
  if (result.ingestId) {
1706
1752
  const dashHost = dashHostForIngestHost(host);
1707
1753
  const reportUrl = `https://${dashHost}/${parsed.workspaceId}/scan/${result.ingestId}`;
1708
- console.log(chalk8.dim("View report: ") + chalk8.underline(reportUrl));
1754
+ console.log(chalk9.dim("View report: ") + chalk9.underline(reportUrl));
1709
1755
  }
1710
1756
  } catch (e) {
1711
1757
  const msg = e instanceof Error ? e.message : String(e);
1712
- console.error(chalk8.red(`Upload failed: ${msg}`));
1758
+ console.error(chalk9.red(`Upload failed: ${msg}`));
1713
1759
  if (opts.strict) process.exit(1);
1714
1760
  }
1715
1761
  });
@@ -1718,7 +1764,7 @@ var pushCommand = new Command7("push").description("Push scan results to Vibgrat
1718
1764
  import { execSync } from "child_process";
1719
1765
  import * as path8 from "path";
1720
1766
  import { Command as Command8 } from "commander";
1721
- import chalk9 from "chalk";
1767
+ import chalk10 from "chalk";
1722
1768
 
1723
1769
  // src/utils/update-check.ts
1724
1770
  var import_semver = __toESM(require_semver(), 1);
@@ -1865,21 +1911,21 @@ async function isDevDependency(cwd) {
1865
1911
  }
1866
1912
  }
1867
1913
  var updateCommand = new Command8("update").description("Update vibgrate to the latest version").option("--check", "Only check for updates, do not install").option("--pm <manager>", "Package manager to use (npm, pnpm, yarn, bun)").option("--global", "Update global installation").action(async (opts) => {
1868
- console.log(chalk9.dim(`Current version: ${VERSION}`));
1869
- console.log(chalk9.dim("Checking npm registry..."));
1914
+ console.log(chalk10.dim(`Current version: ${VERSION}`));
1915
+ console.log(chalk10.dim("Checking npm registry..."));
1870
1916
  const latest = await fetchLatestVersion();
1871
1917
  if (!latest) {
1872
- console.error(chalk9.red("Could not reach the npm registry. Check your network connection."));
1918
+ console.error(chalk10.red("Could not reach the npm registry. Check your network connection."));
1873
1919
  process.exit(1);
1874
1920
  }
1875
1921
  const semver2 = await import("./semver-2FJFIYVN.js");
1876
1922
  if (!semver2.gt(latest, VERSION)) {
1877
- console.log(chalk9.green("\u2714") + ` You are on the latest version (${VERSION}).`);
1923
+ console.log(chalk10.green("\u2714") + ` You are on the latest version (${VERSION}).`);
1878
1924
  return;
1879
1925
  }
1880
- console.log(chalk9.yellow(`Update available: ${VERSION} \u2192 ${latest}`));
1926
+ console.log(chalk10.yellow(`Update available: ${VERSION} \u2192 ${latest}`));
1881
1927
  if (opts.check) {
1882
- console.log(chalk9.dim('Run "vibgrate update" to install.'));
1928
+ console.log(chalk10.dim('Run "vibgrate update" to install.'));
1883
1929
  return;
1884
1930
  }
1885
1931
  const cwd = process.cwd();
@@ -1889,17 +1935,17 @@ var updateCommand = new Command8("update").description("Update vibgrate to the l
1889
1935
  let cmd;
1890
1936
  if (isGlobal) {
1891
1937
  cmd = getGlobalUpdateCommand(pm, "@vibgrate/cli", latest);
1892
- console.log(chalk9.dim(`Updating global installation with ${pm}: ${cmd}`));
1938
+ console.log(chalk10.dim(`Updating global installation with ${pm}: ${cmd}`));
1893
1939
  } else {
1894
1940
  const isDev = await isDevDependency(cwd);
1895
1941
  cmd = getInstallCommand(pm, "@vibgrate/cli", latest, isDev);
1896
- console.log(chalk9.dim(`Using ${pm}: ${cmd}`));
1942
+ console.log(chalk10.dim(`Using ${pm}: ${cmd}`));
1897
1943
  }
1898
1944
  try {
1899
1945
  execSync(cmd, { cwd, stdio: "inherit" });
1900
- console.log(chalk9.green("\u2714") + ` Updated to @vibgrate/cli@${latest}`);
1946
+ console.log(chalk10.green("\u2714") + ` Updated to @vibgrate/cli@${latest}`);
1901
1947
  } catch {
1902
- console.error(chalk9.red(`Update failed. Run manually: ${cmd}`));
1948
+ console.error(chalk10.red(`Update failed. Run manually: ${cmd}`));
1903
1949
  process.exit(1);
1904
1950
  }
1905
1951
  });
@@ -1908,7 +1954,7 @@ var updateCommand = new Command8("update").description("Update vibgrate to the l
1908
1954
  import * as path9 from "path";
1909
1955
  import { randomUUID } from "crypto";
1910
1956
  import { Command as Command9 } from "commander";
1911
- import chalk10 from "chalk";
1957
+ import chalk11 from "chalk";
1912
1958
  function flattenDependencies(artifact) {
1913
1959
  const rows = [];
1914
1960
  for (const project of artifact.projects) {
@@ -2048,7 +2094,7 @@ function formatDeltaText(base, current) {
2048
2094
  async function readArtifactOrExit(filePath) {
2049
2095
  const absolutePath = path9.resolve(filePath);
2050
2096
  if (!await pathExists(absolutePath)) {
2051
- console.error(chalk10.red(`Artifact not found: ${absolutePath}`));
2097
+ console.error(chalk11.red(`Artifact not found: ${absolutePath}`));
2052
2098
  process.exit(1);
2053
2099
  }
2054
2100
  return readJsonFile(absolutePath);
@@ -2057,14 +2103,14 @@ var exportCommand = new Command9("export").description("Export scan artifact as
2057
2103
  const artifact = await readArtifactOrExit(opts.in);
2058
2104
  const format = opts.format.toLowerCase();
2059
2105
  if (format !== "cyclonedx" && format !== "spdx") {
2060
- console.error(chalk10.red("Invalid SBOM format. Use cyclonedx or spdx."));
2106
+ console.error(chalk11.red("Invalid SBOM format. Use cyclonedx or spdx."));
2061
2107
  process.exit(1);
2062
2108
  }
2063
2109
  const sbom = format === "cyclonedx" ? toCycloneDx(artifact) : toSpdx(artifact);
2064
2110
  const body = JSON.stringify(sbom, null, 2);
2065
2111
  if (opts.out) {
2066
2112
  await writeTextFile(path9.resolve(opts.out), body);
2067
- console.log(chalk10.green("\u2714") + ` SBOM written to ${opts.out}`);
2113
+ console.log(chalk11.green("\u2714") + ` SBOM written to ${opts.out}`);
2068
2114
  } else {
2069
2115
  console.log(body);
2070
2116
  }
@@ -2075,7 +2121,7 @@ var deltaCommand = new Command9("delta").description("Show SBOM delta between tw
2075
2121
  const report = formatDeltaText(base, current);
2076
2122
  if (opts.out) {
2077
2123
  await writeTextFile(path9.resolve(opts.out), report);
2078
- console.log(chalk10.green("\u2714") + ` SBOM delta report written to ${opts.out}`);
2124
+ console.log(chalk11.green("\u2714") + ` SBOM delta report written to ${opts.out}`);
2079
2125
  } else {
2080
2126
  console.log(report);
2081
2127
  }
@@ -2089,7 +2135,7 @@ import * as fs4 from "fs/promises";
2089
2135
  import { existsSync, rmSync as rmSync2 } from "fs";
2090
2136
  import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
2091
2137
  import { Command as Command10 } from "commander";
2092
- import chalk11 from "chalk";
2138
+ import chalk12 from "chalk";
2093
2139
 
2094
2140
  // src/behavioural/derive.ts
2095
2141
  import { createHash as createHash2 } from "crypto";
@@ -3577,7 +3623,7 @@ async function runNodeWorker(rootDir, language, opts) {
3577
3623
  continue;
3578
3624
  }
3579
3625
  if (opts.verbose) {
3580
- process.stderr.write(chalk11.dim(`[${language}] ${trimmed}
3626
+ process.stderr.write(chalk12.dim(`[${language}] ${trimmed}
3581
3627
  `));
3582
3628
  }
3583
3629
  if (trimmed.startsWith("[error]")) {
@@ -3718,7 +3764,7 @@ async function runNativeWorker(rootDir, language, opts) {
3718
3764
  let stdoutBuf = "";
3719
3765
  let killed = false;
3720
3766
  if (opts.verbose) {
3721
- process.stderr.write(chalk11.dim(`[${language}] Spawning: ${spec.cmd} ${spec.args.join(" ")}
3767
+ process.stderr.write(chalk12.dim(`[${language}] Spawning: ${spec.cmd} ${spec.args.join(" ")}
3722
3768
  `));
3723
3769
  }
3724
3770
  const runtimeReq = NATIVE_RUNTIME_REQUIREMENTS[language];
@@ -3759,7 +3805,7 @@ async function runNativeWorker(rootDir, language, opts) {
3759
3805
  const trimmed = line.trim();
3760
3806
  if (!trimmed) continue;
3761
3807
  if (opts.verbose) {
3762
- process.stderr.write(chalk11.dim(`[${language}] ${trimmed}
3808
+ process.stderr.write(chalk12.dim(`[${language}] ${trimmed}
3763
3809
  `));
3764
3810
  }
3765
3811
  if (trimmed.startsWith("[error]")) {
@@ -3789,14 +3835,14 @@ async function runNativeWorker(rootDir, language, opts) {
3789
3835
  async function pushFacts(facts, dsn, verbose) {
3790
3836
  const parsed = parseDsn2(dsn);
3791
3837
  if (!parsed) {
3792
- process.stderr.write(chalk11.red("Invalid DSN format.\n"));
3793
- process.stderr.write(chalk11.dim("Expected: vibgrate+https://<key_id>:<secret>@<host>/<workspace_id>\n"));
3838
+ process.stderr.write(chalk12.red("Invalid DSN format.\n"));
3839
+ process.stderr.write(chalk12.dim("Expected: vibgrate+https://<key_id>:<secret>@<host>/<workspace_id>\n"));
3794
3840
  return false;
3795
3841
  }
3796
3842
  const body = facts.join("\n") + "\n";
3797
3843
  const url = `${parsed.scheme}://${parsed.host}/v1/ingest/hcs`;
3798
3844
  if (verbose) {
3799
- process.stderr.write(chalk11.dim(`Pushing ${facts.length} facts to ${parsed.host}...
3845
+ process.stderr.write(chalk12.dim(`Pushing ${facts.length} facts to ${parsed.host}...
3800
3846
  `));
3801
3847
  }
3802
3848
  try {
@@ -3814,17 +3860,17 @@ async function pushFacts(facts, dsn, verbose) {
3814
3860
  });
3815
3861
  if (!response.ok) {
3816
3862
  const text = await response.text().catch(() => "");
3817
- process.stderr.write(chalk11.red(`Push failed: HTTP ${response.status} ${text}
3863
+ process.stderr.write(chalk12.red(`Push failed: HTTP ${response.status} ${text}
3818
3864
  `));
3819
3865
  return false;
3820
3866
  }
3821
3867
  if (verbose) {
3822
- process.stderr.write(chalk11.green(`\u2714 Pushed ${facts.length} facts successfully
3868
+ process.stderr.write(chalk12.green(`\u2714 Pushed ${facts.length} facts successfully
3823
3869
  `));
3824
3870
  }
3825
3871
  return true;
3826
3872
  } catch (err) {
3827
- process.stderr.write(chalk11.red(`Push failed: ${err instanceof Error ? err.message : String(err)}
3873
+ process.stderr.write(chalk12.red(`Push failed: ${err instanceof Error ? err.message : String(err)}
3828
3874
  `));
3829
3875
  return false;
3830
3876
  }
@@ -3891,21 +3937,21 @@ var ProgressTracker = class {
3891
3937
  const parts = [];
3892
3938
  for (const [lang, st] of this.langStatus) {
3893
3939
  if (st.done) {
3894
- parts.push(chalk11.green(`${lang} \u2713`));
3940
+ parts.push(chalk12.green(`${lang} \u2713`));
3895
3941
  } else if (st.phase === "waiting") {
3896
- parts.push(chalk11.dim(`${lang} \xB7`));
3942
+ parts.push(chalk12.dim(`${lang} \xB7`));
3897
3943
  } else if (st.phase === "discovering") {
3898
- parts.push(chalk11.yellow(`${lang} \u2026`));
3944
+ parts.push(chalk12.yellow(`${lang} \u2026`));
3899
3945
  } else if (st.phase === "scanning" && st.fileCount > 0) {
3900
3946
  const pct = Math.round(st.fileIndex / st.fileCount * 100);
3901
- parts.push(chalk11.cyan(`${lang} ${st.fileIndex}/${st.fileCount} ${pct}%`));
3947
+ parts.push(chalk12.cyan(`${lang} ${st.fileIndex}/${st.fileCount} ${pct}%`));
3902
3948
  } else if (st.phase === "extracting") {
3903
- parts.push(chalk11.cyan(`${lang} extracting`));
3949
+ parts.push(chalk12.cyan(`${lang} extracting`));
3904
3950
  } else {
3905
- parts.push(chalk11.dim(`${lang} ${st.phase}`));
3951
+ parts.push(chalk12.dim(`${lang} ${st.phase}`));
3906
3952
  }
3907
3953
  }
3908
- const line = ` ${parts.join(" ")} ${chalk11.dim(`${this.totalFacts} facts`)}`;
3954
+ const line = ` ${parts.join(" ")} ${chalk12.dim(`${this.totalFacts} facts`)}`;
3909
3955
  const padding = Math.max(0, this.lastLineLen - line.length);
3910
3956
  process.stderr.write(`\r${line}${" ".repeat(padding)}`);
3911
3957
  this.lastLineLen = line.length;
@@ -3925,7 +3971,7 @@ var extractCommand = new Command10("extract").description("Analyze source code a
3925
3971
  if (urlArg) {
3926
3972
  const cloneTimeoutMins = parseInt(opts.cloneTimeoutMins, 10);
3927
3973
  if (isNaN(cloneTimeoutMins) || cloneTimeoutMins < 1) {
3928
- process.stderr.write(chalk11.red("--clone-timeout-mins must be >= 1\n"));
3974
+ process.stderr.write(chalk12.red("--clone-timeout-mins must be >= 1\n"));
3929
3975
  process.exit(EXIT_USAGE_ERROR);
3930
3976
  }
3931
3977
  manifestRemoteUrl = redactRemoteUrl(urlArg);
@@ -3937,7 +3983,7 @@ var extractCommand = new Command10("extract").description("Analyze source code a
3937
3983
  });
3938
3984
  rootDir = cloned.dir;
3939
3985
  if (opts.keepClone) {
3940
- process.stderr.write(chalk11.dim(`Clone retained at: ${cloned.dir}
3986
+ process.stderr.write(chalk12.dim(`Clone retained at: ${cloned.dir}
3941
3987
  `));
3942
3988
  } else {
3943
3989
  process.once("exit", () => {
@@ -3949,14 +3995,14 @@ var extractCommand = new Command10("extract").description("Analyze source code a
3949
3995
  }
3950
3996
  } catch (err) {
3951
3997
  const msg = err instanceof CloneError ? err.message : err instanceof Error ? err.message : String(err);
3952
- process.stderr.write(chalk11.red(`Clone failed: ${msg}
3998
+ process.stderr.write(chalk12.red(`Clone failed: ${msg}
3953
3999
  `));
3954
4000
  process.exit(EXIT_USAGE_ERROR);
3955
4001
  }
3956
4002
  } else {
3957
4003
  rootDir = path12.resolve(targetPath);
3958
4004
  if (!await pathExists(rootDir)) {
3959
- process.stderr.write(chalk11.red(`Path does not exist: ${rootDir}
4005
+ process.stderr.write(chalk12.red(`Path does not exist: ${rootDir}
3960
4006
  `));
3961
4007
  process.exit(EXIT_USAGE_ERROR);
3962
4008
  }
@@ -3964,48 +4010,48 @@ var extractCommand = new Command10("extract").description("Analyze source code a
3964
4010
  try {
3965
4011
  stat4 = await fs4.stat(rootDir);
3966
4012
  } catch {
3967
- process.stderr.write(chalk11.red(`Cannot read path: ${rootDir}
4013
+ process.stderr.write(chalk12.red(`Cannot read path: ${rootDir}
3968
4014
  `));
3969
4015
  process.exit(EXIT_USAGE_ERROR);
3970
4016
  }
3971
4017
  if (!stat4.isDirectory()) {
3972
- process.stderr.write(chalk11.red(`Path must be a directory: ${rootDir}
4018
+ process.stderr.write(chalk12.red(`Path must be a directory: ${rootDir}
3973
4019
  `));
3974
4020
  process.exit(EXIT_USAGE_ERROR);
3975
4021
  }
3976
4022
  }
3977
4023
  const dsn = opts.dsn || process.env.VIBGRATE_DSN;
3978
4024
  if (opts.push && !dsn) {
3979
- process.stderr.write(chalk11.red("--push requires --dsn or VIBGRATE_DSN environment variable\n"));
4025
+ process.stderr.write(chalk12.red("--push requires --dsn or VIBGRATE_DSN environment variable\n"));
3980
4026
  process.exit(EXIT_USAGE_ERROR);
3981
4027
  }
3982
4028
  if (dsn && !parseDsn2(dsn)) {
3983
- process.stderr.write(chalk11.red("Invalid DSN format.\n"));
3984
- process.stderr.write(chalk11.dim("Expected: vibgrate+https://<key_id>:<secret>@<host>/<workspace_id>\n"));
4029
+ process.stderr.write(chalk12.red("Invalid DSN format.\n"));
4030
+ process.stderr.write(chalk12.dim("Expected: vibgrate+https://<key_id>:<secret>@<host>/<workspace_id>\n"));
3985
4031
  process.exit(EXIT_USAGE_ERROR);
3986
4032
  }
3987
4033
  const concurrency = opts.concurrency ? parseInt(opts.concurrency, 10) : os4.cpus().length;
3988
4034
  if (isNaN(concurrency) || concurrency < 1) {
3989
- process.stderr.write(chalk11.red("--concurrency must be >= 1\n"));
4035
+ process.stderr.write(chalk12.red("--concurrency must be >= 1\n"));
3990
4036
  process.exit(EXIT_USAGE_ERROR);
3991
4037
  }
3992
4038
  const timeoutMins = parseInt(opts.timeoutMins, 10);
3993
4039
  if (isNaN(timeoutMins) || timeoutMins < 1) {
3994
- process.stderr.write(chalk11.red("--timeout-mins must be >= 1\n"));
4040
+ process.stderr.write(chalk12.red("--timeout-mins must be >= 1\n"));
3995
4041
  process.exit(EXIT_USAGE_ERROR);
3996
4042
  }
3997
4043
  const timeoutMs = timeoutMins * 60 * 1e3;
3998
4044
  if (opts.out) {
3999
4045
  const outDir = path12.dirname(path12.resolve(opts.out));
4000
4046
  if (!await pathExists(outDir)) {
4001
- process.stderr.write(chalk11.red(`Output directory does not exist: ${outDir}
4047
+ process.stderr.write(chalk12.red(`Output directory does not exist: ${outDir}
4002
4048
  `));
4003
4049
  process.exit(EXIT_USAGE_ERROR);
4004
4050
  }
4005
4051
  try {
4006
4052
  const outStat = await fs4.stat(path12.resolve(opts.out));
4007
4053
  if (outStat.isDirectory()) {
4008
- process.stderr.write(chalk11.red(`--out cannot be a directory: ${opts.out}
4054
+ process.stderr.write(chalk12.red(`--out cannot be a directory: ${opts.out}
4009
4055
  `));
4010
4056
  process.exit(EXIT_USAGE_ERROR);
4011
4057
  }
@@ -4016,14 +4062,14 @@ var extractCommand = new Command10("extract").description("Analyze source code a
4016
4062
  if (opts.feedback) {
4017
4063
  const feedbackPath = path12.resolve(opts.feedback);
4018
4064
  if (!await pathExists(feedbackPath)) {
4019
- process.stderr.write(chalk11.red(`Feedback file not found: ${feedbackPath}
4065
+ process.stderr.write(chalk12.red(`Feedback file not found: ${feedbackPath}
4020
4066
  `));
4021
4067
  process.exit(EXIT_USAGE_ERROR);
4022
4068
  }
4023
4069
  try {
4024
4070
  feedbackLines = await loadFeedback(feedbackPath);
4025
4071
  } catch (err) {
4026
- process.stderr.write(chalk11.red(`Invalid feedback file: ${err instanceof Error ? err.message : String(err)}
4072
+ process.stderr.write(chalk12.red(`Invalid feedback file: ${err instanceof Error ? err.message : String(err)}
4027
4073
  `));
4028
4074
  process.exit(EXIT_USAGE_ERROR);
4029
4075
  }
@@ -4033,9 +4079,9 @@ var extractCommand = new Command10("extract").description("Analyze source code a
4033
4079
  targetLanguages = opts.language.split(",").map((l) => normalizeLanguageToken(l)).filter(Boolean);
4034
4080
  for (const lang of targetLanguages) {
4035
4081
  if (!SUPPORTED_LANGUAGES.has(lang)) {
4036
- process.stderr.write(chalk11.red(`Unknown language: "${lang}"
4082
+ process.stderr.write(chalk12.red(`Unknown language: "${lang}"
4037
4083
  `));
4038
- process.stderr.write(chalk11.dim(`Supported: ${[...SUPPORTED_LANGUAGES].sort().join(", ")}
4084
+ process.stderr.write(chalk12.dim(`Supported: ${[...SUPPORTED_LANGUAGES].sort().join(", ")}
4039
4085
  `));
4040
4086
  process.exit(EXIT_USAGE_ERROR);
4041
4087
  }
@@ -4043,14 +4089,14 @@ var extractCommand = new Command10("extract").description("Analyze source code a
4043
4089
  } else {
4044
4090
  const detected = await detectLanguages(rootDir, opts.includeTests ?? false);
4045
4091
  if (detected.length === 0) {
4046
- process.stderr.write(chalk11.yellow("No supported source files detected.\n"));
4092
+ process.stderr.write(chalk12.yellow("No supported source files detected.\n"));
4047
4093
  process.exit(EXIT_SUCCESS);
4048
4094
  }
4049
4095
  targetLanguages = detected.map((d) => d.language);
4050
4096
  if (opts.verbose) {
4051
- process.stderr.write(chalk11.dim("Detected languages:\n"));
4097
+ process.stderr.write(chalk12.dim("Detected languages:\n"));
4052
4098
  for (const d of detected) {
4053
- process.stderr.write(chalk11.dim(` ${d.language}: ${d.fileCount} files
4099
+ process.stderr.write(chalk12.dim(` ${d.language}: ${d.fileCount} files
4054
4100
  `));
4055
4101
  }
4056
4102
  }
@@ -4058,20 +4104,20 @@ var extractCommand = new Command10("extract").description("Analyze source code a
4058
4104
  const runnableLanguages = targetLanguages.filter((l) => ALL_WORKER_LANGS.has(l));
4059
4105
  const unknownWorkerLangs = targetLanguages.filter((l) => !ALL_WORKER_LANGS.has(l));
4060
4106
  if (unknownWorkerLangs.length > 0 && opts.verbose) {
4061
- process.stderr.write(chalk11.dim(
4107
+ process.stderr.write(chalk12.dim(
4062
4108
  `No worker registered for: ${unknownWorkerLangs.join(", ")} \u2014 skipping.
4063
4109
  `
4064
4110
  ));
4065
4111
  }
4066
4112
  if (runnableLanguages.length === 0) {
4067
- process.stderr.write(chalk11.yellow("No languages with available HCS workers found.\n"));
4113
+ process.stderr.write(chalk12.yellow("No languages with available HCS workers found.\n"));
4068
4114
  process.exit(EXIT_SUCCESS);
4069
4115
  }
4070
4116
  const startTime = Date.now();
4071
4117
  const globalDeadline = startTime + timeoutMs;
4072
4118
  process.stderr.write(
4073
- chalk11.bold(`Extracting HCS facts from ${rootDir}
4074
- `) + chalk11.dim(`Languages: ${runnableLanguages.join(", ")} Concurrency: ${concurrency} Timeout: ${timeoutMins}m
4119
+ chalk12.bold(`Extracting HCS facts from ${rootDir}
4120
+ `) + chalk12.dim(`Languages: ${runnableLanguages.join(", ")} Concurrency: ${concurrency} Timeout: ${timeoutMins}m
4075
4121
  `)
4076
4122
  );
4077
4123
  const progress = new ProgressTracker(runnableLanguages);
@@ -4118,7 +4164,7 @@ var extractCommand = new Command10("extract").description("Analyze source code a
4118
4164
  hasSchemaFailure = true;
4119
4165
  allErrors.push(`[${language}] Schema validation: ${validation.error}`);
4120
4166
  if (opts.verbose) {
4121
- process.stderr.write(chalk11.red(`[${language}] Invalid fact: ${validation.error}
4167
+ process.stderr.write(chalk12.red(`[${language}] Invalid fact: ${validation.error}
4122
4168
  `));
4123
4169
  }
4124
4170
  }
@@ -4155,7 +4201,7 @@ var extractCommand = new Command10("extract").description("Analyze source code a
4155
4201
  allErrors.push("[behavioural] derived fact failed schema validation");
4156
4202
  }
4157
4203
  }
4158
- process.stderr.write(chalk11.dim(
4204
+ process.stderr.write(chalk12.dim(
4159
4205
  `Derived ${summary.assertions} behavioural assertion(s) \xB7 confidence ${summary.behaviouralConfidence} (${summary.assertedFacts}/${summary.surfaceFacts} surface facts)
4160
4206
  `
4161
4207
  ));
@@ -4190,7 +4236,7 @@ var extractCommand = new Command10("extract").description("Analyze source code a
4190
4236
  if (opts.out) {
4191
4237
  const outPath = path12.resolve(opts.out);
4192
4238
  await fs4.writeFile(outPath, ndjsonOutput, "utf-8");
4193
- process.stderr.write(chalk11.green(`\u2714 Wrote ${allFacts.length} facts to ${outPath}
4239
+ process.stderr.write(chalk12.green(`\u2714 Wrote ${allFacts.length} facts to ${outPath}
4194
4240
  `));
4195
4241
  } else {
4196
4242
  process.stdout.write(ndjsonOutput);
@@ -4202,38 +4248,38 @@ var extractCommand = new Command10("extract").description("Analyze source code a
4202
4248
  }
4203
4249
  }
4204
4250
  if (opts.verbose) {
4205
- process.stderr.write(chalk11.dim("\n\u2500\u2500 Summary \u2500\u2500\n"));
4206
- process.stderr.write(chalk11.dim(` Facts emitted : ${allFacts.length}
4251
+ process.stderr.write(chalk12.dim("\n\u2500\u2500 Summary \u2500\u2500\n"));
4252
+ process.stderr.write(chalk12.dim(` Facts emitted : ${allFacts.length}
4207
4253
  `));
4208
- process.stderr.write(chalk11.dim(` Languages : ${runnableLanguages.join(", ")}
4254
+ process.stderr.write(chalk12.dim(` Languages : ${runnableLanguages.join(", ")}
4209
4255
  `));
4210
- process.stderr.write(chalk11.dim(` Elapsed : ${elapsed}s
4256
+ process.stderr.write(chalk12.dim(` Elapsed : ${elapsed}s
4211
4257
  `));
4212
4258
  if (allErrors.length > 0) {
4213
- process.stderr.write(chalk11.dim(` Errors : ${allErrors.length}
4259
+ process.stderr.write(chalk12.dim(` Errors : ${allErrors.length}
4214
4260
  `));
4215
4261
  for (const err of allErrors.slice(0, 10)) {
4216
- process.stderr.write(chalk11.dim(` ${err}
4262
+ process.stderr.write(chalk12.dim(` ${err}
4217
4263
  `));
4218
4264
  }
4219
4265
  if (allErrors.length > 10) {
4220
- process.stderr.write(chalk11.dim(` ... and ${allErrors.length - 10} more
4266
+ process.stderr.write(chalk12.dim(` ... and ${allErrors.length - 10} more
4221
4267
  `));
4222
4268
  }
4223
4269
  }
4224
- process.stderr.write(chalk11.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n"));
4270
+ process.stderr.write(chalk12.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n"));
4225
4271
  }
4226
4272
  if (hasTimeout) {
4227
- process.stderr.write(chalk11.red(`Timeout exceeded (${timeoutMins} minutes)
4273
+ process.stderr.write(chalk12.red(`Timeout exceeded (${timeoutMins} minutes)
4228
4274
  `));
4229
4275
  process.exit(EXIT_TIMEOUT);
4230
4276
  }
4231
4277
  if (hasSchemaFailure) {
4232
- process.stderr.write(chalk11.red("Fact schema validation failures detected\n"));
4278
+ process.stderr.write(chalk12.red("Fact schema validation failures detected\n"));
4233
4279
  process.exit(EXIT_SCHEMA_FAILURE);
4234
4280
  }
4235
4281
  if (hasParseFailure) {
4236
- process.stderr.write(chalk11.red("Parsing failures detected\n"));
4282
+ process.stderr.write(chalk12.red("Parsing failures detected\n"));
4237
4283
  process.exit(EXIT_PARSE_FAILURE);
4238
4284
  }
4239
4285
  });
@@ -4243,7 +4289,7 @@ import * as path13 from "path";
4243
4289
  import * as fs5 from "fs/promises";
4244
4290
  import * as crypto4 from "crypto";
4245
4291
  import { Command as Command11 } from "commander";
4246
- import chalk12 from "chalk";
4292
+ import chalk13 from "chalk";
4247
4293
  var EXIT_INVALID_PATH = 2;
4248
4294
  var EXIT_USAGE_ERROR2 = 5;
4249
4295
  var VALID_FORMATS = /* @__PURE__ */ new Set(["ndjson", "json", "patch"]);
@@ -4476,7 +4522,7 @@ var diffCommand = new Command11("diff").description("Compare two directory trees
4476
4522
  const genDir = path13.resolve(generatedPath);
4477
4523
  for (const [label, dir] of [["original_path", origDir], ["generated_path", genDir]]) {
4478
4524
  if (!await pathExists(dir)) {
4479
- process.stderr.write(chalk12.red(`${label} does not exist: ${dir}
4525
+ process.stderr.write(chalk13.red(`${label} does not exist: ${dir}
4480
4526
  `));
4481
4527
  process.exit(EXIT_INVALID_PATH);
4482
4528
  }
@@ -4484,25 +4530,25 @@ var diffCommand = new Command11("diff").description("Compare two directory trees
4484
4530
  try {
4485
4531
  stat4 = await fs5.stat(dir);
4486
4532
  } catch {
4487
- process.stderr.write(chalk12.red(`Cannot read ${label}: ${dir}
4533
+ process.stderr.write(chalk13.red(`Cannot read ${label}: ${dir}
4488
4534
  `));
4489
4535
  process.exit(EXIT_INVALID_PATH);
4490
4536
  }
4491
4537
  if (!stat4.isDirectory()) {
4492
- process.stderr.write(chalk12.red(`${label} must be a directory: ${dir}
4538
+ process.stderr.write(chalk13.red(`${label} must be a directory: ${dir}
4493
4539
  `));
4494
4540
  process.exit(EXIT_INVALID_PATH);
4495
4541
  }
4496
4542
  }
4497
4543
  const format = opts.format.toLowerCase();
4498
4544
  if (!VALID_FORMATS.has(format)) {
4499
- process.stderr.write(chalk12.red(`Invalid format: "${opts.format}". Allowed: ndjson, json, patch
4545
+ process.stderr.write(chalk13.red(`Invalid format: "${opts.format}". Allowed: ndjson, json, patch
4500
4546
  `));
4501
4547
  process.exit(EXIT_USAGE_ERROR2);
4502
4548
  }
4503
4549
  const contextLines = parseInt(opts.context, 10);
4504
4550
  if (isNaN(contextLines) || contextLines < 0) {
4505
- process.stderr.write(chalk12.red("--context must be >= 0\n"));
4551
+ process.stderr.write(chalk13.red("--context must be >= 0\n"));
4506
4552
  process.exit(EXIT_USAGE_ERROR2);
4507
4553
  }
4508
4554
  const includeGlobs = opts.include ? opts.include.split(",").map((g) => g.trim()).filter(Boolean) : void 0;
@@ -4514,9 +4560,9 @@ var diffCommand = new Command11("diff").description("Compare two directory trees
4514
4560
  const origMap = new Map(origFiles.map((f) => [f.relPath, f]));
4515
4561
  const genMap = new Map(genFiles.map((f) => [f.relPath, f]));
4516
4562
  if (opts.verbose) {
4517
- process.stderr.write(chalk12.dim(`Original: ${origFiles.length} files
4563
+ process.stderr.write(chalk13.dim(`Original: ${origFiles.length} files
4518
4564
  `));
4519
- process.stderr.write(chalk12.dim(`Generated: ${genFiles.length} files
4565
+ process.stderr.write(chalk13.dim(`Generated: ${genFiles.length} files
4520
4566
  `));
4521
4567
  }
4522
4568
  const deltas = [];
@@ -4550,7 +4596,7 @@ var diffCommand = new Command11("diff").description("Compare two directory trees
4550
4596
  }
4551
4597
  deltas.push(delta);
4552
4598
  if (opts.verbose) {
4553
- process.stderr.write(chalk12.dim(` modified: ${relPath} (+${diffResult.insertions} -${diffResult.deletions})
4599
+ process.stderr.write(chalk13.dim(` modified: ${relPath} (+${diffResult.insertions} -${diffResult.deletions})
4554
4600
  `));
4555
4601
  }
4556
4602
  }
@@ -4614,7 +4660,7 @@ var diffCommand = new Command11("diff").description("Compare two directory trees
4614
4660
  }
4615
4661
  deltas.push(delta);
4616
4662
  if (opts.verbose) {
4617
- process.stderr.write(chalk12.dim(
4663
+ process.stderr.write(chalk13.dim(
4618
4664
  ` renamed: ${pair.origPath} \u2192 ${pair.genPath} (${(pair.similarity * 100).toFixed(0)}% similar)
4619
4665
  `
4620
4666
  ));
@@ -4639,7 +4685,7 @@ var diffCommand = new Command11("diff").description("Compare two directory trees
4639
4685
  }
4640
4686
  deltas.push(delta);
4641
4687
  if (opts.verbose) {
4642
- process.stderr.write(chalk12.dim(` removed: ${file.relPath}
4688
+ process.stderr.write(chalk13.dim(` removed: ${file.relPath}
4643
4689
  `));
4644
4690
  }
4645
4691
  }
@@ -4661,7 +4707,7 @@ var diffCommand = new Command11("diff").description("Compare two directory trees
4661
4707
  }
4662
4708
  deltas.push(delta);
4663
4709
  if (opts.verbose) {
4664
- process.stderr.write(chalk12.dim(` added: ${file.relPath}
4710
+ process.stderr.write(chalk13.dim(` added: ${file.relPath}
4665
4711
  `));
4666
4712
  }
4667
4713
  }
@@ -4689,9 +4735,9 @@ var diffCommand = new Command11("diff").description("Compare two directory trees
4689
4735
  const modified = deltas.filter((d) => d.changeKind === "modified").length;
4690
4736
  const renamed = deltas.filter((d) => d.changeKind === "renamed").length;
4691
4737
  process.stderr.write(
4692
- chalk12.green(`\u2714 `) + `${deltas.length} changes: ` + chalk12.green(`+${added} added`) + ", " + chalk12.red(`-${removed} removed`) + ", " + chalk12.yellow(`~${modified} modified`) + ", " + chalk12.blue(`\u2192${renamed} renamed`) + "\n"
4738
+ chalk13.green(`\u2714 `) + `${deltas.length} changes: ` + chalk13.green(`+${added} added`) + ", " + chalk13.red(`-${removed} removed`) + ", " + chalk13.yellow(`~${modified} modified`) + ", " + chalk13.blue(`\u2192${renamed} renamed`) + "\n"
4693
4739
  );
4694
- process.stderr.write(chalk12.dim(` Written to ${outPath}
4740
+ process.stderr.write(chalk13.dim(` Written to ${outPath}
4695
4741
  `));
4696
4742
  if (opts.verbose && opts.stats) {
4697
4743
  let totalIns = 0;
@@ -4702,193 +4748,193 @@ var diffCommand = new Command11("diff").description("Compare two directory trees
4702
4748
  totalDel += d.stats.deletions;
4703
4749
  }
4704
4750
  }
4705
- process.stderr.write(chalk12.dim(` Total: +${totalIns} insertions, -${totalDel} deletions
4751
+ process.stderr.write(chalk13.dim(` Total: +${totalIns} insertions, -${totalDel} deletions
4706
4752
  `));
4707
4753
  }
4708
4754
  });
4709
4755
 
4710
4756
  // src/commands/help.ts
4711
4757
  import { Command as Command12 } from "commander";
4712
- import chalk13 from "chalk";
4758
+ import chalk14 from "chalk";
4713
4759
  var HELP_URL = "https://vibgrate.com/help";
4714
4760
  function printFooter() {
4715
4761
  console.log("");
4716
- console.log(chalk13.dim(`See ${HELP_URL} for more guidance`));
4762
+ console.log(chalk14.dim(`See ${HELP_URL} for more guidance`));
4717
4763
  }
4718
4764
  var detailedHelp = {
4719
4765
  scan: () => {
4720
4766
  console.log("");
4721
- console.log(chalk13.bold.underline("vibgrate scan") + chalk13.dim(" \u2014 Scan a project for upgrade drift"));
4767
+ console.log(chalk14.bold.underline("vibgrate scan") + chalk14.dim(" \u2014 Scan a project for upgrade drift"));
4722
4768
  console.log("");
4723
- console.log(chalk13.bold("Usage:"));
4769
+ console.log(chalk14.bold("Usage:"));
4724
4770
  console.log(" vibgrate scan [path] [options]");
4725
4771
  console.log("");
4726
- console.log(chalk13.bold("Arguments:"));
4727
- console.log(` ${chalk13.cyan("[path]")} Path to scan (default: current directory)`);
4772
+ console.log(chalk14.bold("Arguments:"));
4773
+ console.log(` ${chalk14.cyan("[path]")} Path to scan (default: current directory)`);
4728
4774
  console.log("");
4729
- console.log(chalk13.bold("Output options:"));
4730
- console.log(` ${chalk13.cyan("--format <format>")} Output format: ${chalk13.white("text")} | json | sarif | md (default: text)`);
4731
- console.log(` ${chalk13.cyan("--out <file>")} Write output to a file instead of stdout`);
4775
+ console.log(chalk14.bold("Output options:"));
4776
+ console.log(` ${chalk14.cyan("--format <format>")} Output format: ${chalk14.white("text")} | json | sarif | md (default: text)`);
4777
+ console.log(` ${chalk14.cyan("--out <file>")} Write output to a file instead of stdout`);
4732
4778
  console.log("");
4733
- console.log(chalk13.bold("Baseline & gating:"));
4734
- console.log(` ${chalk13.cyan("--baseline <file>")} Compare results against a saved baseline`);
4735
- console.log(` ${chalk13.cyan("--drift-budget <score>")} Fail if drift score exceeds this value (0\u2013100)`);
4736
- console.log(` ${chalk13.cyan("--drift-worsening <percent>")} Fail if drift worsens by more than % since baseline`);
4737
- console.log(` ${chalk13.cyan("--fail-on <level>")} Fail exit code on warn or error findings`);
4779
+ console.log(chalk14.bold("Baseline & gating:"));
4780
+ console.log(` ${chalk14.cyan("--baseline <file>")} Compare results against a saved baseline`);
4781
+ console.log(` ${chalk14.cyan("--drift-budget <score>")} Fail if drift score exceeds this value (0\u2013100)`);
4782
+ console.log(` ${chalk14.cyan("--drift-worsening <percent>")} Fail if drift worsens by more than % since baseline`);
4783
+ console.log(` ${chalk14.cyan("--fail-on <level>")} Fail exit code on warn or error findings`);
4738
4784
  console.log("");
4739
- console.log(chalk13.bold("Performance:"));
4740
- console.log(` ${chalk13.cyan("--concurrency <n>")} Max concurrent registry calls (default: 8)`);
4741
- console.log(` ${chalk13.cyan("--changed-only")} Only scan files changed since last git commit`);
4785
+ console.log(chalk14.bold("Performance:"));
4786
+ console.log(` ${chalk14.cyan("--concurrency <n>")} Max concurrent registry calls (default: 8)`);
4787
+ console.log(` ${chalk14.cyan("--changed-only")} Only scan files changed since last git commit`);
4742
4788
  console.log("");
4743
- console.log(chalk13.bold("Privacy & offline:"));
4744
- console.log(` ${chalk13.cyan("--offline")} Run without any network calls; skip result upload`);
4745
- console.log(` ${chalk13.cyan("--package-manifest <file>")} Use a local package-version manifest (JSON or ZIP) for offline mode`);
4746
- console.log(` ${chalk13.cyan("--no-local-artifacts")} Do not write .vibgrate JSON artifacts to disk`);
4747
- console.log(` ${chalk13.cyan("--max-privacy")} Strongest privacy mode: minimal scanners + no local artifacts`);
4789
+ console.log(chalk14.bold("Privacy & offline:"));
4790
+ console.log(` ${chalk14.cyan("--offline")} Run without any network calls; skip result upload`);
4791
+ console.log(` ${chalk14.cyan("--package-manifest <file>")} Use a local package-version manifest (JSON or ZIP) for offline mode`);
4792
+ console.log(` ${chalk14.cyan("--no-local-artifacts")} Do not write .vibgrate JSON artifacts to disk`);
4793
+ console.log(` ${chalk14.cyan("--max-privacy")} Strongest privacy mode: minimal scanners + no local artifacts`);
4748
4794
  console.log("");
4749
- console.log(chalk13.bold("Tooling:"));
4750
- console.log(` ${chalk13.cyan("--install-tools")} Auto-install missing security scanners via Homebrew`);
4751
- console.log(` ${chalk13.cyan("--ui-purpose")} Enable UI purpose evidence extraction (slower)`);
4795
+ console.log(chalk14.bold("Tooling:"));
4796
+ console.log(` ${chalk14.cyan("--install-tools")} Auto-install missing security scanners via Homebrew`);
4797
+ console.log(` ${chalk14.cyan("--ui-purpose")} Enable UI purpose evidence extraction (slower)`);
4752
4798
  console.log("");
4753
- console.log(chalk13.bold("Uploading results:"));
4754
- console.log(` ${chalk13.cyan("--push")} Auto-push results to Vibgrate API after scan`);
4755
- console.log(` ${chalk13.cyan("--dsn <dsn>")} DSN token for push (or set VIBGRATE_DSN env var)`);
4756
- console.log(` ${chalk13.cyan("--region <region>")} Data residency region: us | eu (default: us)`);
4757
- console.log(` ${chalk13.cyan("--strict")} Fail if the upload to Vibgrate API fails`);
4799
+ console.log(chalk14.bold("Uploading results:"));
4800
+ console.log(` ${chalk14.cyan("--push")} Auto-push results to Vibgrate API after scan`);
4801
+ console.log(` ${chalk14.cyan("--dsn <dsn>")} DSN token for push (or set VIBGRATE_DSN env var)`);
4802
+ console.log(` ${chalk14.cyan("--region <region>")} Data residency region: us | eu (default: us)`);
4803
+ console.log(` ${chalk14.cyan("--strict")} Fail if the upload to Vibgrate API fails`);
4758
4804
  console.log("");
4759
- console.log(chalk13.bold("Examples:"));
4760
- console.log(` ${chalk13.dim("# Scan the current directory and display a text report")}`);
4805
+ console.log(chalk14.bold("Examples:"));
4806
+ console.log(` ${chalk14.dim("# Scan the current directory and display a text report")}`);
4761
4807
  console.log(" vibgrate scan .");
4762
4808
  console.log("");
4763
- console.log(` ${chalk13.dim("# Scan, fail if drift score > 40, and write SARIF for GitHub Actions")}`);
4809
+ console.log(` ${chalk14.dim("# Scan, fail if drift score > 40, and write SARIF for GitHub Actions")}`);
4764
4810
  console.log(" vibgrate scan . --drift-budget 40 --format sarif --out drift.sarif");
4765
4811
  console.log("");
4766
- console.log(` ${chalk13.dim("# Scan and automatically upload results via a DSN")}`);
4812
+ console.log(` ${chalk14.dim("# Scan and automatically upload results via a DSN")}`);
4767
4813
  console.log(" vibgrate scan . --push --dsn $VIBGRATE_DSN");
4768
4814
  console.log("");
4769
- console.log(` ${chalk13.dim("# Offline scan using a pre-downloaded package manifest")}`);
4815
+ console.log(` ${chalk14.dim("# Offline scan using a pre-downloaded package manifest")}`);
4770
4816
  console.log(" vibgrate scan . --offline --package-manifest ./manifest.zip");
4771
4817
  },
4772
4818
  init: () => {
4773
4819
  console.log("");
4774
- console.log(chalk13.bold.underline("vibgrate init") + chalk13.dim(" \u2014 Initialise vibgrate in a project directory"));
4820
+ console.log(chalk14.bold.underline("vibgrate init") + chalk14.dim(" \u2014 Initialise vibgrate in a project directory"));
4775
4821
  console.log("");
4776
- console.log(chalk13.bold("Usage:"));
4822
+ console.log(chalk14.bold("Usage:"));
4777
4823
  console.log(" vibgrate init [path] [options]");
4778
4824
  console.log("");
4779
- console.log(chalk13.bold("Arguments:"));
4780
- console.log(` ${chalk13.cyan("[path]")} Directory to initialise (default: current directory)`);
4825
+ console.log(chalk14.bold("Arguments:"));
4826
+ console.log(` ${chalk14.cyan("[path]")} Directory to initialise (default: current directory)`);
4781
4827
  console.log("");
4782
- console.log(chalk13.bold("Options:"));
4783
- console.log(` ${chalk13.cyan("--baseline")} Create an initial drift baseline after init`);
4784
- console.log(` ${chalk13.cyan("--yes")} Skip all confirmation prompts`);
4828
+ console.log(chalk14.bold("Options:"));
4829
+ console.log(` ${chalk14.cyan("--baseline")} Create an initial drift baseline after init`);
4830
+ console.log(` ${chalk14.cyan("--yes")} Skip all confirmation prompts`);
4785
4831
  console.log("");
4786
- console.log(chalk13.bold("What it does:"));
4832
+ console.log(chalk14.bold("What it does:"));
4787
4833
  console.log(" \u2022 Creates a .vibgrate/ directory");
4788
4834
  console.log(" \u2022 Writes a vibgrate.config.ts starter config");
4789
4835
  console.log(" \u2022 Optionally runs an initial baseline scan (--baseline)");
4790
4836
  console.log("");
4791
- console.log(chalk13.bold("Examples:"));
4837
+ console.log(chalk14.bold("Examples:"));
4792
4838
  console.log(" vibgrate init");
4793
4839
  console.log(" vibgrate init ./my-project --baseline");
4794
4840
  },
4795
4841
  baseline: () => {
4796
4842
  console.log("");
4797
- console.log(chalk13.bold.underline("vibgrate baseline") + chalk13.dim(" \u2014 Save a drift baseline snapshot"));
4843
+ console.log(chalk14.bold.underline("vibgrate baseline") + chalk14.dim(" \u2014 Save a drift baseline snapshot"));
4798
4844
  console.log("");
4799
- console.log(chalk13.bold("Usage:"));
4845
+ console.log(chalk14.bold("Usage:"));
4800
4846
  console.log(" vibgrate baseline [path]");
4801
4847
  console.log("");
4802
- console.log(chalk13.bold("Arguments:"));
4803
- console.log(` ${chalk13.cyan("[path]")} Path to baseline (default: current directory)`);
4848
+ console.log(chalk14.bold("Arguments:"));
4849
+ console.log(` ${chalk14.cyan("[path]")} Path to baseline (default: current directory)`);
4804
4850
  console.log("");
4805
- console.log(chalk13.bold("What it does:"));
4851
+ console.log(chalk14.bold("What it does:"));
4806
4852
  console.log(" Runs a full scan and saves the result as .vibgrate/baseline.json.");
4807
4853
  console.log(" Future scans can compare against this file using --baseline.");
4808
4854
  console.log("");
4809
- console.log(chalk13.bold("Examples:"));
4855
+ console.log(chalk14.bold("Examples:"));
4810
4856
  console.log(" vibgrate baseline .");
4811
4857
  console.log(" vibgrate scan . --baseline .vibgrate/baseline.json --drift-worsening 10");
4812
4858
  },
4813
4859
  report: () => {
4814
4860
  console.log("");
4815
- console.log(chalk13.bold.underline("vibgrate report") + chalk13.dim(" \u2014 Generate a report from a saved scan artifact"));
4861
+ console.log(chalk14.bold.underline("vibgrate report") + chalk14.dim(" \u2014 Generate a report from a saved scan artifact"));
4816
4862
  console.log("");
4817
- console.log(chalk13.bold("Usage:"));
4863
+ console.log(chalk14.bold("Usage:"));
4818
4864
  console.log(" vibgrate report [options]");
4819
4865
  console.log("");
4820
- console.log(chalk13.bold("Options:"));
4821
- console.log(` ${chalk13.cyan("--in <file>")} Input artifact file (default: .vibgrate/scan_result.json)`);
4822
- console.log(` ${chalk13.cyan("--format <format>")} Output format: ${chalk13.white("text")} | md | json (default: text)`);
4866
+ console.log(chalk14.bold("Options:"));
4867
+ console.log(` ${chalk14.cyan("--in <file>")} Input artifact file (default: .vibgrate/scan_result.json)`);
4868
+ console.log(` ${chalk14.cyan("--format <format>")} Output format: ${chalk14.white("text")} | md | json (default: text)`);
4823
4869
  console.log("");
4824
- console.log(chalk13.bold("Examples:"));
4870
+ console.log(chalk14.bold("Examples:"));
4825
4871
  console.log(" vibgrate report");
4826
4872
  console.log(" vibgrate report --format md > DRIFT-REPORT.md");
4827
4873
  console.log(" vibgrate report --in ./ci/scan_result.json --format json");
4828
4874
  },
4829
4875
  sbom: () => {
4830
4876
  console.log("");
4831
- console.log(chalk13.bold.underline("vibgrate sbom") + chalk13.dim(" \u2014 Export a Software Bill of Materials from a scan artifact"));
4877
+ console.log(chalk14.bold.underline("vibgrate sbom") + chalk14.dim(" \u2014 Export a Software Bill of Materials from a scan artifact"));
4832
4878
  console.log("");
4833
- console.log(chalk13.bold("Usage:"));
4879
+ console.log(chalk14.bold("Usage:"));
4834
4880
  console.log(" vibgrate sbom [options]");
4835
4881
  console.log("");
4836
- console.log(chalk13.bold("Options:"));
4837
- console.log(` ${chalk13.cyan("--in <file>")} Input artifact (default: .vibgrate/scan_result.json)`);
4838
- console.log(` ${chalk13.cyan("--format <format>")} SBOM format: ${chalk13.white("cyclonedx")} | spdx (default: cyclonedx)`);
4839
- console.log(` ${chalk13.cyan("--out <file>")} Write SBOM to file instead of stdout`);
4882
+ console.log(chalk14.bold("Options:"));
4883
+ console.log(` ${chalk14.cyan("--in <file>")} Input artifact (default: .vibgrate/scan_result.json)`);
4884
+ console.log(` ${chalk14.cyan("--format <format>")} SBOM format: ${chalk14.white("cyclonedx")} | spdx (default: cyclonedx)`);
4885
+ console.log(` ${chalk14.cyan("--out <file>")} Write SBOM to file instead of stdout`);
4840
4886
  console.log("");
4841
- console.log(chalk13.bold("Examples:"));
4887
+ console.log(chalk14.bold("Examples:"));
4842
4888
  console.log(" vibgrate sbom --format cyclonedx --out sbom.json");
4843
4889
  console.log(" vibgrate sbom --format spdx --out sbom.spdx.json");
4844
4890
  },
4845
4891
  push: () => {
4846
4892
  console.log("");
4847
- console.log(chalk13.bold.underline("vibgrate push") + chalk13.dim(" \u2014 Upload a scan artifact to the Vibgrate API"));
4893
+ console.log(chalk14.bold.underline("vibgrate push") + chalk14.dim(" \u2014 Upload a scan artifact to the Vibgrate API"));
4848
4894
  console.log("");
4849
- console.log(chalk13.bold("Usage:"));
4895
+ console.log(chalk14.bold("Usage:"));
4850
4896
  console.log(" vibgrate push [options]");
4851
4897
  console.log("");
4852
- console.log(chalk13.bold("Options:"));
4853
- console.log(` ${chalk13.cyan("--dsn <dsn>")} DSN token (or set VIBGRATE_DSN env var)`);
4854
- console.log(` ${chalk13.cyan("--file <file>")} Artifact to upload (default: .vibgrate/scan_result.json)`);
4855
- console.log(` ${chalk13.cyan("--region <region>")} Override data residency region: us | eu`);
4856
- console.log(` ${chalk13.cyan("--strict")} Fail with non-zero exit code on upload error`);
4898
+ console.log(chalk14.bold("Options:"));
4899
+ console.log(` ${chalk14.cyan("--dsn <dsn>")} DSN token (or set VIBGRATE_DSN env var)`);
4900
+ console.log(` ${chalk14.cyan("--file <file>")} Artifact to upload (default: .vibgrate/scan_result.json)`);
4901
+ console.log(` ${chalk14.cyan("--region <region>")} Override data residency region: us | eu`);
4902
+ console.log(` ${chalk14.cyan("--strict")} Fail with non-zero exit code on upload error`);
4857
4903
  console.log("");
4858
- console.log(chalk13.bold("Examples:"));
4904
+ console.log(chalk14.bold("Examples:"));
4859
4905
  console.log(" vibgrate push --dsn $VIBGRATE_DSN");
4860
4906
  console.log(" vibgrate push --file ./ci/scan_result.json --strict");
4861
4907
  },
4862
4908
  dsn: () => {
4863
4909
  console.log("");
4864
- console.log(chalk13.bold.underline("vibgrate dsn") + chalk13.dim(" \u2014 Manage DSN tokens for API authentication"));
4910
+ console.log(chalk14.bold.underline("vibgrate dsn") + chalk14.dim(" \u2014 Manage DSN tokens for API authentication"));
4865
4911
  console.log("");
4866
- console.log(chalk13.bold("Subcommands:"));
4867
- console.log(` ${chalk13.cyan("vibgrate dsn create")} Generate a new DSN token`);
4912
+ console.log(chalk14.bold("Subcommands:"));
4913
+ console.log(` ${chalk14.cyan("vibgrate dsn create")} Generate a new DSN token`);
4868
4914
  console.log("");
4869
- console.log(chalk13.bold("dsn create options:"));
4870
- console.log(` ${chalk13.cyan("--workspace <id>")} Workspace ID or "new" to auto-generate ${chalk13.red("(required)")}`);
4871
- console.log(` ${chalk13.cyan("--region <region>")} Data residency region: us | eu (default: us)`);
4872
- console.log(` ${chalk13.cyan("--ingest <url>")} Override ingest API URL`);
4873
- console.log(` ${chalk13.cyan("--write <path>")} Write the DSN to a file (add to .gitignore!)`);
4915
+ console.log(chalk14.bold("dsn create options:"));
4916
+ console.log(` ${chalk14.cyan("--workspace <id>")} Workspace ID or "new" to auto-generate ${chalk14.red("(required)")}`);
4917
+ console.log(` ${chalk14.cyan("--region <region>")} Data residency region: us | eu (default: us)`);
4918
+ console.log(` ${chalk14.cyan("--ingest <url>")} Override ingest API URL`);
4919
+ console.log(` ${chalk14.cyan("--write <path>")} Write the DSN to a file (add to .gitignore!)`);
4874
4920
  console.log("");
4875
- console.log(chalk13.bold("Examples:"));
4921
+ console.log(chalk14.bold("Examples:"));
4876
4922
  console.log(" vibgrate dsn create --workspace new");
4877
4923
  console.log(" vibgrate dsn create --workspace abc123");
4878
4924
  console.log(" vibgrate dsn create --workspace new --region eu --write .vibgrate/.dsn");
4879
4925
  },
4880
4926
  update: () => {
4881
4927
  console.log("");
4882
- console.log(chalk13.bold.underline("vibgrate update") + chalk13.dim(" \u2014 Update the vibgrate CLI to the latest version"));
4928
+ console.log(chalk14.bold.underline("vibgrate update") + chalk14.dim(" \u2014 Update the vibgrate CLI to the latest version"));
4883
4929
  console.log("");
4884
- console.log(chalk13.bold("Usage:"));
4930
+ console.log(chalk14.bold("Usage:"));
4885
4931
  console.log(" vibgrate update [options]");
4886
4932
  console.log("");
4887
- console.log(chalk13.bold("Options:"));
4888
- console.log(` ${chalk13.cyan("--check")} Check for a newer version without installing`);
4889
- console.log(` ${chalk13.cyan("--pm <manager>")} Force a package manager: npm | pnpm | yarn | bun`);
4933
+ console.log(chalk14.bold("Options:"));
4934
+ console.log(` ${chalk14.cyan("--check")} Check for a newer version without installing`);
4935
+ console.log(` ${chalk14.cyan("--pm <manager>")} Force a package manager: npm | pnpm | yarn | bun`);
4890
4936
  console.log("");
4891
- console.log(chalk13.bold("Examples:"));
4937
+ console.log(chalk14.bold("Examples:"));
4892
4938
  console.log(" vibgrate update");
4893
4939
  console.log(" vibgrate update --check");
4894
4940
  console.log(" vibgrate update --pm pnpm");
@@ -4896,33 +4942,33 @@ var detailedHelp = {
4896
4942
  };
4897
4943
  function printSummaryHelp() {
4898
4944
  console.log("");
4899
- console.log(chalk13.bold("vibgrate") + chalk13.dim(" \u2014 Continuous Drift Intelligence"));
4945
+ console.log(chalk14.bold("vibgrate") + chalk14.dim(" \u2014 Continuous Drift Intelligence"));
4900
4946
  console.log("");
4901
- console.log(chalk13.bold("Usage:"));
4947
+ console.log(chalk14.bold("Usage:"));
4902
4948
  console.log(" vibgrate <command> [options]");
4903
4949
  console.log(" vibgrate help [command] Show detailed help for a command");
4904
4950
  console.log("");
4905
- console.log(chalk13.bold("Getting started:"));
4906
- console.log(` ${chalk13.cyan("init")} Initialise vibgrate in a project (creates config & .vibgrate/ dir)`);
4907
- console.log(` ${chalk13.cyan("login")} Sign the CLI into your workspace via the browser`);
4908
- console.log(` ${chalk13.cyan("logout")} Clear stored login credentials`);
4951
+ console.log(chalk14.bold("Getting started:"));
4952
+ console.log(` ${chalk14.cyan("init")} Initialise vibgrate in a project (creates config & .vibgrate/ dir)`);
4953
+ console.log(` ${chalk14.cyan("login")} Sign the CLI into your workspace via the browser`);
4954
+ console.log(` ${chalk14.cyan("logout")} Clear stored login credentials`);
4909
4955
  console.log("");
4910
- console.log(chalk13.bold("Core scanning:"));
4911
- console.log(` ${chalk13.cyan("scan")} Scan a project for upgrade drift and generate a report`);
4912
- console.log(` ${chalk13.cyan("baseline")} Save a baseline snapshot to compare future scans against`);
4956
+ console.log(chalk14.bold("Core scanning:"));
4957
+ console.log(` ${chalk14.cyan("scan")} Scan a project for upgrade drift and generate a report`);
4958
+ console.log(` ${chalk14.cyan("baseline")} Save a baseline snapshot to compare future scans against`);
4913
4959
  console.log("");
4914
- console.log(chalk13.bold("Reporting & export:"));
4915
- console.log(` ${chalk13.cyan("report")} Re-generate a report from a previously saved scan artifact`);
4916
- console.log(` ${chalk13.cyan("sbom")} Export a Software Bill of Materials (CycloneDX or SPDX)`);
4960
+ console.log(chalk14.bold("Reporting & export:"));
4961
+ console.log(` ${chalk14.cyan("report")} Re-generate a report from a previously saved scan artifact`);
4962
+ console.log(` ${chalk14.cyan("sbom")} Export a Software Bill of Materials (CycloneDX or SPDX)`);
4917
4963
  console.log("");
4918
- console.log(chalk13.bold("CI/CD integration:"));
4919
- console.log(` ${chalk13.cyan("push")} Upload a scan artifact to the Vibgrate API`);
4920
- console.log(` ${chalk13.cyan("dsn")} Create and manage DSN tokens for API authentication`);
4964
+ console.log(chalk14.bold("CI/CD integration:"));
4965
+ console.log(` ${chalk14.cyan("push")} Upload a scan artifact to the Vibgrate API`);
4966
+ console.log(` ${chalk14.cyan("dsn")} Create and manage DSN tokens for API authentication`);
4921
4967
  console.log("");
4922
- console.log(chalk13.bold("Maintenance:"));
4923
- console.log(` ${chalk13.cyan("update")} Update the vibgrate CLI to the latest version`);
4968
+ console.log(chalk14.bold("Maintenance:"));
4969
+ console.log(` ${chalk14.cyan("update")} Update the vibgrate CLI to the latest version`);
4924
4970
  console.log("");
4925
- console.log(chalk13.dim("Run") + ` ${chalk13.cyan("vibgrate help <command>")} ` + chalk13.dim("for detailed options, e.g.") + ` ${chalk13.cyan("vibgrate help scan")}`);
4971
+ console.log(chalk14.dim("Run") + ` ${chalk14.cyan("vibgrate help <command>")} ` + chalk14.dim("for detailed options, e.g.") + ` ${chalk14.cyan("vibgrate help scan")}`);
4926
4972
  }
4927
4973
  var helpCommand = new Command12("help").description("Show help for vibgrate commands").argument("[command]", "Command to show detailed help for").helpOption(false).action((cmd) => {
4928
4974
  const name = cmd?.toLowerCase().trim();
@@ -4930,8 +4976,8 @@ var helpCommand = new Command12("help").description("Show help for vibgrate comm
4930
4976
  detailedHelp[name]();
4931
4977
  } else if (name) {
4932
4978
  console.log("");
4933
- console.log(chalk13.red(`Unknown command: ${name}`));
4934
- console.log(chalk13.dim(`Available commands: ${Object.keys(detailedHelp).join(", ")}`));
4979
+ console.log(chalk14.red(`Unknown command: ${name}`));
4980
+ console.log(chalk14.dim(`Available commands: ${Object.keys(detailedHelp).join(", ")}`));
4935
4981
  printSummaryHelp();
4936
4982
  } else {
4937
4983
  printSummaryHelp();
@@ -4959,8 +5005,8 @@ function notifyIfUpdateAvailable() {
4959
5005
  void checkForUpdate().then((update) => {
4960
5006
  if (!update?.updateAvailable) return;
4961
5007
  console.error("");
4962
- console.error(chalk14.yellow(` Update available: ${update.current} \u2192 ${update.latest}`));
4963
- console.error(chalk14.dim(' Run "vibgrate update" to install the latest version.'));
5008
+ console.error(chalk15.yellow(` Update available: ${update.current} \u2192 ${update.latest}`));
5009
+ console.error(chalk15.dim(' Run "vibgrate update" to install the latest version.'));
4964
5010
  console.error("");
4965
5011
  }).catch(() => {
4966
5012
  });