@aiready/cli 0.14.8 → 0.14.10

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.
@@ -0,0 +1,289 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/index.ts
9
+ import {
10
+ ToolRegistry,
11
+ ToolName,
12
+ calculateOverallScore,
13
+ calculateTokenBudget,
14
+ GLOBAL_INFRA_OPTIONS,
15
+ COMMON_FINE_TUNING_OPTIONS,
16
+ initializeParsers
17
+ } from "@aiready/core";
18
+ import "@aiready/pattern-detect";
19
+ import "@aiready/context-analyzer";
20
+ import "@aiready/consistency";
21
+ import "@aiready/ai-signal-clarity";
22
+ import "@aiready/agent-grounding";
23
+ import "@aiready/testability";
24
+ import "@aiready/doc-drift";
25
+ import "@aiready/deps";
26
+ import "@aiready/change-amplification";
27
+ var TOOL_PACKAGE_MAP = {
28
+ [ToolName.PatternDetect]: "@aiready/pattern-detect",
29
+ [ToolName.ContextAnalyzer]: "@aiready/context-analyzer",
30
+ [ToolName.NamingConsistency]: "@aiready/consistency",
31
+ [ToolName.AiSignalClarity]: "@aiready/ai-signal-clarity",
32
+ [ToolName.AgentGrounding]: "@aiready/agent-grounding",
33
+ [ToolName.TestabilityIndex]: "@aiready/testability",
34
+ [ToolName.DocDrift]: "@aiready/doc-drift",
35
+ [ToolName.DependencyHealth]: "@aiready/deps",
36
+ [ToolName.ChangeAmplification]: "@aiready/change-amplification",
37
+ // Aliases handled by registry
38
+ patterns: "@aiready/pattern-detect",
39
+ duplicates: "@aiready/pattern-detect",
40
+ context: "@aiready/context-analyzer",
41
+ fragmentation: "@aiready/context-analyzer",
42
+ consistency: "@aiready/consistency",
43
+ "ai-signal": "@aiready/ai-signal-clarity",
44
+ grounding: "@aiready/agent-grounding",
45
+ testability: "@aiready/testability",
46
+ "deps-health": "@aiready/deps",
47
+ "change-amp": "@aiready/change-amplification"
48
+ };
49
+ function sanitizeConfigRecursive(obj) {
50
+ if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
51
+ const sanitized = {};
52
+ const infraToStrip = [
53
+ "rootDir",
54
+ "onProgress",
55
+ "progressCallback",
56
+ "streamResults",
57
+ "batchSize",
58
+ "useSmartDefaults"
59
+ ];
60
+ for (const [key, value] of Object.entries(obj)) {
61
+ if (infraToStrip.includes(key)) continue;
62
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
63
+ sanitized[key] = sanitizeConfigRecursive(value);
64
+ } else {
65
+ sanitized[key] = value;
66
+ }
67
+ }
68
+ return sanitized;
69
+ }
70
+ function sanitizeToolConfig(config) {
71
+ return sanitizeConfigRecursive(config);
72
+ }
73
+ async function analyzeUnified(options) {
74
+ await initializeParsers();
75
+ const startTime = Date.now();
76
+ const requestedTools = options.tools ?? [
77
+ "patterns",
78
+ "context",
79
+ "consistency"
80
+ ];
81
+ const result = {
82
+ summary: {
83
+ totalIssues: 0,
84
+ criticalIssues: 0,
85
+ // Added as per instruction
86
+ majorIssues: 0,
87
+ // Added as per instruction
88
+ totalFiles: 0,
89
+ toolsRun: [],
90
+ executionTime: 0,
91
+ config: options,
92
+ toolConfigs: {}
93
+ }
94
+ };
95
+ for (const toolName of requestedTools) {
96
+ let provider = ToolRegistry.find(toolName);
97
+ if (!provider) {
98
+ const packageName = TOOL_PACKAGE_MAP[toolName] || (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
99
+ try {
100
+ await import(packageName);
101
+ provider = ToolRegistry.find(toolName);
102
+ if (provider) {
103
+ console.log(
104
+ `\u2705 Successfully loaded tool provider: ${toolName} from ${packageName}`
105
+ );
106
+ } else {
107
+ console.log(
108
+ `\u26A0\uFE0F Loaded ${packageName} but provider ${toolName} still not found in registry.`
109
+ );
110
+ }
111
+ } catch (err) {
112
+ console.log(
113
+ `\u274C Failed to dynamically load tool ${toolName} (${packageName}):`,
114
+ err.message
115
+ );
116
+ }
117
+ }
118
+ if (!provider) {
119
+ console.warn(
120
+ `\u26A0\uFE0F Warning: Tool provider for '${toolName}' not found. Skipping.`
121
+ );
122
+ continue;
123
+ }
124
+ try {
125
+ const sanitizedOptions = { ...options };
126
+ delete sanitizedOptions.onProgress;
127
+ delete sanitizedOptions.progressCallback;
128
+ const toolOptions = {
129
+ rootDir: options.rootDir
130
+ // Always include rootDir
131
+ };
132
+ [...GLOBAL_INFRA_OPTIONS, ...COMMON_FINE_TUNING_OPTIONS].forEach(
133
+ (key) => {
134
+ if (key in options && key !== "toolConfigs" && key !== "tools") {
135
+ toolOptions[key] = options[key];
136
+ }
137
+ }
138
+ );
139
+ if (options.toolConfigs?.[provider.id]) {
140
+ Object.assign(toolOptions, options.toolConfigs[provider.id]);
141
+ } else if (options.tools && !Array.isArray(options.tools) && typeof options.tools === "object" && options.tools[provider.id]) {
142
+ Object.assign(toolOptions, options.tools[provider.id]);
143
+ } else if (options[provider.id]) {
144
+ Object.assign(toolOptions, options[provider.id]);
145
+ }
146
+ toolOptions.onProgress = (processed, total, message) => {
147
+ if (options.progressCallback) {
148
+ options.progressCallback({
149
+ tool: provider.id,
150
+ processed,
151
+ total,
152
+ message
153
+ });
154
+ }
155
+ };
156
+ const output = await provider.analyze(toolOptions);
157
+ if (output.metadata) {
158
+ output.metadata.config = sanitizeToolConfig(toolOptions);
159
+ }
160
+ if (options.progressCallback) {
161
+ options.progressCallback({ tool: provider.id, data: output });
162
+ }
163
+ result[provider.id] = output;
164
+ result.summary.toolsRun.push(provider.id);
165
+ if (output.summary?.config) {
166
+ result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
167
+ output.summary.config
168
+ );
169
+ } else if (output.metadata?.config) {
170
+ result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
171
+ output.metadata.config
172
+ );
173
+ } else {
174
+ result.summary.toolConfigs[provider.id] = sanitizeToolConfig(toolOptions);
175
+ }
176
+ const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
177
+ if (toolFiles > result.summary.totalFiles) {
178
+ result.summary.totalFiles = toolFiles;
179
+ }
180
+ const issueCount = output.results.reduce(
181
+ (sum, file) => sum + (file.issues?.length ?? 0),
182
+ 0
183
+ );
184
+ result.summary.totalIssues += issueCount;
185
+ } catch (err) {
186
+ console.error(`\u274C Error running tool '${provider.id}':`, err);
187
+ }
188
+ }
189
+ result.summary.config = sanitizeConfigRecursive({
190
+ scan: {
191
+ tools: requestedTools,
192
+ include: options.include,
193
+ exclude: options.exclude
194
+ },
195
+ // Use 'tools' for tool-specific configurations to match AIReadyConfig
196
+ tools: result.summary.toolConfigs
197
+ });
198
+ result.summary.executionTime = Date.now() - startTime;
199
+ return result;
200
+ }
201
+ async function scoreUnified(results, options) {
202
+ const toolScores = /* @__PURE__ */ new Map();
203
+ for (const toolId of results.summary.toolsRun) {
204
+ const provider = ToolRegistry.get(toolId);
205
+ if (!provider) continue;
206
+ const output = results[toolId];
207
+ if (!output) continue;
208
+ try {
209
+ const toolScore = provider.score(output, options);
210
+ if (!toolScore.tokenBudget) {
211
+ if (toolId === ToolName.PatternDetect && output.duplicates) {
212
+ const wastedTokens = output.duplicates.reduce(
213
+ (sum, d) => sum + (d.tokenCost ?? 0),
214
+ 0
215
+ );
216
+ toolScore.tokenBudget = calculateTokenBudget({
217
+ totalContextTokens: wastedTokens * 2,
218
+ wastedTokens: {
219
+ duplication: wastedTokens,
220
+ fragmentation: 0,
221
+ chattiness: 0
222
+ }
223
+ });
224
+ } else if (toolId === ToolName.ContextAnalyzer && output.summary) {
225
+ toolScore.tokenBudget = calculateTokenBudget({
226
+ totalContextTokens: output.summary.totalTokens,
227
+ wastedTokens: {
228
+ duplication: 0,
229
+ fragmentation: output.summary.totalPotentialSavings ?? 0,
230
+ chattiness: 0
231
+ }
232
+ });
233
+ }
234
+ }
235
+ toolScores.set(toolId, toolScore);
236
+ } catch (err) {
237
+ console.error(`\u274C Error scoring tool '${toolId}':`, err);
238
+ }
239
+ }
240
+ if (toolScores.size === 0) {
241
+ return {
242
+ overall: 0,
243
+ rating: "Critical",
244
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
245
+ toolsUsed: [],
246
+ breakdown: [],
247
+ calculation: {
248
+ formula: "0 / 0 = 0",
249
+ weights: {},
250
+ normalized: "0 / 0 = 0"
251
+ }
252
+ };
253
+ }
254
+ return calculateOverallScore(toolScores, options, void 0);
255
+ }
256
+ function generateUnifiedSummary(result) {
257
+ const { summary } = result;
258
+ let output = `\u{1F680} AIReady Analysis Complete
259
+
260
+ `;
261
+ output += `\u{1F4CA} Summary:
262
+ `;
263
+ output += ` Tools run: ${summary.toolsRun.join(", ")}
264
+ `;
265
+ output += ` Total issues found: ${summary.totalIssues}
266
+ `;
267
+ output += ` Execution time: ${(summary.executionTime / 1e3).toFixed(2)}s
268
+
269
+ `;
270
+ for (const provider of ToolRegistry.getAll()) {
271
+ const toolResult = result[provider.id];
272
+ if (toolResult) {
273
+ const issueCount = toolResult.results.reduce(
274
+ (sum, r) => sum + (r.issues?.length ?? 0),
275
+ 0
276
+ );
277
+ output += `\u2022 ${provider.id}: ${issueCount} issues
278
+ `;
279
+ }
280
+ }
281
+ return output;
282
+ }
283
+
284
+ export {
285
+ __require,
286
+ analyzeUnified,
287
+ scoreUnified,
288
+ generateUnifiedSummary
289
+ };
package/dist/cli.js CHANGED
@@ -95,7 +95,7 @@ function sanitizeToolConfig(config) {
95
95
  async function analyzeUnified(options) {
96
96
  await (0, import_core.initializeParsers)();
97
97
  const startTime = Date.now();
98
- const requestedTools = options.tools || [
98
+ const requestedTools = options.tools ?? [
99
99
  "patterns",
100
100
  "context",
101
101
  "consistency"
@@ -117,7 +117,7 @@ async function analyzeUnified(options) {
117
117
  for (const toolName of requestedTools) {
118
118
  let provider = import_core.ToolRegistry.find(toolName);
119
119
  if (!provider) {
120
- const packageName = TOOL_PACKAGE_MAP[toolName] || (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
120
+ const packageName = TOOL_PACKAGE_MAP[toolName] ?? (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
121
121
  try {
122
122
  await import(packageName);
123
123
  provider = import_core.ToolRegistry.find(toolName);
@@ -195,29 +195,15 @@ async function analyzeUnified(options) {
195
195
  } else {
196
196
  result.summary.toolConfigs[provider.id] = sanitizeToolConfig(toolOptions);
197
197
  }
198
- const toolFiles = output.summary?.totalFiles || output.summary?.filesAnalyzed || 0;
198
+ const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
199
199
  if (toolFiles > result.summary.totalFiles) {
200
200
  result.summary.totalFiles = toolFiles;
201
201
  }
202
202
  const issueCount = output.results.reduce(
203
- (sum, file) => sum + (file.issues?.length || 0),
203
+ (sum, file) => sum + (file.issues?.length ?? 0),
204
204
  0
205
205
  );
206
206
  result.summary.totalIssues += issueCount;
207
- if (provider.alias && Array.isArray(provider.alias)) {
208
- for (const alias of provider.alias) {
209
- if (!result[alias]) {
210
- result[alias] = output;
211
- }
212
- }
213
- }
214
- const camelCaseId = provider.id.replace(
215
- /-([a-z])/g,
216
- (g) => g[1].toUpperCase()
217
- );
218
- if (camelCaseId !== provider.id && !result[camelCaseId]) {
219
- result[camelCaseId] = output;
220
- }
221
207
  } catch (err) {
222
208
  console.error(`\u274C Error running tool '${provider.id}':`, err);
223
209
  }
@@ -232,6 +218,24 @@ async function analyzeUnified(options) {
232
218
  tools: result.summary.toolConfigs
233
219
  });
234
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
+ }
235
239
  return result;
236
240
  }
237
241
  async function scoreUnified(results, options) {
@@ -246,7 +250,7 @@ async function scoreUnified(results, options) {
246
250
  if (!toolScore.tokenBudget) {
247
251
  if (toolId === import_core.ToolName.PatternDetect && output.duplicates) {
248
252
  const wastedTokens = output.duplicates.reduce(
249
- (sum, d) => sum + (d.tokenCost || 0),
253
+ (sum, d) => sum + (d.tokenCost ?? 0),
250
254
  0
251
255
  );
252
256
  toolScore.tokenBudget = (0, import_core.calculateTokenBudget)({
@@ -262,7 +266,7 @@ async function scoreUnified(results, options) {
262
266
  totalContextTokens: output.summary.totalTokens,
263
267
  wastedTokens: {
264
268
  duplication: 0,
265
- fragmentation: output.summary.totalPotentialSavings || 0,
269
+ fragmentation: output.summary.totalPotentialSavings ?? 0,
266
270
  chattiness: 0
267
271
  }
268
272
  });
@@ -393,7 +397,7 @@ var import_core4 = require("@aiready/core");
393
397
  function printScanSummary(results, startTime) {
394
398
  console.log(import_chalk2.default.cyan("\n=== AIReady Run Summary ==="));
395
399
  console.log(
396
- ` Total issues (all tools): ${import_chalk2.default.bold(String(results.summary.totalIssues || 0))}`
400
+ ` Total issues (all tools): ${import_chalk2.default.bold(String(results.summary.totalIssues ?? 0))}`
397
401
  );
398
402
  console.log(
399
403
  ` Execution time: ${import_chalk2.default.bold(((Date.now() - startTime) / 1e3).toFixed(2) + "s")}`
@@ -428,7 +432,7 @@ function printScoring(scoringResult, scoringProfile) {
428
432
  );
429
433
  });
430
434
  const allRecs = scoringResult.breakdown.flatMap(
431
- (t) => (t.recommendations || []).map((r) => ({ ...r, tool: t.toolName }))
435
+ (t) => (t.recommendations ?? []).map((r) => ({ ...r, tool: t.toolName }))
432
436
  ).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 3);
433
437
  if (allRecs.length > 0) {
434
438
  console.log(import_chalk2.default.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
@@ -482,8 +486,8 @@ var import_core5 = require("@aiready/core");
482
486
  async function uploadAction(file, options) {
483
487
  const startTime = Date.now();
484
488
  const filePath = (0, import_path2.resolve)(process.cwd(), file);
485
- const serverUrl = options.server || process.env.AIREADY_SERVER || "https://dev.platform.getaiready.dev";
486
- const apiKey = options.apiKey || process.env.AIREADY_API_KEY;
489
+ const serverUrl = options.server ?? process.env.AIREADY_SERVER ?? "https://dev.platform.getaiready.dev";
490
+ const apiKey = options.apiKey ?? process.env.AIREADY_API_KEY;
487
491
  if (!apiKey) {
488
492
  console.error(import_chalk3.default.red("\u274C API Key is required for upload."));
489
493
  console.log(
@@ -508,7 +512,7 @@ async function uploadAction(file, options) {
508
512
  const reportContent = import_fs2.default.readFileSync(filePath, "utf-8");
509
513
  const reportData = JSON.parse(reportContent);
510
514
  console.log(import_chalk3.default.dim(` Successfully parsed report JSON.`));
511
- const repoId = options.repoId || reportData.repository?.repoId;
515
+ const repoId = options.repoId ?? reportData.repository?.repoId;
512
516
  const response = await fetch(`${serverUrl}/api/analysis/upload`, {
513
517
  method: "POST",
514
518
  headers: {
@@ -527,12 +531,12 @@ async function uploadAction(file, options) {
527
531
  uploadResult = await response.json();
528
532
  } else {
529
533
  const text = await response.text();
530
- uploadResult = { error: text || response.statusText };
534
+ uploadResult = { error: text ?? response.statusText };
531
535
  }
532
536
  if (!response.ok) {
533
537
  console.error(
534
538
  import_chalk3.default.red(
535
- `\u274C Upload failed: ${uploadResult.error || response.statusText}`
539
+ `\u274C Upload failed: ${uploadResult.error ?? response.statusText}`
536
540
  )
537
541
  );
538
542
  if (contentType?.includes("text/html")) {
@@ -583,7 +587,7 @@ ENVIRONMENT VARIABLES:
583
587
  async function scanAction(directory, options) {
584
588
  console.log(import_chalk4.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
585
589
  const startTime = Date.now();
586
- const resolvedDir = (0, import_path3.resolve)(process.cwd(), directory || ".");
590
+ const resolvedDir = (0, import_path3.resolve)(process.cwd(), directory ?? ".");
587
591
  const repoMetadata = (0, import_core6.getRepoMetadata)(resolvedDir);
588
592
  try {
589
593
  const defaults = {
@@ -673,7 +677,7 @@ async function scanAction(directory, options) {
673
677
  const { getSmartDefaults } = await import("@aiready/pattern-detect");
674
678
  const patternSmartDefaults = await getSmartDefaults(
675
679
  resolvedDir,
676
- finalOptions.toolConfigs?.[import_core6.ToolName.PatternDetect] || {}
680
+ finalOptions.toolConfigs?.[import_core6.ToolName.PatternDetect] ?? {}
677
681
  );
678
682
  if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
679
683
  finalOptions.toolConfigs[import_core6.ToolName.PatternDetect] = {
@@ -684,7 +688,7 @@ async function scanAction(directory, options) {
684
688
  console.log(import_chalk4.default.cyan("\n=== AIReady Run Preview ==="));
685
689
  console.log(
686
690
  import_chalk4.default.white("Tools to run:"),
687
- (finalOptions.tools || []).join(", ")
691
+ (finalOptions.tools ?? []).join(", ")
688
692
  );
689
693
  const progressCallback = (event) => {
690
694
  if (event.message) {
@@ -705,7 +709,7 @@ async function scanAction(directory, options) {
705
709
  );
706
710
  }
707
711
  };
708
- const scoringProfile = options.profile || baseOptions.scoring?.profile || "default";
712
+ const scoringProfile = options.profile ?? baseOptions.scoring?.profile ?? "default";
709
713
  const results = await analyzeUnified({
710
714
  ...finalOptions,
711
715
  progressCallback,
@@ -729,7 +733,7 @@ async function scanAction(directory, options) {
729
733
  const prevReport = JSON.parse(
730
734
  (0, import_fs3.readFileSync)((0, import_path3.resolve)(process.cwd(), options.compareTo), "utf8")
731
735
  );
732
- const prevScore = prevReport.scoring?.overall || prevReport.scoring?.score;
736
+ const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
733
737
  if (typeof prevScore === "number") {
734
738
  const diff = scoringResult.overall - prevScore;
735
739
  const diffStr = diff > 0 ? `+${diff}` : String(diff);
@@ -756,17 +760,17 @@ async function scanAction(directory, options) {
756
760
  void e;
757
761
  }
758
762
  }
759
- const totalWastedDuplication = (scoringResult.breakdown || []).reduce(
760
- (sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.duplication || 0),
763
+ const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
764
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
761
765
  0
762
766
  );
763
- const totalWastedFragmentation = (scoringResult.breakdown || []).reduce(
764
- (sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.fragmentation || 0),
767
+ const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
768
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
765
769
  0
766
770
  );
767
771
  const totalContext = Math.max(
768
- ...(scoringResult.breakdown || []).map(
769
- (s) => s.tokenBudget?.totalContextTokens || 0
772
+ ...(scoringResult.breakdown ?? []).map(
773
+ (s) => s.tokenBudget?.totalContextTokens ?? 0
770
774
  ),
771
775
  0
772
776
  );
@@ -790,7 +794,7 @@ async function scanAction(directory, options) {
790
794
  });
791
795
  }
792
796
  }
793
- const modelId = options.model || "claude-3-5-sonnet";
797
+ const modelId = options.model ?? "gpt-5.4-mini";
794
798
  const roi = (await import("@aiready/core")).calculateBusinessROI({
795
799
  tokenWaste: unifiedBudget.wastedTokens.total,
796
800
  issues: allIssues,
@@ -827,9 +831,9 @@ async function scanAction(directory, options) {
827
831
  ...mapToUnifiedReport(results, scoringResult),
828
832
  repository: repoMetadata
829
833
  };
830
- const outputFormat = options.output || finalOptions.output?.format || "console";
834
+ const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
831
835
  const outputPath = (0, import_core6.resolveOutputPath)(
832
- options.outputFile || finalOptions.output?.file,
836
+ options.outputFile ?? finalOptions.output?.file,
833
837
  `aiready-report-${getReportTimestamp()}.json`,
834
838
  resolvedDir
835
839
  );
@@ -856,8 +860,8 @@ async function scanAction(directory, options) {
856
860
  await warnIfGraphCapExceeded(outputData, resolvedDir);
857
861
  if (scoringResult) {
858
862
  const threshold = options.threshold ? parseInt(options.threshold) : void 0;
859
- const failOnLevel = options.failOn || "critical";
860
- const isCI = options.ci || process.env.CI === "true";
863
+ const failOnLevel = options.failOn ?? "critical";
864
+ const isCI = options.ci ?? process.env.CI === "true";
861
865
  let shouldFail = false;
862
866
  let failReason = "";
863
867
  const report = mapToUnifiedReport(results, scoringResult);
@@ -1041,7 +1045,7 @@ var import_core8 = require("@aiready/core");
1041
1045
  async function patternsAction(directory, options) {
1042
1046
  console.log(import_chalk6.default.blue("\u{1F50D} Analyzing patterns...\n"));
1043
1047
  const startTime = Date.now();
1044
- const resolvedDir = (0, import_path5.resolve)(process.cwd(), directory || ".");
1048
+ const resolvedDir = (0, import_path5.resolve)(process.cwd(), directory ?? ".");
1045
1049
  try {
1046
1050
  const useSmartDefaults = !options.fullScan;
1047
1051
  const defaults = {
@@ -1085,8 +1089,8 @@ async function patternsAction(directory, options) {
1085
1089
  if (options.score) {
1086
1090
  patternScore = calculatePatternScore(duplicates, results.length);
1087
1091
  }
1088
- const outputFormat = options.output || finalOptions.output?.format || "console";
1089
- const userOutputFile = options.outputFile || finalOptions.output?.file;
1092
+ const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1093
+ const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1090
1094
  if (outputFormat === "json") {
1091
1095
  const outputData = {
1092
1096
  results,
@@ -1187,7 +1191,7 @@ var import_core9 = require("@aiready/core");
1187
1191
  async function contextAction(directory, options) {
1188
1192
  console.log(import_chalk7.default.blue("\u{1F9E0} Analyzing context costs...\n"));
1189
1193
  const startTime = Date.now();
1190
- const resolvedDir = (0, import_path6.resolve)(process.cwd(), directory || ".");
1194
+ const resolvedDir = (0, import_path6.resolve)(process.cwd(), directory ?? ".");
1191
1195
  try {
1192
1196
  const defaults = {
1193
1197
  maxDepth: 5,
@@ -1231,8 +1235,8 @@ async function contextAction(directory, options) {
1231
1235
  if (options.score) {
1232
1236
  contextScore = calculateContextScore(summary);
1233
1237
  }
1234
- const outputFormat = options.output || finalOptions.output?.format || "console";
1235
- const userOutputFile = options.outputFile || finalOptions.output?.file;
1238
+ const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1239
+ const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1236
1240
  if (outputFormat === "json") {
1237
1241
  const outputData = {
1238
1242
  results,
@@ -1250,7 +1254,7 @@ async function contextAction(directory, options) {
1250
1254
  `\u2705 Results saved to ${outputPath}`
1251
1255
  );
1252
1256
  } else {
1253
- const terminalWidth = process.stdout.columns || 80;
1257
+ const terminalWidth = process.stdout.columns ?? 80;
1254
1258
  const dividerWidth = Math.min(60, terminalWidth - 2);
1255
1259
  const divider = "\u2501".repeat(dividerWidth);
1256
1260
  console.log(import_chalk7.default.cyan(divider));
@@ -1388,7 +1392,7 @@ var import_core10 = require("@aiready/core");
1388
1392
  async function consistencyAction(directory, options) {
1389
1393
  console.log(import_chalk8.default.blue("\u{1F50D} Analyzing consistency...\n"));
1390
1394
  const startTime = Date.now();
1391
- const resolvedDir = (0, import_path7.resolve)(process.cwd(), directory || ".");
1395
+ const resolvedDir = (0, import_path7.resolve)(process.cwd(), directory ?? ".");
1392
1396
  try {
1393
1397
  const defaults = {
1394
1398
  checkNaming: true,
@@ -1413,14 +1417,14 @@ async function consistencyAction(directory, options) {
1413
1417
  const elapsedTime = (0, import_core10.getElapsedTime)(startTime);
1414
1418
  let consistencyScore;
1415
1419
  if (options.score) {
1416
- const issues = report.results?.flatMap((r) => r.issues) || [];
1420
+ const issues = report.results?.flatMap((r) => r.issues) ?? [];
1417
1421
  consistencyScore = calculateConsistencyScore(
1418
1422
  issues,
1419
1423
  report.summary.filesAnalyzed
1420
1424
  );
1421
1425
  }
1422
- const outputFormat = options.output || finalOptions.output?.format || "console";
1423
- const userOutputFile = options.outputFile || finalOptions.output?.file;
1426
+ const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1427
+ const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1424
1428
  if (outputFormat === "json") {
1425
1429
  const outputData = {
1426
1430
  ...report,
@@ -1458,7 +1462,7 @@ async function consistencyAction(directory, options) {
1458
1462
  console.log(` Naming: ${import_chalk8.default.yellow(report.summary.namingIssues)}`);
1459
1463
  console.log(` Patterns: ${import_chalk8.default.yellow(report.summary.patternIssues)}`);
1460
1464
  console.log(
1461
- ` Architecture: ${import_chalk8.default.yellow(report.summary.architectureIssues || 0)}`
1465
+ ` Architecture: ${import_chalk8.default.yellow(report.summary.architectureIssues ?? 0)}`
1462
1466
  );
1463
1467
  console.log(`Analysis Time: ${import_chalk8.default.gray(elapsedTime + "s")}
1464
1468
  `);
@@ -1557,7 +1561,7 @@ var import_core11 = require("@aiready/core");
1557
1561
  var import_core12 = require("@aiready/core");
1558
1562
  async function visualizeAction(directory, options) {
1559
1563
  try {
1560
- const dirPath = (0, import_path8.resolve)(process.cwd(), directory || ".");
1564
+ const dirPath = (0, import_path8.resolve)(process.cwd(), directory ?? ".");
1561
1565
  let reportPath = options.report ? (0, import_path8.resolve)(dirPath, options.report) : null;
1562
1566
  if (!reportPath || !(0, import_fs6.existsSync)(reportPath)) {
1563
1567
  const latestScan = (0, import_core12.findLatestReport)(dirPath);
@@ -1603,7 +1607,7 @@ Or specify a custom report:
1603
1607
  console.log("Building graph from report...");
1604
1608
  const { GraphBuilder } = await import("@aiready/visualizer/graph");
1605
1609
  const graph = GraphBuilder.buildFromReport(report, dirPath);
1606
- let useDevMode = options.dev || false;
1610
+ let useDevMode = options.dev ?? false;
1607
1611
  let devServerStarted = false;
1608
1612
  if (useDevMode) {
1609
1613
  try {
@@ -1719,7 +1723,7 @@ Or specify a custom report:
1719
1723
  console.log("Generating HTML...");
1720
1724
  const html = (0, import_core12.generateHTML)(graph);
1721
1725
  const defaultOutput = "visualization.html";
1722
- const outPath = (0, import_path8.resolve)(dirPath, options.output || defaultOutput);
1726
+ const outPath = (0, import_path8.resolve)(dirPath, options.output ?? defaultOutput);
1723
1727
  (0, import_fs6.writeFileSync)(outPath, html, "utf8");
1724
1728
  console.log(import_chalk9.default.green(`\u2705 Visualization written to: ${outPath}`));
1725
1729
  if (options.open || options.serve) {
@@ -1731,7 +1735,7 @@ Or specify a custom report:
1731
1735
  const fsp = await import("fs/promises");
1732
1736
  const server = http.createServer(async (req, res) => {
1733
1737
  try {
1734
- const urlPath = req.url || "/";
1738
+ const urlPath = req.url ?? "/";
1735
1739
  if (urlPath === "/" || urlPath === "/index.html") {
1736
1740
  const content = await fsp.readFile(outPath, "utf8");
1737
1741
  res.writeHead(200, {
@@ -1869,7 +1873,7 @@ async function bugAction(message, options) {
1869
1873
  const repoUrl = "https://github.com/caopengau/aiready-cli";
1870
1874
  const repoSlug = "caopengau/aiready-cli";
1871
1875
  if (message) {
1872
- const type = options.type || "bug";
1876
+ const type = options.type ?? "bug";
1873
1877
  const title = `[${type.toUpperCase()}] ${message}`;
1874
1878
  const label = type === "bug" ? "bug" : type === "feature" ? "enhancement" : "metric";
1875
1879
  const body = `
@@ -1958,15 +1962,17 @@ AI READINESS SCORING:
1958
1962
  EXAMPLES:
1959
1963
  $ aiready scan # Comprehensive analysis with AI Readiness Score
1960
1964
  $ aiready scan --no-score # Run scan without score calculation
1961
- $ aiready scan --tools patterns # Run only pattern detection
1965
+ $ aiready init # Create a default aiready.json configuration
1966
+ $ aiready init --full # Create configuration with ALL available options
1962
1967
  $ npx @aiready/cli scan # Industry standard way to run standard scan
1963
1968
  $ aiready scan --output json # Output raw JSON for piping
1964
1969
 
1965
1970
  GETTING STARTED:
1966
- 1. Run 'aiready scan' to analyze your codebase and get an AI Readiness Score
1967
- 2. Use '--profile agentic' for agent-focused analysis
1968
- 3. Create aiready.json for persistent configuration
1969
- 4. Set up CI/CD with '--threshold' for quality gates
1971
+ 1. Run 'aiready init' to create a persistent 'aiready.json' config file
1972
+ 2. Run 'aiready scan' to analyze your codebase and get an AI Readiness Score
1973
+ 3. Use 'aiready init --full' to see every fine-tuning parameter available
1974
+ 4. Use '--profile agentic' for agent-focused analysis
1975
+ 5. Set up CI/CD with '--threshold' for quality gates
1970
1976
 
1971
1977
  CONFIGURATION:
1972
1978
  Config files (searched upward): aiready.json, .aiready.json, aiready.config.*