@ipation/specbridge 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/index.ts
4
- import { Command as Command18 } from "commander";
5
- import chalk16 from "chalk";
4
+ import { Command as Command19 } from "commander";
5
+ import chalk19 from "chalk";
6
6
  import { readFileSync as readFileSync2 } from "fs";
7
7
  import { fileURLToPath as fileURLToPath4 } from "url";
8
8
  import { dirname as dirname5, join as join12 } from "path";
@@ -1345,11 +1345,12 @@ Detected ${patterns.length} pattern(s):
1345
1345
 
1346
1346
  // src/cli/commands/verify.ts
1347
1347
  import { Command as Command3 } from "commander";
1348
- import chalk3 from "chalk";
1348
+ import chalk5 from "chalk";
1349
1349
  import ora3 from "ora";
1350
1350
 
1351
1351
  // src/verification/engine.ts
1352
1352
  import { Project as Project2 } from "ts-morph";
1353
+ import chalk3 from "chalk";
1353
1354
 
1354
1355
  // src/registry/loader.ts
1355
1356
  import { join as join4 } from "path";
@@ -1382,6 +1383,10 @@ var ConstraintExceptionSchema = z2.object({
1382
1383
  approvedBy: z2.string().optional(),
1383
1384
  expiresAt: z2.string().datetime().optional()
1384
1385
  });
1386
+ var ConstraintCheckSchema = z2.object({
1387
+ verifier: z2.string().min(1),
1388
+ params: z2.record(z2.unknown()).optional()
1389
+ });
1385
1390
  var ConstraintSchema = z2.object({
1386
1391
  id: z2.string().min(1).regex(/^[a-z0-9-]+$/, "Constraint ID must be lowercase alphanumeric with hyphens"),
1387
1392
  type: ConstraintTypeSchema,
@@ -1389,6 +1394,7 @@ var ConstraintSchema = z2.object({
1389
1394
  severity: SeveritySchema2,
1390
1395
  scope: z2.string().min(1),
1391
1396
  verifier: z2.string().optional(),
1397
+ check: ConstraintCheckSchema.optional(),
1392
1398
  autofix: z2.boolean().optional(),
1393
1399
  exceptions: z2.array(ConstraintExceptionSchema).optional()
1394
1400
  });
@@ -2671,7 +2677,13 @@ function getVerifier(id) {
2671
2677
  const factory = builtinVerifiers[id];
2672
2678
  return factory ? factory() : null;
2673
2679
  }
2674
- function selectVerifierForConstraint(rule, specifiedVerifier) {
2680
+ function getVerifierIds() {
2681
+ return Object.keys(builtinVerifiers);
2682
+ }
2683
+ function selectVerifierForConstraint(rule, specifiedVerifier, check) {
2684
+ if (check?.verifier) {
2685
+ return getVerifier(check.verifier);
2686
+ }
2675
2687
  if (specifiedVerifier) {
2676
2688
  return getVerifier(specifiedVerifier);
2677
2689
  }
@@ -2802,10 +2814,14 @@ var VerificationEngine = class {
2802
2814
  passed: 0,
2803
2815
  failed: 0,
2804
2816
  skipped: 0,
2805
- duration: Date.now() - startTime
2817
+ duration: Date.now() - startTime,
2818
+ warnings: [],
2819
+ errors: []
2806
2820
  };
2807
2821
  }
2808
2822
  const allViolations = [];
2823
+ const allWarnings = [];
2824
+ const allErrors = [];
2809
2825
  let checked = 0;
2810
2826
  let passed = 0;
2811
2827
  let failed = 0;
@@ -2820,8 +2836,11 @@ var VerificationEngine = class {
2820
2836
  decisions,
2821
2837
  severityFilter,
2822
2838
  cwd,
2823
- (violations) => {
2839
+ options.reporter,
2840
+ (violations, warnings, errors) => {
2824
2841
  allViolations.push(...violations);
2842
+ allWarnings.push(...warnings);
2843
+ allErrors.push(...errors);
2825
2844
  checked++;
2826
2845
  if (violations.length > 0) {
2827
2846
  failed++;
@@ -2841,7 +2860,9 @@ var VerificationEngine = class {
2841
2860
  passed,
2842
2861
  failed,
2843
2862
  skipped: filesToVerify.length - checked,
2844
- duration: timeout
2863
+ duration: timeout,
2864
+ warnings: allWarnings,
2865
+ errors: allErrors
2845
2866
  };
2846
2867
  }
2847
2868
  } finally {
@@ -2866,23 +2887,64 @@ var VerificationEngine = class {
2866
2887
  passed,
2867
2888
  failed,
2868
2889
  skipped,
2869
- duration: Date.now() - startTime
2890
+ duration: Date.now() - startTime,
2891
+ warnings: allWarnings,
2892
+ errors: allErrors
2870
2893
  };
2871
2894
  }
2872
2895
  /**
2873
2896
  * Verify a single file
2874
2897
  */
2875
- async verifyFile(filePath, decisions, severityFilter, cwd = process.cwd()) {
2898
+ async verifyFile(filePath, decisions, severityFilter, cwd = process.cwd(), reporter) {
2876
2899
  const violations = [];
2900
+ const warnings = [];
2901
+ const errors = [];
2877
2902
  const sourceFile = await this.astCache.get(filePath, this.project);
2878
- if (!sourceFile) return violations;
2903
+ if (!sourceFile) return { violations, warnings, errors };
2879
2904
  for (const decision of decisions) {
2880
2905
  for (const constraint of decision.constraints) {
2881
2906
  if (!shouldApplyConstraintToFile({ filePath, constraint, cwd, severityFilter })) {
2907
+ if (reporter) {
2908
+ reporter.add({
2909
+ file: filePath,
2910
+ decision,
2911
+ constraint,
2912
+ applied: false,
2913
+ reason: "File does not match scope pattern or severity filter"
2914
+ });
2915
+ }
2882
2916
  continue;
2883
2917
  }
2884
- const verifier = selectVerifierForConstraint(constraint.rule, constraint.verifier);
2918
+ const verifier = selectVerifierForConstraint(
2919
+ constraint.rule,
2920
+ constraint.verifier,
2921
+ constraint.check
2922
+ );
2885
2923
  if (!verifier) {
2924
+ const requestedVerifier = constraint.check?.verifier || constraint.verifier || "auto-detected";
2925
+ console.warn(
2926
+ chalk3.yellow(
2927
+ `Warning: No verifier found for ${decision.metadata.id}/${constraint.id}
2928
+ Requested: ${requestedVerifier}
2929
+ Available: ${getVerifierIds().join(", ")}`
2930
+ )
2931
+ );
2932
+ warnings.push({
2933
+ type: "missing_verifier",
2934
+ message: `No verifier found for constraint (requested: ${requestedVerifier})`,
2935
+ decisionId: decision.metadata.id,
2936
+ constraintId: constraint.id,
2937
+ file: filePath
2938
+ });
2939
+ if (reporter) {
2940
+ reporter.add({
2941
+ file: filePath,
2942
+ decision,
2943
+ constraint,
2944
+ applied: false,
2945
+ reason: `No verifier found (requested: ${requestedVerifier})`
2946
+ });
2947
+ }
2886
2948
  continue;
2887
2949
  }
2888
2950
  const ctx = {
@@ -2891,27 +2953,78 @@ var VerificationEngine = class {
2891
2953
  constraint,
2892
2954
  decisionId: decision.metadata.id
2893
2955
  };
2956
+ const verificationStart = Date.now();
2894
2957
  try {
2895
2958
  const constraintViolations = await verifier.verify(ctx);
2896
2959
  violations.push(...constraintViolations);
2897
- } catch {
2960
+ if (reporter) {
2961
+ reporter.add({
2962
+ file: filePath,
2963
+ decision,
2964
+ constraint,
2965
+ applied: true,
2966
+ reason: "Constraint matches file scope",
2967
+ selectedVerifier: verifier.id,
2968
+ verifierOutput: {
2969
+ violations: constraintViolations.length,
2970
+ duration: Date.now() - verificationStart
2971
+ }
2972
+ });
2973
+ }
2974
+ } catch (error) {
2975
+ const errorMessage = error instanceof Error ? error.message : String(error);
2976
+ const errorStack = error instanceof Error ? error.stack : void 0;
2977
+ console.error(
2978
+ chalk3.red(
2979
+ `Error: Verifier '${verifier.id}' failed
2980
+ File: ${filePath}
2981
+ Decision: ${decision.metadata.id}/${constraint.id}
2982
+ Error: ${errorMessage}`
2983
+ )
2984
+ );
2985
+ if (errorStack) {
2986
+ console.error(chalk3.dim(errorStack));
2987
+ }
2988
+ errors.push({
2989
+ type: "verifier_exception",
2990
+ message: `Verifier '${verifier.id}' failed: ${errorMessage}`,
2991
+ decisionId: decision.metadata.id,
2992
+ constraintId: constraint.id,
2993
+ file: filePath,
2994
+ stack: errorStack
2995
+ });
2996
+ if (reporter) {
2997
+ reporter.add({
2998
+ file: filePath,
2999
+ decision,
3000
+ constraint,
3001
+ applied: true,
3002
+ reason: "Constraint matches file scope",
3003
+ selectedVerifier: verifier.id,
3004
+ verifierOutput: {
3005
+ violations: 0,
3006
+ duration: Date.now() - verificationStart,
3007
+ error: errorMessage
3008
+ }
3009
+ });
3010
+ }
2898
3011
  }
2899
3012
  }
2900
3013
  }
2901
- return violations;
3014
+ return { violations, warnings, errors };
2902
3015
  }
2903
3016
  /**
2904
3017
  * Verify multiple files
2905
3018
  */
2906
- async verifyFiles(files, decisions, severityFilter, cwd, onFileVerified) {
3019
+ async verifyFiles(files, decisions, severityFilter, cwd, reporter, onFileVerified) {
2907
3020
  const BATCH_SIZE = 10;
2908
3021
  for (let i = 0; i < files.length; i += BATCH_SIZE) {
2909
3022
  const batch = files.slice(i, i + BATCH_SIZE);
2910
3023
  const results = await Promise.all(
2911
- batch.map((file) => this.verifyFile(file, decisions, severityFilter, cwd))
3024
+ batch.map((file) => this.verifyFile(file, decisions, severityFilter, cwd, reporter))
2912
3025
  );
2913
- for (const violations of results) {
2914
- onFileVerified(violations);
3026
+ for (const result of results) {
3027
+ onFileVerified(result.violations, result.warnings, result.errors);
2915
3028
  }
2916
3029
  }
2917
3030
  }
@@ -3029,8 +3142,77 @@ async function getChangedFiles(cwd) {
3029
3142
  }
3030
3143
  }
3031
3144
 
3145
+ // src/verification/explain.ts
3146
+ import chalk4 from "chalk";
3147
+ var ExplainReporter = class {
3148
+ entries = [];
3149
+ /**
3150
+ * Add an entry to the explanation trace
3151
+ */
3152
+ add(entry) {
3153
+ this.entries.push(entry);
3154
+ }
3155
+ /**
3156
+ * Print the explanation trace
3157
+ */
3158
+ print() {
3159
+ if (this.entries.length === 0) {
3160
+ console.log(chalk4.dim("No constraints were evaluated."));
3161
+ return;
3162
+ }
3163
+ console.log(chalk4.bold("\n=== Verification Explanation ===\n"));
3164
+ const byFile = /* @__PURE__ */ new Map();
3165
+ for (const entry of this.entries) {
3166
+ const existing = byFile.get(entry.file) || [];
3167
+ existing.push(entry);
3168
+ byFile.set(entry.file, existing);
3169
+ }
3170
+ for (const [file, entries] of byFile) {
3171
+ console.log(chalk4.underline(file));
3172
+ for (const entry of entries) {
3173
+ const icon = entry.applied ? chalk4.green("\u2713") : chalk4.dim("\u2298");
3174
+ const constraintId = `${entry.decision.metadata.id}/${entry.constraint.id}`;
3175
+ console.log(` ${icon} ${constraintId}`);
3176
+ console.log(chalk4.dim(` ${entry.reason}`));
3177
+ if (entry.applied && entry.selectedVerifier) {
3178
+ console.log(chalk4.dim(` Verifier: ${entry.selectedVerifier}`));
3179
+ if (entry.verifierOutput) {
3180
+ if (entry.verifierOutput.error) {
3181
+ console.log(chalk4.red(` Error: ${entry.verifierOutput.error}`));
3182
+ } else {
3183
+ const violationText = entry.verifierOutput.violations === 1 ? "1 violation" : `${entry.verifierOutput.violations} violations`;
3184
+ const resultColor = entry.verifierOutput.violations > 0 ? chalk4.red : chalk4.green;
3185
+ console.log(
3186
+ chalk4.dim(` Result: `) + resultColor(violationText) + chalk4.dim(` in ${entry.verifierOutput.duration}ms`)
3187
+ );
3188
+ }
3189
+ }
3190
+ }
3191
+ console.log("");
3192
+ }
3193
+ }
3194
+ const applied = this.entries.filter((e) => e.applied).length;
3195
+ const skipped = this.entries.filter((e) => !e.applied).length;
3196
+ console.log(chalk4.bold("Summary:"));
3197
+ console.log(` Constraints Applied: ${chalk4.green(applied)}`);
3198
+ console.log(` Constraints Skipped: ${chalk4.dim(skipped)}`);
3199
+ }
3200
+ /**
3201
+ * Get all entries
3202
+ */
3203
+ getEntries() {
3204
+ return [...this.entries];
3205
+ }
3206
+ /**
3207
+ * Clear all entries
3208
+ */
3209
+ clear() {
3210
+ this.entries = [];
3211
+ }
3212
+ };
3213
+
3032
3214
  // src/cli/commands/verify.ts
3033
- var verifyCommand = new Command3("verify").description("Verify code compliance against decisions").option("-l, --level <level>", "Verification level (commit, pr, full)", "full").option("-f, --files <patterns>", "Comma-separated file patterns to check").option("-d, --decisions <ids>", "Comma-separated decision IDs to check").option("-s, --severity <levels>", "Comma-separated severity levels (critical, high, medium, low)").option("--json", "Output as JSON").option("--incremental", "Only verify changed files (git diff --name-only --diff-filter=AM HEAD)").option("--fix", "Apply auto-fixes for supported violations").option("--dry-run", "Show what would be fixed without applying (requires --fix)").option("--interactive", "Confirm each fix interactively (requires --fix)").action(async (options) => {
3215
+ var verifyCommand = new Command3("verify").description("Verify code compliance against decisions").option("-l, --level <level>", "Verification level (commit, pr, full)", "full").option("-f, --files <patterns>", "Comma-separated file patterns to check").option("-d, --decisions <ids>", "Comma-separated decision IDs to check").option("-s, --severity <levels>", "Comma-separated severity levels (critical, high, medium, low)").option("--json", "Output as JSON").option("--incremental", "Only verify changed files (git diff --name-only --diff-filter=AM HEAD)").option("--explain", "Show detailed explanation of verification process").option("--fix", "Apply auto-fixes for supported violations").option("--dry-run", "Show what would be fixed without applying (requires --fix)").option("--interactive", "Confirm each fix interactively (requires --fix)").action(async (options) => {
3034
3216
  const cwd = process.cwd();
3035
3217
  if (!await pathExists(getSpecBridgeDir(cwd))) {
3036
3218
  throw new NotInitializedError();
@@ -3047,13 +3229,15 @@ var verifyCommand = new Command3("verify").description("Verify code compliance a
3047
3229
  files = changed.length > 0 ? changed : [];
3048
3230
  }
3049
3231
  spinner.text = `Running ${level}-level verification...`;
3232
+ const reporter = options.explain ? new ExplainReporter() : void 0;
3050
3233
  const engine = createVerificationEngine();
3051
3234
  let result = await engine.verify(config, {
3052
3235
  level,
3053
3236
  files,
3054
3237
  decisions,
3055
3238
  severity,
3056
- cwd
3239
+ cwd,
3240
+ reporter
3057
3241
  });
3058
3242
  let fixResult;
3059
3243
  if (options.fix && result.violations.length > 0) {
@@ -3061,7 +3245,7 @@ var verifyCommand = new Command3("verify").description("Verify code compliance a
3061
3245
  if (fixableCount === 0) {
3062
3246
  spinner.stop();
3063
3247
  if (!options.json) {
3064
- console.log(chalk3.yellow("No auto-fixable violations found"));
3248
+ console.log(chalk5.yellow("No auto-fixable violations found"));
3065
3249
  }
3066
3250
  } else {
3067
3251
  spinner.text = `Applying ${fixableCount} auto-fix(es)...`;
@@ -3085,14 +3269,41 @@ var verifyCommand = new Command3("verify").description("Verify code compliance a
3085
3269
  if (options.json) {
3086
3270
  console.log(JSON.stringify({ ...result, autofix: fixResult }, null, 2));
3087
3271
  } else {
3272
+ if (result.warnings && result.warnings.length > 0) {
3273
+ console.log(chalk5.yellow.bold("\nWarnings:"));
3274
+ for (const warning of result.warnings) {
3275
+ console.log(chalk5.yellow(` \u26A0 ${warning.message}`));
3276
+ console.log(chalk5.dim(` ${warning.decisionId}/${warning.constraintId}`));
3277
+ if (warning.file) {
3278
+ console.log(chalk5.dim(` File: ${warning.file}`));
3279
+ }
3280
+ }
3281
+ console.log("");
3282
+ }
3283
+ if (result.errors && result.errors.length > 0) {
3284
+ console.log(chalk5.red.bold("\nErrors:"));
3285
+ for (const error of result.errors) {
3286
+ console.log(chalk5.red(` \u2717 ${error.message}`));
3287
+ if (error.decisionId && error.constraintId) {
3288
+ console.log(chalk5.dim(` ${error.decisionId}/${error.constraintId}`));
3289
+ }
3290
+ if (error.file) {
3291
+ console.log(chalk5.dim(` File: ${error.file}`));
3292
+ }
3293
+ }
3294
+ console.log("");
3295
+ }
3088
3296
  printResult(result, level);
3089
3297
  if (options.fix && fixResult) {
3090
- console.log(chalk3.green(`\u2713 Applied ${fixResult.applied.length} fix(es)`));
3298
+ console.log(chalk5.green(`\u2713 Applied ${fixResult.applied.length} fix(es)`));
3091
3299
  if (fixResult.skipped > 0) {
3092
- console.log(chalk3.yellow(`\u2298 Skipped ${fixResult.skipped} fix(es)`));
3300
+ console.log(chalk5.yellow(`\u2298 Skipped ${fixResult.skipped} fix(es)`));
3093
3301
  }
3094
3302
  console.log("");
3095
3303
  }
3304
+ if (options.explain && reporter) {
3305
+ reporter.print();
3306
+ }
3096
3307
  }
3097
3308
  if (!result.success) {
3098
3309
  process.exit(1);
@@ -3105,8 +3316,8 @@ var verifyCommand = new Command3("verify").description("Verify code compliance a
3105
3316
  function printResult(result, level) {
3106
3317
  console.log("");
3107
3318
  if (result.violations.length === 0) {
3108
- console.log(chalk3.green("\u2713 All checks passed!"));
3109
- console.log(chalk3.dim(` ${result.checked} files checked in ${result.duration}ms`));
3319
+ console.log(chalk5.green("\u2713 All checks passed!"));
3320
+ console.log(chalk5.dim(` ${result.checked} files checked in ${result.duration}ms`));
3110
3321
  return;
3111
3322
  }
3112
3323
  const byFile = /* @__PURE__ */ new Map();
@@ -3116,7 +3327,7 @@ function printResult(result, level) {
3116
3327
  byFile.set(violation.file, existing);
3117
3328
  }
3118
3329
  for (const [file, violations] of byFile) {
3119
- console.log(chalk3.underline(file));
3330
+ console.log(chalk5.underline(file));
3120
3331
  for (const v of violations) {
3121
3332
  const typeIcon = getTypeIcon(v.type);
3122
3333
  const severityColor = getSeverityColor(v.severity);
@@ -3124,9 +3335,9 @@ function printResult(result, level) {
3124
3335
  console.log(
3125
3336
  ` ${typeIcon} ${severityColor(`[${v.severity}]`)} ${v.message}`
3126
3337
  );
3127
- console.log(chalk3.dim(` ${v.decisionId}/${v.constraintId}${location}`));
3338
+ console.log(chalk5.dim(` ${v.decisionId}/${v.constraintId}${location}`));
3128
3339
  if (v.suggestion) {
3129
- console.log(chalk3.cyan(` Suggestion: ${v.suggestion}`));
3340
+ console.log(chalk5.cyan(` Suggestion: ${v.suggestion}`));
3130
3341
  }
3131
3342
  }
3132
3343
  console.log("");
@@ -3135,29 +3346,29 @@ function printResult(result, level) {
3135
3346
  const highCount = result.violations.filter((v) => v.severity === "high").length;
3136
3347
  const mediumCount = result.violations.filter((v) => v.severity === "medium").length;
3137
3348
  const lowCount = result.violations.filter((v) => v.severity === "low").length;
3138
- console.log(chalk3.bold("Summary:"));
3349
+ console.log(chalk5.bold("Summary:"));
3139
3350
  console.log(` Files: ${result.checked} checked, ${result.passed} passed, ${result.failed} failed`);
3140
3351
  const violationParts = [];
3141
- if (criticalCount > 0) violationParts.push(chalk3.red(`${criticalCount} critical`));
3142
- if (highCount > 0) violationParts.push(chalk3.yellow(`${highCount} high`));
3143
- if (mediumCount > 0) violationParts.push(chalk3.cyan(`${mediumCount} medium`));
3144
- if (lowCount > 0) violationParts.push(chalk3.dim(`${lowCount} low`));
3352
+ if (criticalCount > 0) violationParts.push(chalk5.red(`${criticalCount} critical`));
3353
+ if (highCount > 0) violationParts.push(chalk5.yellow(`${highCount} high`));
3354
+ if (mediumCount > 0) violationParts.push(chalk5.cyan(`${mediumCount} medium`));
3355
+ if (lowCount > 0) violationParts.push(chalk5.dim(`${lowCount} low`));
3145
3356
  console.log(` Violations: ${violationParts.join(", ")}`);
3146
3357
  console.log(` Duration: ${result.duration}ms`);
3147
3358
  if (!result.success) {
3148
3359
  console.log("");
3149
3360
  const blockingTypes = level === "commit" ? "invariant or critical" : level === "pr" ? "invariant, critical, or high" : "invariant";
3150
- console.log(chalk3.red(`\u2717 Verification failed. ${blockingTypes} violations must be resolved.`));
3361
+ console.log(chalk5.red(`\u2717 Verification failed. ${blockingTypes} violations must be resolved.`));
3151
3362
  }
3152
3363
  }
3153
3364
  function getTypeIcon(type) {
3154
3365
  switch (type) {
3155
3366
  case "invariant":
3156
- return chalk3.red("\u25CF");
3367
+ return chalk5.red("\u25CF");
3157
3368
  case "convention":
3158
- return chalk3.yellow("\u25CF");
3369
+ return chalk5.yellow("\u25CF");
3159
3370
  case "guideline":
3160
- return chalk3.green("\u25CF");
3371
+ return chalk5.green("\u25CF");
3161
3372
  default:
3162
3373
  return "\u25CB";
3163
3374
  }
@@ -3165,15 +3376,15 @@ function getTypeIcon(type) {
3165
3376
  function getSeverityColor(severity) {
3166
3377
  switch (severity) {
3167
3378
  case "critical":
3168
- return chalk3.red;
3379
+ return chalk5.red;
3169
3380
  case "high":
3170
- return chalk3.yellow;
3381
+ return chalk5.yellow;
3171
3382
  case "medium":
3172
- return chalk3.cyan;
3383
+ return chalk5.cyan;
3173
3384
  case "low":
3174
- return chalk3.dim;
3385
+ return chalk5.dim;
3175
3386
  default:
3176
- return chalk3.white;
3387
+ return chalk5.white;
3177
3388
  }
3178
3389
  }
3179
3390
 
@@ -3182,15 +3393,15 @@ import { Command as Command8 } from "commander";
3182
3393
 
3183
3394
  // src/cli/commands/decision/list.ts
3184
3395
  import { Command as Command4 } from "commander";
3185
- import chalk4 from "chalk";
3396
+ import chalk6 from "chalk";
3186
3397
  import { table } from "table";
3187
3398
  var listDecisions = new Command4("list").description("List all architectural decisions").option("-s, --status <status>", "Filter by status (draft, active, deprecated, superseded)").option("-t, --tag <tag>", "Filter by tag").option("--json", "Output as JSON").action(async (options) => {
3188
3399
  const registry = createRegistry();
3189
3400
  const result = await registry.load();
3190
3401
  if (result.errors.length > 0) {
3191
- console.warn(chalk4.yellow("\nWarnings:"));
3402
+ console.warn(chalk6.yellow("\nWarnings:"));
3192
3403
  for (const err of result.errors) {
3193
- console.warn(chalk4.yellow(` - ${err.filePath}: ${err.error}`));
3404
+ console.warn(chalk6.yellow(` - ${err.filePath}: ${err.error}`));
3194
3405
  }
3195
3406
  console.log("");
3196
3407
  }
@@ -3203,7 +3414,7 @@ var listDecisions = new Command4("list").description("List all architectural dec
3203
3414
  }
3204
3415
  const decisions = registry.getAll(filter);
3205
3416
  if (decisions.length === 0) {
3206
- console.log(chalk4.yellow("No decisions found."));
3417
+ console.log(chalk6.yellow("No decisions found."));
3207
3418
  return;
3208
3419
  }
3209
3420
  if (options.json) {
@@ -3212,11 +3423,11 @@ var listDecisions = new Command4("list").description("List all architectural dec
3212
3423
  }
3213
3424
  const data = [
3214
3425
  [
3215
- chalk4.bold("ID"),
3216
- chalk4.bold("Title"),
3217
- chalk4.bold("Status"),
3218
- chalk4.bold("Constraints"),
3219
- chalk4.bold("Tags")
3426
+ chalk6.bold("ID"),
3427
+ chalk6.bold("Title"),
3428
+ chalk6.bold("Status"),
3429
+ chalk6.bold("Constraints"),
3430
+ chalk6.bold("Tags")
3220
3431
  ]
3221
3432
  ];
3222
3433
  for (const decision of decisions) {
@@ -3250,20 +3461,20 @@ var listDecisions = new Command4("list").description("List all architectural dec
3250
3461
  },
3251
3462
  drawHorizontalLine: (index) => index === 1
3252
3463
  }));
3253
- console.log(chalk4.dim(`Total: ${decisions.length} decision(s)`));
3464
+ console.log(chalk6.dim(`Total: ${decisions.length} decision(s)`));
3254
3465
  });
3255
3466
  function getStatusColor(status) {
3256
3467
  switch (status) {
3257
3468
  case "active":
3258
- return chalk4.green;
3469
+ return chalk6.green;
3259
3470
  case "draft":
3260
- return chalk4.yellow;
3471
+ return chalk6.yellow;
3261
3472
  case "deprecated":
3262
- return chalk4.gray;
3473
+ return chalk6.gray;
3263
3474
  case "superseded":
3264
- return chalk4.blue;
3475
+ return chalk6.blue;
3265
3476
  default:
3266
- return chalk4.white;
3477
+ return chalk6.white;
3267
3478
  }
3268
3479
  }
3269
3480
  function getConstraintTypeSummary(types) {
@@ -3276,9 +3487,9 @@ function getConstraintTypeSummary(types) {
3276
3487
  counts[type]++;
3277
3488
  }
3278
3489
  const parts = [];
3279
- if (counts.invariant > 0) parts.push(chalk4.red(`${counts.invariant}I`));
3280
- if (counts.convention > 0) parts.push(chalk4.yellow(`${counts.convention}C`));
3281
- if (counts.guideline > 0) parts.push(chalk4.green(`${counts.guideline}G`));
3490
+ if (counts.invariant > 0) parts.push(chalk6.red(`${counts.invariant}I`));
3491
+ if (counts.convention > 0) parts.push(chalk6.yellow(`${counts.convention}C`));
3492
+ if (counts.guideline > 0) parts.push(chalk6.green(`${counts.guideline}G`));
3282
3493
  return parts.join(" ") || "-";
3283
3494
  }
3284
3495
  function truncate(str, length) {
@@ -3288,7 +3499,7 @@ function truncate(str, length) {
3288
3499
 
3289
3500
  // src/cli/commands/decision/show.ts
3290
3501
  import { Command as Command5 } from "commander";
3291
- import chalk5 from "chalk";
3502
+ import chalk7 from "chalk";
3292
3503
  var showDecision = new Command5("show").description("Show details of a specific decision").argument("<id>", "Decision ID").option("--json", "Output as JSON").action(async (id, options) => {
3293
3504
  const registry = createRegistry();
3294
3505
  await registry.load();
@@ -3301,74 +3512,74 @@ var showDecision = new Command5("show").description("Show details of a specific
3301
3512
  });
3302
3513
  function printDecision(decision) {
3303
3514
  const { metadata, decision: content, constraints } = decision;
3304
- console.log(chalk5.bold.blue(`
3515
+ console.log(chalk7.bold.blue(`
3305
3516
  ${metadata.title}`));
3306
- console.log(chalk5.dim(`ID: ${metadata.id}`));
3517
+ console.log(chalk7.dim(`ID: ${metadata.id}`));
3307
3518
  console.log("");
3308
- console.log(chalk5.bold("Status:"), getStatusBadge(metadata.status));
3309
- console.log(chalk5.bold("Owners:"), metadata.owners.join(", "));
3519
+ console.log(chalk7.bold("Status:"), getStatusBadge(metadata.status));
3520
+ console.log(chalk7.bold("Owners:"), metadata.owners.join(", "));
3310
3521
  if (metadata.tags && metadata.tags.length > 0) {
3311
- console.log(chalk5.bold("Tags:"), metadata.tags.map((t) => chalk5.cyan(t)).join(", "));
3522
+ console.log(chalk7.bold("Tags:"), metadata.tags.map((t) => chalk7.cyan(t)).join(", "));
3312
3523
  }
3313
3524
  if (metadata.createdAt) {
3314
- console.log(chalk5.bold("Created:"), metadata.createdAt);
3525
+ console.log(chalk7.bold("Created:"), metadata.createdAt);
3315
3526
  }
3316
3527
  if (metadata.supersededBy) {
3317
- console.log(chalk5.bold("Superseded by:"), chalk5.yellow(metadata.supersededBy));
3528
+ console.log(chalk7.bold("Superseded by:"), chalk7.yellow(metadata.supersededBy));
3318
3529
  }
3319
3530
  console.log("");
3320
- console.log(chalk5.bold.underline("Summary"));
3531
+ console.log(chalk7.bold.underline("Summary"));
3321
3532
  console.log(content.summary);
3322
3533
  console.log("");
3323
- console.log(chalk5.bold.underline("Rationale"));
3534
+ console.log(chalk7.bold.underline("Rationale"));
3324
3535
  console.log(content.rationale);
3325
3536
  console.log("");
3326
3537
  if (content.context) {
3327
- console.log(chalk5.bold.underline("Context"));
3538
+ console.log(chalk7.bold.underline("Context"));
3328
3539
  console.log(content.context);
3329
3540
  console.log("");
3330
3541
  }
3331
3542
  if (content.consequences && content.consequences.length > 0) {
3332
- console.log(chalk5.bold.underline("Consequences"));
3543
+ console.log(chalk7.bold.underline("Consequences"));
3333
3544
  for (const consequence of content.consequences) {
3334
3545
  console.log(` \u2022 ${consequence}`);
3335
3546
  }
3336
3547
  console.log("");
3337
3548
  }
3338
- console.log(chalk5.bold.underline(`Constraints (${constraints.length})`));
3549
+ console.log(chalk7.bold.underline(`Constraints (${constraints.length})`));
3339
3550
  for (const constraint of constraints) {
3340
3551
  const typeIcon = getTypeIcon2(constraint.type);
3341
3552
  const severityBadge = getSeverityBadge(constraint.severity);
3342
3553
  console.log(`
3343
- ${typeIcon} ${chalk5.bold(constraint.id)} ${severityBadge}`);
3554
+ ${typeIcon} ${chalk7.bold(constraint.id)} ${severityBadge}`);
3344
3555
  console.log(` ${constraint.rule}`);
3345
- console.log(chalk5.dim(` Scope: ${constraint.scope}`));
3556
+ console.log(chalk7.dim(` Scope: ${constraint.scope}`));
3346
3557
  if (constraint.verifier) {
3347
- console.log(chalk5.dim(` Verifier: ${constraint.verifier}`));
3558
+ console.log(chalk7.dim(` Verifier: ${constraint.verifier}`));
3348
3559
  }
3349
3560
  if (constraint.exceptions && constraint.exceptions.length > 0) {
3350
- console.log(chalk5.dim(` Exceptions: ${constraint.exceptions.length}`));
3561
+ console.log(chalk7.dim(` Exceptions: ${constraint.exceptions.length}`));
3351
3562
  }
3352
3563
  }
3353
3564
  console.log("");
3354
3565
  if (decision.verification?.automated && decision.verification.automated.length > 0) {
3355
- console.log(chalk5.bold.underline("Automated Verification"));
3566
+ console.log(chalk7.bold.underline("Automated Verification"));
3356
3567
  for (const check of decision.verification.automated) {
3357
3568
  console.log(` \u2022 ${check.check} (${check.frequency})`);
3358
- console.log(chalk5.dim(` Target: ${check.target}`));
3569
+ console.log(chalk7.dim(` Target: ${check.target}`));
3359
3570
  }
3360
3571
  console.log("");
3361
3572
  }
3362
3573
  if (decision.links) {
3363
3574
  const { related, supersedes, references } = decision.links;
3364
3575
  if (related && related.length > 0) {
3365
- console.log(chalk5.bold("Related:"), related.join(", "));
3576
+ console.log(chalk7.bold("Related:"), related.join(", "));
3366
3577
  }
3367
3578
  if (supersedes && supersedes.length > 0) {
3368
- console.log(chalk5.bold("Supersedes:"), supersedes.join(", "));
3579
+ console.log(chalk7.bold("Supersedes:"), supersedes.join(", "));
3369
3580
  }
3370
3581
  if (references && references.length > 0) {
3371
- console.log(chalk5.bold("References:"));
3582
+ console.log(chalk7.bold("References:"));
3372
3583
  for (const ref of references) {
3373
3584
  console.log(` \u2022 ${ref}`);
3374
3585
  }
@@ -3378,13 +3589,13 @@ ${metadata.title}`));
3378
3589
  function getStatusBadge(status) {
3379
3590
  switch (status) {
3380
3591
  case "active":
3381
- return chalk5.bgGreen.black(" ACTIVE ");
3592
+ return chalk7.bgGreen.black(" ACTIVE ");
3382
3593
  case "draft":
3383
- return chalk5.bgYellow.black(" DRAFT ");
3594
+ return chalk7.bgYellow.black(" DRAFT ");
3384
3595
  case "deprecated":
3385
- return chalk5.bgGray.white(" DEPRECATED ");
3596
+ return chalk7.bgGray.white(" DEPRECATED ");
3386
3597
  case "superseded":
3387
- return chalk5.bgBlue.white(" SUPERSEDED ");
3598
+ return chalk7.bgBlue.white(" SUPERSEDED ");
3388
3599
  default:
3389
3600
  return status;
3390
3601
  }
@@ -3392,11 +3603,11 @@ function getStatusBadge(status) {
3392
3603
  function getTypeIcon2(type) {
3393
3604
  switch (type) {
3394
3605
  case "invariant":
3395
- return chalk5.red("\u25CF");
3606
+ return chalk7.red("\u25CF");
3396
3607
  case "convention":
3397
- return chalk5.yellow("\u25CF");
3608
+ return chalk7.yellow("\u25CF");
3398
3609
  case "guideline":
3399
- return chalk5.green("\u25CF");
3610
+ return chalk7.green("\u25CF");
3400
3611
  default:
3401
3612
  return "\u25CB";
3402
3613
  }
@@ -3404,13 +3615,13 @@ function getTypeIcon2(type) {
3404
3615
  function getSeverityBadge(severity) {
3405
3616
  switch (severity) {
3406
3617
  case "critical":
3407
- return chalk5.bgRed.white(" CRITICAL ");
3618
+ return chalk7.bgRed.white(" CRITICAL ");
3408
3619
  case "high":
3409
- return chalk5.bgYellow.black(" HIGH ");
3620
+ return chalk7.bgYellow.black(" HIGH ");
3410
3621
  case "medium":
3411
- return chalk5.bgCyan.black(" MEDIUM ");
3622
+ return chalk7.bgCyan.black(" MEDIUM ");
3412
3623
  case "low":
3413
- return chalk5.bgGray.white(" LOW ");
3624
+ return chalk7.bgGray.white(" LOW ");
3414
3625
  default:
3415
3626
  return severity;
3416
3627
  }
@@ -3418,7 +3629,7 @@ function getSeverityBadge(severity) {
3418
3629
 
3419
3630
  // src/cli/commands/decision/validate.ts
3420
3631
  import { Command as Command6 } from "commander";
3421
- import chalk6 from "chalk";
3632
+ import chalk8 from "chalk";
3422
3633
  import ora4 from "ora";
3423
3634
  import { join as join5 } from "path";
3424
3635
  var validateDecisions = new Command6("validate").description("Validate decision files").option("-f, --file <path>", "Validate a specific file").action(async (options) => {
@@ -3457,14 +3668,14 @@ var validateDecisions = new Command6("validate").description("Validate decision
3457
3668
  }
3458
3669
  spinner.stop();
3459
3670
  if (invalid === 0) {
3460
- console.log(chalk6.green(`\u2713 All ${valid} decision file(s) are valid.`));
3671
+ console.log(chalk8.green(`\u2713 All ${valid} decision file(s) are valid.`));
3461
3672
  } else {
3462
- console.log(chalk6.red(`\u2717 ${invalid} of ${files.length} decision file(s) have errors.
3673
+ console.log(chalk8.red(`\u2717 ${invalid} of ${files.length} decision file(s) have errors.
3463
3674
  `));
3464
3675
  for (const { file, errors: fileErrors } of errors) {
3465
- console.log(chalk6.red(`File: ${file}`));
3676
+ console.log(chalk8.red(`File: ${file}`));
3466
3677
  for (const err of fileErrors) {
3467
- console.log(chalk6.dim(` - ${err}`));
3678
+ console.log(chalk8.dim(` - ${err}`));
3468
3679
  }
3469
3680
  console.log("");
3470
3681
  }
@@ -3478,7 +3689,7 @@ var validateDecisions = new Command6("validate").description("Validate decision
3478
3689
 
3479
3690
  // src/cli/commands/decision/create.ts
3480
3691
  import { Command as Command7 } from "commander";
3481
- import chalk7 from "chalk";
3692
+ import chalk9 from "chalk";
3482
3693
  import { join as join6 } from "path";
3483
3694
  var createDecision = new Command7("create").description("Create a new decision file").argument("<id>", "Decision ID (e.g., auth-001)").requiredOption("-t, --title <title>", "Decision title").requiredOption("-s, --summary <summary>", "One-sentence summary").option("--type <type>", "Default constraint type (invariant, convention, guideline)", "convention").option("--severity <severity>", "Default constraint severity (critical, high, medium, low)", "medium").option("--scope <scope>", "Default constraint scope (glob pattern)", "src/**/*.ts").option("-o, --owner <owner>", "Owner name", "team").action(async (id, options) => {
3484
3695
  const cwd = process.cwd();
@@ -3486,13 +3697,13 @@ var createDecision = new Command7("create").description("Create a new decision f
3486
3697
  throw new NotInitializedError();
3487
3698
  }
3488
3699
  if (!/^[a-z0-9-]+$/.test(id)) {
3489
- console.error(chalk7.red("Error: Decision ID must be lowercase alphanumeric with hyphens only."));
3700
+ console.error(chalk9.red("Error: Decision ID must be lowercase alphanumeric with hyphens only."));
3490
3701
  process.exit(1);
3491
3702
  }
3492
3703
  const decisionsDir = getDecisionsDir(cwd);
3493
3704
  const filePath = join6(decisionsDir, `${id}.decision.yaml`);
3494
3705
  if (await pathExists(filePath)) {
3495
- console.error(chalk7.red(`Error: Decision file already exists: ${filePath}`));
3706
+ console.error(chalk9.red(`Error: Decision file already exists: ${filePath}`));
3496
3707
  process.exit(1);
3497
3708
  }
3498
3709
  const decision = {
@@ -3528,13 +3739,13 @@ var createDecision = new Command7("create").description("Create a new decision f
3528
3739
  }
3529
3740
  };
3530
3741
  await writeTextFile(filePath, stringifyYaml(decision));
3531
- console.log(chalk7.green(`\u2713 Created decision: ${filePath}`));
3742
+ console.log(chalk9.green(`\u2713 Created decision: ${filePath}`));
3532
3743
  console.log("");
3533
- console.log(chalk7.cyan("Next steps:"));
3744
+ console.log(chalk9.cyan("Next steps:"));
3534
3745
  console.log(` 1. Edit the file to add rationale, context, and consequences`);
3535
3746
  console.log(` 2. Define constraints with appropriate scopes`);
3536
- console.log(` 3. Run ${chalk7.bold("specbridge decision validate")} to check syntax`);
3537
- console.log(` 4. Change status from ${chalk7.yellow("draft")} to ${chalk7.green("active")} when ready`);
3747
+ console.log(` 3. Run ${chalk9.bold("specbridge decision validate")} to check syntax`);
3748
+ console.log(` 4. Change status from ${chalk9.yellow("draft")} to ${chalk9.green("active")} when ready`);
3538
3749
  });
3539
3750
 
3540
3751
  // src/cli/commands/decision/index.ts
@@ -3542,7 +3753,7 @@ var decisionCommand = new Command8("decision").description("Manage architectural
3542
3753
 
3543
3754
  // src/cli/commands/hook.ts
3544
3755
  import { Command as Command9 } from "commander";
3545
- import chalk8 from "chalk";
3756
+ import chalk10 from "chalk";
3546
3757
  import ora5 from "ora";
3547
3758
  import { join as join7 } from "path";
3548
3759
  var HOOK_SCRIPT = `#!/bin/sh
@@ -3574,9 +3785,9 @@ function createHookCommand() {
3574
3785
  } else if (options.lefthook) {
3575
3786
  spinner.succeed("Lefthook detected");
3576
3787
  console.log("");
3577
- console.log(chalk8.cyan("Add this to your lefthook.yml:"));
3788
+ console.log(chalk10.cyan("Add this to your lefthook.yml:"));
3578
3789
  console.log("");
3579
- console.log(chalk8.dim(`pre-commit:
3790
+ console.log(chalk10.dim(`pre-commit:
3580
3791
  commands:
3581
3792
  specbridge:
3582
3793
  glob: "*.{ts,tsx}"
@@ -3591,9 +3802,9 @@ function createHookCommand() {
3591
3802
  } else if (await pathExists(join7(cwd, "lefthook.yml"))) {
3592
3803
  spinner.succeed("Lefthook detected");
3593
3804
  console.log("");
3594
- console.log(chalk8.cyan("Add this to your lefthook.yml:"));
3805
+ console.log(chalk10.cyan("Add this to your lefthook.yml:"));
3595
3806
  console.log("");
3596
- console.log(chalk8.dim(`pre-commit:
3807
+ console.log(chalk10.dim(`pre-commit:
3597
3808
  commands:
3598
3809
  specbridge:
3599
3810
  glob: "*.{ts,tsx}"
@@ -3608,7 +3819,7 @@ function createHookCommand() {
3608
3819
  }
3609
3820
  if (await pathExists(hookPath) && !options.force) {
3610
3821
  spinner.fail("Hook already exists");
3611
- console.log(chalk8.yellow(`Use --force to overwrite: ${hookPath}`));
3822
+ console.log(chalk10.yellow(`Use --force to overwrite: ${hookPath}`));
3612
3823
  return;
3613
3824
  }
3614
3825
  await writeTextFile(hookPath, hookContent);
@@ -3618,9 +3829,9 @@ function createHookCommand() {
3618
3829
  } catch {
3619
3830
  }
3620
3831
  spinner.succeed("Pre-commit hook installed");
3621
- console.log(chalk8.dim(` Path: ${hookPath}`));
3832
+ console.log(chalk10.dim(` Path: ${hookPath}`));
3622
3833
  console.log("");
3623
- console.log(chalk8.cyan("The hook will run on each commit and verify staged files."));
3834
+ console.log(chalk10.cyan("The hook will run on each commit and verify staged files."));
3624
3835
  } catch (error) {
3625
3836
  spinner.fail("Failed to install hook");
3626
3837
  throw error;
@@ -3656,21 +3867,21 @@ function createHookCommand() {
3656
3867
  cwd
3657
3868
  });
3658
3869
  if (result.violations.length === 0) {
3659
- console.log(chalk8.green("\u2713 SpecBridge: All checks passed"));
3870
+ console.log(chalk10.green("\u2713 SpecBridge: All checks passed"));
3660
3871
  process.exit(0);
3661
3872
  }
3662
- console.log(chalk8.red(`\u2717 SpecBridge: ${result.violations.length} violation(s) found`));
3873
+ console.log(chalk10.red(`\u2717 SpecBridge: ${result.violations.length} violation(s) found`));
3663
3874
  console.log("");
3664
3875
  for (const v of result.violations) {
3665
3876
  const location = v.line ? `:${v.line}` : "";
3666
3877
  console.log(` ${v.file}${location}: ${v.message}`);
3667
- console.log(chalk8.dim(` [${v.severity}] ${v.decisionId}/${v.constraintId}`));
3878
+ console.log(chalk10.dim(` [${v.severity}] ${v.decisionId}/${v.constraintId}`));
3668
3879
  }
3669
3880
  console.log("");
3670
- console.log(chalk8.yellow("Run `specbridge verify` for full details."));
3881
+ console.log(chalk10.yellow("Run `specbridge verify` for full details."));
3671
3882
  process.exit(result.success ? 0 : 1);
3672
3883
  } catch (error) {
3673
- console.error(chalk8.red("SpecBridge verification failed"));
3884
+ console.error(chalk10.red("SpecBridge verification failed"));
3674
3885
  console.error(error instanceof Error ? error.message : String(error));
3675
3886
  process.exit(1);
3676
3887
  }
@@ -3709,7 +3920,7 @@ var hookCommand = createHookCommand();
3709
3920
 
3710
3921
  // src/cli/commands/report.ts
3711
3922
  import { Command as Command10 } from "commander";
3712
- import chalk10 from "chalk";
3923
+ import chalk12 from "chalk";
3713
3924
  import ora6 from "ora";
3714
3925
  import { join as join9 } from "path";
3715
3926
 
@@ -3764,54 +3975,54 @@ async function generateReport(config, options = {}) {
3764
3975
  }
3765
3976
 
3766
3977
  // src/reporting/formats/console.ts
3767
- import chalk9 from "chalk";
3978
+ import chalk11 from "chalk";
3768
3979
  import { table as table2 } from "table";
3769
3980
  function formatConsoleReport(report) {
3770
3981
  const lines = [];
3771
3982
  lines.push("");
3772
- lines.push(chalk9.bold.blue("SpecBridge Compliance Report"));
3773
- lines.push(chalk9.dim(`Generated: ${new Date(report.timestamp).toLocaleString()}`));
3774
- lines.push(chalk9.dim(`Project: ${report.project}`));
3983
+ lines.push(chalk11.bold.blue("SpecBridge Compliance Report"));
3984
+ lines.push(chalk11.dim(`Generated: ${new Date(report.timestamp).toLocaleString()}`));
3985
+ lines.push(chalk11.dim(`Project: ${report.project}`));
3775
3986
  lines.push("");
3776
3987
  const complianceColor = getComplianceColor(report.summary.compliance);
3777
- lines.push(chalk9.bold("Overall Compliance"));
3988
+ lines.push(chalk11.bold("Overall Compliance"));
3778
3989
  lines.push(` ${complianceColor(formatComplianceBar(report.summary.compliance))} ${complianceColor(`${report.summary.compliance}%`)}`);
3779
3990
  lines.push("");
3780
- lines.push(chalk9.bold("Summary"));
3991
+ lines.push(chalk11.bold("Summary"));
3781
3992
  lines.push(` Decisions: ${report.summary.activeDecisions} active / ${report.summary.totalDecisions} total`);
3782
3993
  lines.push(` Constraints: ${report.summary.totalConstraints}`);
3783
3994
  lines.push("");
3784
- lines.push(chalk9.bold("Violations"));
3995
+ lines.push(chalk11.bold("Violations"));
3785
3996
  const { violations } = report.summary;
3786
3997
  const violationParts = [];
3787
3998
  if (violations.critical > 0) {
3788
- violationParts.push(chalk9.red(`${violations.critical} critical`));
3999
+ violationParts.push(chalk11.red(`${violations.critical} critical`));
3789
4000
  }
3790
4001
  if (violations.high > 0) {
3791
- violationParts.push(chalk9.yellow(`${violations.high} high`));
4002
+ violationParts.push(chalk11.yellow(`${violations.high} high`));
3792
4003
  }
3793
4004
  if (violations.medium > 0) {
3794
- violationParts.push(chalk9.cyan(`${violations.medium} medium`));
4005
+ violationParts.push(chalk11.cyan(`${violations.medium} medium`));
3795
4006
  }
3796
4007
  if (violations.low > 0) {
3797
- violationParts.push(chalk9.dim(`${violations.low} low`));
4008
+ violationParts.push(chalk11.dim(`${violations.low} low`));
3798
4009
  }
3799
4010
  if (violationParts.length > 0) {
3800
4011
  lines.push(` ${violationParts.join(" | ")}`);
3801
4012
  } else {
3802
- lines.push(chalk9.green(" No violations"));
4013
+ lines.push(chalk11.green(" No violations"));
3803
4014
  }
3804
4015
  lines.push("");
3805
4016
  if (report.byDecision.length > 0) {
3806
- lines.push(chalk9.bold("By Decision"));
4017
+ lines.push(chalk11.bold("By Decision"));
3807
4018
  lines.push("");
3808
4019
  const tableData = [
3809
4020
  [
3810
- chalk9.bold("Decision"),
3811
- chalk9.bold("Status"),
3812
- chalk9.bold("Constraints"),
3813
- chalk9.bold("Violations"),
3814
- chalk9.bold("Compliance")
4021
+ chalk11.bold("Decision"),
4022
+ chalk11.bold("Status"),
4023
+ chalk11.bold("Constraints"),
4024
+ chalk11.bold("Violations"),
4025
+ chalk11.bold("Compliance")
3815
4026
  ]
3816
4027
  ];
3817
4028
  for (const dec of report.byDecision) {
@@ -3821,7 +4032,7 @@ function formatConsoleReport(report) {
3821
4032
  truncate2(dec.title, 40),
3822
4033
  statusColor(dec.status),
3823
4034
  String(dec.constraints),
3824
- dec.violations > 0 ? chalk9.red(String(dec.violations)) : chalk9.green("0"),
4035
+ dec.violations > 0 ? chalk11.red(String(dec.violations)) : chalk11.green("0"),
3825
4036
  compColor(`${dec.compliance}%`)
3826
4037
  ]);
3827
4038
  }
@@ -3855,23 +4066,23 @@ function formatComplianceBar(compliance) {
3855
4066
  return "\u2588".repeat(filled) + "\u2591".repeat(empty);
3856
4067
  }
3857
4068
  function getComplianceColor(compliance) {
3858
- if (compliance >= 90) return chalk9.green;
3859
- if (compliance >= 70) return chalk9.yellow;
3860
- if (compliance >= 50) return chalk9.hex("#FFA500");
3861
- return chalk9.red;
4069
+ if (compliance >= 90) return chalk11.green;
4070
+ if (compliance >= 70) return chalk11.yellow;
4071
+ if (compliance >= 50) return chalk11.hex("#FFA500");
4072
+ return chalk11.red;
3862
4073
  }
3863
4074
  function getStatusColor2(status) {
3864
4075
  switch (status) {
3865
4076
  case "active":
3866
- return chalk9.green;
4077
+ return chalk11.green;
3867
4078
  case "draft":
3868
- return chalk9.yellow;
4079
+ return chalk11.yellow;
3869
4080
  case "deprecated":
3870
- return chalk9.gray;
4081
+ return chalk11.gray;
3871
4082
  case "superseded":
3872
- return chalk9.blue;
4083
+ return chalk11.blue;
3873
4084
  default:
3874
- return chalk9.white;
4085
+ return chalk11.white;
3875
4086
  }
3876
4087
  }
3877
4088
  function truncate2(str, length) {
@@ -4243,29 +4454,29 @@ var reportCommand = new Command10("report").description("Generate compliance rep
4243
4454
  const storage = new ReportStorage(cwd);
4244
4455
  await storage.save(report);
4245
4456
  if (options.trend) {
4246
- console.log("\n" + chalk10.blue.bold("=== Compliance Trend Analysis ===\n"));
4457
+ console.log("\n" + chalk12.blue.bold("=== Compliance Trend Analysis ===\n"));
4247
4458
  const days = parseInt(options.days || "30", 10);
4248
4459
  const history = await storage.loadHistory(days);
4249
4460
  if (history.length < 2) {
4250
- console.log(chalk10.yellow(`Not enough data for trend analysis. Found ${history.length} report(s), need at least 2.`));
4461
+ console.log(chalk12.yellow(`Not enough data for trend analysis. Found ${history.length} report(s), need at least 2.`));
4251
4462
  } else {
4252
4463
  const trend = await analyzeTrend(history);
4253
- console.log(chalk10.bold(`Period: ${trend.period.start} to ${trend.period.end} (${trend.period.days} days)`));
4464
+ console.log(chalk12.bold(`Period: ${trend.period.start} to ${trend.period.end} (${trend.period.days} days)`));
4254
4465
  console.log(`
4255
4466
  Overall Compliance: ${trend.overall.startCompliance}% \u2192 ${trend.overall.endCompliance}% (${trend.overall.change > 0 ? "+" : ""}${trend.overall.change.toFixed(1)}%)`);
4256
4467
  const trendEmoji = trend.overall.trend === "improving" ? "\u{1F4C8}" : trend.overall.trend === "degrading" ? "\u{1F4C9}" : "\u27A1\uFE0F";
4257
- const trendColor = trend.overall.trend === "improving" ? chalk10.green : trend.overall.trend === "degrading" ? chalk10.red : chalk10.yellow;
4468
+ const trendColor = trend.overall.trend === "improving" ? chalk12.green : trend.overall.trend === "degrading" ? chalk12.red : chalk12.yellow;
4258
4469
  console.log(trendColor(`${trendEmoji} Trend: ${trend.overall.trend.toUpperCase()}`));
4259
4470
  const degrading = trend.decisions.filter((d) => d.trend === "degrading").slice(0, 3);
4260
4471
  if (degrading.length > 0) {
4261
- console.log(chalk10.red("\n\u26A0\uFE0F Most Degraded Decisions:"));
4472
+ console.log(chalk12.red("\n\u26A0\uFE0F Most Degraded Decisions:"));
4262
4473
  degrading.forEach((d) => {
4263
4474
  console.log(` \u2022 ${d.title}: ${d.startCompliance}% \u2192 ${d.endCompliance}% (${d.change.toFixed(1)}%)`);
4264
4475
  });
4265
4476
  }
4266
4477
  const improving = trend.decisions.filter((d) => d.trend === "improving").slice(0, 3);
4267
4478
  if (improving.length > 0) {
4268
- console.log(chalk10.green("\n\u2705 Most Improved Decisions:"));
4479
+ console.log(chalk12.green("\n\u2705 Most Improved Decisions:"));
4269
4480
  improving.forEach((d) => {
4270
4481
  console.log(` \u2022 ${d.title}: ${d.startCompliance}% \u2192 ${d.endCompliance}% (+${d.change.toFixed(1)}%)`);
4271
4482
  });
@@ -4274,26 +4485,26 @@ Overall Compliance: ${trend.overall.startCompliance}% \u2192 ${trend.overall.end
4274
4485
  console.log("");
4275
4486
  }
4276
4487
  if (options.drift) {
4277
- console.log("\n" + chalk10.blue.bold("=== Drift Analysis ===\n"));
4488
+ console.log("\n" + chalk12.blue.bold("=== Drift Analysis ===\n"));
4278
4489
  const history = await storage.loadHistory(2);
4279
4490
  if (history.length < 2) {
4280
- console.log(chalk10.yellow("Not enough data for drift analysis. Need at least 2 reports."));
4491
+ console.log(chalk12.yellow("Not enough data for drift analysis. Need at least 2 reports."));
4281
4492
  } else {
4282
4493
  const currentEntry = history[0];
4283
4494
  const previousEntry = history[1];
4284
4495
  if (!currentEntry || !previousEntry) {
4285
- console.log(chalk10.yellow("Invalid history data."));
4496
+ console.log(chalk12.yellow("Invalid history data."));
4286
4497
  return;
4287
4498
  }
4288
4499
  const drift = await detectDrift(currentEntry.report, previousEntry.report);
4289
- console.log(chalk10.bold(`Comparing: ${previousEntry.timestamp} vs ${currentEntry.timestamp}`));
4500
+ console.log(chalk12.bold(`Comparing: ${previousEntry.timestamp} vs ${currentEntry.timestamp}`));
4290
4501
  console.log(`
4291
4502
  Compliance Change: ${drift.complianceChange > 0 ? "+" : ""}${drift.complianceChange.toFixed(1)}%`);
4292
4503
  const driftEmoji = drift.trend === "improving" ? "\u{1F4C8}" : drift.trend === "degrading" ? "\u{1F4C9}" : "\u27A1\uFE0F";
4293
- const driftColor = drift.trend === "improving" ? chalk10.green : drift.trend === "degrading" ? chalk10.red : chalk10.yellow;
4504
+ const driftColor = drift.trend === "improving" ? chalk12.green : drift.trend === "degrading" ? chalk12.red : chalk12.yellow;
4294
4505
  console.log(driftColor(`${driftEmoji} Overall Trend: ${drift.trend.toUpperCase()}`));
4295
4506
  if (drift.summary.newViolations.total > 0) {
4296
- console.log(chalk10.red(`
4507
+ console.log(chalk12.red(`
4297
4508
  \u26A0\uFE0F New Violations: ${drift.summary.newViolations.total}`));
4298
4509
  if (drift.summary.newViolations.critical > 0) {
4299
4510
  console.log(` \u2022 Critical: ${drift.summary.newViolations.critical}`);
@@ -4309,7 +4520,7 @@ Compliance Change: ${drift.complianceChange > 0 ? "+" : ""}${drift.complianceCha
4309
4520
  }
4310
4521
  }
4311
4522
  if (drift.summary.fixedViolations.total > 0) {
4312
- console.log(chalk10.green(`
4523
+ console.log(chalk12.green(`
4313
4524
  \u2705 Fixed Violations: ${drift.summary.fixedViolations.total}`));
4314
4525
  if (drift.summary.fixedViolations.critical > 0) {
4315
4526
  console.log(` \u2022 Critical: ${drift.summary.fixedViolations.critical}`);
@@ -4325,7 +4536,7 @@ Compliance Change: ${drift.complianceChange > 0 ? "+" : ""}${drift.complianceCha
4325
4536
  }
4326
4537
  }
4327
4538
  if (drift.mostDegraded.length > 0) {
4328
- console.log(chalk10.red("\n\u{1F4C9} Most Degraded:"));
4539
+ console.log(chalk12.red("\n\u{1F4C9} Most Degraded:"));
4329
4540
  drift.mostDegraded.forEach((d) => {
4330
4541
  console.log(` \u2022 ${d.title}: ${d.previousCompliance}% \u2192 ${d.currentCompliance}% (${d.complianceChange.toFixed(1)}%)`);
4331
4542
  if (d.newViolations > 0) {
@@ -4334,7 +4545,7 @@ Compliance Change: ${drift.complianceChange > 0 ? "+" : ""}${drift.complianceCha
4334
4545
  });
4335
4546
  }
4336
4547
  if (drift.mostImproved.length > 0) {
4337
- console.log(chalk10.green("\n\u{1F4C8} Most Improved:"));
4548
+ console.log(chalk12.green("\n\u{1F4C8} Most Improved:"));
4338
4549
  drift.mostImproved.forEach((d) => {
4339
4550
  console.log(` \u2022 ${d.title}: ${d.previousCompliance}% \u2192 ${d.currentCompliance}% (+${d.complianceChange.toFixed(1)}%)`);
4340
4551
  if (d.fixedViolations > 0) {
@@ -4374,7 +4585,7 @@ Compliance Change: ${drift.complianceChange > 0 ? "+" : ""}${drift.complianceCha
4374
4585
  `health-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.${extension}`
4375
4586
  );
4376
4587
  await writeTextFile(outputPath, output);
4377
- console.log(chalk10.green(`
4588
+ console.log(chalk12.green(`
4378
4589
  Report saved to: ${outputPath}`));
4379
4590
  if (options.save && !options.output) {
4380
4591
  const latestPath = join9(getReportsDir(cwd), `health-latest.${extension}`);
@@ -4389,7 +4600,7 @@ Report saved to: ${outputPath}`));
4389
4600
 
4390
4601
  // src/cli/commands/context.ts
4391
4602
  import { Command as Command11 } from "commander";
4392
- import chalk11 from "chalk";
4603
+ import chalk13 from "chalk";
4393
4604
 
4394
4605
  // src/agent/context.generator.ts
4395
4606
  async function generateContext(filePath, config, options = {}) {
@@ -4509,12 +4720,12 @@ var contextCommand = new Command11("context").description("Generate architectura
4509
4720
  });
4510
4721
  if (options.output) {
4511
4722
  await writeTextFile(options.output, output);
4512
- console.log(chalk11.green(`Context saved to: ${options.output}`));
4723
+ console.log(chalk13.green(`Context saved to: ${options.output}`));
4513
4724
  } else {
4514
4725
  console.log(output);
4515
4726
  }
4516
4727
  } catch (error) {
4517
- console.error(chalk11.red("Failed to generate context"));
4728
+ console.error(chalk13.red("Failed to generate context"));
4518
4729
  throw error;
4519
4730
  }
4520
4731
  });
@@ -4528,7 +4739,7 @@ import { TextDocument } from "vscode-languageserver-textdocument";
4528
4739
  import { fileURLToPath } from "url";
4529
4740
  import path3 from "path";
4530
4741
  import { Project as Project3 } from "ts-morph";
4531
- import chalk12 from "chalk";
4742
+ import chalk14 from "chalk";
4532
4743
  function severityToDiagnostic(severity) {
4533
4744
  switch (severity) {
4534
4745
  case "critical":
@@ -4635,7 +4846,7 @@ var SpecBridgeLspServer = class {
4635
4846
  if (!await pathExists(getSpecBridgeDir(this.cwd))) {
4636
4847
  const err = new NotInitializedError();
4637
4848
  this.initError = err.message;
4638
- if (this.options.verbose) this.connection.console.error(chalk12.red(this.initError));
4849
+ if (this.options.verbose) this.connection.console.error(chalk14.red(this.initError));
4639
4850
  return;
4640
4851
  }
4641
4852
  try {
@@ -4651,11 +4862,11 @@ var SpecBridgeLspServer = class {
4651
4862
  }
4652
4863
  }
4653
4864
  if (this.options.verbose) {
4654
- this.connection.console.log(chalk12.dim(`Loaded ${this.decisions.length} active decision(s)`));
4865
+ this.connection.console.log(chalk14.dim(`Loaded ${this.decisions.length} active decision(s)`));
4655
4866
  }
4656
4867
  } catch (error) {
4657
4868
  this.initError = error instanceof Error ? error.message : String(error);
4658
- if (this.options.verbose) this.connection.console.error(chalk12.red(this.initError));
4869
+ if (this.options.verbose) this.connection.console.error(chalk14.red(this.initError));
4659
4870
  }
4660
4871
  }
4661
4872
  async verifyTextDocument(doc) {
@@ -4727,7 +4938,7 @@ var lspCommand = new Command12("lsp").description("Start SpecBridge language ser
4727
4938
 
4728
4939
  // src/cli/commands/watch.ts
4729
4940
  import { Command as Command13 } from "commander";
4730
- import chalk13 from "chalk";
4941
+ import chalk15 from "chalk";
4731
4942
  import chokidar from "chokidar";
4732
4943
  import path4 from "path";
4733
4944
  var watchCommand = new Command13("watch").description("Watch for changes and verify files continuously").option("-l, --level <level>", "Verification level (commit, pr, full)", "full").option("--debounce <ms>", "Debounce verify on rapid changes", "150").action(async (options) => {
@@ -4748,15 +4959,15 @@ var watchCommand = new Command13("watch").description("Watch for changes and ver
4748
4959
  files: [absolutePath],
4749
4960
  cwd
4750
4961
  });
4751
- const prefix = result.success ? chalk13.green("\u2713") : chalk13.red("\u2717");
4962
+ const prefix = result.success ? chalk15.green("\u2713") : chalk15.red("\u2717");
4752
4963
  const summary = `${prefix} ${path4.relative(cwd, absolutePath)}: ${result.violations.length} violation(s)`;
4753
4964
  console.log(summary);
4754
4965
  for (const v of result.violations.slice(0, 20)) {
4755
4966
  const loc = v.line ? `:${v.line}${v.column ? `:${v.column}` : ""}` : "";
4756
- console.log(chalk13.dim(` - ${v.file}${loc}: ${v.message} [${v.severity}]`));
4967
+ console.log(chalk15.dim(` - ${v.file}${loc}: ${v.message} [${v.severity}]`));
4757
4968
  }
4758
4969
  if (result.violations.length > 20) {
4759
- console.log(chalk13.dim(` \u2026 ${result.violations.length - 20} more`));
4970
+ console.log(chalk15.dim(` \u2026 ${result.violations.length - 20} more`));
4760
4971
  }
4761
4972
  };
4762
4973
  const watcher = chokidar.watch(config.project.sourceRoots, {
@@ -4765,7 +4976,7 @@ var watchCommand = new Command13("watch").description("Watch for changes and ver
4765
4976
  ignoreInitial: true,
4766
4977
  persistent: true
4767
4978
  });
4768
- console.log(chalk13.blue("Watching for changes..."));
4979
+ console.log(chalk15.blue("Watching for changes..."));
4769
4980
  watcher.on("change", (changedPath) => {
4770
4981
  pendingPath = changedPath;
4771
4982
  if (timer) clearTimeout(timer);
@@ -5057,7 +5268,7 @@ var promptCommand = new Command15("prompt").description("Generate AI agent promp
5057
5268
 
5058
5269
  // src/cli/commands/analytics.ts
5059
5270
  import { Command as Command16 } from "commander";
5060
- import chalk14 from "chalk";
5271
+ import chalk16 from "chalk";
5061
5272
  import ora7 from "ora";
5062
5273
 
5063
5274
  // src/analytics/engine.ts
@@ -5286,7 +5497,7 @@ var analyticsCommand = new Command16("analytics").description("Analyze complianc
5286
5497
  const history = await storage.loadHistory(days);
5287
5498
  if (history.length === 0) {
5288
5499
  spinner.fail("No historical reports found");
5289
- console.log(chalk14.yellow("\nGenerate reports with: specbridge report"));
5500
+ console.log(chalk16.yellow("\nGenerate reports with: specbridge report"));
5290
5501
  return;
5291
5502
  }
5292
5503
  spinner.succeed(`Loaded ${history.length} historical report(s)`);
@@ -5303,17 +5514,17 @@ var analyticsCommand = new Command16("analytics").description("Analyze complianc
5303
5514
  }
5304
5515
  if (decisionId) {
5305
5516
  const metrics = await engine.analyzeDecision(decisionId, history);
5306
- console.log("\n" + chalk14.blue.bold(`=== Decision Analytics: ${metrics.title} ===
5517
+ console.log("\n" + chalk16.blue.bold(`=== Decision Analytics: ${metrics.title} ===
5307
5518
  `));
5308
- console.log(chalk14.bold("Overview:"));
5519
+ console.log(chalk16.bold("Overview:"));
5309
5520
  console.log(` ID: ${metrics.decisionId}`);
5310
5521
  console.log(` Current Violations: ${metrics.totalViolations}`);
5311
5522
  console.log(` Average Compliance: ${metrics.averageComplianceScore.toFixed(1)}%`);
5312
5523
  const trendEmoji = metrics.trendDirection === "up" ? "\u{1F4C8}" : metrics.trendDirection === "down" ? "\u{1F4C9}" : "\u27A1\uFE0F";
5313
- const trendColor = metrics.trendDirection === "up" ? chalk14.green : metrics.trendDirection === "down" ? chalk14.red : chalk14.yellow;
5524
+ const trendColor = metrics.trendDirection === "up" ? chalk16.green : metrics.trendDirection === "down" ? chalk16.red : chalk16.yellow;
5314
5525
  console.log(` ${trendColor(`${trendEmoji} Trend: ${metrics.trendDirection.toUpperCase()}`)}`);
5315
5526
  if (metrics.history.length > 0) {
5316
- console.log(chalk14.bold("\nCompliance History:"));
5527
+ console.log(chalk16.bold("\nCompliance History:"));
5317
5528
  const recentHistory = metrics.history.slice(-10);
5318
5529
  recentHistory.forEach((h) => {
5319
5530
  const icon = h.violations === 0 ? "\u2705" : "\u26A0\uFE0F";
@@ -5322,58 +5533,58 @@ var analyticsCommand = new Command16("analytics").description("Analyze complianc
5322
5533
  }
5323
5534
  } else {
5324
5535
  const summary = await engine.generateSummary(history);
5325
- console.log("\n" + chalk14.blue.bold("=== Overall Analytics ===\n"));
5326
- console.log(chalk14.bold("Summary:"));
5536
+ console.log("\n" + chalk16.blue.bold("=== Overall Analytics ===\n"));
5537
+ console.log(chalk16.bold("Summary:"));
5327
5538
  console.log(` Total Decisions: ${summary.totalDecisions}`);
5328
5539
  console.log(` Average Compliance: ${summary.averageCompliance}%`);
5329
5540
  console.log(` Critical Issues: ${summary.criticalIssues}`);
5330
5541
  const trendEmoji = summary.overallTrend === "up" ? "\u{1F4C8}" : summary.overallTrend === "down" ? "\u{1F4C9}" : "\u27A1\uFE0F";
5331
- const trendColor = summary.overallTrend === "up" ? chalk14.green : summary.overallTrend === "down" ? chalk14.red : chalk14.yellow;
5542
+ const trendColor = summary.overallTrend === "up" ? chalk16.green : summary.overallTrend === "down" ? chalk16.red : chalk16.yellow;
5332
5543
  console.log(` ${trendColor(`${trendEmoji} Overall Trend: ${summary.overallTrend.toUpperCase()}`)}`);
5333
5544
  if (summary.topDecisions.length > 0) {
5334
- console.log(chalk14.green("\n\u2705 Top Performing Decisions:"));
5545
+ console.log(chalk16.green("\n\u2705 Top Performing Decisions:"));
5335
5546
  summary.topDecisions.forEach((d, i) => {
5336
5547
  console.log(` ${i + 1}. ${d.title}: ${d.compliance}%`);
5337
5548
  });
5338
5549
  }
5339
5550
  if (summary.bottomDecisions.length > 0) {
5340
- console.log(chalk14.red("\n\u26A0\uFE0F Decisions Needing Attention:"));
5551
+ console.log(chalk16.red("\n\u26A0\uFE0F Decisions Needing Attention:"));
5341
5552
  summary.bottomDecisions.forEach((d, i) => {
5342
5553
  console.log(` ${i + 1}. ${d.title}: ${d.compliance}%`);
5343
5554
  });
5344
5555
  }
5345
5556
  if (options.insights || summary.criticalIssues > 0) {
5346
- console.log(chalk14.blue.bold("\n=== Insights ===\n"));
5557
+ console.log(chalk16.blue.bold("\n=== Insights ===\n"));
5347
5558
  const insights = summary.insights;
5348
5559
  const warnings = insights.filter((i) => i.type === "warning");
5349
5560
  const successes = insights.filter((i) => i.type === "success");
5350
5561
  const infos = insights.filter((i) => i.type === "info");
5351
5562
  if (warnings.length > 0) {
5352
- console.log(chalk14.red("\u26A0\uFE0F Warnings:"));
5563
+ console.log(chalk16.red("\u26A0\uFE0F Warnings:"));
5353
5564
  warnings.forEach((i) => {
5354
5565
  console.log(` \u2022 ${i.message}`);
5355
5566
  if (i.details) {
5356
- console.log(chalk14.gray(` ${i.details}`));
5567
+ console.log(chalk16.gray(` ${i.details}`));
5357
5568
  }
5358
5569
  });
5359
5570
  console.log("");
5360
5571
  }
5361
5572
  if (successes.length > 0) {
5362
- console.log(chalk14.green("\u2705 Positive Trends:"));
5573
+ console.log(chalk16.green("\u2705 Positive Trends:"));
5363
5574
  successes.forEach((i) => {
5364
5575
  console.log(` \u2022 ${i.message}`);
5365
5576
  if (i.details) {
5366
- console.log(chalk14.gray(` ${i.details}`));
5577
+ console.log(chalk16.gray(` ${i.details}`));
5367
5578
  }
5368
5579
  });
5369
5580
  console.log("");
5370
5581
  }
5371
5582
  if (infos.length > 0) {
5372
- console.log(chalk14.blue("\u{1F4A1} Suggestions:"));
5583
+ console.log(chalk16.blue("\u{1F4A1} Suggestions:"));
5373
5584
  infos.forEach((i) => {
5374
5585
  console.log(` \u2022 ${i.message}`);
5375
5586
  if (i.details) {
5376
- console.log(chalk14.gray(` ${i.details}`));
5587
+ console.log(chalk16.gray(` ${i.details}`));
5377
5588
  }
5378
5589
  });
5379
5590
  console.log("");
@@ -5383,10 +5594,10 @@ var analyticsCommand = new Command16("analytics").description("Analyze complianc
5383
5594
  const latestEntry = history[history.length - 1];
5384
5595
  const oldestEntry = history[0];
5385
5596
  if (latestEntry && oldestEntry) {
5386
- console.log(chalk14.gray(`
5597
+ console.log(chalk16.gray(`
5387
5598
  Data range: ${latestEntry.timestamp} to ${oldestEntry.timestamp}`));
5388
5599
  }
5389
- console.log(chalk14.gray(`Analyzing ${history.length} report(s) over ${days} days
5600
+ console.log(chalk16.gray(`Analyzing ${history.length} report(s) over ${days} days
5390
5601
  `));
5391
5602
  } catch (error) {
5392
5603
  spinner.fail("Analytics failed");
@@ -5396,7 +5607,7 @@ Data range: ${latestEntry.timestamp} to ${oldestEntry.timestamp}`));
5396
5607
 
5397
5608
  // src/cli/commands/dashboard.ts
5398
5609
  import { Command as Command17 } from "commander";
5399
- import chalk15 from "chalk";
5610
+ import chalk17 from "chalk";
5400
5611
 
5401
5612
  // src/dashboard/server.ts
5402
5613
  import express from "express";
@@ -5611,42 +5822,325 @@ var dashboardCommand = new Command17("dashboard").description("Start compliance
5611
5822
  if (!await pathExists(getSpecBridgeDir(cwd))) {
5612
5823
  throw new NotInitializedError();
5613
5824
  }
5614
- console.log(chalk15.blue("Starting SpecBridge dashboard..."));
5825
+ console.log(chalk17.blue("Starting SpecBridge dashboard..."));
5615
5826
  try {
5616
5827
  const config = await loadConfig(cwd);
5617
5828
  const app = createDashboardServer({ cwd, config });
5618
5829
  const port = parseInt(options.port || "3000", 10);
5619
5830
  const host = options.host || "localhost";
5620
5831
  app.listen(port, host, () => {
5621
- console.log(chalk15.green(`
5832
+ console.log(chalk17.green(`
5622
5833
  \u2713 Dashboard running at http://${host}:${port}`));
5623
- console.log(chalk15.gray(" Press Ctrl+C to stop\n"));
5624
- console.log(chalk15.bold("API Endpoints:"));
5625
- console.log(` ${chalk15.cyan(`http://${host}:${port}/api/health`)} - Health check`);
5626
- console.log(` ${chalk15.cyan(`http://${host}:${port}/api/report/latest`)} - Latest report`);
5627
- console.log(` ${chalk15.cyan(`http://${host}:${port}/api/decisions`)} - All decisions`);
5628
- console.log(` ${chalk15.cyan(`http://${host}:${port}/api/analytics/summary`)} - Analytics`);
5834
+ console.log(chalk17.gray(" Press Ctrl+C to stop\n"));
5835
+ console.log(chalk17.bold("API Endpoints:"));
5836
+ console.log(` ${chalk17.cyan(`http://${host}:${port}/api/health`)} - Health check`);
5837
+ console.log(` ${chalk17.cyan(`http://${host}:${port}/api/report/latest`)} - Latest report`);
5838
+ console.log(` ${chalk17.cyan(`http://${host}:${port}/api/decisions`)} - All decisions`);
5839
+ console.log(` ${chalk17.cyan(`http://${host}:${port}/api/analytics/summary`)} - Analytics`);
5629
5840
  console.log("");
5630
5841
  });
5631
5842
  process.on("SIGINT", () => {
5632
- console.log(chalk15.yellow("\n\nShutting down dashboard..."));
5843
+ console.log(chalk17.yellow("\n\nShutting down dashboard..."));
5633
5844
  process.exit(0);
5634
5845
  });
5635
5846
  process.on("SIGTERM", () => {
5636
- console.log(chalk15.yellow("\n\nShutting down dashboard..."));
5847
+ console.log(chalk17.yellow("\n\nShutting down dashboard..."));
5637
5848
  process.exit(0);
5638
5849
  });
5639
5850
  } catch (error) {
5640
- console.error(chalk15.red("Failed to start dashboard:"), error);
5851
+ console.error(chalk17.red("Failed to start dashboard:"), error);
5852
+ throw error;
5853
+ }
5854
+ });
5855
+
5856
+ // src/cli/commands/impact.ts
5857
+ import { Command as Command18 } from "commander";
5858
+ import chalk18 from "chalk";
5859
+ import ora8 from "ora";
5860
+
5861
+ // src/propagation/graph.ts
5862
+ async function buildDependencyGraph2(decisions, files) {
5863
+ const nodes = /* @__PURE__ */ new Map();
5864
+ const decisionToFiles = /* @__PURE__ */ new Map();
5865
+ const fileToDecisions = /* @__PURE__ */ new Map();
5866
+ for (const decision of decisions) {
5867
+ const decisionId = `decision:${decision.metadata.id}`;
5868
+ nodes.set(decisionId, {
5869
+ type: "decision",
5870
+ id: decision.metadata.id,
5871
+ edges: decision.constraints.map((c) => `constraint:${decision.metadata.id}/${c.id}`)
5872
+ });
5873
+ for (const constraint of decision.constraints) {
5874
+ const constraintId = `constraint:${decision.metadata.id}/${constraint.id}`;
5875
+ const matchingFiles = [];
5876
+ for (const file of files) {
5877
+ if (matchesPattern(file, constraint.scope)) {
5878
+ matchingFiles.push(`file:${file}`);
5879
+ const fileDecisions = fileToDecisions.get(file) || /* @__PURE__ */ new Set();
5880
+ fileDecisions.add(decision.metadata.id);
5881
+ fileToDecisions.set(file, fileDecisions);
5882
+ const decFiles = decisionToFiles.get(decision.metadata.id) || /* @__PURE__ */ new Set();
5883
+ decFiles.add(file);
5884
+ decisionToFiles.set(decision.metadata.id, decFiles);
5885
+ }
5886
+ }
5887
+ nodes.set(constraintId, {
5888
+ type: "constraint",
5889
+ id: `${decision.metadata.id}/${constraint.id}`,
5890
+ edges: matchingFiles
5891
+ });
5892
+ }
5893
+ }
5894
+ for (const file of files) {
5895
+ const fileId = `file:${file}`;
5896
+ if (!nodes.has(fileId)) {
5897
+ nodes.set(fileId, {
5898
+ type: "file",
5899
+ id: file,
5900
+ edges: []
5901
+ });
5902
+ }
5903
+ }
5904
+ return {
5905
+ nodes,
5906
+ decisionToFiles,
5907
+ fileToDecisions
5908
+ };
5909
+ }
5910
+ function getAffectedFiles(graph, decisionId) {
5911
+ const files = graph.decisionToFiles.get(decisionId);
5912
+ return files ? Array.from(files) : [];
5913
+ }
5914
+
5915
+ // src/propagation/engine.ts
5916
+ var PropagationEngine = class {
5917
+ registry;
5918
+ graph = null;
5919
+ constructor(registry) {
5920
+ this.registry = registry || createRegistry();
5921
+ }
5922
+ /**
5923
+ * Initialize the engine with current state
5924
+ */
5925
+ async initialize(config, options = {}) {
5926
+ const { cwd = process.cwd() } = options;
5927
+ await this.registry.load();
5928
+ const files = await glob(config.project.sourceRoots, {
5929
+ cwd,
5930
+ ignore: config.project.exclude,
5931
+ absolute: true
5932
+ });
5933
+ const decisions = this.registry.getActive();
5934
+ this.graph = await buildDependencyGraph2(decisions, files);
5935
+ }
5936
+ /**
5937
+ * Analyze impact of changing a decision
5938
+ */
5939
+ async analyzeImpact(decisionId, change, config, options = {}) {
5940
+ const { cwd = process.cwd() } = options;
5941
+ if (!this.graph) {
5942
+ await this.initialize(config, options);
5943
+ }
5944
+ const affectedFilePaths = getAffectedFiles(this.graph, decisionId);
5945
+ const verificationEngine = createVerificationEngine(this.registry);
5946
+ const result = await verificationEngine.verify(config, {
5947
+ files: affectedFilePaths,
5948
+ decisions: [decisionId],
5949
+ cwd
5950
+ });
5951
+ const fileViolations = /* @__PURE__ */ new Map();
5952
+ for (const violation of result.violations) {
5953
+ const existing = fileViolations.get(violation.file) || { total: 0, autoFixable: 0 };
5954
+ existing.total++;
5955
+ if (violation.autofix) {
5956
+ existing.autoFixable++;
5957
+ }
5958
+ fileViolations.set(violation.file, existing);
5959
+ }
5960
+ const affectedFiles = affectedFilePaths.map((path5) => ({
5961
+ path: path5,
5962
+ violations: fileViolations.get(path5)?.total || 0,
5963
+ autoFixable: fileViolations.get(path5)?.autoFixable || 0
5964
+ }));
5965
+ affectedFiles.sort((a, b) => b.violations - a.violations);
5966
+ const totalViolations = result.violations.length;
5967
+ const totalAutoFixable = result.violations.filter((v) => v.autofix).length;
5968
+ const manualFixes = totalViolations - totalAutoFixable;
5969
+ let estimatedEffort;
5970
+ if (manualFixes === 0) {
5971
+ estimatedEffort = "low";
5972
+ } else if (manualFixes <= 10) {
5973
+ estimatedEffort = "medium";
5974
+ } else {
5975
+ estimatedEffort = "high";
5976
+ }
5977
+ const migrationSteps = this.generateMigrationSteps(
5978
+ affectedFiles,
5979
+ totalAutoFixable > 0
5980
+ );
5981
+ return {
5982
+ decision: decisionId,
5983
+ change,
5984
+ affectedFiles,
5985
+ estimatedEffort,
5986
+ migrationSteps
5987
+ };
5988
+ }
5989
+ /**
5990
+ * Generate migration steps
5991
+ */
5992
+ generateMigrationSteps(affectedFiles, hasAutoFixes) {
5993
+ const steps = [];
5994
+ let order = 1;
5995
+ if (hasAutoFixes) {
5996
+ steps.push({
5997
+ order: order++,
5998
+ description: "Run auto-fix for mechanical violations",
5999
+ files: affectedFiles.filter((f) => f.autoFixable > 0).map((f) => f.path),
6000
+ automated: true
6001
+ });
6002
+ }
6003
+ const filesWithManualFixes = affectedFiles.filter(
6004
+ (f) => f.violations > f.autoFixable
6005
+ );
6006
+ if (filesWithManualFixes.length > 0) {
6007
+ const highPriority = filesWithManualFixes.filter((f) => f.violations > 5);
6008
+ const mediumPriority = filesWithManualFixes.filter(
6009
+ (f) => f.violations <= 5 && f.violations > 1
6010
+ );
6011
+ const lowPriority = filesWithManualFixes.filter((f) => f.violations === 1);
6012
+ if (highPriority.length > 0) {
6013
+ steps.push({
6014
+ order: order++,
6015
+ description: "Fix high-violation files first",
6016
+ files: highPriority.map((f) => f.path),
6017
+ automated: false
6018
+ });
6019
+ }
6020
+ if (mediumPriority.length > 0) {
6021
+ steps.push({
6022
+ order: order++,
6023
+ description: "Fix medium-violation files",
6024
+ files: mediumPriority.map((f) => f.path),
6025
+ automated: false
6026
+ });
6027
+ }
6028
+ if (lowPriority.length > 0) {
6029
+ steps.push({
6030
+ order: order++,
6031
+ description: "Fix remaining files",
6032
+ files: lowPriority.map((f) => f.path),
6033
+ automated: false
6034
+ });
6035
+ }
6036
+ }
6037
+ steps.push({
6038
+ order: order++,
6039
+ description: "Run verification to confirm all violations resolved",
6040
+ files: [],
6041
+ automated: true
6042
+ });
6043
+ return steps;
6044
+ }
6045
+ /**
6046
+ * Get dependency graph
6047
+ */
6048
+ getGraph() {
6049
+ return this.graph;
6050
+ }
6051
+ };
6052
+ function createPropagationEngine(registry) {
6053
+ return new PropagationEngine(registry);
6054
+ }
6055
+
6056
+ // src/cli/commands/impact.ts
6057
+ var impactCommand = new Command18("impact").description("Analyze impact of decision changes").argument("<decision-id>", "Decision ID to analyze").option("-c, --change <type>", "Type of change (created, modified, deprecated)", "modified").option("--json", "Output as JSON").option("--show-steps", "Show detailed migration steps", true).action(async (decisionId, options) => {
6058
+ const cwd = process.cwd();
6059
+ if (!await pathExists(getSpecBridgeDir(cwd))) {
6060
+ throw new NotInitializedError();
6061
+ }
6062
+ const spinner = ora8("Loading configuration...").start();
6063
+ try {
6064
+ const config = await loadConfig(cwd);
6065
+ const changeType = options.change || "modified";
6066
+ if (!["created", "modified", "deprecated"].includes(changeType)) {
6067
+ spinner.fail();
6068
+ console.error(chalk18.red(`Invalid change type: ${changeType}`));
6069
+ console.error(chalk18.dim("Valid types: created, modified, deprecated"));
6070
+ process.exit(1);
6071
+ }
6072
+ spinner.text = `Analyzing impact of ${changeType} decision ${decisionId}...`;
6073
+ const engine = createPropagationEngine();
6074
+ const analysis = await engine.analyzeImpact(decisionId, changeType, config, { cwd });
6075
+ spinner.stop();
6076
+ if (options.json) {
6077
+ console.log(JSON.stringify(analysis, null, 2));
6078
+ } else {
6079
+ printImpactAnalysis(analysis, options.showSteps !== false);
6080
+ }
6081
+ } catch (error) {
6082
+ spinner.fail("Impact analysis failed");
5641
6083
  throw error;
5642
6084
  }
5643
6085
  });
6086
+ function printImpactAnalysis(analysis, showSteps) {
6087
+ console.log(chalk18.bold(`
6088
+ === Impact Analysis: ${analysis.decision} ===
6089
+ `));
6090
+ const changeLabel = chalk18.cyan(analysis.change);
6091
+ console.log(`Change Type: ${changeLabel}`);
6092
+ const effortColor = analysis.estimatedEffort === "high" ? chalk18.red : analysis.estimatedEffort === "medium" ? chalk18.yellow : chalk18.green;
6093
+ console.log(`Estimated Effort: ${effortColor(analysis.estimatedEffort.toUpperCase())}
6094
+ `);
6095
+ console.log(chalk18.bold(`Affected Files: ${analysis.affectedFiles.length}`));
6096
+ if (analysis.affectedFiles.length > 0) {
6097
+ const displayCount = Math.min(analysis.affectedFiles.length, 10);
6098
+ for (let i = 0; i < displayCount; i++) {
6099
+ const file = analysis.affectedFiles[i];
6100
+ if (!file) continue;
6101
+ const violationText = file.violations === 1 ? "1 violation" : `${file.violations} violations`;
6102
+ const autoFixText = file.autoFixable > 0 ? chalk18.green(` (${file.autoFixable} auto-fixable)`) : "";
6103
+ console.log(` ${chalk18.red("\u25CF")} ${file.path} - ${violationText}${autoFixText}`);
6104
+ }
6105
+ if (analysis.affectedFiles.length > displayCount) {
6106
+ const remaining = analysis.affectedFiles.length - displayCount;
6107
+ console.log(chalk18.dim(` ... and ${remaining} more file(s)`));
6108
+ }
6109
+ } else {
6110
+ console.log(chalk18.green(" No violations found"));
6111
+ }
6112
+ if (showSteps && analysis.migrationSteps && analysis.migrationSteps.length > 0) {
6113
+ console.log(chalk18.bold("\nMigration Plan:"));
6114
+ for (const step of analysis.migrationSteps) {
6115
+ const icon = step.automated ? "\u{1F916}" : "\u{1F464}";
6116
+ const typeLabel = step.automated ? chalk18.green("[Automated]") : chalk18.yellow("[Manual]");
6117
+ console.log(` ${icon} Step ${step.order}: ${step.description} ${typeLabel}`);
6118
+ if (step.files.length > 0) {
6119
+ const displayFiles = Math.min(step.files.length, 3);
6120
+ for (let i = 0; i < displayFiles; i++) {
6121
+ console.log(chalk18.dim(` - ${step.files[i]}`));
6122
+ }
6123
+ if (step.files.length > displayFiles) {
6124
+ console.log(chalk18.dim(` ... and ${step.files.length - displayFiles} more file(s)`));
6125
+ }
6126
+ }
6127
+ console.log("");
6128
+ }
6129
+ }
6130
+ const totalViolations = analysis.affectedFiles.reduce((sum, f) => sum + f.violations, 0);
6131
+ const totalAutoFixable = analysis.affectedFiles.reduce((sum, f) => sum + f.autoFixable, 0);
6132
+ const manualFixes = totalViolations - totalAutoFixable;
6133
+ console.log(chalk18.bold("Summary:"));
6134
+ console.log(` Total Violations: ${totalViolations}`);
6135
+ console.log(` Auto-fixable: ${chalk18.green(totalAutoFixable)}`);
6136
+ console.log(` Manual Fixes Required: ${manualFixes > 0 ? chalk18.yellow(manualFixes) : chalk18.green(0)}`);
6137
+ }
5644
6138
 
5645
6139
  // src/cli/index.ts
5646
6140
  var __dirname2 = dirname5(fileURLToPath4(import.meta.url));
5647
6141
  var packageJsonPath = join12(__dirname2, "../package.json");
5648
6142
  var packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
5649
- var program = new Command18();
6143
+ var program = new Command19();
5650
6144
  program.name("specbridge").description("Architecture Decision Runtime - Transform architectural decisions into executable, verifiable constraints").version(packageJson.version);
5651
6145
  program.addCommand(initCommand);
5652
6146
  program.addCommand(inferCommand);
@@ -5661,6 +6155,7 @@ program.addCommand(mcpServerCommand);
5661
6155
  program.addCommand(promptCommand);
5662
6156
  program.addCommand(analyticsCommand);
5663
6157
  program.addCommand(dashboardCommand);
6158
+ program.addCommand(impactCommand);
5664
6159
  program.exitOverride((err) => {
5665
6160
  if (err.code === "commander.help" || err.code === "commander.helpDisplayed") {
5666
6161
  process.exit(0);
@@ -5668,11 +6163,11 @@ program.exitOverride((err) => {
5668
6163
  if (err.code === "commander.version") {
5669
6164
  process.exit(0);
5670
6165
  }
5671
- console.error(chalk16.red(formatError(err)));
6166
+ console.error(chalk19.red(formatError(err)));
5672
6167
  process.exit(1);
5673
6168
  });
5674
6169
  program.parseAsync(process.argv).catch((error) => {
5675
- console.error(chalk16.red(formatError(error)));
6170
+ console.error(chalk19.red(formatError(error)));
5676
6171
  process.exit(1);
5677
6172
  });
5678
6173
  //# sourceMappingURL=cli.js.map