@aiready/cli 0.3.3 → 0.3.4

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.
@@ -1,6 +1,6 @@
1
1
 
2
2
  
3
- > @aiready/cli@0.3.3 build /Users/pengcao/projects/aiready/packages/cli
3
+ > @aiready/cli@0.3.4 build /Users/pengcao/projects/aiready/packages/cli
4
4
  > tsup src/index.ts src/cli.ts --format cjs,esm --dts
5
5
 
6
6
  CLI Building entry: src/cli.ts, src/index.ts
@@ -9,15 +9,15 @@
9
9
  CLI Target: es2020
10
10
  CJS Build start
11
11
  ESM Build start
12
+ CJS dist/cli.js 9.79 KB
12
13
  CJS dist/index.js 2.57 KB
13
- CJS dist/cli.js 11.02 KB
14
- CJS ⚡️ Build success in 56ms
14
+ CJS ⚡️ Build success in 55ms
15
15
  ESM dist/chunk-KZKXZKES.mjs 1.45 KB
16
- ESM dist/cli.mjs 8.12 KB
16
+ ESM dist/cli.mjs 6.94 KB
17
17
  ESM dist/index.mjs 138.00 B
18
- ESM ⚡️ Build success in 56ms
18
+ ESM ⚡️ Build success in 54ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 513ms
20
+ DTS ⚡️ Build success in 529ms
21
21
  DTS dist/cli.d.ts 20.00 B
22
22
  DTS dist/index.d.ts 731.00 B
23
23
  DTS dist/cli.d.mts 20.00 B
package/dist/cli.js CHANGED
@@ -78,18 +78,16 @@ function generateUnifiedSummary(result) {
78
78
 
79
79
  // src/cli.ts
80
80
  var import_chalk = __toESM(require("chalk"));
81
- var import_fs = require("fs");
82
81
  var import_path = require("path");
83
82
  var import_core = require("@aiready/core");
84
- var import_fs2 = require("fs");
85
- var packageJson = JSON.parse((0, import_fs2.readFileSync)((0, import_path.join)(__dirname, "../package.json"), "utf8"));
83
+ var import_fs = require("fs");
84
+ var packageJson = JSON.parse((0, import_fs.readFileSync)((0, import_path.join)(__dirname, "../package.json"), "utf8"));
86
85
  var program = new import_commander.Command();
87
86
  program.name("aiready").description("AIReady - Unified AI-readiness analysis tools").version(packageJson.version).addHelpText("after", "\nCONFIGURATION:\n Supports config files: aiready.json, aiready.config.json, .aiready.json, .aireadyrc.json, aiready.config.js, .aireadyrc.js\n CLI options override config file settings");
88
87
  program.command("scan").description("Run unified analysis on a codebase").argument("<directory>", "Directory to analyze").option("-t, --tools <tools>", "Tools to run (comma-separated: patterns,context)", "patterns,context").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) => {
89
88
  console.log(import_chalk.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
90
89
  const startTime = Date.now();
91
90
  try {
92
- const config = (0, import_core.loadConfig)(directory);
93
91
  const defaults = {
94
92
  tools: ["patterns", "context"],
95
93
  include: void 0,
@@ -99,17 +97,15 @@ program.command("scan").description("Run unified analysis on a codebase").argume
99
97
  file: void 0
100
98
  }
101
99
  };
102
- const mergedConfig = (0, import_core.mergeConfigWithDefaults)(config, defaults);
103
- const finalOptions = {
104
- rootDir: directory,
105
- tools: options.tools ? options.tools.split(",").map((t) => t.trim()) : mergedConfig.tools,
106
- include: options.include?.split(",") || mergedConfig.include,
107
- exclude: options.exclude?.split(",") || mergedConfig.exclude
108
- };
100
+ const finalOptions = (0, import_core.loadMergedConfig)(directory, defaults, {
101
+ tools: options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0,
102
+ include: options.include?.split(","),
103
+ exclude: options.exclude?.split(",")
104
+ });
109
105
  const results = await analyzeUnified(finalOptions);
110
- const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
111
- const outputFormat = options.output || mergedConfig.output?.format || "console";
112
- const outputFile = options.outputFile || mergedConfig.output?.file;
106
+ const elapsedTime = (0, import_core.getElapsedTime)(startTime);
107
+ const outputFormat = options.output || finalOptions.output?.format || "console";
108
+ const outputFile = options.outputFile || finalOptions.output?.file;
113
109
  if (outputFormat === "json") {
114
110
  const outputData = {
115
111
  ...results,
@@ -118,25 +114,18 @@ program.command("scan").description("Run unified analysis on a codebase").argume
118
114
  executionTime: parseFloat(elapsedTime)
119
115
  }
120
116
  };
121
- if (outputFile) {
122
- (0, import_fs.writeFileSync)(outputFile, JSON.stringify(outputData, null, 2));
123
- console.log(import_chalk.default.green(`\u2705 Results saved to ${outputFile}`));
124
- } else {
125
- console.log(JSON.stringify(outputData, null, 2));
126
- }
117
+ (0, import_core.handleJSONOutput)(outputData, outputFile, `\u2705 Results saved to ${outputFile}`);
127
118
  } else {
128
119
  console.log(generateUnifiedSummary(results));
129
120
  }
130
121
  } catch (error) {
131
- console.error(import_chalk.default.red("\u274C Analysis failed:"), error);
132
- process.exit(1);
122
+ (0, import_core.handleCLIError)(error, "Analysis");
133
123
  }
134
124
  });
135
125
  program.command("patterns").description("Run pattern detection analysis").argument("<directory>", "Directory to analyze").option("-s, --similarity <number>", "Minimum similarity score (0-1)", "0.40").option("-l, --min-lines <number>", "Minimum lines to consider", "5").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) => {
136
126
  console.log(import_chalk.default.blue("\u{1F50D} Analyzing patterns...\n"));
137
127
  const startTime = Date.now();
138
128
  try {
139
- const config = (0, import_core.loadConfig)(directory);
140
129
  const defaults = {
141
130
  minSimilarity: 0.4,
142
131
  minLines: 5,
@@ -147,46 +136,37 @@ program.command("patterns").description("Run pattern detection analysis").argume
147
136
  file: void 0
148
137
  }
149
138
  };
150
- const mergedConfig = (0, import_core.mergeConfigWithDefaults)(config, defaults);
151
- const finalOptions = {
152
- rootDir: directory,
153
- minSimilarity: options.similarity ? parseFloat(options.similarity) : mergedConfig.minSimilarity,
154
- minLines: options.minLines ? parseInt(options.minLines) : mergedConfig.minLines,
155
- include: options.include?.split(",") || mergedConfig.include,
156
- exclude: options.exclude?.split(",") || mergedConfig.exclude
157
- };
139
+ const finalOptions = (0, import_core.loadMergedConfig)(directory, defaults, {
140
+ minSimilarity: options.similarity ? parseFloat(options.similarity) : void 0,
141
+ minLines: options.minLines ? parseInt(options.minLines) : void 0,
142
+ include: options.include?.split(","),
143
+ exclude: options.exclude?.split(",")
144
+ });
158
145
  const { analyzePatterns: analyzePatterns2, generateSummary } = await import("@aiready/pattern-detect");
159
146
  const { results } = await analyzePatterns2(finalOptions);
160
- const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
147
+ const elapsedTime = (0, import_core.getElapsedTime)(startTime);
161
148
  const summary = generateSummary(results);
162
- const outputFormat = options.output || mergedConfig.output?.format || "console";
163
- const outputFile = options.outputFile || mergedConfig.output?.file;
149
+ const outputFormat = options.output || finalOptions.output?.format || "console";
150
+ const outputFile = options.outputFile || finalOptions.output?.file;
164
151
  if (outputFormat === "json") {
165
152
  const outputData = {
166
153
  results,
167
154
  summary: { ...summary, executionTime: parseFloat(elapsedTime) }
168
155
  };
169
- if (outputFile) {
170
- (0, import_fs.writeFileSync)(outputFile, JSON.stringify(outputData, null, 2));
171
- console.log(import_chalk.default.green(`\u2705 Results saved to ${outputFile}`));
172
- } else {
173
- console.log(JSON.stringify(outputData, null, 2));
174
- }
156
+ (0, import_core.handleJSONOutput)(outputData, outputFile, `\u2705 Results saved to ${outputFile}`);
175
157
  } else {
176
158
  console.log(`Pattern Analysis Complete (${elapsedTime}s)`);
177
159
  console.log(`Found ${summary.totalPatterns} duplicate patterns`);
178
160
  console.log(`Total token cost: ${summary.totalTokenCost} tokens`);
179
161
  }
180
162
  } catch (error) {
181
- console.error(import_chalk.default.red("\u274C Pattern analysis failed:"), error);
182
- process.exit(1);
163
+ (0, import_core.handleCLIError)(error, "Pattern analysis");
183
164
  }
184
165
  });
185
166
  program.command("context").description("Run context window cost analysis").argument("<directory>", "Directory to analyze").option("--max-depth <number>", "Maximum acceptable import depth", "5").option("--max-context <number>", "Maximum acceptable context budget (tokens)", "10000").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) => {
186
167
  console.log(import_chalk.default.blue("\u{1F9E0} Analyzing context costs...\n"));
187
168
  const startTime = Date.now();
188
169
  try {
189
- const config = (0, import_core.loadConfig)(directory);
190
170
  const defaults = {
191
171
  maxDepth: 5,
192
172
  maxContextBudget: 1e4,
@@ -197,31 +177,24 @@ program.command("context").description("Run context window cost analysis").argum
197
177
  file: void 0
198
178
  }
199
179
  };
200
- const mergedConfig = (0, import_core.mergeConfigWithDefaults)(config, defaults);
201
- const finalOptions = {
202
- rootDir: directory,
203
- maxDepth: options.maxDepth ? parseInt(options.maxDepth) : mergedConfig.maxDepth,
204
- maxContextBudget: options.maxContext ? parseInt(options.maxContext) : mergedConfig.maxContextBudget,
205
- include: options.include?.split(",") || mergedConfig.include,
206
- exclude: options.exclude?.split(",") || mergedConfig.exclude
207
- };
180
+ const finalOptions = (0, import_core.loadMergedConfig)(directory, defaults, {
181
+ maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
182
+ maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
183
+ include: options.include?.split(","),
184
+ exclude: options.exclude?.split(",")
185
+ });
208
186
  const { analyzeContext: analyzeContext2, generateSummary } = await import("@aiready/context-analyzer");
209
187
  const results = await analyzeContext2(finalOptions);
210
- const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
188
+ const elapsedTime = (0, import_core.getElapsedTime)(startTime);
211
189
  const summary = generateSummary(results);
212
- const outputFormat = options.output || mergedConfig.output?.format || "console";
213
- const outputFile = options.outputFile || mergedConfig.output?.file;
190
+ const outputFormat = options.output || finalOptions.output?.format || "console";
191
+ const outputFile = options.outputFile || finalOptions.output?.file;
214
192
  if (outputFormat === "json") {
215
193
  const outputData = {
216
194
  results,
217
195
  summary: { ...summary, executionTime: parseFloat(elapsedTime) }
218
196
  };
219
- if (outputFile) {
220
- (0, import_fs.writeFileSync)(outputFile, JSON.stringify(outputData, null, 2));
221
- console.log(import_chalk.default.green(`\u2705 Results saved to ${outputFile}`));
222
- } else {
223
- console.log(JSON.stringify(outputData, null, 2));
224
- }
197
+ (0, import_core.handleJSONOutput)(outputData, outputFile, `\u2705 Results saved to ${outputFile}`);
225
198
  } else {
226
199
  console.log(`Context Analysis Complete (${elapsedTime}s)`);
227
200
  console.log(`Files analyzed: ${summary.totalFiles}`);
@@ -230,8 +203,7 @@ program.command("context").description("Run context window cost analysis").argum
230
203
  console.log(`Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(1)}%`);
231
204
  }
232
205
  } catch (error) {
233
- console.error(import_chalk.default.red("\u274C Context analysis failed:"), error);
234
- process.exit(1);
206
+ (0, import_core.handleCLIError)(error, "Context analysis");
235
207
  }
236
208
  });
237
209
  program.parse();
package/dist/cli.mjs CHANGED
@@ -7,9 +7,8 @@ import {
7
7
  // src/cli.ts
8
8
  import { Command } from "commander";
9
9
  import chalk from "chalk";
10
- import { writeFileSync } from "fs";
11
10
  import { join } from "path";
12
- import { loadConfig, mergeConfigWithDefaults } from "@aiready/core";
11
+ import { loadMergedConfig, handleJSONOutput, handleCLIError, getElapsedTime } from "@aiready/core";
13
12
  import { readFileSync } from "fs";
14
13
  var packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf8"));
15
14
  var program = new Command();
@@ -18,7 +17,6 @@ program.command("scan").description("Run unified analysis on a codebase").argume
18
17
  console.log(chalk.blue("\u{1F680} Starting AIReady unified analysis...\n"));
19
18
  const startTime = Date.now();
20
19
  try {
21
- const config = loadConfig(directory);
22
20
  const defaults = {
23
21
  tools: ["patterns", "context"],
24
22
  include: void 0,
@@ -28,17 +26,15 @@ program.command("scan").description("Run unified analysis on a codebase").argume
28
26
  file: void 0
29
27
  }
30
28
  };
31
- const mergedConfig = mergeConfigWithDefaults(config, defaults);
32
- const finalOptions = {
33
- rootDir: directory,
34
- tools: options.tools ? options.tools.split(",").map((t) => t.trim()) : mergedConfig.tools,
35
- include: options.include?.split(",") || mergedConfig.include,
36
- exclude: options.exclude?.split(",") || mergedConfig.exclude
37
- };
29
+ const finalOptions = loadMergedConfig(directory, defaults, {
30
+ tools: options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0,
31
+ include: options.include?.split(","),
32
+ exclude: options.exclude?.split(",")
33
+ });
38
34
  const results = await analyzeUnified(finalOptions);
39
- const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
40
- const outputFormat = options.output || mergedConfig.output?.format || "console";
41
- const outputFile = options.outputFile || mergedConfig.output?.file;
35
+ const elapsedTime = getElapsedTime(startTime);
36
+ const outputFormat = options.output || finalOptions.output?.format || "console";
37
+ const outputFile = options.outputFile || finalOptions.output?.file;
42
38
  if (outputFormat === "json") {
43
39
  const outputData = {
44
40
  ...results,
@@ -47,25 +43,18 @@ program.command("scan").description("Run unified analysis on a codebase").argume
47
43
  executionTime: parseFloat(elapsedTime)
48
44
  }
49
45
  };
50
- if (outputFile) {
51
- writeFileSync(outputFile, JSON.stringify(outputData, null, 2));
52
- console.log(chalk.green(`\u2705 Results saved to ${outputFile}`));
53
- } else {
54
- console.log(JSON.stringify(outputData, null, 2));
55
- }
46
+ handleJSONOutput(outputData, outputFile, `\u2705 Results saved to ${outputFile}`);
56
47
  } else {
57
48
  console.log(generateUnifiedSummary(results));
58
49
  }
59
50
  } catch (error) {
60
- console.error(chalk.red("\u274C Analysis failed:"), error);
61
- process.exit(1);
51
+ handleCLIError(error, "Analysis");
62
52
  }
63
53
  });
64
54
  program.command("patterns").description("Run pattern detection analysis").argument("<directory>", "Directory to analyze").option("-s, --similarity <number>", "Minimum similarity score (0-1)", "0.40").option("-l, --min-lines <number>", "Minimum lines to consider", "5").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) => {
65
55
  console.log(chalk.blue("\u{1F50D} Analyzing patterns...\n"));
66
56
  const startTime = Date.now();
67
57
  try {
68
- const config = loadConfig(directory);
69
58
  const defaults = {
70
59
  minSimilarity: 0.4,
71
60
  minLines: 5,
@@ -76,46 +65,37 @@ program.command("patterns").description("Run pattern detection analysis").argume
76
65
  file: void 0
77
66
  }
78
67
  };
79
- const mergedConfig = mergeConfigWithDefaults(config, defaults);
80
- const finalOptions = {
81
- rootDir: directory,
82
- minSimilarity: options.similarity ? parseFloat(options.similarity) : mergedConfig.minSimilarity,
83
- minLines: options.minLines ? parseInt(options.minLines) : mergedConfig.minLines,
84
- include: options.include?.split(",") || mergedConfig.include,
85
- exclude: options.exclude?.split(",") || mergedConfig.exclude
86
- };
68
+ const finalOptions = loadMergedConfig(directory, defaults, {
69
+ minSimilarity: options.similarity ? parseFloat(options.similarity) : void 0,
70
+ minLines: options.minLines ? parseInt(options.minLines) : void 0,
71
+ include: options.include?.split(","),
72
+ exclude: options.exclude?.split(",")
73
+ });
87
74
  const { analyzePatterns, generateSummary } = await import("@aiready/pattern-detect");
88
75
  const { results } = await analyzePatterns(finalOptions);
89
- const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
76
+ const elapsedTime = getElapsedTime(startTime);
90
77
  const summary = generateSummary(results);
91
- const outputFormat = options.output || mergedConfig.output?.format || "console";
92
- const outputFile = options.outputFile || mergedConfig.output?.file;
78
+ const outputFormat = options.output || finalOptions.output?.format || "console";
79
+ const outputFile = options.outputFile || finalOptions.output?.file;
93
80
  if (outputFormat === "json") {
94
81
  const outputData = {
95
82
  results,
96
83
  summary: { ...summary, executionTime: parseFloat(elapsedTime) }
97
84
  };
98
- if (outputFile) {
99
- writeFileSync(outputFile, JSON.stringify(outputData, null, 2));
100
- console.log(chalk.green(`\u2705 Results saved to ${outputFile}`));
101
- } else {
102
- console.log(JSON.stringify(outputData, null, 2));
103
- }
85
+ handleJSONOutput(outputData, outputFile, `\u2705 Results saved to ${outputFile}`);
104
86
  } else {
105
87
  console.log(`Pattern Analysis Complete (${elapsedTime}s)`);
106
88
  console.log(`Found ${summary.totalPatterns} duplicate patterns`);
107
89
  console.log(`Total token cost: ${summary.totalTokenCost} tokens`);
108
90
  }
109
91
  } catch (error) {
110
- console.error(chalk.red("\u274C Pattern analysis failed:"), error);
111
- process.exit(1);
92
+ handleCLIError(error, "Pattern analysis");
112
93
  }
113
94
  });
114
95
  program.command("context").description("Run context window cost analysis").argument("<directory>", "Directory to analyze").option("--max-depth <number>", "Maximum acceptable import depth", "5").option("--max-context <number>", "Maximum acceptable context budget (tokens)", "10000").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) => {
115
96
  console.log(chalk.blue("\u{1F9E0} Analyzing context costs...\n"));
116
97
  const startTime = Date.now();
117
98
  try {
118
- const config = loadConfig(directory);
119
99
  const defaults = {
120
100
  maxDepth: 5,
121
101
  maxContextBudget: 1e4,
@@ -126,31 +106,24 @@ program.command("context").description("Run context window cost analysis").argum
126
106
  file: void 0
127
107
  }
128
108
  };
129
- const mergedConfig = mergeConfigWithDefaults(config, defaults);
130
- const finalOptions = {
131
- rootDir: directory,
132
- maxDepth: options.maxDepth ? parseInt(options.maxDepth) : mergedConfig.maxDepth,
133
- maxContextBudget: options.maxContext ? parseInt(options.maxContext) : mergedConfig.maxContextBudget,
134
- include: options.include?.split(",") || mergedConfig.include,
135
- exclude: options.exclude?.split(",") || mergedConfig.exclude
136
- };
109
+ const finalOptions = loadMergedConfig(directory, defaults, {
110
+ maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
111
+ maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
112
+ include: options.include?.split(","),
113
+ exclude: options.exclude?.split(",")
114
+ });
137
115
  const { analyzeContext, generateSummary } = await import("@aiready/context-analyzer");
138
116
  const results = await analyzeContext(finalOptions);
139
- const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
117
+ const elapsedTime = getElapsedTime(startTime);
140
118
  const summary = generateSummary(results);
141
- const outputFormat = options.output || mergedConfig.output?.format || "console";
142
- const outputFile = options.outputFile || mergedConfig.output?.file;
119
+ const outputFormat = options.output || finalOptions.output?.format || "console";
120
+ const outputFile = options.outputFile || finalOptions.output?.file;
143
121
  if (outputFormat === "json") {
144
122
  const outputData = {
145
123
  results,
146
124
  summary: { ...summary, executionTime: parseFloat(elapsedTime) }
147
125
  };
148
- if (outputFile) {
149
- writeFileSync(outputFile, JSON.stringify(outputData, null, 2));
150
- console.log(chalk.green(`\u2705 Results saved to ${outputFile}`));
151
- } else {
152
- console.log(JSON.stringify(outputData, null, 2));
153
- }
126
+ handleJSONOutput(outputData, outputFile, `\u2705 Results saved to ${outputFile}`);
154
127
  } else {
155
128
  console.log(`Context Analysis Complete (${elapsedTime}s)`);
156
129
  console.log(`Files analyzed: ${summary.totalFiles}`);
@@ -159,8 +132,7 @@ program.command("context").description("Run context window cost analysis").argum
159
132
  console.log(`Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(1)}%`);
160
133
  }
161
134
  } catch (error) {
162
- console.error(chalk.red("\u274C Context analysis failed:"), error);
163
- process.exit(1);
135
+ handleCLIError(error, "Context analysis");
164
136
  }
165
137
  });
166
138
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiready/cli",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Unified CLI for AIReady analysis tools",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -11,9 +11,9 @@
11
11
  "dependencies": {
12
12
  "commander": "^12.1.0",
13
13
  "chalk": "^5.3.0",
14
- "@aiready/pattern-detect": "0.7.5",
15
- "@aiready/core": "0.3.1",
16
- "@aiready/context-analyzer": "0.3.3"
14
+ "@aiready/core": "0.3.2",
15
+ "@aiready/pattern-detect": "0.7.6",
16
+ "@aiready/context-analyzer": "0.3.4"
17
17
  },
18
18
  "devDependencies": {
19
19
  "tsup": "^8.3.5",
package/src/cli.ts CHANGED
@@ -5,7 +5,7 @@ import { analyzeUnified, generateUnifiedSummary } from './index';
5
5
  import chalk from 'chalk';
6
6
  import { writeFileSync } from 'fs';
7
7
  import { join } from 'path';
8
- import { loadConfig, mergeConfigWithDefaults } from '@aiready/core';
8
+ import { loadMergedConfig, handleJSONOutput, handleCLIError, getElapsedTime } from '@aiready/core';
9
9
  import { readFileSync } from 'fs';
10
10
 
11
11
  const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
@@ -33,9 +33,6 @@ program
33
33
  const startTime = Date.now();
34
34
 
35
35
  try {
36
- // Load config file if it exists
37
- const config = loadConfig(directory);
38
-
39
36
  // Define defaults
40
37
  const defaults = {
41
38
  tools: ['patterns', 'context'],
@@ -47,23 +44,19 @@ program
47
44
  },
48
45
  };
49
46
 
50
- // Merge config with defaults
51
- const mergedConfig = mergeConfigWithDefaults(config, defaults);
52
-
53
- // Override with CLI options (CLI takes precedence)
54
- const finalOptions = {
55
- rootDir: directory,
56
- tools: options.tools ? options.tools.split(',').map((t: string) => t.trim()) as ('patterns' | 'context')[] : mergedConfig.tools,
57
- include: options.include?.split(',') || mergedConfig.include,
58
- exclude: options.exclude?.split(',') || mergedConfig.exclude,
59
- };
47
+ // Load and merge config with CLI options
48
+ const finalOptions = loadMergedConfig(directory, defaults, {
49
+ tools: options.tools ? options.tools.split(',').map((t: string) => t.trim()) as ('patterns' | 'context')[] : undefined,
50
+ include: options.include?.split(','),
51
+ exclude: options.exclude?.split(','),
52
+ }) as any;
60
53
 
61
54
  const results = await analyzeUnified(finalOptions);
62
55
 
63
- const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
56
+ const elapsedTime = getElapsedTime(startTime);
64
57
 
65
- const outputFormat = options.output || mergedConfig.output?.format || 'console';
66
- const outputFile = options.outputFile || mergedConfig.output?.file;
58
+ const outputFormat = options.output || finalOptions.output?.format || 'console';
59
+ const outputFile = options.outputFile || finalOptions.output?.file;
67
60
 
68
61
  if (outputFormat === 'json') {
69
62
  const outputData = {
@@ -74,19 +67,13 @@ program
74
67
  },
75
68
  };
76
69
 
77
- if (outputFile) {
78
- writeFileSync(outputFile, JSON.stringify(outputData, null, 2));
79
- console.log(chalk.green(`✅ Results saved to ${outputFile}`));
80
- } else {
81
- console.log(JSON.stringify(outputData, null, 2));
82
- }
70
+ handleJSONOutput(outputData, outputFile, `✅ Results saved to ${outputFile}`);
83
71
  } else {
84
72
  // Console output
85
73
  console.log(generateUnifiedSummary(results));
86
74
  }
87
75
  } catch (error) {
88
- console.error(chalk.red('Analysis failed:'), error);
89
- process.exit(1);
76
+ handleCLIError(error, 'Analysis');
90
77
  }
91
78
  });
92
79
 
@@ -107,9 +94,6 @@ program
107
94
  const startTime = Date.now();
108
95
 
109
96
  try {
110
- // Load config file if it exists
111
- const config = loadConfig(directory);
112
-
113
97
  // Define defaults
114
98
  const defaults = {
115
99
  minSimilarity: 0.4,
@@ -122,27 +106,23 @@ program
122
106
  },
123
107
  };
124
108
 
125
- // Merge config with defaults
126
- const mergedConfig = mergeConfigWithDefaults(config, defaults);
127
-
128
- // Override with CLI options (CLI takes precedence)
129
- const finalOptions = {
130
- rootDir: directory,
131
- minSimilarity: options.similarity ? parseFloat(options.similarity) : mergedConfig.minSimilarity,
132
- minLines: options.minLines ? parseInt(options.minLines) : mergedConfig.minLines,
133
- include: options.include?.split(',') || mergedConfig.include,
134
- exclude: options.exclude?.split(',') || mergedConfig.exclude,
135
- };
109
+ // Load and merge config with CLI options
110
+ const finalOptions = loadMergedConfig(directory, defaults, {
111
+ minSimilarity: options.similarity ? parseFloat(options.similarity) : undefined,
112
+ minLines: options.minLines ? parseInt(options.minLines) : undefined,
113
+ include: options.include?.split(','),
114
+ exclude: options.exclude?.split(','),
115
+ });
136
116
 
137
117
  const { analyzePatterns, generateSummary } = await import('@aiready/pattern-detect');
138
118
 
139
119
  const { results } = await analyzePatterns(finalOptions);
140
120
 
141
- const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
121
+ const elapsedTime = getElapsedTime(startTime);
142
122
  const summary = generateSummary(results);
143
123
 
144
- const outputFormat = options.output || mergedConfig.output?.format || 'console';
145
- const outputFile = options.outputFile || mergedConfig.output?.file;
124
+ const outputFormat = options.output || finalOptions.output?.format || 'console';
125
+ const outputFile = options.outputFile || finalOptions.output?.file;
146
126
 
147
127
  if (outputFormat === 'json') {
148
128
  const outputData = {
@@ -150,20 +130,14 @@ program
150
130
  summary: { ...summary, executionTime: parseFloat(elapsedTime) },
151
131
  };
152
132
 
153
- if (outputFile) {
154
- writeFileSync(outputFile, JSON.stringify(outputData, null, 2));
155
- console.log(chalk.green(`✅ Results saved to ${outputFile}`));
156
- } else {
157
- console.log(JSON.stringify(outputData, null, 2));
158
- }
133
+ handleJSONOutput(outputData, outputFile, `✅ Results saved to ${outputFile}`);
159
134
  } else {
160
135
  console.log(`Pattern Analysis Complete (${elapsedTime}s)`);
161
136
  console.log(`Found ${summary.totalPatterns} duplicate patterns`);
162
137
  console.log(`Total token cost: ${summary.totalTokenCost} tokens`);
163
138
  }
164
139
  } catch (error) {
165
- console.error(chalk.red('Pattern analysis failed:'), error);
166
- process.exit(1);
140
+ handleCLIError(error, 'Pattern analysis');
167
141
  }
168
142
  });
169
143
 
@@ -183,9 +157,6 @@ program
183
157
  const startTime = Date.now();
184
158
 
185
159
  try {
186
- // Load config file if it exists
187
- const config = loadConfig(directory);
188
-
189
160
  // Define defaults
190
161
  const defaults = {
191
162
  maxDepth: 5,
@@ -198,27 +169,23 @@ program
198
169
  },
199
170
  };
200
171
 
201
- // Merge config with defaults
202
- const mergedConfig = mergeConfigWithDefaults(config, defaults);
203
-
204
- // Override with CLI options (CLI takes precedence)
205
- const finalOptions = {
206
- rootDir: directory,
207
- maxDepth: options.maxDepth ? parseInt(options.maxDepth) : mergedConfig.maxDepth,
208
- maxContextBudget: options.maxContext ? parseInt(options.maxContext) : mergedConfig.maxContextBudget,
209
- include: options.include?.split(',') || mergedConfig.include,
210
- exclude: options.exclude?.split(',') || mergedConfig.exclude,
211
- };
172
+ // Load and merge config with CLI options
173
+ const finalOptions = loadMergedConfig(directory, defaults, {
174
+ maxDepth: options.maxDepth ? parseInt(options.maxDepth) : undefined,
175
+ maxContextBudget: options.maxContext ? parseInt(options.maxContext) : undefined,
176
+ include: options.include?.split(','),
177
+ exclude: options.exclude?.split(','),
178
+ });
212
179
 
213
180
  const { analyzeContext, generateSummary } = await import('@aiready/context-analyzer');
214
181
 
215
182
  const results = await analyzeContext(finalOptions);
216
183
 
217
- const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
184
+ const elapsedTime = getElapsedTime(startTime);
218
185
  const summary = generateSummary(results);
219
186
 
220
- const outputFormat = options.output || mergedConfig.output?.format || 'console';
221
- const outputFile = options.outputFile || mergedConfig.output?.file;
187
+ const outputFormat = options.output || finalOptions.output?.format || 'console';
188
+ const outputFile = options.outputFile || finalOptions.output?.file;
222
189
 
223
190
  if (outputFormat === 'json') {
224
191
  const outputData = {
@@ -226,12 +193,7 @@ program
226
193
  summary: { ...summary, executionTime: parseFloat(elapsedTime) },
227
194
  };
228
195
 
229
- if (outputFile) {
230
- writeFileSync(outputFile, JSON.stringify(outputData, null, 2));
231
- console.log(chalk.green(`✅ Results saved to ${outputFile}`));
232
- } else {
233
- console.log(JSON.stringify(outputData, null, 2));
234
- }
196
+ handleJSONOutput(outputData, outputFile, `✅ Results saved to ${outputFile}`);
235
197
  } else {
236
198
  console.log(`Context Analysis Complete (${elapsedTime}s)`);
237
199
  console.log(`Files analyzed: ${summary.totalFiles}`);
@@ -240,8 +202,7 @@ program
240
202
  console.log(`Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(1)}%`);
241
203
  }
242
204
  } catch (error) {
243
- console.error(chalk.red('Context analysis failed:'), error);
244
- process.exit(1);
205
+ handleCLIError(error, 'Context analysis');
245
206
  }
246
207
  });
247
208