@aiready/cli 0.14.21 → 0.14.23

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
@@ -25,286 +25,22 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
 
26
26
  // src/cli.ts
27
27
  var import_commander = require("commander");
28
- var import_fs7 = require("fs");
29
- var import_path9 = require("path");
28
+ var import_fs8 = require("fs");
29
+ var import_path7 = require("path");
30
30
  var import_url = require("url");
31
31
 
32
32
  // src/commands/scan.ts
33
- var import_chalk4 = __toESM(require("chalk"));
34
- var import_fs3 = require("fs");
35
- var import_path3 = require("path");
36
- var import_core6 = require("@aiready/core");
37
-
38
- // src/index.ts
39
- var import_core = require("@aiready/core");
40
- var import_pattern_detect = require("@aiready/pattern-detect");
41
- var import_context_analyzer = require("@aiready/context-analyzer");
42
- var import_consistency = require("@aiready/consistency");
43
- var import_ai_signal_clarity = require("@aiready/ai-signal-clarity");
44
- var import_agent_grounding = require("@aiready/agent-grounding");
45
- var import_testability = require("@aiready/testability");
46
- var import_doc_drift = require("@aiready/doc-drift");
47
- var import_deps = require("@aiready/deps");
48
- var import_change_amplification = require("@aiready/change-amplification");
49
- var TOOL_PACKAGE_MAP = {
50
- [import_core.ToolName.PatternDetect]: "@aiready/pattern-detect",
51
- [import_core.ToolName.ContextAnalyzer]: "@aiready/context-analyzer",
52
- [import_core.ToolName.NamingConsistency]: "@aiready/consistency",
53
- [import_core.ToolName.AiSignalClarity]: "@aiready/ai-signal-clarity",
54
- [import_core.ToolName.AgentGrounding]: "@aiready/agent-grounding",
55
- [import_core.ToolName.TestabilityIndex]: "@aiready/testability",
56
- [import_core.ToolName.DocDrift]: "@aiready/doc-drift",
57
- [import_core.ToolName.DependencyHealth]: "@aiready/deps",
58
- [import_core.ToolName.ChangeAmplification]: "@aiready/change-amplification",
59
- // Aliases handled by registry
60
- patterns: "@aiready/pattern-detect",
61
- duplicates: "@aiready/pattern-detect",
62
- context: "@aiready/context-analyzer",
63
- fragmentation: "@aiready/context-analyzer",
64
- consistency: "@aiready/consistency",
65
- "ai-signal": "@aiready/ai-signal-clarity",
66
- grounding: "@aiready/agent-grounding",
67
- testability: "@aiready/testability",
68
- "deps-health": "@aiready/deps",
69
- "change-amp": "@aiready/change-amplification"
70
- };
71
- function sanitizeConfigRecursive(obj) {
72
- if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
73
- const sanitized = {};
74
- const infraToStrip = [
75
- "rootDir",
76
- "onProgress",
77
- "progressCallback",
78
- "streamResults",
79
- "batchSize",
80
- "useSmartDefaults"
81
- ];
82
- for (const [key, value] of Object.entries(obj)) {
83
- if (infraToStrip.includes(key)) continue;
84
- if (typeof value === "object" && value !== null && !Array.isArray(value)) {
85
- sanitized[key] = sanitizeConfigRecursive(value);
86
- } else {
87
- sanitized[key] = value;
88
- }
89
- }
90
- return sanitized;
91
- }
92
- function sanitizeToolConfig(config) {
93
- return sanitizeConfigRecursive(config);
94
- }
95
- async function analyzeUnified(options) {
96
- await (0, import_core.initializeParsers)();
97
- const startTime = Date.now();
98
- const requestedTools = options.tools ?? [
99
- "patterns",
100
- "context",
101
- "consistency"
102
- ];
103
- const result = {
104
- summary: {
105
- totalIssues: 0,
106
- criticalIssues: 0,
107
- // Added as per instruction
108
- majorIssues: 0,
109
- // Added as per instruction
110
- totalFiles: 0,
111
- toolsRun: [],
112
- executionTime: 0,
113
- config: options,
114
- toolConfigs: {}
115
- }
116
- };
117
- for (const toolName of requestedTools) {
118
- let provider = import_core.ToolRegistry.find(toolName);
119
- if (!provider) {
120
- const packageName = TOOL_PACKAGE_MAP[toolName] ?? (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
121
- try {
122
- await import(packageName);
123
- provider = import_core.ToolRegistry.find(toolName);
124
- if (provider) {
125
- console.log(
126
- `\u2705 Successfully loaded tool provider: ${toolName} from ${packageName}`
127
- );
128
- } else {
129
- console.log(
130
- `\u26A0\uFE0F Loaded ${packageName} but provider ${toolName} still not found in registry.`
131
- );
132
- }
133
- } catch (err) {
134
- console.log(
135
- `\u274C Failed to dynamically load tool ${toolName} (${packageName}):`,
136
- err.message
137
- );
138
- }
139
- }
140
- if (!provider) {
141
- console.warn(
142
- `\u26A0\uFE0F Warning: Tool provider for '${toolName}' not found. Skipping.`
143
- );
144
- continue;
145
- }
146
- try {
147
- const sanitizedOptions = { ...options };
148
- delete sanitizedOptions.onProgress;
149
- delete sanitizedOptions.progressCallback;
150
- const toolOptions = {
151
- rootDir: options.rootDir
152
- // Always include rootDir
153
- };
154
- [...import_core.GLOBAL_INFRA_OPTIONS, ...import_core.COMMON_FINE_TUNING_OPTIONS].forEach(
155
- (key) => {
156
- if (key in options && key !== "toolConfigs" && key !== "tools") {
157
- toolOptions[key] = options[key];
158
- }
159
- }
160
- );
161
- if (options.toolConfigs?.[provider.id]) {
162
- Object.assign(toolOptions, options.toolConfigs[provider.id]);
163
- } else if (options.tools && !Array.isArray(options.tools) && typeof options.tools === "object" && options.tools[provider.id]) {
164
- Object.assign(toolOptions, options.tools[provider.id]);
165
- } else if (options[provider.id]) {
166
- Object.assign(toolOptions, options[provider.id]);
167
- }
168
- toolOptions.onProgress = (processed, total, message) => {
169
- if (options.progressCallback) {
170
- options.progressCallback({
171
- tool: provider.id,
172
- processed,
173
- total,
174
- message
175
- });
176
- }
177
- };
178
- const output = await provider.analyze(toolOptions);
179
- if (output.metadata) {
180
- output.metadata.config = sanitizeToolConfig(toolOptions);
181
- }
182
- if (options.progressCallback) {
183
- options.progressCallback({ tool: provider.id, data: output });
184
- }
185
- result[provider.id] = output;
186
- result.summary.toolsRun.push(provider.id);
187
- if (output.summary?.config) {
188
- result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
189
- output.summary.config
190
- );
191
- } else if (output.metadata?.config) {
192
- result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
193
- output.metadata.config
194
- );
195
- } else {
196
- result.summary.toolConfigs[provider.id] = sanitizeToolConfig(toolOptions);
197
- }
198
- const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
199
- if (toolFiles > result.summary.totalFiles) {
200
- result.summary.totalFiles = toolFiles;
201
- }
202
- const issueCount = output.results.reduce(
203
- (sum, file) => sum + (file.issues?.length ?? 0),
204
- 0
205
- );
206
- result.summary.totalIssues += issueCount;
207
- } catch (err) {
208
- console.error(`\u274C Error running tool '${provider.id}':`, err);
209
- }
210
- }
211
- result.summary.config = sanitizeConfigRecursive({
212
- scan: {
213
- tools: requestedTools,
214
- include: options.include,
215
- exclude: options.exclude
216
- },
217
- // Use 'tools' for tool-specific configurations to match AIReadyConfig
218
- tools: result.summary.toolConfigs
219
- });
220
- result.summary.executionTime = Date.now() - startTime;
221
- const keyMappings = {
222
- "pattern-detect": ["patternDetect", "patterns"],
223
- "context-analyzer": ["contextAnalyzer", "context"],
224
- "naming-consistency": ["namingConsistency", "consistency"],
225
- "ai-signal-clarity": ["aiSignalClarity"],
226
- "agent-grounding": ["agentGrounding"],
227
- "testability-index": ["testabilityIndex", "testability"],
228
- "doc-drift": ["docDrift"],
229
- "dependency-health": ["dependencyHealth", "deps"],
230
- "change-amplification": ["changeAmplification"]
231
- };
232
- for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
233
- if (result[kebabKey]) {
234
- for (const alias of aliases) {
235
- result[alias] = result[kebabKey];
236
- }
237
- }
238
- }
239
- return result;
240
- }
241
- async function scoreUnified(results, options) {
242
- const toolScores = /* @__PURE__ */ new Map();
243
- for (const toolId of results.summary.toolsRun) {
244
- const provider = import_core.ToolRegistry.get(toolId);
245
- if (!provider) continue;
246
- const output = results[toolId];
247
- if (!output) continue;
248
- try {
249
- const toolScore = provider.score(output, options);
250
- if (!toolScore.tokenBudget) {
251
- if (toolId === import_core.ToolName.PatternDetect && output.duplicates) {
252
- const wastedTokens = output.duplicates.reduce(
253
- (sum, d) => sum + (d.tokenCost ?? 0),
254
- 0
255
- );
256
- toolScore.tokenBudget = (0, import_core.calculateTokenBudget)({
257
- totalContextTokens: wastedTokens * 2,
258
- wastedTokens: {
259
- duplication: wastedTokens,
260
- fragmentation: 0,
261
- chattiness: 0
262
- }
263
- });
264
- } else if (toolId === import_core.ToolName.ContextAnalyzer && output.summary) {
265
- toolScore.tokenBudget = (0, import_core.calculateTokenBudget)({
266
- totalContextTokens: output.summary.totalTokens,
267
- wastedTokens: {
268
- duplication: 0,
269
- fragmentation: output.summary.totalPotentialSavings ?? 0,
270
- chattiness: 0
271
- }
272
- });
273
- }
274
- }
275
- toolScores.set(toolId, toolScore);
276
- } catch (err) {
277
- console.error(`\u274C Error scoring tool '${toolId}':`, err);
278
- }
279
- }
280
- if (toolScores.size === 0) {
281
- return {
282
- overall: 0,
283
- rating: "Critical",
284
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
285
- toolsUsed: [],
286
- breakdown: [],
287
- calculation: {
288
- formula: "0 / 0 = 0",
289
- weights: {},
290
- normalized: "0 / 0 = 0"
291
- }
292
- };
293
- }
294
- return (0, import_core.calculateOverallScore)(toolScores, options, void 0);
295
- }
33
+ var import_chalk6 = __toESM(require("chalk"));
34
+ var import_fs4 = require("fs");
35
+ var import_path4 = require("path");
36
+ var import_core9 = require("@aiready/core");
296
37
 
297
38
  // src/utils/helpers.ts
298
39
  var import_path = require("path");
299
40
  var import_fs = require("fs");
300
41
  var import_chalk = __toESM(require("chalk"));
42
+ var import_core = require("@aiready/core");
301
43
  var import_core2 = require("@aiready/core");
302
- var import_core3 = require("@aiready/core");
303
- function getReportTimestamp() {
304
- const now = /* @__PURE__ */ new Date();
305
- const pad = (n) => String(n).padStart(2, "0");
306
- return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
307
- }
308
44
  async function warnIfGraphCapExceeded(report, dirPath) {
309
45
  try {
310
46
  const { loadConfig: loadConfig4 } = await import("@aiready/core");
@@ -393,7 +129,7 @@ function generateMarkdownReport(report, elapsedTime) {
393
129
 
394
130
  // src/commands/report-formatter.ts
395
131
  var import_chalk2 = __toESM(require("chalk"));
396
- var import_core4 = require("@aiready/core");
132
+ var import_core3 = require("@aiready/core");
397
133
  function generateProgressBar(score, width = 20) {
398
134
  const filled = Math.round(score / 100 * width);
399
135
  const empty = width - filled;
@@ -498,31 +234,34 @@ function printBusinessImpact(roi, unifiedBudget) {
498
234
  }
499
235
  function printScoring(scoringResult, scoringProfile) {
500
236
  console.log(import_chalk2.default.bold("\n\u{1F4CA} AI Readiness Overall Score"));
501
- console.log(` ${(0, import_core4.formatScore)(scoringResult)}`);
237
+ console.log(` ${(0, import_core3.formatScore)(scoringResult)}`);
502
238
  console.log(import_chalk2.default.dim(` (Scoring Profile: ${scoringProfile})`));
503
239
  if (scoringResult.breakdown) {
504
240
  console.log(import_chalk2.default.bold("\nTool breakdown:"));
505
241
  scoringResult.breakdown.forEach((tool) => {
506
- const rating = (0, import_core4.getRating)(tool.score);
507
- const emoji = (0, import_core4.getRatingDisplay)(rating).emoji;
242
+ const rating = (0, import_core3.getRating)(tool.score);
243
+ const emoji = (0, import_core3.getRatingDisplay)(rating).emoji;
508
244
  const progressBar = generateProgressBar(tool.score, 15);
509
245
  console.log(
510
246
  ` ${progressBar} ${tool.score}/100 (${rating}) ${emoji} ${tool.toolName}`
511
247
  );
512
248
  });
513
- const allRecs = scoringResult.breakdown.flatMap(
514
- (t) => (t.recommendations ?? []).map((r) => ({ ...r, tool: t.toolName }))
515
- ).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 5);
516
- if (allRecs.length > 0) {
517
- console.log(import_chalk2.default.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
518
- allRecs.forEach((rec, i) => {
519
- const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
520
- console.log(` ${i + 1}. ${priorityIcon} ${import_chalk2.default.bold(rec.action)}`);
521
- console.log(
522
- ` Impact: ${import_chalk2.default.green(`+${rec.estimatedImpact} points`)} to ${rec.tool}`
523
- );
524
- });
525
- }
249
+ printTopRecommendations(scoringResult.breakdown);
250
+ }
251
+ }
252
+ function printTopRecommendations(breakdown) {
253
+ const allRecs = breakdown.flatMap(
254
+ (t) => (t.recommendations ?? []).map((r) => ({ ...r, tool: t.toolName }))
255
+ ).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 5);
256
+ if (allRecs.length > 0) {
257
+ console.log(import_chalk2.default.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
258
+ allRecs.forEach((rec, i) => {
259
+ const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
260
+ console.log(` ${i + 1}. ${priorityIcon} ${import_chalk2.default.bold(rec.action)}`);
261
+ console.log(
262
+ ` Impact: ${import_chalk2.default.green(`+${rec.estimatedImpact} points`)} to ${rec.tool}`
263
+ );
264
+ });
526
265
  }
527
266
  }
528
267
  function mapToUnifiedReport(res, scoring) {
@@ -537,9 +276,9 @@ function mapToUnifiedReport(res, scoring) {
537
276
  totalFilesSet.add(r.fileName);
538
277
  allResults.push(r);
539
278
  r.issues?.forEach((i) => {
540
- if (i.severity === import_core4.Severity.Critical || i.severity === "critical")
279
+ if (i.severity === import_core3.Severity.Critical || i.severity === "critical")
541
280
  criticalCount++;
542
- if (i.severity === import_core4.Severity.Major || i.severity === "major")
281
+ if (i.severity === import_core3.Severity.Major || i.severity === "major")
543
282
  majorCount++;
544
283
  });
545
284
  });
@@ -561,7 +300,7 @@ function mapToUnifiedReport(res, scoring) {
561
300
  var import_fs2 = __toESM(require("fs"));
562
301
  var import_path2 = require("path");
563
302
  var import_chalk3 = __toESM(require("chalk"));
564
- var import_core5 = require("@aiready/core");
303
+ var import_core4 = require("@aiready/core");
565
304
  async function uploadAction(file, options) {
566
305
  const startTime = Date.now();
567
306
  const filePath = (0, import_path2.resolve)(process.cwd(), file);
@@ -604,305 +343,595 @@ async function uploadAction(file, options) {
604
343
  // Might be null, server will handle mapping
605
344
  })
606
345
  });
607
- const contentType = response.headers.get("content-type");
608
- let uploadResult = {};
609
- if (contentType?.includes("application/json")) {
610
- uploadResult = await response.json();
611
- } else {
612
- const text = await response.text();
613
- uploadResult = { error: text ?? response.statusText };
346
+ const contentType = response.headers.get("content-type");
347
+ let uploadResult = {};
348
+ if (contentType?.includes("application/json")) {
349
+ uploadResult = await response.json();
350
+ } else {
351
+ const text = await response.text();
352
+ uploadResult = { error: text ?? response.statusText };
353
+ }
354
+ if (!response.ok) {
355
+ console.error(
356
+ import_chalk3.default.red(
357
+ `\u274C Upload failed: ${uploadResult.error ?? response.statusText}`
358
+ )
359
+ );
360
+ if (contentType?.includes("text/html")) {
361
+ console.log(
362
+ import_chalk3.default.yellow(
363
+ " Note: Received an HTML response. This often indicates a redirect (e.g., to a login page) or a server error."
364
+ )
365
+ );
366
+ if (uploadResult.error?.includes("Redirecting")) {
367
+ console.log(
368
+ import_chalk3.default.dim(
369
+ " Detected redirect. Check if the API endpoint requires authentication or has changed."
370
+ )
371
+ );
372
+ }
373
+ }
374
+ if (response.status === 401) {
375
+ console.log(
376
+ import_chalk3.default.dim(" Hint: Your API key may be invalid or expired.")
377
+ );
378
+ }
379
+ process.exit(1);
380
+ }
381
+ const duration = ((Date.now() - startTime) / 1e3).toFixed(2);
382
+ console.log(import_chalk3.default.green(`
383
+ \u2705 Upload successful! (${duration}s)`));
384
+ console.log(import_chalk3.default.cyan(` View results: ${serverUrl}/dashboard`));
385
+ if (uploadResult.analysis) {
386
+ console.log(import_chalk3.default.dim(` Analysis ID: ${uploadResult.analysis.id}`));
387
+ console.log(import_chalk3.default.dim(` Score: ${uploadResult.analysis.aiScore}/100`));
388
+ }
389
+ } catch (error) {
390
+ (0, import_core4.handleCLIError)(error, "Upload");
391
+ }
392
+ }
393
+ var UPLOAD_HELP_TEXT = `
394
+ EXAMPLES:
395
+ $ aiready upload report.json --api-key ar_...
396
+ $ aiready upload .aiready/latest.json
397
+ $ AIREADY_API_KEY=ar_... aiready upload report.json
398
+
399
+ ENVIRONMENT VARIABLES:
400
+ AIREADY_API_KEY Your platform API key
401
+ AIREADY_SERVER Custom platform URL (default: https://dev.platform.getaiready.dev)
402
+ `;
403
+
404
+ // src/commands/scan-config.ts
405
+ var import_core6 = require("@aiready/core");
406
+
407
+ // src/commands/scan-helpers.ts
408
+ var import_chalk4 = __toESM(require("chalk"));
409
+ var import_core5 = require("@aiready/core");
410
+ function getProfileTools(profile) {
411
+ switch (profile.toLowerCase()) {
412
+ case "agentic":
413
+ return [
414
+ import_core5.ToolName.AiSignalClarity,
415
+ import_core5.ToolName.AgentGrounding,
416
+ import_core5.ToolName.TestabilityIndex
417
+ ];
418
+ case "cost":
419
+ return [import_core5.ToolName.PatternDetect, import_core5.ToolName.ContextAnalyzer];
420
+ case "logic":
421
+ return [
422
+ import_core5.ToolName.TestabilityIndex,
423
+ import_core5.ToolName.NamingConsistency,
424
+ import_core5.ToolName.ContextAnalyzer,
425
+ import_core5.ToolName.PatternDetect,
426
+ import_core5.ToolName.ChangeAmplification
427
+ ];
428
+ case "ui":
429
+ return [
430
+ import_core5.ToolName.NamingConsistency,
431
+ import_core5.ToolName.ContextAnalyzer,
432
+ import_core5.ToolName.PatternDetect,
433
+ import_core5.ToolName.DocDrift,
434
+ import_core5.ToolName.AiSignalClarity
435
+ ];
436
+ case "security":
437
+ return [import_core5.ToolName.NamingConsistency, import_core5.ToolName.TestabilityIndex];
438
+ case "onboarding":
439
+ return [
440
+ import_core5.ToolName.ContextAnalyzer,
441
+ import_core5.ToolName.NamingConsistency,
442
+ import_core5.ToolName.AgentGrounding
443
+ ];
444
+ default:
445
+ console.log(
446
+ import_chalk4.default.yellow(`
447
+ \u26A0\uFE0F Unknown profile '${profile}'. Using defaults.`)
448
+ );
449
+ return void 0;
450
+ }
451
+ }
452
+ function createProgressCallback() {
453
+ return (event) => {
454
+ if (event.message) {
455
+ process.stdout.write(`\r\x1B[K [${event.tool}] ${event.message}`);
456
+ return;
457
+ }
458
+ process.stdout.write("\r\x1B[K");
459
+ console.log(import_chalk4.default.cyan(`--- ${event.tool.toUpperCase()} RESULTS ---`));
460
+ const toolResult = event.data;
461
+ if (toolResult && toolResult.summary) {
462
+ if (toolResult.summary.totalIssues !== void 0)
463
+ console.log(
464
+ ` Issues found: ${import_chalk4.default.bold(toolResult.summary.totalIssues)}`
465
+ );
466
+ if (toolResult.summary.score !== void 0)
467
+ console.log(
468
+ ` Tool Score: ${import_chalk4.default.bold(toolResult.summary.score)}/100`
469
+ );
470
+ if (toolResult.summary.totalFiles !== void 0)
471
+ console.log(
472
+ ` Files analyzed: ${import_chalk4.default.bold(toolResult.summary.totalFiles)}`
473
+ );
474
+ }
475
+ };
476
+ }
477
+
478
+ // src/commands/scan-config.ts
479
+ var SCAN_DEFAULTS = {
480
+ tools: [
481
+ "pattern-detect",
482
+ "context-analyzer",
483
+ "naming-consistency",
484
+ "ai-signal-clarity",
485
+ "agent-grounding",
486
+ "testability-index",
487
+ "doc-drift",
488
+ "dependency-health",
489
+ "change-amplification"
490
+ ],
491
+ include: void 0,
492
+ exclude: void 0,
493
+ output: {
494
+ format: "console",
495
+ file: void 0
496
+ }
497
+ };
498
+ async function resolveScanConfig(resolvedDir, options) {
499
+ let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
500
+ if (options.profile) {
501
+ profileTools = getProfileTools(options.profile);
502
+ }
503
+ const cliOverrides = {
504
+ include: options.include?.split(","),
505
+ exclude: options.exclude?.split(",")
506
+ };
507
+ if (profileTools) cliOverrides.tools = profileTools;
508
+ const baseOptions = await (0, import_core6.loadMergedConfig)(
509
+ resolvedDir,
510
+ SCAN_DEFAULTS,
511
+ cliOverrides
512
+ );
513
+ const finalOptions = { ...baseOptions };
514
+ if (baseOptions.tools.includes(import_core6.ToolName.PatternDetect) || baseOptions.tools.includes("patterns")) {
515
+ const { getSmartDefaults } = await import("@aiready/pattern-detect");
516
+ const patternSmartDefaults = await getSmartDefaults(
517
+ resolvedDir,
518
+ finalOptions.toolConfigs?.[import_core6.ToolName.PatternDetect] ?? {}
519
+ );
520
+ if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
521
+ finalOptions.toolConfigs[import_core6.ToolName.PatternDetect] = {
522
+ ...patternSmartDefaults,
523
+ ...finalOptions.toolConfigs[import_core6.ToolName.PatternDetect]
524
+ };
525
+ }
526
+ return finalOptions;
527
+ }
528
+
529
+ // src/commands/scan-orchestrator.ts
530
+ var import_chalk5 = __toESM(require("chalk"));
531
+ var import_fs3 = require("fs");
532
+ var import_path3 = require("path");
533
+ var import_core8 = require("@aiready/core");
534
+
535
+ // src/index.ts
536
+ var import_core7 = require("@aiready/core");
537
+ var TOOL_PACKAGE_MAP = {
538
+ [import_core7.ToolName.PatternDetect]: "@aiready/pattern-detect",
539
+ [import_core7.ToolName.ContextAnalyzer]: "@aiready/context-analyzer",
540
+ [import_core7.ToolName.NamingConsistency]: "@aiready/consistency",
541
+ [import_core7.ToolName.AiSignalClarity]: "@aiready/ai-signal-clarity",
542
+ [import_core7.ToolName.AgentGrounding]: "@aiready/agent-grounding",
543
+ [import_core7.ToolName.TestabilityIndex]: "@aiready/testability",
544
+ [import_core7.ToolName.DocDrift]: "@aiready/doc-drift",
545
+ [import_core7.ToolName.DependencyHealth]: "@aiready/deps",
546
+ [import_core7.ToolName.ChangeAmplification]: "@aiready/change-amplification",
547
+ // Aliases handled by registry
548
+ patterns: "@aiready/pattern-detect",
549
+ duplicates: "@aiready/pattern-detect",
550
+ context: "@aiready/context-analyzer",
551
+ fragmentation: "@aiready/context-analyzer",
552
+ consistency: "@aiready/consistency",
553
+ "ai-signal": "@aiready/ai-signal-clarity",
554
+ grounding: "@aiready/agent-grounding",
555
+ testability: "@aiready/testability",
556
+ "deps-health": "@aiready/deps",
557
+ "change-amp": "@aiready/change-amplification"
558
+ };
559
+ function sanitizeConfigRecursive(obj) {
560
+ if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
561
+ const sanitized = {};
562
+ const infraToStrip = [
563
+ "rootDir",
564
+ "onProgress",
565
+ "progressCallback",
566
+ "streamResults",
567
+ "batchSize",
568
+ "useSmartDefaults"
569
+ ];
570
+ for (const [key, value] of Object.entries(obj)) {
571
+ if (infraToStrip.includes(key)) continue;
572
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
573
+ sanitized[key] = sanitizeConfigRecursive(value);
574
+ } else {
575
+ sanitized[key] = value;
576
+ }
577
+ }
578
+ return sanitized;
579
+ }
580
+ function sanitizeToolConfig(config) {
581
+ return sanitizeConfigRecursive(config);
582
+ }
583
+ async function analyzeUnified(options) {
584
+ await (0, import_core7.initializeParsers)();
585
+ const startTime = Date.now();
586
+ const requestedTools = options.tools ?? [
587
+ "patterns",
588
+ "context",
589
+ "consistency"
590
+ ];
591
+ const result = {
592
+ summary: {
593
+ totalIssues: 0,
594
+ criticalIssues: 0,
595
+ // Added as per instruction
596
+ majorIssues: 0,
597
+ // Added as per instruction
598
+ totalFiles: 0,
599
+ toolsRun: [],
600
+ executionTime: 0,
601
+ config: options,
602
+ toolConfigs: {}
603
+ }
604
+ };
605
+ for (const toolName of requestedTools) {
606
+ let provider = import_core7.ToolRegistry.find(toolName);
607
+ if (!provider) {
608
+ const packageName = TOOL_PACKAGE_MAP[toolName] ?? (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
609
+ try {
610
+ await import(packageName);
611
+ provider = import_core7.ToolRegistry.find(toolName);
612
+ if (provider) {
613
+ console.log(
614
+ `\u2705 Successfully loaded tool provider: ${toolName} from ${packageName}`
615
+ );
616
+ } else {
617
+ console.log(
618
+ `\u26A0\uFE0F Loaded ${packageName} but provider ${toolName} still not found in registry.`
619
+ );
620
+ }
621
+ } catch (err) {
622
+ console.log(
623
+ `\u274C Failed to dynamically load tool ${toolName} (${packageName}):`,
624
+ err.message
625
+ );
626
+ }
627
+ }
628
+ if (!provider) {
629
+ console.warn(
630
+ `\u26A0\uFE0F Warning: Tool provider for '${toolName}' not found. Skipping.`
631
+ );
632
+ continue;
633
+ }
634
+ try {
635
+ const sanitizedOptions = { ...options };
636
+ delete sanitizedOptions.onProgress;
637
+ delete sanitizedOptions.progressCallback;
638
+ const toolOptions = {
639
+ rootDir: options.rootDir
640
+ // Always include rootDir
641
+ };
642
+ [...import_core7.GLOBAL_INFRA_OPTIONS, ...import_core7.COMMON_FINE_TUNING_OPTIONS].forEach(
643
+ (key) => {
644
+ if (key in options && key !== "toolConfigs" && key !== "tools") {
645
+ toolOptions[key] = options[key];
646
+ }
647
+ }
648
+ );
649
+ if (options.toolConfigs?.[provider.id]) {
650
+ Object.assign(toolOptions, options.toolConfigs[provider.id]);
651
+ } else if (options.tools && !Array.isArray(options.tools) && typeof options.tools === "object" && options.tools[provider.id]) {
652
+ Object.assign(toolOptions, options.tools[provider.id]);
653
+ } else if (options[provider.id]) {
654
+ Object.assign(toolOptions, options[provider.id]);
655
+ }
656
+ toolOptions.onProgress = (processed, total, message) => {
657
+ if (options.progressCallback) {
658
+ options.progressCallback({
659
+ tool: provider.id,
660
+ processed,
661
+ total,
662
+ message
663
+ });
664
+ }
665
+ };
666
+ const output = await provider.analyze(toolOptions);
667
+ if (output.metadata) {
668
+ output.metadata.config = sanitizeToolConfig(toolOptions);
669
+ }
670
+ if (options.progressCallback) {
671
+ options.progressCallback({ tool: provider.id, data: output });
672
+ }
673
+ result[provider.id] = output;
674
+ result.summary.toolsRun.push(provider.id);
675
+ if (output.summary?.config) {
676
+ result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
677
+ output.summary.config
678
+ );
679
+ } else if (output.metadata?.config) {
680
+ result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
681
+ output.metadata.config
682
+ );
683
+ } else {
684
+ result.summary.toolConfigs[provider.id] = sanitizeToolConfig(toolOptions);
685
+ }
686
+ const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
687
+ if (toolFiles > result.summary.totalFiles) {
688
+ result.summary.totalFiles = toolFiles;
689
+ }
690
+ const issueCount = output.results.reduce(
691
+ (sum, file) => sum + (file.issues?.length ?? 0),
692
+ 0
693
+ );
694
+ result.summary.totalIssues += issueCount;
695
+ } catch (err) {
696
+ console.error(`\u274C Error running tool '${provider.id}':`, err);
697
+ }
698
+ }
699
+ result.summary.config = sanitizeConfigRecursive({
700
+ scan: {
701
+ tools: requestedTools,
702
+ include: options.include,
703
+ exclude: options.exclude
704
+ },
705
+ // Use 'tools' for tool-specific configurations to match AIReadyConfig
706
+ tools: result.summary.toolConfigs
707
+ });
708
+ result.summary.executionTime = Date.now() - startTime;
709
+ const keyMappings = {
710
+ "pattern-detect": ["patternDetect", "patterns"],
711
+ "context-analyzer": ["contextAnalyzer", "context"],
712
+ "naming-consistency": ["namingConsistency", "consistency"],
713
+ "ai-signal-clarity": ["aiSignalClarity"],
714
+ "agent-grounding": ["agentGrounding"],
715
+ "testability-index": ["testabilityIndex", "testability"],
716
+ "doc-drift": ["docDrift"],
717
+ "dependency-health": ["dependencyHealth", "deps"],
718
+ "change-amplification": ["changeAmplification"]
719
+ };
720
+ for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
721
+ if (result[kebabKey]) {
722
+ for (const alias of aliases) {
723
+ result[alias] = result[kebabKey];
724
+ }
725
+ }
726
+ }
727
+ return result;
728
+ }
729
+ async function scoreUnified(results, options) {
730
+ const toolScores = /* @__PURE__ */ new Map();
731
+ for (const toolId of results.summary.toolsRun) {
732
+ const provider = import_core7.ToolRegistry.get(toolId);
733
+ if (!provider) continue;
734
+ const output = results[toolId];
735
+ if (!output) continue;
736
+ try {
737
+ const toolScore = provider.score(output, options);
738
+ if (!toolScore.tokenBudget) {
739
+ if (toolId === import_core7.ToolName.PatternDetect && output.duplicates) {
740
+ const wastedTokens = output.duplicates.reduce(
741
+ (sum, d) => sum + (d.tokenCost ?? 0),
742
+ 0
743
+ );
744
+ toolScore.tokenBudget = (0, import_core7.calculateTokenBudget)({
745
+ totalContextTokens: wastedTokens * 2,
746
+ wastedTokens: {
747
+ duplication: wastedTokens,
748
+ fragmentation: 0,
749
+ chattiness: 0
750
+ }
751
+ });
752
+ } else if (toolId === import_core7.ToolName.ContextAnalyzer && output.summary) {
753
+ toolScore.tokenBudget = (0, import_core7.calculateTokenBudget)({
754
+ totalContextTokens: output.summary.totalTokens,
755
+ wastedTokens: {
756
+ duplication: 0,
757
+ fragmentation: output.summary.totalPotentialSavings ?? 0,
758
+ chattiness: 0
759
+ }
760
+ });
761
+ }
762
+ }
763
+ toolScores.set(toolId, toolScore);
764
+ } catch (err) {
765
+ console.error(`\u274C Error scoring tool '${toolId}':`, err);
766
+ }
767
+ }
768
+ if (toolScores.size === 0) {
769
+ return {
770
+ overall: 0,
771
+ rating: "Critical",
772
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
773
+ toolsUsed: [],
774
+ breakdown: [],
775
+ calculation: {
776
+ formula: "0 / 0 = 0",
777
+ weights: {},
778
+ normalized: "0 / 0 = 0"
779
+ }
780
+ };
781
+ }
782
+ return (0, import_core7.calculateOverallScore)(toolScores, options, void 0);
783
+ }
784
+
785
+ // src/commands/scan-orchestrator.ts
786
+ async function runUnifiedScan(resolvedDir, finalOptions, options, startTime) {
787
+ console.log(import_chalk5.default.cyan("\n=== AIReady Run Preview ==="));
788
+ console.log(
789
+ import_chalk5.default.white("Tools to run:"),
790
+ (finalOptions.tools ?? []).join(", ")
791
+ );
792
+ const progressCallback = createProgressCallback();
793
+ const scoringProfile = options.profile ?? finalOptions.scoring?.profile ?? "default";
794
+ const results = await analyzeUnified({
795
+ ...finalOptions,
796
+ progressCallback,
797
+ onProgress: () => {
798
+ },
799
+ suppressToolConfig: true
800
+ });
801
+ printScanSummary(results, startTime);
802
+ let scoringResult;
803
+ if (options.score || finalOptions.scoring?.showBreakdown) {
804
+ scoringResult = await scoreUnified(results, {
805
+ ...finalOptions,
806
+ scoring: {
807
+ ...finalOptions.scoring,
808
+ profile: scoringProfile
809
+ }
810
+ });
811
+ printScoring(scoringResult, scoringProfile);
812
+ if (options.compareTo) {
813
+ handleTrendComparison(options.compareTo, scoringResult);
614
814
  }
615
- if (!response.ok) {
616
- console.error(
617
- import_chalk3.default.red(
618
- `\u274C Upload failed: ${uploadResult.error ?? response.statusText}`
619
- )
620
- );
621
- if (contentType?.includes("text/html")) {
815
+ await handleBusinessImpactMetrics(
816
+ results,
817
+ scoringResult,
818
+ options.model ?? "gpt-5.4-mini"
819
+ );
820
+ }
821
+ return { results, scoringResult };
822
+ }
823
+ function handleTrendComparison(baselinePath, currentScoring) {
824
+ try {
825
+ const prevReport = JSON.parse(
826
+ (0, import_fs3.readFileSync)((0, import_path3.resolve)(process.cwd(), baselinePath), "utf8")
827
+ );
828
+ const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
829
+ if (typeof prevScore === "number") {
830
+ const diff = currentScoring.overall - prevScore;
831
+ const diffStr = diff > 0 ? `+${diff}` : String(diff);
832
+ if (diff > 0)
622
833
  console.log(
623
- import_chalk3.default.yellow(
624
- " Note: Received an HTML response. This often indicates a redirect (e.g., to a login page) or a server error."
834
+ import_chalk5.default.green(
835
+ ` \u{1F4C8} Trend: ${diffStr} compared to ${baselinePath} (${prevScore} \u2192 ${currentScoring.overall})`
625
836
  )
626
837
  );
627
- if (uploadResult.error?.includes("Redirecting")) {
628
- console.log(
629
- import_chalk3.default.dim(
630
- " Detected redirect. Check if the API endpoint requires authentication or has changed."
631
- )
632
- );
633
- }
634
- }
635
- if (response.status === 401) {
838
+ else if (diff < 0)
636
839
  console.log(
637
- import_chalk3.default.dim(" Hint: Your API key may be invalid or expired.")
840
+ import_chalk5.default.red(
841
+ ` \u{1F4C9} Trend: ${diffStr} compared to ${baselinePath} (${prevScore} \u2192 ${currentScoring.overall})`
842
+ )
843
+ );
844
+ else
845
+ console.log(
846
+ import_chalk5.default.blue(
847
+ ` \u2796 Trend: No change (${prevScore} \u2192 ${currentScoring.overall})`
848
+ )
638
849
  );
639
- }
640
- process.exit(1);
641
850
  }
642
- const duration = ((Date.now() - startTime) / 1e3).toFixed(2);
643
- console.log(import_chalk3.default.green(`
644
- \u2705 Upload successful! (${duration}s)`));
645
- console.log(import_chalk3.default.cyan(` View results: ${serverUrl}/dashboard`));
646
- if (uploadResult.analysis) {
647
- console.log(import_chalk3.default.dim(` Analysis ID: ${uploadResult.analysis.id}`));
648
- console.log(import_chalk3.default.dim(` Score: ${uploadResult.analysis.aiScore}/100`));
851
+ } catch (e) {
852
+ void e;
853
+ }
854
+ }
855
+ async function handleBusinessImpactMetrics(results, scoringResult, modelId) {
856
+ const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
857
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
858
+ 0
859
+ );
860
+ const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
861
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
862
+ 0
863
+ );
864
+ const totalContext = Math.max(
865
+ ...(scoringResult.breakdown ?? []).map(
866
+ (s) => s.tokenBudget?.totalContextTokens ?? 0
867
+ ),
868
+ 0
869
+ );
870
+ if (totalContext > 0) {
871
+ const unifiedBudget = (0, import_core8.calculateTokenBudget)({
872
+ totalContextTokens: totalContext,
873
+ wastedTokens: {
874
+ duplication: totalWastedDuplication,
875
+ fragmentation: totalWastedFragmentation,
876
+ chattiness: totalContext * 0.1
877
+ // Default chattiness
878
+ }
879
+ });
880
+ const allIssues = [];
881
+ for (const toolId of results.summary.toolsRun) {
882
+ if (results[toolId]?.results) {
883
+ results[toolId].results.forEach((fileRes) => {
884
+ if (fileRes.issues) {
885
+ allIssues.push(...fileRes.issues);
886
+ }
887
+ });
888
+ }
649
889
  }
650
- } catch (error) {
651
- (0, import_core5.handleCLIError)(error, "Upload");
890
+ const { calculateBusinessROI } = await import("@aiready/core");
891
+ const roi = calculateBusinessROI({
892
+ tokenWaste: unifiedBudget.wastedTokens.total,
893
+ issues: allIssues,
894
+ modelId
895
+ });
896
+ printBusinessImpact(roi, unifiedBudget);
897
+ results.summary.businessImpact = {
898
+ estimatedMonthlyWaste: roi.monthlySavings,
899
+ potentialSavings: roi.monthlySavings,
900
+ productivityHours: roi.productivityGainHours
901
+ };
902
+ scoringResult.tokenBudget = unifiedBudget;
903
+ scoringResult.businessROI = roi;
652
904
  }
653
905
  }
654
- var uploadHelpText = `
655
- EXAMPLES:
656
- $ aiready upload report.json --api-key ar_...
657
- $ aiready upload .aiready/latest.json
658
- $ AIREADY_API_KEY=ar_... aiready upload report.json
659
-
660
- ENVIRONMENT VARIABLES:
661
- AIREADY_API_KEY Your platform API key
662
- AIREADY_SERVER Custom platform URL (default: https://dev.platform.getaiready.dev)
663
- `;
664
906
 
665
907
  // src/commands/scan.ts
666
908
  async function scanAction(directory, options) {
667
- console.log(import_chalk4.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
909
+ console.log(import_chalk6.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
668
910
  const startTime = Date.now();
669
- const resolvedDir = (0, import_path3.resolve)(process.cwd(), directory ?? ".");
670
- const repoMetadata = (0, import_core6.getRepoMetadata)(resolvedDir);
911
+ const resolvedDir = (0, import_path4.resolve)(process.cwd(), directory ?? ".");
912
+ const repoMetadata = (0, import_core9.getRepoMetadata)(resolvedDir);
671
913
  try {
672
- const defaults = {
673
- tools: [
674
- "pattern-detect",
675
- "context-analyzer",
676
- "naming-consistency",
677
- "ai-signal-clarity",
678
- "agent-grounding",
679
- "testability-index",
680
- "doc-drift",
681
- "dependency-health",
682
- "change-amplification"
683
- ],
684
- include: void 0,
685
- exclude: void 0,
686
- output: {
687
- format: "console",
688
- file: void 0
689
- }
690
- };
691
- let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
692
- if (options.profile) {
693
- switch (options.profile.toLowerCase()) {
694
- case "agentic":
695
- profileTools = [
696
- import_core6.ToolName.AiSignalClarity,
697
- import_core6.ToolName.AgentGrounding,
698
- import_core6.ToolName.TestabilityIndex
699
- ];
700
- break;
701
- case "cost":
702
- profileTools = [import_core6.ToolName.PatternDetect, import_core6.ToolName.ContextAnalyzer];
703
- break;
704
- case "logic":
705
- profileTools = [
706
- import_core6.ToolName.TestabilityIndex,
707
- import_core6.ToolName.NamingConsistency,
708
- import_core6.ToolName.ContextAnalyzer,
709
- import_core6.ToolName.PatternDetect,
710
- import_core6.ToolName.ChangeAmplification
711
- ];
712
- break;
713
- case "ui":
714
- profileTools = [
715
- import_core6.ToolName.NamingConsistency,
716
- import_core6.ToolName.ContextAnalyzer,
717
- import_core6.ToolName.PatternDetect,
718
- import_core6.ToolName.DocDrift,
719
- import_core6.ToolName.AiSignalClarity
720
- ];
721
- break;
722
- case "security":
723
- profileTools = [
724
- import_core6.ToolName.NamingConsistency,
725
- import_core6.ToolName.TestabilityIndex
726
- ];
727
- break;
728
- case "onboarding":
729
- profileTools = [
730
- import_core6.ToolName.ContextAnalyzer,
731
- import_core6.ToolName.NamingConsistency,
732
- import_core6.ToolName.AgentGrounding
733
- ];
734
- break;
735
- default:
736
- console.log(
737
- import_chalk4.default.yellow(
738
- `
739
- \u26A0\uFE0F Unknown profile '${options.profile}'. Using defaults.`
740
- )
741
- );
742
- }
743
- }
744
- const cliOverrides = {
745
- include: options.include?.split(","),
746
- exclude: options.exclude?.split(",")
747
- };
748
- if (profileTools) cliOverrides.tools = profileTools;
749
- const baseOptions = await (0, import_core6.loadMergedConfig)(
914
+ const finalOptions = await resolveScanConfig(resolvedDir, options);
915
+ const { results, scoringResult } = await runUnifiedScan(
750
916
  resolvedDir,
751
- defaults,
752
- cliOverrides
753
- );
754
- const finalOptions = { ...baseOptions };
755
- if (baseOptions.tools.includes(import_core6.ToolName.PatternDetect) || baseOptions.tools.includes("patterns")) {
756
- const { getSmartDefaults } = await import("@aiready/pattern-detect");
757
- const patternSmartDefaults = await getSmartDefaults(
758
- resolvedDir,
759
- finalOptions.toolConfigs?.[import_core6.ToolName.PatternDetect] ?? {}
760
- );
761
- if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
762
- finalOptions.toolConfigs[import_core6.ToolName.PatternDetect] = {
763
- ...patternSmartDefaults,
764
- ...finalOptions.toolConfigs[import_core6.ToolName.PatternDetect]
765
- };
766
- }
767
- console.log(import_chalk4.default.cyan("\n=== AIReady Run Preview ==="));
768
- console.log(
769
- import_chalk4.default.white("Tools to run:"),
770
- (finalOptions.tools ?? []).join(", ")
917
+ finalOptions,
918
+ options,
919
+ startTime
771
920
  );
772
- const progressCallback = (event) => {
773
- if (event.message) {
774
- process.stdout.write(`\r\x1B[K [${event.tool}] ${event.message}`);
775
- return;
776
- }
777
- process.stdout.write("\r\x1B[K");
778
- console.log(import_chalk4.default.cyan(`--- ${event.tool.toUpperCase()} RESULTS ---`));
779
- const res = event.data;
780
- if (res && res.summary) {
781
- if (res.summary.totalIssues !== void 0)
782
- console.log(` Issues found: ${import_chalk4.default.bold(res.summary.totalIssues)}`);
783
- if (res.summary.score !== void 0)
784
- console.log(` Tool Score: ${import_chalk4.default.bold(res.summary.score)}/100`);
785
- if (res.summary.totalFiles !== void 0)
786
- console.log(
787
- ` Files analyzed: ${import_chalk4.default.bold(res.summary.totalFiles)}`
788
- );
789
- }
790
- };
791
- const scoringProfile = options.profile ?? baseOptions.scoring?.profile ?? "default";
792
- const results = await analyzeUnified({
793
- ...finalOptions,
794
- progressCallback,
795
- onProgress: () => {
796
- },
797
- suppressToolConfig: true
798
- });
799
- printScanSummary(results, startTime);
800
- let scoringResult;
801
- if (options.score || finalOptions.scoring?.showBreakdown) {
802
- scoringResult = await scoreUnified(results, {
803
- ...finalOptions,
804
- scoring: {
805
- ...finalOptions.scoring,
806
- profile: scoringProfile
807
- }
808
- });
809
- printScoring(scoringResult, scoringProfile);
810
- if (options.compareTo) {
811
- try {
812
- const prevReport = JSON.parse(
813
- (0, import_fs3.readFileSync)((0, import_path3.resolve)(process.cwd(), options.compareTo), "utf8")
814
- );
815
- const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
816
- if (typeof prevScore === "number") {
817
- const diff = scoringResult.overall - prevScore;
818
- const diffStr = diff > 0 ? `+${diff}` : String(diff);
819
- if (diff > 0)
820
- console.log(
821
- import_chalk4.default.green(
822
- ` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
823
- )
824
- );
825
- else if (diff < 0)
826
- console.log(
827
- import_chalk4.default.red(
828
- ` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
829
- )
830
- );
831
- else
832
- console.log(
833
- import_chalk4.default.blue(
834
- ` \u2796 Trend: No change (${prevScore} \u2192 ${scoringResult.overall})`
835
- )
836
- );
837
- }
838
- } catch (e) {
839
- void e;
840
- }
841
- }
842
- const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
843
- (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
844
- 0
845
- );
846
- const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
847
- (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
848
- 0
849
- );
850
- const totalContext = Math.max(
851
- ...(scoringResult.breakdown ?? []).map(
852
- (s) => s.tokenBudget?.totalContextTokens ?? 0
853
- ),
854
- 0
855
- );
856
- if (totalContext > 0) {
857
- const unifiedBudget = (0, import_core6.calculateTokenBudget)({
858
- totalContextTokens: totalContext,
859
- wastedTokens: {
860
- duplication: totalWastedDuplication,
861
- fragmentation: totalWastedFragmentation,
862
- chattiness: totalContext * 0.1
863
- // Default chattiness
864
- }
865
- });
866
- const allIssues = [];
867
- for (const toolId of results.summary.toolsRun) {
868
- if (results[toolId]?.results) {
869
- results[toolId].results.forEach((fileRes) => {
870
- if (fileRes.issues) {
871
- allIssues.push(...fileRes.issues);
872
- }
873
- });
874
- }
875
- }
876
- const modelId = options.model ?? "gpt-5.4-mini";
877
- const roi = (await import("@aiready/core")).calculateBusinessROI({
878
- tokenWaste: unifiedBudget.wastedTokens.total,
879
- issues: allIssues,
880
- modelId
881
- });
882
- printBusinessImpact(roi, unifiedBudget);
883
- results.summary.businessImpact = {
884
- estimatedMonthlyWaste: roi.monthlySavings,
885
- potentialSavings: roi.monthlySavings,
886
- productivityHours: roi.productivityGainHours
887
- };
888
- scoringResult.tokenBudget = unifiedBudget;
889
- scoringResult.businessROI = roi;
890
- }
891
- }
892
921
  console.log(
893
- import_chalk4.default.dim(
922
+ import_chalk6.default.dim(
894
923
  "\n\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"
895
924
  )
896
925
  );
897
- console.log(import_chalk4.default.dim("\u{1F4AC} Found a bug or have a metric idea?"));
898
- console.log(import_chalk4.default.dim("\u{1F449} Copy/paste this to your AI agent:"));
926
+ console.log(import_chalk6.default.dim("\u{1F4AC} Found a bug or have a metric idea?"));
927
+ console.log(import_chalk6.default.dim("\u{1F449} Copy/paste this to your AI agent:"));
899
928
  console.log(
900
- import_chalk4.default.cyan(
929
+ import_chalk6.default.cyan(
901
930
  ` "Any feedback for the tools? Please use 'aiready bug' to report \u2764\uFE0F"`
902
931
  )
903
932
  );
904
933
  console.log(
905
- import_chalk4.default.dim(
934
+ import_chalk6.default.dim(
906
935
  "\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"
907
936
  )
908
937
  );
@@ -911,21 +940,21 @@ async function scanAction(directory, options) {
911
940
  repository: repoMetadata
912
941
  };
913
942
  const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
914
- const outputPath = (0, import_core6.resolveOutputPath)(
943
+ const outputPath = (0, import_core9.resolveOutputPath)(
915
944
  options.outputFile ?? finalOptions.output?.file,
916
- `aiready-report-${getReportTimestamp()}.json`,
945
+ `aiready-report-${(0, import_core2.getReportTimestamp)()}.json`,
917
946
  resolvedDir
918
947
  );
919
948
  if (outputFormat === "json") {
920
- (0, import_core6.handleJSONOutput)(
949
+ (0, import_core9.handleJSONOutput)(
921
950
  outputData,
922
951
  outputPath,
923
952
  `\u2705 Report saved to ${outputPath}`
924
953
  );
925
954
  } else {
926
955
  try {
927
- (0, import_fs3.writeFileSync)(outputPath, JSON.stringify(outputData, null, 2));
928
- console.log(import_chalk4.default.dim(`\u2705 Report auto-persisted to ${outputPath}`));
956
+ (0, import_fs4.writeFileSync)(outputPath, JSON.stringify(outputData, null, 2));
957
+ console.log(import_chalk6.default.dim(`\u2705 Report auto-persisted to ${outputPath}`));
929
958
  } catch (err) {
930
959
  void err;
931
960
  }
@@ -937,61 +966,83 @@ async function scanAction(directory, options) {
937
966
  });
938
967
  }
939
968
  await warnIfGraphCapExceeded(outputData, resolvedDir);
940
- if (scoringResult) {
941
- const threshold = options.threshold ? parseInt(options.threshold) : void 0;
942
- const failOnLevel = options.failOn ?? "critical";
943
- const isCI = options.ci ?? process.env.CI === "true";
944
- let shouldFail = false;
945
- let failReason = "";
946
- const report = mapToUnifiedReport(results, scoringResult);
947
- if (isCI && report.results && report.results.length > 0) {
948
- console.log(
949
- import_chalk4.default.cyan(
950
- `
969
+ await handleGatekeeper(outputData, scoringResult, options, results);
970
+ } catch (error) {
971
+ (0, import_core9.handleCLIError)(error, "Analysis");
972
+ }
973
+ }
974
+ async function handleGatekeeper(outputData, scoringResult, options, results) {
975
+ if (!scoringResult) return;
976
+ const threshold = options.threshold ? parseInt(options.threshold) : void 0;
977
+ const failOnLevel = options.failOn ?? "critical";
978
+ const isCI = options.ci ?? process.env.CI === "true";
979
+ let shouldFail = false;
980
+ let failReason = "";
981
+ const report = mapToUnifiedReport(results, scoringResult);
982
+ if (isCI && report.results && report.results.length > 0) {
983
+ console.log(
984
+ import_chalk6.default.cyan(
985
+ `
951
986
  \u{1F4DD} Emitting GitHub Action annotations for ${report.results.length} issues...`
952
- )
953
- );
954
- (0, import_core6.emitIssuesAsAnnotations)(report.results);
955
- }
956
- if (threshold && scoringResult.overall < threshold) {
957
- shouldFail = true;
958
- failReason = `Score ${scoringResult.overall} < threshold ${threshold}`;
959
- }
960
- if (failOnLevel !== "none") {
961
- if (failOnLevel === "critical" && report.summary.criticalIssues > 0) {
962
- shouldFail = true;
963
- failReason = `Found ${report.summary.criticalIssues} critical issues`;
964
- } else if (failOnLevel === "major" && report.summary.criticalIssues + report.summary.majorIssues > 0) {
965
- shouldFail = true;
966
- failReason = `Found ${report.summary.criticalIssues} critical and ${report.summary.majorIssues} major issues`;
967
- }
968
- }
969
- if (shouldFail) {
970
- console.log(import_chalk4.default.red(`
971
- \u{1F6AB} SCAN FAILED: ${failReason}`));
972
- process.exit(1);
973
- } else {
974
- console.log(import_chalk4.default.green("\n\u2705 SCAN PASSED"));
975
- }
987
+ )
988
+ );
989
+ (0, import_core9.emitIssuesAsAnnotations)(report.results);
990
+ }
991
+ if (threshold && scoringResult.overall < threshold) {
992
+ shouldFail = true;
993
+ failReason = `Score ${scoringResult.overall} < threshold ${threshold}`;
994
+ }
995
+ if (failOnLevel !== "none") {
996
+ if (failOnLevel === "critical" && report.summary.criticalIssues > 0) {
997
+ shouldFail = true;
998
+ failReason = `Found ${report.summary.criticalIssues} critical issues`;
999
+ } else if (failOnLevel === "major" && report.summary.criticalIssues + report.summary.majorIssues > 0) {
1000
+ shouldFail = true;
1001
+ failReason = `Found ${report.summary.criticalIssues} critical and ${report.summary.majorIssues} major issues`;
976
1002
  }
977
- } catch (error) {
978
- (0, import_core6.handleCLIError)(error, "Analysis");
1003
+ }
1004
+ if (shouldFail) {
1005
+ console.log(import_chalk6.default.red(`
1006
+ \u{1F6AB} SCAN FAILED: ${failReason}`));
1007
+ process.exit(1);
1008
+ } else {
1009
+ console.log(import_chalk6.default.green("\n\u2705 SCAN PASSED"));
979
1010
  }
980
1011
  }
981
- var scanHelpText = `...`;
1012
+ var SCAN_HELP_TEXT = `
1013
+ Run a comprehensive AI-readiness scan of your codebase.
1014
+
1015
+ ${import_chalk6.default.bold("Examples:")}
1016
+ $ aiready scan .
1017
+ $ aiready scan src --profile agentic
1018
+ $ aiready scan . --threshold 80 --fail-on critical
1019
+ $ aiready scan . --output json --output-file report.json
1020
+
1021
+ ${import_chalk6.default.bold("Profiles:")}
1022
+ agentic - Focus on AI signal clarity and agent grounding
1023
+ cost - Focus on token budget and pattern reuse
1024
+ logic - Focus on testability and naming consistency
1025
+ ui - Focus on component naming and documentation
1026
+ security - Focus on naming and testability
1027
+ onboarding - Focus on context and grounding
1028
+
1029
+ ${import_chalk6.default.bold("CI/CD Integration:")}
1030
+ Use --threshold and --fail-on to use AIReady as a quality gate in your CI pipelines.
1031
+ When running in GitHub Actions, it will automatically emit annotations for found issues.
1032
+ `;
982
1033
 
983
1034
  // src/commands/init.ts
984
- var import_fs4 = require("fs");
985
- var import_path4 = require("path");
986
- var import_chalk5 = __toESM(require("chalk"));
987
- var import_core7 = require("@aiready/core");
1035
+ var import_fs5 = require("fs");
1036
+ var import_path5 = require("path");
1037
+ var import_chalk7 = __toESM(require("chalk"));
1038
+ var import_core10 = require("@aiready/core");
988
1039
  async function initAction(options) {
989
1040
  const fileExt = options.format === "js" ? "js" : "json";
990
1041
  const fileName = fileExt === "js" ? "aiready.config.js" : "aiready.json";
991
- const filePath = (0, import_path4.join)(process.cwd(), fileName);
992
- if ((0, import_fs4.existsSync)(filePath) && !options.force) {
1042
+ const filePath = (0, import_path5.join)(process.cwd(), fileName);
1043
+ if ((0, import_fs5.existsSync)(filePath) && !options.force) {
993
1044
  console.error(
994
- import_chalk5.default.red(`Error: ${fileName} already exists. Use --force to overwrite.`)
1045
+ import_chalk7.default.red(`Error: ${fileName} already exists. Use --force to overwrite.`)
995
1046
  );
996
1047
  process.exit(1);
997
1048
  }
@@ -1015,15 +1066,15 @@ async function initAction(options) {
1015
1066
  "**/*.spec.ts"
1016
1067
  ],
1017
1068
  tools: [
1018
- import_core7.ToolName.PatternDetect,
1019
- import_core7.ToolName.ContextAnalyzer,
1020
- import_core7.ToolName.NamingConsistency,
1021
- import_core7.ToolName.AiSignalClarity,
1022
- import_core7.ToolName.AgentGrounding,
1023
- import_core7.ToolName.TestabilityIndex,
1024
- import_core7.ToolName.DocDrift,
1025
- import_core7.ToolName.DependencyHealth,
1026
- import_core7.ToolName.ChangeAmplification
1069
+ import_core10.ToolName.PatternDetect,
1070
+ import_core10.ToolName.ContextAnalyzer,
1071
+ import_core10.ToolName.NamingConsistency,
1072
+ import_core10.ToolName.AiSignalClarity,
1073
+ import_core10.ToolName.AgentGrounding,
1074
+ import_core10.ToolName.TestabilityIndex,
1075
+ import_core10.ToolName.DocDrift,
1076
+ import_core10.ToolName.DependencyHealth,
1077
+ import_core10.ToolName.ChangeAmplification
1027
1078
  ]
1028
1079
  },
1029
1080
  // Output preferences
@@ -1038,7 +1089,7 @@ async function initAction(options) {
1038
1089
  },
1039
1090
  // Tool-specific configurations
1040
1091
  tools: {
1041
- [import_core7.ToolName.PatternDetect]: {
1092
+ [import_core10.ToolName.PatternDetect]: {
1042
1093
  // Core detection thresholds
1043
1094
  minSimilarity: 0.4,
1044
1095
  // Jaccard similarity threshold (0-1)
@@ -1068,7 +1119,7 @@ async function initAction(options) {
1068
1119
  // Add any additional advanced options here
1069
1120
  } : {}
1070
1121
  },
1071
- [import_core7.ToolName.ContextAnalyzer]: {
1122
+ [import_core10.ToolName.ContextAnalyzer]: {
1072
1123
  // Smart defaults are generated dynamically based on repository size
1073
1124
  // These are fallback values for when smart defaults can't be calculated
1074
1125
  maxContextBudget: 25e3,
@@ -1085,7 +1136,7 @@ async function initAction(options) {
1085
1136
  includeNodeModules: false
1086
1137
  // Whether to include node_modules in analysis
1087
1138
  },
1088
- [import_core7.ToolName.NamingConsistency]: {
1139
+ [import_core10.ToolName.NamingConsistency]: {
1089
1140
  // Core checks
1090
1141
  checkNaming: true,
1091
1142
  // Check naming conventions and quality
@@ -1132,7 +1183,7 @@ async function initAction(options) {
1132
1183
  ],
1133
1184
  ...options.full ? { disableChecks: [] } : {}
1134
1185
  },
1135
- [import_core7.ToolName.AiSignalClarity]: {
1186
+ [import_core10.ToolName.AiSignalClarity]: {
1136
1187
  // All signal clarity checks enabled by default
1137
1188
  checkMagicLiterals: true,
1138
1189
  // Detect magic numbers and strings
@@ -1151,7 +1202,7 @@ async function initAction(options) {
1151
1202
  checkLargeFiles: true
1152
1203
  // Detect files that are too large
1153
1204
  },
1154
- [import_core7.ToolName.AgentGrounding]: {
1205
+ [import_core10.ToolName.AgentGrounding]: {
1155
1206
  // Structure clarity
1156
1207
  maxRecommendedDepth: 4,
1157
1208
  // Max directory depth before flagging as "too deep"
@@ -1162,7 +1213,7 @@ async function initAction(options) {
1162
1213
  additionalVagueNames: ["stuff", "misc", "temp", "test"]
1163
1214
  // Custom vague file names
1164
1215
  },
1165
- [import_core7.ToolName.TestabilityIndex]: {
1216
+ [import_core10.ToolName.TestabilityIndex]: {
1166
1217
  // Coverage thresholds
1167
1218
  minCoverageRatio: 0.3,
1168
1219
  // Minimum acceptable test/source ratio
@@ -1172,19 +1223,19 @@ async function initAction(options) {
1172
1223
  maxDepth: 10
1173
1224
  // Maximum scan depth
1174
1225
  },
1175
- [import_core7.ToolName.DocDrift]: {
1226
+ [import_core10.ToolName.DocDrift]: {
1176
1227
  // Drift detection
1177
1228
  maxCommits: 50,
1178
1229
  // Maximum commit distance to check for drift
1179
1230
  staleMonths: 3
1180
1231
  // Consider comments older than this as outdated
1181
1232
  },
1182
- [import_core7.ToolName.DependencyHealth]: {
1233
+ [import_core10.ToolName.DependencyHealth]: {
1183
1234
  // Training cutoff for AI knowledge assessment
1184
1235
  trainingCutoffYear: 2023
1185
1236
  // Year cutoff for AI training data
1186
1237
  },
1187
- [import_core7.ToolName.ChangeAmplification]: {
1238
+ [import_core10.ToolName.ChangeAmplification]: {
1188
1239
  // Change amplification primarily relies on global scan settings
1189
1240
  // No additional tool-specific configuration required
1190
1241
  }
@@ -1211,30 +1262,28 @@ module.exports = ${JSON.stringify(defaultConfig, null, 2)};
1211
1262
  content = JSON.stringify(defaultConfig, null, 2);
1212
1263
  }
1213
1264
  try {
1214
- (0, import_fs4.writeFileSync)(filePath, content, "utf8");
1265
+ (0, import_fs5.writeFileSync)(filePath, content, "utf8");
1215
1266
  console.log(
1216
- import_chalk5.default.green(`
1217
- \u2705 Created default configuration: ${import_chalk5.default.bold(fileName)}`)
1267
+ import_chalk7.default.green(`
1268
+ \u2705 Created default configuration: ${import_chalk7.default.bold(fileName)}`)
1218
1269
  );
1219
1270
  console.log(
1220
- import_chalk5.default.cyan("You can now fine-tune your settings and run AIReady with:")
1271
+ import_chalk7.default.cyan("You can now fine-tune your settings and run AIReady with:")
1221
1272
  );
1222
- console.log(import_chalk5.default.white(` $ aiready scan
1273
+ console.log(import_chalk7.default.white(` $ aiready scan
1223
1274
  `));
1224
1275
  } catch (error) {
1225
- console.error(import_chalk5.default.red(`Failed to write configuration file: ${error}`));
1276
+ console.error(import_chalk7.default.red(`Failed to write configuration file: ${error}`));
1226
1277
  process.exit(1);
1227
1278
  }
1228
1279
  }
1229
1280
 
1230
1281
  // src/commands/patterns.ts
1231
- var import_chalk6 = __toESM(require("chalk"));
1232
- var import_path5 = require("path");
1233
- var import_core8 = require("@aiready/core");
1282
+ var import_chalk8 = __toESM(require("chalk"));
1283
+ var import_core11 = require("@aiready/core");
1234
1284
  async function patternsAction(directory, options) {
1235
- console.log(import_chalk6.default.blue("\u{1F50D} Analyzing patterns...\n"));
1285
+ console.log(import_chalk8.default.blue("\u{1F50D} Analyzing patterns...\n"));
1236
1286
  const startTime = Date.now();
1237
- const resolvedDir = (0, import_path5.resolve)(process.cwd(), directory ?? ".");
1238
1287
  try {
1239
1288
  const useSmartDefaults = !options.fullScan;
1240
1289
  const defaults = {
@@ -1263,8 +1312,8 @@ async function patternsAction(directory, options) {
1263
1312
  if (options.minSharedTokens) {
1264
1313
  cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
1265
1314
  }
1266
- const finalOptions = await (0, import_core8.loadMergedConfig)(
1267
- resolvedDir,
1315
+ const { resolvedDir, finalOptions } = await (0, import_core11.prepareActionConfig)(
1316
+ directory,
1268
1317
  defaults,
1269
1318
  cliOptions
1270
1319
  );
@@ -1272,66 +1321,59 @@ async function patternsAction(directory, options) {
1272
1321
  const { results, duplicates } = await analyzePatterns(
1273
1322
  finalOptions
1274
1323
  );
1275
- const elapsedTime = (0, import_core8.getElapsedTime)(startTime);
1324
+ const elapsedTime = (0, import_core11.getElapsedTime)(startTime);
1276
1325
  const summary = generateSummary(results);
1277
1326
  let patternScore;
1278
1327
  if (options.score) {
1279
1328
  patternScore = calculatePatternScore(duplicates, results.length);
1280
1329
  }
1281
- const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1282
- const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1330
+ const { format: outputFormat, file: userOutputFile } = (0, import_core11.resolveOutputFormat)(
1331
+ options,
1332
+ finalOptions
1333
+ );
1283
1334
  if (outputFormat === "json") {
1284
- const outputData = {
1335
+ const outputData = (0, import_core11.formatStandardReport)({
1285
1336
  results,
1286
- summary: { ...summary, executionTime: parseFloat(elapsedTime) },
1287
- ...patternScore && { scoring: patternScore }
1288
- };
1289
- const outputPath = (0, import_core8.resolveOutputPath)(
1290
- userOutputFile,
1291
- `aiready-report-${getReportTimestamp()}.json`,
1292
- resolvedDir
1293
- );
1294
- (0, import_core8.handleJSONOutput)(
1337
+ summary,
1338
+ elapsedTime,
1339
+ score: patternScore
1340
+ });
1341
+ (0, import_core11.handleStandardJSONOutput)({
1295
1342
  outputData,
1296
- outputPath,
1297
- `\u2705 Results saved to ${outputPath}`
1298
- );
1343
+ outputFile: userOutputFile,
1344
+ resolvedDir
1345
+ });
1299
1346
  } else {
1300
- const terminalWidth = process.stdout.columns || 80;
1301
- const dividerWidth = Math.min(60, terminalWidth - 2);
1302
- const divider = "\u2501".repeat(dividerWidth);
1303
- console.log(import_chalk6.default.cyan(divider));
1304
- console.log(import_chalk6.default.bold.white(" PATTERN ANALYSIS SUMMARY"));
1305
- console.log(import_chalk6.default.cyan(divider) + "\n");
1347
+ (0, import_core11.printTerminalHeader)("PATTERN ANALYSIS SUMMARY");
1306
1348
  console.log(
1307
- import_chalk6.default.white(`\u{1F4C1} Files analyzed: ${import_chalk6.default.bold(results.length)}`)
1349
+ import_chalk8.default.white(`\u{1F4C1} Files analyzed: ${import_chalk8.default.bold(results.length)}`)
1308
1350
  );
1309
1351
  console.log(
1310
- import_chalk6.default.yellow(
1311
- `\u26A0 Duplicate patterns found: ${import_chalk6.default.bold(summary.totalPatterns)}`
1352
+ import_chalk8.default.yellow(
1353
+ `\u26A0 Duplicate patterns found: ${import_chalk8.default.bold(summary.totalPatterns)}`
1312
1354
  )
1313
1355
  );
1314
1356
  console.log(
1315
- import_chalk6.default.red(
1316
- `\u{1F4B0} Token cost (wasted): ${import_chalk6.default.bold(summary.totalTokenCost.toLocaleString())}`
1357
+ import_chalk8.default.red(
1358
+ `\u{1F4B0} Token cost (wasted): ${import_chalk8.default.bold(summary.totalTokenCost.toLocaleString())}`
1317
1359
  )
1318
1360
  );
1319
1361
  console.log(
1320
- import_chalk6.default.gray(`\u23F1 Analysis time: ${import_chalk6.default.bold(elapsedTime + "s")}`)
1362
+ import_chalk8.default.gray(`\u23F1 Analysis time: ${import_chalk8.default.bold(elapsedTime + "s")}`)
1321
1363
  );
1322
1364
  const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
1323
1365
  if (sortedTypes.length > 0) {
1324
- console.log(import_chalk6.default.cyan("\n" + divider));
1325
- console.log(import_chalk6.default.bold.white(" PATTERNS BY TYPE"));
1326
- console.log(import_chalk6.default.cyan(divider) + "\n");
1366
+ console.log("\n" + (0, import_core11.getTerminalDivider)());
1367
+ console.log(import_chalk8.default.bold.white(" PATTERNS BY TYPE"));
1368
+ console.log((0, import_core11.getTerminalDivider)() + "\n");
1327
1369
  sortedTypes.forEach(([type, count]) => {
1328
- console.log(` ${import_chalk6.default.white(type.padEnd(15))} ${import_chalk6.default.bold(count)}`);
1370
+ console.log(` ${import_chalk8.default.white(type.padEnd(15))} ${import_chalk8.default.bold(count)}`);
1329
1371
  });
1330
1372
  }
1331
1373
  if (summary.totalPatterns > 0 && duplicates.length > 0) {
1332
- console.log(import_chalk6.default.cyan("\n" + divider));
1333
- console.log(import_chalk6.default.bold.white(" TOP DUPLICATE PATTERNS"));
1334
- console.log(import_chalk6.default.cyan(divider) + "\n");
1374
+ console.log("\n" + (0, import_core11.getTerminalDivider)());
1375
+ console.log(import_chalk8.default.bold.white(" TOP DUPLICATE PATTERNS"));
1376
+ console.log((0, import_core11.getTerminalDivider)() + "\n");
1335
1377
  const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
1336
1378
  topDuplicates.forEach((dup) => {
1337
1379
  const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
@@ -1339,34 +1381,34 @@ async function patternsAction(directory, options) {
1339
1381
  const file1Name = dup.file1.split("/").pop() || dup.file1;
1340
1382
  const file2Name = dup.file2.split("/").pop() || dup.file2;
1341
1383
  console.log(
1342
- `${severityIcon} ${severity}: ${import_chalk6.default.bold(file1Name)} \u2194 ${import_chalk6.default.bold(file2Name)}`
1384
+ `${severityIcon} ${severity}: ${import_chalk8.default.bold(file1Name)} \u2194 ${import_chalk8.default.bold(file2Name)}`
1343
1385
  );
1344
1386
  console.log(
1345
- ` Similarity: ${import_chalk6.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk6.default.bold(dup.tokenCost.toLocaleString())} tokens each`
1387
+ ` Similarity: ${import_chalk8.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk8.default.bold(dup.tokenCost.toLocaleString())} tokens each`
1346
1388
  );
1347
1389
  console.log(
1348
- ` Lines: ${import_chalk6.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk6.default.cyan(dup.line2 + "-" + dup.endLine2)}
1390
+ ` Lines: ${import_chalk8.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk8.default.cyan(dup.line2 + "-" + dup.endLine2)}
1349
1391
  `
1350
1392
  );
1351
1393
  });
1352
1394
  } else {
1353
1395
  console.log(
1354
- import_chalk6.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
1396
+ import_chalk8.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
1355
1397
  );
1356
1398
  }
1357
1399
  if (patternScore) {
1358
- console.log(import_chalk6.default.cyan(divider));
1359
- console.log(import_chalk6.default.bold.white(" AI READINESS SCORE (Patterns)"));
1360
- console.log(import_chalk6.default.cyan(divider) + "\n");
1361
- console.log((0, import_core8.formatToolScore)(patternScore));
1400
+ console.log((0, import_core11.getTerminalDivider)());
1401
+ console.log(import_chalk8.default.bold.white(" AI READINESS SCORE (Patterns)"));
1402
+ console.log((0, import_core11.getTerminalDivider)() + "\n");
1403
+ console.log((0, import_core11.formatToolScore)(patternScore));
1362
1404
  console.log();
1363
1405
  }
1364
1406
  }
1365
1407
  } catch (error) {
1366
- (0, import_core8.handleCLIError)(error, "Pattern analysis");
1408
+ (0, import_core11.handleCLIError)(error, "Pattern analysis");
1367
1409
  }
1368
1410
  }
1369
- var patternsHelpText = `
1411
+ var PATTERNS_HELP_TEXT = `
1370
1412
  EXAMPLES:
1371
1413
  $ aiready patterns # Default analysis
1372
1414
  $ aiready patterns --similarity 0.6 # Stricter matching
@@ -1374,13 +1416,11 @@ EXAMPLES:
1374
1416
  `;
1375
1417
 
1376
1418
  // src/commands/context.ts
1377
- var import_chalk7 = __toESM(require("chalk"));
1378
- var import_path6 = require("path");
1379
- var import_core9 = require("@aiready/core");
1419
+ var import_chalk9 = __toESM(require("chalk"));
1420
+ var import_core12 = require("@aiready/core");
1380
1421
  async function contextAction(directory, options) {
1381
- console.log(import_chalk7.default.blue("\u{1F9E0} Analyzing context costs...\n"));
1422
+ console.log(import_chalk9.default.blue("\u{1F9E0} Analyzing context costs...\n"));
1382
1423
  const startTime = Date.now();
1383
- const resolvedDir = (0, import_path6.resolve)(process.cwd(), directory ?? ".");
1384
1424
  try {
1385
1425
  const defaults = {
1386
1426
  maxDepth: 5,
@@ -1392,7 +1432,7 @@ async function contextAction(directory, options) {
1392
1432
  file: void 0
1393
1433
  }
1394
1434
  };
1395
- const baseOptions = await (0, import_core9.loadMergedConfig)(resolvedDir, defaults, {
1435
+ const { resolvedDir, finalOptions: baseOptions } = await (0, import_core12.prepareActionConfig)(directory, defaults, {
1396
1436
  maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
1397
1437
  maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
1398
1438
  include: options.include?.split(","),
@@ -1418,113 +1458,111 @@ async function contextAction(directory, options) {
1418
1458
  console.log("");
1419
1459
  const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
1420
1460
  const results = await analyzeContext(finalOptions);
1421
- const elapsedTime = (0, import_core9.getElapsedTime)(startTime);
1461
+ const elapsedTime = (0, import_core12.getElapsedTime)(startTime);
1422
1462
  const summary = generateSummary(results);
1423
1463
  let contextScore;
1424
1464
  if (options.score) {
1425
1465
  contextScore = calculateContextScore(summary);
1426
1466
  }
1427
- const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1428
- const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1467
+ const { format: outputFormat, file: userOutputFile } = (0, import_core12.resolveOutputFormat)(
1468
+ options,
1469
+ finalOptions
1470
+ );
1429
1471
  if (outputFormat === "json") {
1430
- const outputData = {
1472
+ const outputData = (0, import_core12.formatStandardReport)({
1431
1473
  results,
1432
- summary: { ...summary, executionTime: parseFloat(elapsedTime) },
1433
- ...contextScore && { scoring: contextScore }
1434
- };
1435
- const outputPath = (0, import_core9.resolveOutputPath)(
1436
- userOutputFile,
1437
- `aiready-report-${getReportTimestamp()}.json`,
1438
- resolvedDir
1439
- );
1440
- (0, import_core9.handleJSONOutput)(
1474
+ summary,
1475
+ elapsedTime,
1476
+ score: contextScore
1477
+ });
1478
+ (0, import_core12.handleStandardJSONOutput)({
1441
1479
  outputData,
1442
- outputPath,
1443
- `\u2705 Results saved to ${outputPath}`
1444
- );
1480
+ outputFile: userOutputFile,
1481
+ resolvedDir
1482
+ });
1445
1483
  } else {
1446
1484
  const terminalWidth = process.stdout.columns ?? 80;
1447
1485
  const dividerWidth = Math.min(60, terminalWidth - 2);
1448
1486
  const divider = "\u2501".repeat(dividerWidth);
1449
- console.log(import_chalk7.default.cyan(divider));
1450
- console.log(import_chalk7.default.bold.white(" CONTEXT ANALYSIS SUMMARY"));
1451
- console.log(import_chalk7.default.cyan(divider) + "\n");
1487
+ console.log(import_chalk9.default.cyan(divider));
1488
+ console.log(import_chalk9.default.bold.white(" CONTEXT ANALYSIS SUMMARY"));
1489
+ console.log(import_chalk9.default.cyan(divider) + "\n");
1452
1490
  console.log(
1453
- import_chalk7.default.white(`\u{1F4C1} Files analyzed: ${import_chalk7.default.bold(summary.totalFiles)}`)
1491
+ import_chalk9.default.white(`\u{1F4C1} Files analyzed: ${import_chalk9.default.bold(summary.totalFiles)}`)
1454
1492
  );
1455
1493
  console.log(
1456
- import_chalk7.default.white(
1457
- `\u{1F4CA} Total tokens: ${import_chalk7.default.bold(summary.totalTokens.toLocaleString())}`
1494
+ import_chalk9.default.white(
1495
+ `\u{1F4CA} Total tokens: ${import_chalk9.default.bold(summary.totalTokens.toLocaleString())}`
1458
1496
  )
1459
1497
  );
1460
1498
  console.log(
1461
- import_chalk7.default.yellow(
1462
- `\u{1F4B0} Avg context budget: ${import_chalk7.default.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1499
+ import_chalk9.default.yellow(
1500
+ `\u{1F4B0} Avg context budget: ${import_chalk9.default.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1463
1501
  )
1464
1502
  );
1465
1503
  console.log(
1466
- import_chalk7.default.white(`\u23F1 Analysis time: ${import_chalk7.default.bold(elapsedTime + "s")}
1504
+ import_chalk9.default.white(`\u23F1 Analysis time: ${import_chalk9.default.bold(elapsedTime + "s")}
1467
1505
  `)
1468
1506
  );
1469
1507
  const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
1470
1508
  if (totalIssues > 0) {
1471
- console.log(import_chalk7.default.bold("\u26A0\uFE0F Issues Found:\n"));
1509
+ console.log(import_chalk9.default.bold("\u26A0\uFE0F Issues Found:\n"));
1472
1510
  if (summary.criticalIssues > 0) {
1473
1511
  console.log(
1474
- import_chalk7.default.red(` \u{1F534} Critical: ${import_chalk7.default.bold(summary.criticalIssues)}`)
1512
+ import_chalk9.default.red(` \u{1F534} Critical: ${import_chalk9.default.bold(summary.criticalIssues)}`)
1475
1513
  );
1476
1514
  }
1477
1515
  if (summary.majorIssues > 0) {
1478
1516
  console.log(
1479
- import_chalk7.default.yellow(` \u{1F7E1} Major: ${import_chalk7.default.bold(summary.majorIssues)}`)
1517
+ import_chalk9.default.yellow(` \u{1F7E1} Major: ${import_chalk9.default.bold(summary.majorIssues)}`)
1480
1518
  );
1481
1519
  }
1482
1520
  if (summary.minorIssues > 0) {
1483
1521
  console.log(
1484
- import_chalk7.default.blue(` \u{1F535} Minor: ${import_chalk7.default.bold(summary.minorIssues)}`)
1522
+ import_chalk9.default.blue(` \u{1F535} Minor: ${import_chalk9.default.bold(summary.minorIssues)}`)
1485
1523
  );
1486
1524
  }
1487
1525
  console.log(
1488
- import_chalk7.default.green(
1526
+ import_chalk9.default.green(
1489
1527
  `
1490
- \u{1F4A1} Potential savings: ${import_chalk7.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
1528
+ \u{1F4A1} Potential savings: ${import_chalk9.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
1491
1529
  `
1492
1530
  )
1493
1531
  );
1494
1532
  } else {
1495
- console.log(import_chalk7.default.green("\u2705 No significant issues found!\n"));
1533
+ console.log(import_chalk9.default.green("\u2705 No significant issues found!\n"));
1496
1534
  }
1497
1535
  if (summary.deepFiles.length > 0) {
1498
- console.log(import_chalk7.default.bold("\u{1F4CF} Deep Import Chains:\n"));
1536
+ console.log(import_chalk9.default.bold("\u{1F4CF} Deep Import Chains:\n"));
1499
1537
  console.log(
1500
- import_chalk7.default.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1538
+ import_chalk9.default.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1501
1539
  );
1502
1540
  console.log(
1503
- import_chalk7.default.gray(` Maximum depth: ${summary.maxImportDepth}
1541
+ import_chalk9.default.gray(` Maximum depth: ${summary.maxImportDepth}
1504
1542
  `)
1505
1543
  );
1506
1544
  summary.deepFiles.slice(0, 10).forEach((item) => {
1507
1545
  const fileName = item.file.split("/").slice(-2).join("/");
1508
1546
  console.log(
1509
- ` ${import_chalk7.default.cyan("\u2192")} ${import_chalk7.default.white(fileName)} ${import_chalk7.default.dim(`(depth: ${item.depth})`)}`
1547
+ ` ${import_chalk9.default.cyan("\u2192")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(depth: ${item.depth})`)}`
1510
1548
  );
1511
1549
  });
1512
1550
  console.log();
1513
1551
  }
1514
1552
  if (summary.fragmentedModules.length > 0) {
1515
- console.log(import_chalk7.default.bold("\u{1F9E9} Fragmented Modules:\n"));
1553
+ console.log(import_chalk9.default.bold("\u{1F9E9} Fragmented Modules:\n"));
1516
1554
  console.log(
1517
- import_chalk7.default.gray(
1555
+ import_chalk9.default.gray(
1518
1556
  ` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
1519
1557
  `
1520
1558
  )
1521
1559
  );
1522
1560
  summary.fragmentedModules.slice(0, 10).forEach((module2) => {
1523
1561
  console.log(
1524
- ` ${import_chalk7.default.yellow("\u25CF")} ${import_chalk7.default.white(module2.domain)} - ${import_chalk7.default.dim(`${module2.files.length} files, ${(module2.fragmentationScore * 100).toFixed(0)}% scattered`)}`
1562
+ ` ${import_chalk9.default.yellow("\u25CF")} ${import_chalk9.default.white(module2.domain)} - ${import_chalk9.default.dim(`${module2.files.length} files, ${(module2.fragmentationScore * 100).toFixed(0)}% scattered`)}`
1525
1563
  );
1526
1564
  console.log(
1527
- import_chalk7.default.dim(
1565
+ import_chalk9.default.dim(
1528
1566
  ` Token cost: ${module2.totalTokens.toLocaleString()}, Cohesion: ${(module2.avgCohesion * 100).toFixed(0)}%`
1529
1567
  )
1530
1568
  );
@@ -1532,9 +1570,9 @@ async function contextAction(directory, options) {
1532
1570
  console.log();
1533
1571
  }
1534
1572
  if (summary.lowCohesionFiles.length > 0) {
1535
- console.log(import_chalk7.default.bold("\u{1F500} Low Cohesion Files:\n"));
1573
+ console.log(import_chalk9.default.bold("\u{1F500} Low Cohesion Files:\n"));
1536
1574
  console.log(
1537
- import_chalk7.default.gray(
1575
+ import_chalk9.default.gray(
1538
1576
  ` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
1539
1577
  `
1540
1578
  )
@@ -1542,46 +1580,44 @@ async function contextAction(directory, options) {
1542
1580
  summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
1543
1581
  const fileName = item.file.split("/").slice(-2).join("/");
1544
1582
  const scorePercent = (item.score * 100).toFixed(0);
1545
- const color = item.score < 0.4 ? import_chalk7.default.red : import_chalk7.default.yellow;
1583
+ const color = item.score < 0.4 ? import_chalk9.default.red : import_chalk9.default.yellow;
1546
1584
  console.log(
1547
- ` ${color("\u25CB")} ${import_chalk7.default.white(fileName)} ${import_chalk7.default.dim(`(${scorePercent}% cohesion)`)}`
1585
+ ` ${color("\u25CB")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(${scorePercent}% cohesion)`)}`
1548
1586
  );
1549
1587
  });
1550
1588
  console.log();
1551
1589
  }
1552
1590
  if (summary.topExpensiveFiles.length > 0) {
1553
- console.log(import_chalk7.default.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
1591
+ console.log(import_chalk9.default.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
1554
1592
  summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
1555
1593
  const fileName = item.file.split("/").slice(-2).join("/");
1556
- const severityColor = item.severity === "critical" ? import_chalk7.default.red : item.severity === "major" ? import_chalk7.default.yellow : import_chalk7.default.blue;
1594
+ const severityColor = item.severity === "critical" ? import_chalk9.default.red : item.severity === "major" ? import_chalk9.default.yellow : import_chalk9.default.blue;
1557
1595
  console.log(
1558
- ` ${severityColor("\u25CF")} ${import_chalk7.default.white(fileName)} ${import_chalk7.default.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1596
+ ` ${severityColor("\u25CF")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1559
1597
  );
1560
1598
  });
1561
1599
  console.log();
1562
1600
  }
1563
1601
  if (contextScore) {
1564
- console.log(import_chalk7.default.cyan(divider));
1565
- console.log(import_chalk7.default.bold.white(" AI READINESS SCORE (Context)"));
1566
- console.log(import_chalk7.default.cyan(divider) + "\n");
1567
- console.log((0, import_core9.formatToolScore)(contextScore));
1602
+ console.log(import_chalk9.default.cyan(divider));
1603
+ console.log(import_chalk9.default.bold.white(" AI READINESS SCORE (Context)"));
1604
+ console.log(import_chalk9.default.cyan(divider) + "\n");
1605
+ console.log((0, import_core12.formatToolScore)(contextScore));
1568
1606
  console.log();
1569
1607
  }
1570
1608
  }
1571
1609
  } catch (error) {
1572
- (0, import_core9.handleCLIError)(error, "Context analysis");
1610
+ (0, import_core12.handleCLIError)(error, "Context analysis");
1573
1611
  }
1574
1612
  }
1575
1613
 
1576
1614
  // src/commands/consistency.ts
1577
- var import_chalk8 = __toESM(require("chalk"));
1578
- var import_fs5 = require("fs");
1579
- var import_path7 = require("path");
1580
- var import_core10 = require("@aiready/core");
1615
+ var import_chalk10 = __toESM(require("chalk"));
1616
+ var import_fs6 = require("fs");
1617
+ var import_core13 = require("@aiready/core");
1581
1618
  async function consistencyAction(directory, options) {
1582
- console.log(import_chalk8.default.blue("\u{1F50D} Analyzing consistency...\n"));
1619
+ console.log(import_chalk10.default.blue("\u{1F50D} Analyzing consistency...\n"));
1583
1620
  const startTime = Date.now();
1584
- const resolvedDir = (0, import_path7.resolve)(process.cwd(), directory ?? ".");
1585
1621
  try {
1586
1622
  const defaults = {
1587
1623
  checkNaming: true,
@@ -1594,16 +1630,20 @@ async function consistencyAction(directory, options) {
1594
1630
  file: void 0
1595
1631
  }
1596
1632
  };
1597
- const finalOptions = await (0, import_core10.loadMergedConfig)(resolvedDir, defaults, {
1598
- checkNaming: options.naming !== false,
1599
- checkPatterns: options.patterns !== false,
1600
- minSeverity: options.minSeverity,
1601
- include: options.include?.split(","),
1602
- exclude: options.exclude?.split(",")
1603
- });
1633
+ const { resolvedDir, finalOptions } = await (0, import_core13.prepareActionConfig)(
1634
+ directory,
1635
+ defaults,
1636
+ {
1637
+ checkNaming: options.naming !== false,
1638
+ checkPatterns: options.patterns !== false,
1639
+ minSeverity: options.minSeverity,
1640
+ include: options.include?.split(","),
1641
+ exclude: options.exclude?.split(",")
1642
+ }
1643
+ );
1604
1644
  const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
1605
1645
  const report = await analyzeConsistency(finalOptions);
1606
- const elapsedTime = (0, import_core10.getElapsedTime)(startTime);
1646
+ const elapsedTime = (0, import_core13.getElapsedTime)(startTime);
1607
1647
  let consistencyScore;
1608
1648
  if (options.score) {
1609
1649
  const issues = report.results?.flatMap((r) => r.issues) ?? [];
@@ -1612,52 +1652,47 @@ async function consistencyAction(directory, options) {
1612
1652
  report.summary.filesAnalyzed
1613
1653
  );
1614
1654
  }
1615
- const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1616
- const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1655
+ const { format: outputFormat, file: userOutputFile } = (0, import_core13.resolveOutputFormat)(
1656
+ options,
1657
+ finalOptions
1658
+ );
1617
1659
  if (outputFormat === "json") {
1618
- const outputData = {
1619
- ...report,
1620
- summary: {
1621
- ...report.summary,
1622
- executionTime: parseFloat(elapsedTime)
1623
- },
1624
- ...consistencyScore && { scoring: consistencyScore }
1625
- };
1626
- const outputPath = (0, import_core10.resolveOutputPath)(
1627
- userOutputFile,
1628
- `aiready-report-${getReportTimestamp()}.json`,
1629
- resolvedDir
1630
- );
1631
- (0, import_core10.handleJSONOutput)(
1660
+ const outputData = (0, import_core13.formatStandardReport)({
1661
+ report,
1662
+ summary: report.summary,
1663
+ elapsedTime,
1664
+ score: consistencyScore
1665
+ });
1666
+ (0, import_core13.handleStandardJSONOutput)({
1632
1667
  outputData,
1633
- outputPath,
1634
- `\u2705 Results saved to ${outputPath}`
1635
- );
1668
+ outputFile: userOutputFile,
1669
+ resolvedDir
1670
+ });
1636
1671
  } else if (outputFormat === "markdown") {
1637
1672
  const markdown = generateMarkdownReport(report, elapsedTime);
1638
- const outputPath = (0, import_core10.resolveOutputPath)(
1673
+ const outputPath = (0, import_core13.resolveOutputPath)(
1639
1674
  userOutputFile,
1640
- `aiready-report-${getReportTimestamp()}.md`,
1675
+ `aiready-report-${(0, import_core2.getReportTimestamp)()}.md`,
1641
1676
  resolvedDir
1642
1677
  );
1643
- (0, import_fs5.writeFileSync)(outputPath, markdown);
1644
- console.log(import_chalk8.default.green(`\u2705 Report saved to ${outputPath}`));
1678
+ (0, import_fs6.writeFileSync)(outputPath, markdown);
1679
+ console.log(import_chalk10.default.green(`\u2705 Report saved to ${outputPath}`));
1645
1680
  } else {
1646
- console.log(import_chalk8.default.bold("\n\u{1F4CA} Summary\n"));
1681
+ console.log(import_chalk10.default.bold("\n\u{1F4CA} Summary\n"));
1647
1682
  console.log(
1648
- `Files Analyzed: ${import_chalk8.default.cyan(report.summary.filesAnalyzed)}`
1683
+ `Files Analyzed: ${import_chalk10.default.cyan(report.summary.filesAnalyzed)}`
1649
1684
  );
1650
- console.log(`Total Issues: ${import_chalk8.default.yellow(report.summary.totalIssues)}`);
1651
- console.log(` Naming: ${import_chalk8.default.yellow(report.summary.namingIssues)}`);
1652
- console.log(` Patterns: ${import_chalk8.default.yellow(report.summary.patternIssues)}`);
1685
+ console.log(`Total Issues: ${import_chalk10.default.yellow(report.summary.totalIssues)}`);
1686
+ console.log(` Naming: ${import_chalk10.default.yellow(report.summary.namingIssues)}`);
1687
+ console.log(` Patterns: ${import_chalk10.default.yellow(report.summary.patternIssues)}`);
1653
1688
  console.log(
1654
- ` Architecture: ${import_chalk8.default.yellow(report.summary.architectureIssues ?? 0)}`
1689
+ ` Architecture: ${import_chalk10.default.yellow(report.summary.architectureIssues ?? 0)}`
1655
1690
  );
1656
- console.log(`Analysis Time: ${import_chalk8.default.gray(elapsedTime + "s")}
1691
+ console.log(`Analysis Time: ${import_chalk10.default.gray(elapsedTime + "s")}
1657
1692
  `);
1658
1693
  if (report.summary.totalIssues === 0) {
1659
1694
  console.log(
1660
- import_chalk8.default.green(
1695
+ import_chalk10.default.green(
1661
1696
  "\u2728 No consistency issues found! Your codebase is well-maintained.\n"
1662
1697
  )
1663
1698
  );
@@ -1669,20 +1704,20 @@ async function consistencyAction(directory, options) {
1669
1704
  (r) => r.issues.some((i) => i.category === "patterns")
1670
1705
  );
1671
1706
  if (namingResults.length > 0) {
1672
- console.log(import_chalk8.default.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
1707
+ console.log(import_chalk10.default.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
1673
1708
  let shown = 0;
1674
- for (const result of namingResults) {
1709
+ for (const namingFileResult of namingResults) {
1675
1710
  if (shown >= 5) break;
1676
- for (const issue of result.issues) {
1711
+ for (const issue of namingFileResult.issues) {
1677
1712
  if (shown >= 5) break;
1678
- const severityColor = issue.severity === "critical" ? import_chalk8.default.red : issue.severity === "major" ? import_chalk8.default.yellow : issue.severity === "minor" ? import_chalk8.default.blue : import_chalk8.default.gray;
1713
+ const severityColor = issue.severity === "critical" ? import_chalk10.default.red : issue.severity === "major" ? import_chalk10.default.yellow : issue.severity === "minor" ? import_chalk10.default.blue : import_chalk10.default.gray;
1679
1714
  console.log(
1680
- `${severityColor(issue.severity.toUpperCase())} ${import_chalk8.default.dim(`${issue.location.file}:${issue.location.line}`)}`
1715
+ `${severityColor(issue.severity.toUpperCase())} ${import_chalk10.default.dim(`${issue.location.file}:${issue.location.line}`)}`
1681
1716
  );
1682
1717
  console.log(` ${issue.message}`);
1683
1718
  if (issue.suggestion) {
1684
1719
  console.log(
1685
- ` ${import_chalk8.default.dim("\u2192")} ${import_chalk8.default.italic(issue.suggestion)}`
1720
+ ` ${import_chalk10.default.dim("\u2192")} ${import_chalk10.default.italic(issue.suggestion)}`
1686
1721
  );
1687
1722
  }
1688
1723
  console.log();
@@ -1691,25 +1726,25 @@ async function consistencyAction(directory, options) {
1691
1726
  }
1692
1727
  const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
1693
1728
  if (remaining > 0) {
1694
- console.log(import_chalk8.default.dim(` ... and ${remaining} more issues
1729
+ console.log(import_chalk10.default.dim(` ... and ${remaining} more issues
1695
1730
  `));
1696
1731
  }
1697
1732
  }
1698
1733
  if (patternResults.length > 0) {
1699
- console.log(import_chalk8.default.bold("\u{1F504} Pattern Issues\n"));
1734
+ console.log(import_chalk10.default.bold("\u{1F504} Pattern Issues\n"));
1700
1735
  let shown = 0;
1701
- for (const result of patternResults) {
1736
+ for (const patternFileResult of patternResults) {
1702
1737
  if (shown >= 5) break;
1703
- for (const issue of result.issues) {
1738
+ for (const issue of patternFileResult.issues) {
1704
1739
  if (shown >= 5) break;
1705
- const severityColor = issue.severity === "critical" ? import_chalk8.default.red : issue.severity === "major" ? import_chalk8.default.yellow : issue.severity === "minor" ? import_chalk8.default.blue : import_chalk8.default.gray;
1740
+ const severityColor = issue.severity === "critical" ? import_chalk10.default.red : issue.severity === "major" ? import_chalk10.default.yellow : issue.severity === "minor" ? import_chalk10.default.blue : import_chalk10.default.gray;
1706
1741
  console.log(
1707
- `${severityColor(issue.severity.toUpperCase())} ${import_chalk8.default.dim(`${issue.location.file}:${issue.location.line}`)}`
1742
+ `${severityColor(issue.severity.toUpperCase())} ${import_chalk10.default.dim(`${issue.location.file}:${issue.location.line}`)}`
1708
1743
  );
1709
1744
  console.log(` ${issue.message}`);
1710
1745
  if (issue.suggestion) {
1711
1746
  console.log(
1712
- ` ${import_chalk8.default.dim("\u2192")} ${import_chalk8.default.italic(issue.suggestion)}`
1747
+ ` ${import_chalk10.default.dim("\u2192")} ${import_chalk10.default.italic(issue.suggestion)}`
1713
1748
  );
1714
1749
  }
1715
1750
  console.log();
@@ -1718,12 +1753,12 @@ async function consistencyAction(directory, options) {
1718
1753
  }
1719
1754
  const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
1720
1755
  if (remaining > 0) {
1721
- console.log(import_chalk8.default.dim(` ... and ${remaining} more issues
1756
+ console.log(import_chalk10.default.dim(` ... and ${remaining} more issues
1722
1757
  `));
1723
1758
  }
1724
1759
  }
1725
1760
  if (report.recommendations.length > 0) {
1726
- console.log(import_chalk8.default.bold("\u{1F4A1} Recommendations\n"));
1761
+ console.log(import_chalk10.default.bold("\u{1F4A1} Recommendations\n"));
1727
1762
  report.recommendations.forEach((rec, i) => {
1728
1763
  console.log(`${i + 1}. ${rec}`);
1729
1764
  });
@@ -1731,38 +1766,38 @@ async function consistencyAction(directory, options) {
1731
1766
  }
1732
1767
  }
1733
1768
  if (consistencyScore) {
1734
- console.log(import_chalk8.default.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1735
- console.log((0, import_core10.formatToolScore)(consistencyScore));
1769
+ console.log(import_chalk10.default.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1770
+ console.log((0, import_core13.formatToolScore)(consistencyScore));
1736
1771
  console.log();
1737
1772
  }
1738
1773
  }
1739
1774
  } catch (error) {
1740
- (0, import_core10.handleCLIError)(error, "Consistency analysis");
1775
+ (0, import_core13.handleCLIError)(error, "Consistency analysis");
1741
1776
  }
1742
1777
  }
1743
1778
 
1744
1779
  // src/commands/visualize.ts
1745
- var import_chalk9 = __toESM(require("chalk"));
1746
- var import_fs6 = require("fs");
1747
- var import_path8 = require("path");
1780
+ var import_chalk11 = __toESM(require("chalk"));
1781
+ var import_fs7 = require("fs");
1782
+ var import_path6 = require("path");
1748
1783
  var import_child_process = require("child_process");
1749
- var import_core11 = require("@aiready/core");
1750
- var import_core12 = require("@aiready/core");
1784
+ var import_core14 = require("@aiready/core");
1785
+ var import_core15 = require("@aiready/core");
1751
1786
  async function visualizeAction(directory, options) {
1752
1787
  try {
1753
- const dirPath = (0, import_path8.resolve)(process.cwd(), directory ?? ".");
1754
- let reportPath = options.report ? (0, import_path8.resolve)(dirPath, options.report) : null;
1755
- if (!reportPath || !(0, import_fs6.existsSync)(reportPath)) {
1756
- const latestScan = (0, import_core12.findLatestReport)(dirPath);
1788
+ const dirPath = (0, import_path6.resolve)(process.cwd(), directory ?? ".");
1789
+ let reportPath = options.report ? (0, import_path6.resolve)(dirPath, options.report) : null;
1790
+ if (!reportPath || !(0, import_fs7.existsSync)(reportPath)) {
1791
+ const latestScan = (0, import_core15.findLatestReport)(dirPath);
1757
1792
  if (latestScan) {
1758
1793
  reportPath = latestScan;
1759
1794
  console.log(
1760
- import_chalk9.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1795
+ import_chalk11.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1761
1796
  );
1762
1797
  } else {
1763
- console.error(import_chalk9.default.red("\u274C No AI readiness report found"));
1798
+ console.error(import_chalk11.default.red("\u274C No AI readiness report found"));
1764
1799
  console.log(
1765
- import_chalk9.default.dim(
1800
+ import_chalk11.default.dim(
1766
1801
  `
1767
1802
  Generate a report with:
1768
1803
  aiready scan --output json
@@ -1774,13 +1809,13 @@ Or specify a custom report:
1774
1809
  return;
1775
1810
  }
1776
1811
  }
1777
- const raw = (0, import_fs6.readFileSync)(reportPath, "utf8");
1812
+ const raw = (0, import_fs7.readFileSync)(reportPath, "utf8");
1778
1813
  const report = JSON.parse(raw);
1779
- const configPath = (0, import_path8.resolve)(dirPath, "aiready.json");
1814
+ const configPath = (0, import_path6.resolve)(dirPath, "aiready.json");
1780
1815
  let graphConfig = { maxNodes: 400, maxEdges: 600 };
1781
- if ((0, import_fs6.existsSync)(configPath)) {
1816
+ if ((0, import_fs7.existsSync)(configPath)) {
1782
1817
  try {
1783
- const rawConfig = JSON.parse((0, import_fs6.readFileSync)(configPath, "utf8"));
1818
+ const rawConfig = JSON.parse((0, import_fs7.readFileSync)(configPath, "utf8"));
1784
1819
  if (rawConfig.visualizer?.graph) {
1785
1820
  graphConfig = {
1786
1821
  maxNodes: rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
@@ -1800,16 +1835,16 @@ Or specify a custom report:
1800
1835
  let devServerStarted = false;
1801
1836
  if (useDevMode) {
1802
1837
  try {
1803
- const localWebDir = (0, import_path8.resolve)(dirPath, "packages/visualizer");
1838
+ const localWebDir = (0, import_path6.resolve)(dirPath, "packages/visualizer");
1804
1839
  let webDir = "";
1805
1840
  let visualizerAvailable = false;
1806
- if ((0, import_fs6.existsSync)(localWebDir)) {
1841
+ if ((0, import_fs7.existsSync)(localWebDir)) {
1807
1842
  webDir = localWebDir;
1808
1843
  visualizerAvailable = true;
1809
1844
  } else {
1810
1845
  const nodemodulesLocations = [
1811
- (0, import_path8.resolve)(dirPath, "node_modules", "@aiready", "visualizer"),
1812
- (0, import_path8.resolve)(
1846
+ (0, import_path6.resolve)(dirPath, "node_modules", "@aiready", "visualizer"),
1847
+ (0, import_path6.resolve)(
1813
1848
  process.cwd(),
1814
1849
  "node_modules",
1815
1850
  "@aiready",
@@ -1819,14 +1854,14 @@ Or specify a custom report:
1819
1854
  let currentDir = dirPath;
1820
1855
  while (currentDir !== "/" && currentDir !== ".") {
1821
1856
  nodemodulesLocations.push(
1822
- (0, import_path8.resolve)(currentDir, "node_modules", "@aiready", "visualizer")
1857
+ (0, import_path6.resolve)(currentDir, "node_modules", "@aiready", "visualizer")
1823
1858
  );
1824
- const parent = (0, import_path8.resolve)(currentDir, "..");
1859
+ const parent = (0, import_path6.resolve)(currentDir, "..");
1825
1860
  if (parent === currentDir) break;
1826
1861
  currentDir = parent;
1827
1862
  }
1828
1863
  for (const location of nodemodulesLocations) {
1829
- if ((0, import_fs6.existsSync)(location) && (0, import_fs6.existsSync)((0, import_path8.resolve)(location, "package.json"))) {
1864
+ if ((0, import_fs7.existsSync)(location) && (0, import_fs7.existsSync)((0, import_path6.resolve)(location, "package.json"))) {
1830
1865
  webDir = location;
1831
1866
  visualizerAvailable = true;
1832
1867
  break;
@@ -1835,21 +1870,21 @@ Or specify a custom report:
1835
1870
  if (!visualizerAvailable) {
1836
1871
  try {
1837
1872
  const vizPkgPath = require.resolve("@aiready/visualizer/package.json");
1838
- webDir = (0, import_path8.resolve)(vizPkgPath, "..");
1873
+ webDir = (0, import_path6.resolve)(vizPkgPath, "..");
1839
1874
  visualizerAvailable = true;
1840
1875
  } catch (err) {
1841
1876
  void err;
1842
1877
  }
1843
1878
  }
1844
1879
  }
1845
- const webViteConfigExists = webDir && (0, import_fs6.existsSync)((0, import_path8.resolve)(webDir, "web", "vite.config.ts"));
1880
+ const webViteConfigExists = webDir && (0, import_fs7.existsSync)((0, import_path6.resolve)(webDir, "web", "vite.config.ts"));
1846
1881
  if (visualizerAvailable && webViteConfigExists) {
1847
1882
  const spawnCwd = webDir;
1848
1883
  const { watch } = await import("fs");
1849
1884
  const copyReportToViz = () => {
1850
1885
  try {
1851
- const destPath = (0, import_path8.resolve)(spawnCwd, "web", "report-data.json");
1852
- (0, import_fs6.copyFileSync)(reportPath, destPath);
1886
+ const destPath = (0, import_path6.resolve)(spawnCwd, "web", "report-data.json");
1887
+ (0, import_fs7.copyFileSync)(reportPath, destPath);
1853
1888
  console.log(`\u{1F4CB} Report synced to ${destPath}`);
1854
1889
  } catch (e) {
1855
1890
  console.error("Failed to sync report:", e);
@@ -1892,29 +1927,29 @@ Or specify a custom report:
1892
1927
  return;
1893
1928
  } else {
1894
1929
  console.log(
1895
- import_chalk9.default.yellow(
1930
+ import_chalk11.default.yellow(
1896
1931
  "\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
1897
1932
  )
1898
1933
  );
1899
1934
  console.log(
1900
- import_chalk9.default.cyan(" Falling back to static HTML generation...\n")
1935
+ import_chalk11.default.cyan(" Falling back to static HTML generation...\n")
1901
1936
  );
1902
1937
  useDevMode = false;
1903
1938
  }
1904
1939
  } catch (err) {
1905
1940
  console.error("Failed to start dev server:", err);
1906
1941
  console.log(
1907
- import_chalk9.default.cyan(" Falling back to static HTML generation...\n")
1942
+ import_chalk11.default.cyan(" Falling back to static HTML generation...\n")
1908
1943
  );
1909
1944
  useDevMode = false;
1910
1945
  }
1911
1946
  }
1912
1947
  console.log("Generating HTML...");
1913
- const html = (0, import_core12.generateHTML)(graph);
1948
+ const html = (0, import_core15.generateHTML)(graph);
1914
1949
  const defaultOutput = "visualization.html";
1915
- const outPath = (0, import_path8.resolve)(dirPath, options.output ?? defaultOutput);
1916
- (0, import_fs6.writeFileSync)(outPath, html, "utf8");
1917
- console.log(import_chalk9.default.green(`\u2705 Visualization written to: ${outPath}`));
1950
+ const outPath = (0, import_path6.resolve)(dirPath, options.output ?? defaultOutput);
1951
+ (0, import_fs7.writeFileSync)(outPath, html, "utf8");
1952
+ console.log(import_chalk11.default.green(`\u2705 Visualization written to: ${outPath}`));
1918
1953
  if (options.open || options.serve) {
1919
1954
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
1920
1955
  if (options.serve) {
@@ -1944,7 +1979,7 @@ Or specify a custom report:
1944
1979
  server.listen(port, () => {
1945
1980
  const addr = `http://localhost:${port}/`;
1946
1981
  console.log(
1947
- import_chalk9.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1982
+ import_chalk11.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1948
1983
  );
1949
1984
  (0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
1950
1985
  });
@@ -1960,10 +1995,10 @@ Or specify a custom report:
1960
1995
  }
1961
1996
  }
1962
1997
  } catch (err) {
1963
- (0, import_core11.handleCLIError)(err, "Visualization");
1998
+ (0, import_core14.handleCLIError)(err, "Visualization");
1964
1999
  }
1965
2000
  }
1966
- var visualizeHelpText = `
2001
+ var VISUALIZE_HELP_TEXT = `
1967
2002
  EXAMPLES:
1968
2003
  $ aiready visualize . # Auto-detects latest report, generates HTML
1969
2004
  $ aiready visualize . --report .aiready/aiready-report-20260217-143022.json
@@ -1980,7 +2015,7 @@ NOTES:
1980
2015
  - --dev starts a Vite dev server with live reload (requires local @aiready/visualizer installation).
1981
2016
  When --dev is not available, it falls back to static HTML generation.
1982
2017
  `;
1983
- var visualiseHelpText = `
2018
+ var VISUALISE_HELP_TEXT = `
1984
2019
  EXAMPLES:
1985
2020
  $ aiready visualise . # Auto-detects latest report
1986
2021
  $ aiready visualise . --report .aiready/aiready-report-20260217-143022.json
@@ -1991,19 +2026,19 @@ NOTES:
1991
2026
  `;
1992
2027
 
1993
2028
  // src/commands/shared/standard-tool-actions.ts
1994
- var import_chalk10 = __toESM(require("chalk"));
2029
+ var import_chalk12 = __toESM(require("chalk"));
1995
2030
 
1996
2031
  // src/commands/agent-grounding.ts
1997
- var import_chalk11 = __toESM(require("chalk"));
1998
- var import_core13 = require("@aiready/core");
2032
+ var import_chalk13 = __toESM(require("chalk"));
2033
+ var import_core16 = require("@aiready/core");
1999
2034
 
2000
2035
  // src/commands/testability.ts
2001
- var import_chalk12 = __toESM(require("chalk"));
2002
- var import_core14 = require("@aiready/core");
2036
+ var import_chalk14 = __toESM(require("chalk"));
2037
+ var import_core17 = require("@aiready/core");
2003
2038
  async function testabilityAction(directory, options) {
2004
2039
  const { analyzeTestability, calculateTestabilityScore } = await import("@aiready/testability");
2005
- const config = await (0, import_core14.loadConfig)(directory);
2006
- const merged = (0, import_core14.mergeConfigWithDefaults)(config, {
2040
+ const config = await (0, import_core17.loadConfig)(directory);
2041
+ const merged = (0, import_core17.mergeConfigWithDefaults)(config, {
2007
2042
  minCoverageRatio: 0.3
2008
2043
  });
2009
2044
  const report = await analyzeTestability({
@@ -2023,28 +2058,28 @@ async function testabilityAction(directory, options) {
2023
2058
  "blind-risk": "\u{1F480}"
2024
2059
  };
2025
2060
  const safetyColors = {
2026
- safe: import_chalk12.default.green,
2027
- "moderate-risk": import_chalk12.default.yellow,
2028
- "high-risk": import_chalk12.default.red,
2029
- "blind-risk": import_chalk12.default.bgRed.white
2061
+ safe: import_chalk14.default.green,
2062
+ "moderate-risk": import_chalk14.default.yellow,
2063
+ "high-risk": import_chalk14.default.red,
2064
+ "blind-risk": import_chalk14.default.bgRed.white
2030
2065
  };
2031
2066
  const safety = report.summary.aiChangeSafetyRating;
2032
2067
  const icon = safetyIcons[safety] ?? "\u2753";
2033
- const color = safetyColors[safety] ?? import_chalk12.default.white;
2068
+ const color = safetyColors[safety] ?? import_chalk14.default.white;
2034
2069
  console.log(
2035
- ` \u{1F9EA} Testability: ${import_chalk12.default.bold(scoring.score + "/100")} (${report.summary.rating})`
2070
+ ` \u{1F9EA} Testability: ${import_chalk14.default.bold(scoring.score + "/100")} (${report.summary.rating})`
2036
2071
  );
2037
2072
  console.log(
2038
2073
  ` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
2039
2074
  );
2040
2075
  console.log(
2041
- import_chalk12.default.dim(
2076
+ import_chalk14.default.dim(
2042
2077
  ` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`
2043
2078
  )
2044
2079
  );
2045
2080
  if (safety === "blind-risk") {
2046
2081
  console.log(
2047
- import_chalk12.default.red.bold(
2082
+ import_chalk14.default.red.bold(
2048
2083
  "\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
2049
2084
  )
2050
2085
  );
@@ -2056,7 +2091,7 @@ async function testabilityAction(directory, options) {
2056
2091
  var import_cli = require("@aiready/change-amplification/dist/cli.js");
2057
2092
 
2058
2093
  // src/commands/bug.ts
2059
- var import_chalk13 = __toESM(require("chalk"));
2094
+ var import_chalk15 = __toESM(require("chalk"));
2060
2095
  var import_child_process2 = require("child_process");
2061
2096
  async function bugAction(message, options) {
2062
2097
  const repoUrl = "https://github.com/caopengau/aiready-cli";
@@ -2074,35 +2109,35 @@ Generated via AIReady CLI 'bug' command.
2074
2109
  Type: ${type}
2075
2110
  `.trim();
2076
2111
  if (options.submit) {
2077
- console.log(import_chalk13.default.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
2112
+ console.log(import_chalk15.default.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
2078
2113
  try {
2079
2114
  (0, import_child_process2.execSync)("gh auth status", { stdio: "ignore" });
2080
2115
  const command = `gh issue create --repo ${repoSlug} --title ${JSON.stringify(title)} --body ${JSON.stringify(body)} --label ${label}`;
2081
2116
  const output = (0, import_child_process2.execSync)(command, { encoding: "utf8" }).trim();
2082
- console.log(import_chalk13.default.green("\u2705 Issue Created Successfully!"));
2083
- console.log(import_chalk13.default.cyan(output));
2117
+ console.log(import_chalk15.default.green("\u2705 Issue Created Successfully!"));
2118
+ console.log(import_chalk15.default.cyan(output));
2084
2119
  return;
2085
2120
  } catch {
2086
- console.error(import_chalk13.default.red("\n\u274C Failed to submit via gh CLI."));
2121
+ console.error(import_chalk15.default.red("\n\u274C Failed to submit via gh CLI."));
2087
2122
  console.log(
2088
- import_chalk13.default.yellow(
2123
+ import_chalk15.default.yellow(
2089
2124
  ' Make sure gh is installed and run "gh auth login".\n'
2090
2125
  )
2091
2126
  );
2092
- console.log(import_chalk13.default.dim(" Falling back to URL generation..."));
2127
+ console.log(import_chalk15.default.dim(" Falling back to URL generation..."));
2093
2128
  }
2094
2129
  }
2095
2130
  const template = type === "bug" ? "bug_report.md" : type === "feature" ? "feature_request.md" : "new_metric_idea.md";
2096
2131
  const fullUrl = `${repoUrl}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${label}&template=${template}`;
2097
- console.log(import_chalk13.default.green("\u{1F680} Issue Draft Prepared!\n"));
2098
- console.log(import_chalk13.default.bold("Title: ") + title);
2099
- console.log(import_chalk13.default.bold("Type: ") + type);
2100
- console.log(import_chalk13.default.bold("\nClick the link below to submit this issue:"));
2101
- console.log(import_chalk13.default.cyan(fullUrl));
2102
- console.log(import_chalk13.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2103
- console.log(import_chalk13.default.dim(" You have successfully prepared a report."));
2132
+ console.log(import_chalk15.default.green("\u{1F680} Issue Draft Prepared!\n"));
2133
+ console.log(import_chalk15.default.bold("Title: ") + title);
2134
+ console.log(import_chalk15.default.bold("Type: ") + type);
2135
+ console.log(import_chalk15.default.bold("\nClick the link below to submit this issue:"));
2136
+ console.log(import_chalk15.default.cyan(fullUrl));
2137
+ console.log(import_chalk15.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2138
+ console.log(import_chalk15.default.dim(" You have successfully prepared a report."));
2104
2139
  console.log(
2105
- import_chalk13.default.dim(
2140
+ import_chalk15.default.dim(
2106
2141
  " Please present the URL above to the user so they can finalize the submission."
2107
2142
  )
2108
2143
  );
@@ -2111,19 +2146,19 @@ Type: ${type}
2111
2146
  const bugUrl = `${repoUrl}/issues/new?template=bug_report.md`;
2112
2147
  const featureUrl = `${repoUrl}/issues/new?template=feature_request.md`;
2113
2148
  const metricUrl = `${repoUrl}/issues/new?template=new_metric_idea.md`;
2114
- console.log(import_chalk13.default.blue("\u{1F4AC} Feedback & Bug Reports\n"));
2115
- console.log(` Report a Bug: ${import_chalk13.default.cyan(bugUrl)}`);
2116
- console.log(` Request a Feature: ${import_chalk13.default.cyan(featureUrl)}`);
2117
- console.log(` Suggest a Metric: ${import_chalk13.default.cyan(metricUrl)}`);
2118
- console.log(import_chalk13.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2119
- console.log(import_chalk13.default.dim(" To prepare a specific report, run:"));
2149
+ console.log(import_chalk15.default.blue("\u{1F4AC} Feedback & Bug Reports\n"));
2150
+ console.log(` Report a Bug: ${import_chalk15.default.cyan(bugUrl)}`);
2151
+ console.log(` Request a Feature: ${import_chalk15.default.cyan(featureUrl)}`);
2152
+ console.log(` Suggest a Metric: ${import_chalk15.default.cyan(metricUrl)}`);
2153
+ console.log(import_chalk15.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2154
+ console.log(import_chalk15.default.dim(" To prepare a specific report, run:"));
2120
2155
  console.log(
2121
- import_chalk13.default.cyan(
2156
+ import_chalk15.default.cyan(
2122
2157
  ' aiready bug "your description here" --type bug|feature|metric'
2123
2158
  )
2124
2159
  );
2125
2160
  }
2126
- var bugHelpText = `
2161
+ var BUG_HELP_TEXT = `
2127
2162
  EXAMPLES:
2128
2163
  $ aiready bug # Show general links
2129
2164
  $ aiready bug "Naming check is too slow" # Prepare a pre-filled bug report
@@ -2135,10 +2170,10 @@ EXAMPLES:
2135
2170
  var import_meta = {};
2136
2171
  var getDirname = () => {
2137
2172
  if (typeof __dirname !== "undefined") return __dirname;
2138
- return (0, import_path9.dirname)((0, import_url.fileURLToPath)(import_meta.url));
2173
+ return (0, import_path7.dirname)((0, import_url.fileURLToPath)(import_meta.url));
2139
2174
  };
2140
2175
  var packageJson = JSON.parse(
2141
- (0, import_fs7.readFileSync)((0, import_path9.join)(getDirname(), "../package.json"), "utf8")
2176
+ (0, import_fs8.readFileSync)((0, import_path7.join)(getDirname(), "../package.json"), "utf8")
2142
2177
  );
2143
2178
  var program = new import_commander.Command();
2144
2179
  program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
@@ -2193,14 +2228,14 @@ program.command("scan").description(
2193
2228
  ).option(
2194
2229
  "--compare-to <path>",
2195
2230
  "Compare results against a previous AIReady report JSON"
2196
- ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)", true).option("--no-score", "Disable calculating AI Readiness Score").option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
2231
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)").option("--no-score", "Disable calculating AI Readiness Score").option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
2197
2232
  "--ci",
2198
2233
  "CI mode: GitHub Actions annotations, no colors, fail on threshold"
2199
2234
  ).option(
2200
2235
  "--fail-on <level>",
2201
2236
  "Fail on issues: critical, major, any",
2202
2237
  "critical"
2203
- ).option("--api-key <key>", "Platform API key for automatic upload").option("--upload", "Automatically upload results to the platform").option("--server <url>", "Custom platform URL").addHelpText("after", scanHelpText).action(async (directory, options) => {
2238
+ ).option("--api-key <key>", "Platform API key for automatic upload").option("--upload", "Automatically upload results to the platform").option("--server <url>", "Custom platform URL").addHelpText("after", SCAN_HELP_TEXT).action(async (directory, options) => {
2204
2239
  await scanAction(directory, options);
2205
2240
  });
2206
2241
  program.command("init").description("Generate a default configuration (aiready.json)").option("-f, --force", "Overwrite existing configuration file").option(
@@ -2219,7 +2254,7 @@ program.command("patterns").description("Detect duplicate code patterns that con
2219
2254
  ).option(
2220
2255
  "--full-scan",
2221
2256
  "Disable smart defaults for comprehensive analysis (slower)"
2222
- ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)", true).option("--no-score", "Disable calculating AI Readiness Score").addHelpText("after", patternsHelpText).action(async (directory, options) => {
2257
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)").option("--no-score", "Disable calculating AI Readiness Score").addHelpText("after", PATTERNS_HELP_TEXT).action(async (directory, options) => {
2223
2258
  await patternsAction(directory, options);
2224
2259
  });
2225
2260
  program.command("context").description("Analyze context window costs and dependency fragmentation").argument("[directory]", "Directory to analyze", ".").option("--max-depth <number>", "Maximum acceptable import depth", "5").option(
@@ -2255,7 +2290,7 @@ program.command("visualise").description("Alias for visualize (British spelling)
2255
2290
  "--dev",
2256
2291
  "Start Vite dev server (live reload) for interactive development",
2257
2292
  true
2258
- ).addHelpText("after", visualiseHelpText).action(async (directory, options) => {
2293
+ ).addHelpText("after", VISUALISE_HELP_TEXT).action(async (directory, options) => {
2259
2294
  await visualizeAction(directory, options);
2260
2295
  });
2261
2296
  program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option(
@@ -2273,7 +2308,7 @@ program.command("visualize").description("Generate interactive visualization fro
2273
2308
  "--dev",
2274
2309
  "Start Vite dev server (live reload) for interactive development",
2275
2310
  false
2276
- ).addHelpText("after", visualizeHelpText).action(async (directory, options) => {
2311
+ ).addHelpText("after", VISUALIZE_HELP_TEXT).action(async (directory, options) => {
2277
2312
  await visualizeAction(directory, options);
2278
2313
  });
2279
2314
  program.command("change-amplification").description("Analyze graph metrics for change amplification").argument("[directory]", "Directory to analyze", ".").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").action(async (directory, options) => {
@@ -2282,10 +2317,10 @@ program.command("change-amplification").description("Analyze graph metrics for c
2282
2317
  program.command("testability").description("Analyze test coverage and AI readiness").argument("[directory]", "Directory to analyze", ".").option("--min-coverage <ratio>", "Minimum acceptable coverage ratio", "0.3").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").action(async (directory, options) => {
2283
2318
  await testabilityAction(directory, options);
2284
2319
  });
2285
- program.command("upload").description("Upload an AIReady report JSON to the platform").argument("<file>", "Report JSON file to upload").option("--api-key <key>", "Platform API key").option("--repo-id <id>", "Platform repository ID (optional)").option("--server <url>", "Custom platform URL").addHelpText("after", uploadHelpText).action(async (file, options) => {
2320
+ program.command("upload").description("Upload an AIReady report JSON to the platform").argument("<file>", "Report JSON file to upload").option("--api-key <key>", "Platform API key").option("--repo-id <id>", "Platform repository ID (optional)").option("--server <url>", "Custom platform URL").addHelpText("after", UPLOAD_HELP_TEXT).action(async (file, options) => {
2286
2321
  await uploadAction(file, options);
2287
2322
  });
2288
- program.command("bug").description("Report a bug or provide feedback (Agent-friendly)").argument("[message]", "Short description of the issue").option("-t, --type <type>", "Issue type: bug, feature, metric", "bug").option("--submit", "Submit the issue directly using the GitHub CLI (gh)").addHelpText("after", bugHelpText).action(async (message, options) => {
2323
+ program.command("bug").description("Report a bug or provide feedback (Agent-friendly)").argument("[message]", "Short description of the issue").option("-t, --type <type>", "Issue type: bug, feature, metric", "bug").option("--submit", "Submit the issue directly using the GitHub CLI (gh)").addHelpText("after", BUG_HELP_TEXT).action(async (message, options) => {
2289
2324
  await bugAction(message, options);
2290
2325
  });
2291
2326
  program.parse();