@aiready/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +24 -0
- package/.turbo/turbo-test.log +9 -0
- package/README.md +138 -0
- package/dist/chunk-CHRHSNKI.mjs +53 -0
- package/dist/chunk-S6JWNLN7.mjs +53 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +189 -0
- package/dist/cli.mjs +119 -0
- package/dist/index.d.mts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +78 -0
- package/dist/index.mjs +8 -0
- package/package.json +36 -0
- package/src/__tests__/cli.test.ts +55 -0
- package/src/cli.ts +174 -0
- package/src/index.ts +66 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @aiready/cli@0.1.0 build /Users/pengcao/projects/aiready/packages/cli
|
|
4
|
+
> tsup src/index.ts src/cli.ts --format cjs,esm --dts
|
|
5
|
+
|
|
6
|
+
[34mCLI[39m Building entry: src/cli.ts, src/index.ts
|
|
7
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
8
|
+
[34mCLI[39m tsup v8.5.1
|
|
9
|
+
[34mCLI[39m Target: es2020
|
|
10
|
+
[34mCJS[39m Build start
|
|
11
|
+
[34mESM[39m Build start
|
|
12
|
+
[32mCJS[39m [1mdist/cli.js [22m[32m8.70 KB[39m
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m2.51 KB[39m
|
|
14
|
+
[32mCJS[39m ⚡️ Build success in 54ms
|
|
15
|
+
[32mESM[39m [1mdist/chunk-S6JWNLN7.mjs [22m[32m1.40 KB[39m
|
|
16
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m138.00 B[39m
|
|
17
|
+
[32mESM[39m [1mdist/cli.mjs [22m[32m5.95 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 55ms
|
|
19
|
+
DTS Build start
|
|
20
|
+
DTS ⚡️ Build success in 560ms
|
|
21
|
+
DTS dist/cli.d.ts 20.00 B
|
|
22
|
+
DTS dist/index.d.ts 731.00 B
|
|
23
|
+
DTS dist/cli.d.mts 20.00 B
|
|
24
|
+
DTS dist/index.d.mts 731.00 B
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @aiready/cli@0.1.0 test /Users/pengcao/projects/aiready/packages/cli
|
|
4
|
+
> vitest run
|
|
5
|
+
|
|
6
|
+
[?25l
|
|
7
|
+
[1m[46m RUN [49m[22m [36mv4.0.16 [39m[90m/Users/pengcao/projects/aiready/packages/cli[39m
|
|
8
|
+
|
|
9
|
+
[41m[30m ELIFECYCLE [39m[49m [31mTest failed. See above for more details.[39m
|
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# @aiready/cli
|
|
2
|
+
|
|
3
|
+
Unified CLI for AIReady analysis tools. Provides both unified analysis and individual tool access.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @aiready/cli
|
|
9
|
+
# or
|
|
10
|
+
pnpm add -g @aiready/cli
|
|
11
|
+
# or
|
|
12
|
+
yarn global add @aiready/cli
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Unified Analysis
|
|
18
|
+
|
|
19
|
+
Run both pattern detection and context analysis:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
aiready scan <directory>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Individual Tools
|
|
26
|
+
|
|
27
|
+
#### Pattern Detection
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
aiready patterns <directory> [options]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Options:
|
|
34
|
+
- `-s, --similarity <number>`: Minimum similarity score (0-1) (default: 0.40)
|
|
35
|
+
- `-l, --min-lines <number>`: Minimum lines to consider (default: 5)
|
|
36
|
+
- `--include <patterns>`: File patterns to include (comma-separated)
|
|
37
|
+
- `--exclude <patterns>`: File patterns to exclude (comma-separated)
|
|
38
|
+
- `-o, --output <format>`: Output format: console, json (default: console)
|
|
39
|
+
- `--output-file <path>`: Output file path (for json)
|
|
40
|
+
|
|
41
|
+
#### Context Analysis
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
aiready context <directory> [options]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Options:
|
|
48
|
+
- `--max-depth <number>`: Maximum acceptable import depth (default: 5)
|
|
49
|
+
- `--max-context <number>`: Maximum acceptable context budget (tokens) (default: 10000)
|
|
50
|
+
- `--include <patterns>`: File patterns to include (comma-separated)
|
|
51
|
+
- `--exclude <patterns>`: File patterns to exclude (comma-separated)
|
|
52
|
+
- `-o, --output <format>`: Output format: console, json (default: console)
|
|
53
|
+
- `--output-file <path>`: Output file path (for json)
|
|
54
|
+
|
|
55
|
+
### Unified Scan Options
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
aiready scan <directory> [options]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Options:
|
|
62
|
+
- `-t, --tools <tools>`: Tools to run (comma-separated: patterns,context) (default: patterns,context)
|
|
63
|
+
- `--include <patterns>`: File patterns to include (comma-separated)
|
|
64
|
+
- `--exclude <patterns>`: File patterns to exclude (comma-separated)
|
|
65
|
+
- `-o, --output <format>`: Output format: console, json (default: console)
|
|
66
|
+
- `--output-file <path>`: Output file path (for json)
|
|
67
|
+
|
|
68
|
+
## Examples
|
|
69
|
+
|
|
70
|
+
### Quick Analysis
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Analyze current directory with both tools
|
|
74
|
+
aiready scan .
|
|
75
|
+
|
|
76
|
+
# Analyze only patterns
|
|
77
|
+
aiready patterns .
|
|
78
|
+
|
|
79
|
+
# Analyze only context costs
|
|
80
|
+
aiready context .
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Advanced Usage
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Analyze specific file types
|
|
87
|
+
aiready scan ./src --include "**/*.ts,**/*.js"
|
|
88
|
+
|
|
89
|
+
# Exclude test files
|
|
90
|
+
aiready scan . --exclude "**/*.test.*,**/*.spec.*"
|
|
91
|
+
|
|
92
|
+
# Save results to JSON file
|
|
93
|
+
aiready scan . --output json --output-file results.json
|
|
94
|
+
|
|
95
|
+
# Run only pattern analysis with custom similarity threshold
|
|
96
|
+
aiready patterns . --similarity 0.6 --min-lines 10
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### CI/CD Integration
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# JSON output for automated processing
|
|
103
|
+
aiready scan . --output json --output-file aiready-results.json
|
|
104
|
+
|
|
105
|
+
# Exit with error code if issues found
|
|
106
|
+
aiready scan . && echo "No issues found" || echo "Issues detected"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Output Formats
|
|
110
|
+
|
|
111
|
+
### Console Output
|
|
112
|
+
|
|
113
|
+
Human-readable summary with key metrics and issue counts.
|
|
114
|
+
|
|
115
|
+
### JSON Output
|
|
116
|
+
|
|
117
|
+
Structured data including:
|
|
118
|
+
- Full analysis results
|
|
119
|
+
- Detailed metrics
|
|
120
|
+
- Issue breakdowns
|
|
121
|
+
- Execution timing
|
|
122
|
+
|
|
123
|
+
## Exit Codes
|
|
124
|
+
|
|
125
|
+
- `0`: Success, no critical issues
|
|
126
|
+
- `1`: Analysis failed or critical issues found
|
|
127
|
+
|
|
128
|
+
## Integration
|
|
129
|
+
|
|
130
|
+
The CLI is designed to integrate with:
|
|
131
|
+
- CI/CD pipelines
|
|
132
|
+
- Pre-commit hooks
|
|
133
|
+
- IDE extensions
|
|
134
|
+
- Automated workflows
|
|
135
|
+
|
|
136
|
+
For programmatic usage, see the individual packages:
|
|
137
|
+
- [@aiready/pattern-detect](../pattern-detect)
|
|
138
|
+
- [@aiready/context-analyzer](../context-analyzer)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { analyzePatterns } from "@aiready/pattern-detect";
|
|
3
|
+
import { analyzeContext } from "@aiready/context-analyzer";
|
|
4
|
+
async function analyzeUnified(options) {
|
|
5
|
+
const startTime = Date.now();
|
|
6
|
+
const tools = options.tools || ["patterns", "context"];
|
|
7
|
+
const result = {
|
|
8
|
+
summary: {
|
|
9
|
+
totalIssues: 0,
|
|
10
|
+
toolsRun: tools,
|
|
11
|
+
executionTime: 0
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
if (tools.includes("patterns")) {
|
|
15
|
+
result.patterns = await analyzePatterns(options);
|
|
16
|
+
result.summary.totalIssues += result.patterns.length;
|
|
17
|
+
}
|
|
18
|
+
if (tools.includes("context")) {
|
|
19
|
+
result.context = await analyzeContext(options);
|
|
20
|
+
result.summary.totalIssues += result.context.length;
|
|
21
|
+
}
|
|
22
|
+
result.summary.executionTime = Date.now() - startTime;
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
function generateUnifiedSummary(result) {
|
|
26
|
+
const { summary } = result;
|
|
27
|
+
let output = `\u{1F680} AIReady Analysis Complete
|
|
28
|
+
|
|
29
|
+
`;
|
|
30
|
+
output += `\u{1F4CA} Summary:
|
|
31
|
+
`;
|
|
32
|
+
output += ` Tools run: ${summary.toolsRun.join(", ")}
|
|
33
|
+
`;
|
|
34
|
+
output += ` Total issues found: ${summary.totalIssues}
|
|
35
|
+
`;
|
|
36
|
+
output += ` Execution time: ${(summary.executionTime / 1e3).toFixed(2)}s
|
|
37
|
+
|
|
38
|
+
`;
|
|
39
|
+
if (result.patterns?.length) {
|
|
40
|
+
output += `\u{1F50D} Pattern Analysis: ${result.patterns.length} issues
|
|
41
|
+
`;
|
|
42
|
+
}
|
|
43
|
+
if (result.context?.length) {
|
|
44
|
+
output += `\u{1F9E0} Context Analysis: ${result.context.length} issues
|
|
45
|
+
`;
|
|
46
|
+
}
|
|
47
|
+
return output;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
analyzeUnified,
|
|
52
|
+
generateUnifiedSummary
|
|
53
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { analyzePatterns } from "@aiready/pattern-detect";
|
|
3
|
+
import { analyzeContext } from "@aiready/context-analyzer";
|
|
4
|
+
async function analyzeUnified(options) {
|
|
5
|
+
const startTime = Date.now();
|
|
6
|
+
const tools = options.tools || ["patterns", "context"];
|
|
7
|
+
const result = {
|
|
8
|
+
summary: {
|
|
9
|
+
totalIssues: 0,
|
|
10
|
+
toolsRun: tools,
|
|
11
|
+
executionTime: 0
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
if (tools.includes("patterns")) {
|
|
15
|
+
result.patterns = await analyzePatterns(options);
|
|
16
|
+
result.summary.totalIssues += result.patterns.length;
|
|
17
|
+
}
|
|
18
|
+
if (tools.includes("context")) {
|
|
19
|
+
result.context = await analyzeContext(options);
|
|
20
|
+
result.summary.totalIssues += result.context?.length || 0;
|
|
21
|
+
}
|
|
22
|
+
result.summary.executionTime = Date.now() - startTime;
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
function generateUnifiedSummary(result) {
|
|
26
|
+
const { summary } = result;
|
|
27
|
+
let output = `\u{1F680} AIReady Analysis Complete
|
|
28
|
+
|
|
29
|
+
`;
|
|
30
|
+
output += `\u{1F4CA} Summary:
|
|
31
|
+
`;
|
|
32
|
+
output += ` Tools run: ${summary.toolsRun.join(", ")}
|
|
33
|
+
`;
|
|
34
|
+
output += ` Total issues found: ${summary.totalIssues}
|
|
35
|
+
`;
|
|
36
|
+
output += ` Execution time: ${(summary.executionTime / 1e3).toFixed(2)}s
|
|
37
|
+
|
|
38
|
+
`;
|
|
39
|
+
if (result.patterns?.length) {
|
|
40
|
+
output += `\u{1F50D} Pattern Analysis: ${result.patterns.length} issues
|
|
41
|
+
`;
|
|
42
|
+
}
|
|
43
|
+
if (result.context?.length) {
|
|
44
|
+
output += `\u{1F9E0} Context Analysis: ${result.context.length} issues
|
|
45
|
+
`;
|
|
46
|
+
}
|
|
47
|
+
return output;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
analyzeUnified,
|
|
52
|
+
generateUnifiedSummary
|
|
53
|
+
};
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/cli.ts
|
|
27
|
+
var import_commander = require("commander");
|
|
28
|
+
|
|
29
|
+
// src/index.ts
|
|
30
|
+
var import_pattern_detect = require("@aiready/pattern-detect");
|
|
31
|
+
var import_context_analyzer = require("@aiready/context-analyzer");
|
|
32
|
+
async function analyzeUnified(options) {
|
|
33
|
+
const startTime = Date.now();
|
|
34
|
+
const tools = options.tools || ["patterns", "context"];
|
|
35
|
+
const result = {
|
|
36
|
+
summary: {
|
|
37
|
+
totalIssues: 0,
|
|
38
|
+
toolsRun: tools,
|
|
39
|
+
executionTime: 0
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
if (tools.includes("patterns")) {
|
|
43
|
+
result.patterns = await (0, import_pattern_detect.analyzePatterns)(options);
|
|
44
|
+
result.summary.totalIssues += result.patterns.length;
|
|
45
|
+
}
|
|
46
|
+
if (tools.includes("context")) {
|
|
47
|
+
result.context = await (0, import_context_analyzer.analyzeContext)(options);
|
|
48
|
+
result.summary.totalIssues += result.context?.length || 0;
|
|
49
|
+
}
|
|
50
|
+
result.summary.executionTime = Date.now() - startTime;
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
function generateUnifiedSummary(result) {
|
|
54
|
+
const { summary } = result;
|
|
55
|
+
let output = `\u{1F680} AIReady Analysis Complete
|
|
56
|
+
|
|
57
|
+
`;
|
|
58
|
+
output += `\u{1F4CA} Summary:
|
|
59
|
+
`;
|
|
60
|
+
output += ` Tools run: ${summary.toolsRun.join(", ")}
|
|
61
|
+
`;
|
|
62
|
+
output += ` Total issues found: ${summary.totalIssues}
|
|
63
|
+
`;
|
|
64
|
+
output += ` Execution time: ${(summary.executionTime / 1e3).toFixed(2)}s
|
|
65
|
+
|
|
66
|
+
`;
|
|
67
|
+
if (result.patterns?.length) {
|
|
68
|
+
output += `\u{1F50D} Pattern Analysis: ${result.patterns.length} issues
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
if (result.context?.length) {
|
|
72
|
+
output += `\u{1F9E0} Context Analysis: ${result.context.length} issues
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
return output;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/cli.ts
|
|
79
|
+
var import_chalk = __toESM(require("chalk"));
|
|
80
|
+
var import_fs = require("fs");
|
|
81
|
+
var program = new import_commander.Command();
|
|
82
|
+
program.name("aiready").description("AIReady - Unified AI-readiness analysis tools").version("0.1.0");
|
|
83
|
+
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) => {
|
|
84
|
+
console.log(import_chalk.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
|
|
85
|
+
const startTime = Date.now();
|
|
86
|
+
try {
|
|
87
|
+
const tools = options.tools.split(",").map((t) => t.trim());
|
|
88
|
+
const results = await analyzeUnified({
|
|
89
|
+
rootDir: directory,
|
|
90
|
+
tools,
|
|
91
|
+
include: options.include?.split(","),
|
|
92
|
+
exclude: options.exclude?.split(",")
|
|
93
|
+
});
|
|
94
|
+
const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
95
|
+
if (options.output === "json") {
|
|
96
|
+
const outputData = {
|
|
97
|
+
...results,
|
|
98
|
+
summary: {
|
|
99
|
+
...results.summary,
|
|
100
|
+
executionTime: parseFloat(elapsedTime)
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
if (options.outputFile) {
|
|
104
|
+
(0, import_fs.writeFileSync)(options.outputFile, JSON.stringify(outputData, null, 2));
|
|
105
|
+
console.log(import_chalk.default.green(`\u2705 Results saved to ${options.outputFile}`));
|
|
106
|
+
} else {
|
|
107
|
+
console.log(JSON.stringify(outputData, null, 2));
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
console.log(generateUnifiedSummary(results));
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(import_chalk.default.red("\u274C Analysis failed:"), error);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
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) => {
|
|
118
|
+
console.log(import_chalk.default.blue("\u{1F50D} Analyzing patterns...\n"));
|
|
119
|
+
const startTime = Date.now();
|
|
120
|
+
try {
|
|
121
|
+
const { analyzePatterns: analyzePatterns2, generateSummary } = await import("@aiready/pattern-detect");
|
|
122
|
+
const results = await analyzePatterns2({
|
|
123
|
+
rootDir: directory,
|
|
124
|
+
minSimilarity: parseFloat(options.similarity),
|
|
125
|
+
minLines: parseInt(options.minLines),
|
|
126
|
+
include: options.include?.split(","),
|
|
127
|
+
exclude: options.exclude?.split(",")
|
|
128
|
+
});
|
|
129
|
+
const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
130
|
+
const summary = generateSummary(results);
|
|
131
|
+
if (options.output === "json") {
|
|
132
|
+
const outputData = {
|
|
133
|
+
results,
|
|
134
|
+
summary: { ...summary, executionTime: parseFloat(elapsedTime) }
|
|
135
|
+
};
|
|
136
|
+
if (options.outputFile) {
|
|
137
|
+
(0, import_fs.writeFileSync)(options.outputFile, JSON.stringify(outputData, null, 2));
|
|
138
|
+
console.log(import_chalk.default.green(`\u2705 Results saved to ${options.outputFile}`));
|
|
139
|
+
} else {
|
|
140
|
+
console.log(JSON.stringify(outputData, null, 2));
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
console.log(`Pattern Analysis Complete (${elapsedTime}s)`);
|
|
144
|
+
console.log(`Found ${summary.totalPatterns} duplicate patterns`);
|
|
145
|
+
console.log(`Total token cost: ${summary.totalTokenCost} tokens`);
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error(import_chalk.default.red("\u274C Pattern analysis failed:"), error);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
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) => {
|
|
153
|
+
console.log(import_chalk.default.blue("\u{1F9E0} Analyzing context costs...\n"));
|
|
154
|
+
const startTime = Date.now();
|
|
155
|
+
try {
|
|
156
|
+
const { analyzeContext: analyzeContext2, generateSummary } = await import("@aiready/context-analyzer");
|
|
157
|
+
const results = await analyzeContext2({
|
|
158
|
+
rootDir: directory,
|
|
159
|
+
maxDepth: parseInt(options.maxDepth),
|
|
160
|
+
maxContextBudget: parseInt(options.maxContext),
|
|
161
|
+
include: options.include?.split(","),
|
|
162
|
+
exclude: options.exclude?.split(",")
|
|
163
|
+
});
|
|
164
|
+
const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
165
|
+
const summary = generateSummary(results);
|
|
166
|
+
if (options.output === "json") {
|
|
167
|
+
const outputData = {
|
|
168
|
+
results,
|
|
169
|
+
summary: { ...summary, executionTime: parseFloat(elapsedTime) }
|
|
170
|
+
};
|
|
171
|
+
if (options.outputFile) {
|
|
172
|
+
(0, import_fs.writeFileSync)(options.outputFile, JSON.stringify(outputData, null, 2));
|
|
173
|
+
console.log(import_chalk.default.green(`\u2705 Results saved to ${options.outputFile}`));
|
|
174
|
+
} else {
|
|
175
|
+
console.log(JSON.stringify(outputData, null, 2));
|
|
176
|
+
}
|
|
177
|
+
} else {
|
|
178
|
+
console.log(`Context Analysis Complete (${elapsedTime}s)`);
|
|
179
|
+
console.log(`Files analyzed: ${summary.totalFiles}`);
|
|
180
|
+
console.log(`Issues found: ${results.length}`);
|
|
181
|
+
console.log(`Average cohesion: ${(summary.avgCohesion * 100).toFixed(1)}%`);
|
|
182
|
+
console.log(`Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(1)}%`);
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error(import_chalk.default.red("\u274C Context analysis failed:"), error);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
program.parse();
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
analyzeUnified,
|
|
4
|
+
generateUnifiedSummary
|
|
5
|
+
} from "./chunk-S6JWNLN7.mjs";
|
|
6
|
+
|
|
7
|
+
// src/cli.ts
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import { writeFileSync } from "fs";
|
|
11
|
+
var program = new Command();
|
|
12
|
+
program.name("aiready").description("AIReady - Unified AI-readiness analysis tools").version("0.1.0");
|
|
13
|
+
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) => {
|
|
14
|
+
console.log(chalk.blue("\u{1F680} Starting AIReady unified analysis...\n"));
|
|
15
|
+
const startTime = Date.now();
|
|
16
|
+
try {
|
|
17
|
+
const tools = options.tools.split(",").map((t) => t.trim());
|
|
18
|
+
const results = await analyzeUnified({
|
|
19
|
+
rootDir: directory,
|
|
20
|
+
tools,
|
|
21
|
+
include: options.include?.split(","),
|
|
22
|
+
exclude: options.exclude?.split(",")
|
|
23
|
+
});
|
|
24
|
+
const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
25
|
+
if (options.output === "json") {
|
|
26
|
+
const outputData = {
|
|
27
|
+
...results,
|
|
28
|
+
summary: {
|
|
29
|
+
...results.summary,
|
|
30
|
+
executionTime: parseFloat(elapsedTime)
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
if (options.outputFile) {
|
|
34
|
+
writeFileSync(options.outputFile, JSON.stringify(outputData, null, 2));
|
|
35
|
+
console.log(chalk.green(`\u2705 Results saved to ${options.outputFile}`));
|
|
36
|
+
} else {
|
|
37
|
+
console.log(JSON.stringify(outputData, null, 2));
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
console.log(generateUnifiedSummary(results));
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error(chalk.red("\u274C Analysis failed:"), error);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
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) => {
|
|
48
|
+
console.log(chalk.blue("\u{1F50D} Analyzing patterns...\n"));
|
|
49
|
+
const startTime = Date.now();
|
|
50
|
+
try {
|
|
51
|
+
const { analyzePatterns, generateSummary } = await import("@aiready/pattern-detect");
|
|
52
|
+
const results = await analyzePatterns({
|
|
53
|
+
rootDir: directory,
|
|
54
|
+
minSimilarity: parseFloat(options.similarity),
|
|
55
|
+
minLines: parseInt(options.minLines),
|
|
56
|
+
include: options.include?.split(","),
|
|
57
|
+
exclude: options.exclude?.split(",")
|
|
58
|
+
});
|
|
59
|
+
const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
60
|
+
const summary = generateSummary(results);
|
|
61
|
+
if (options.output === "json") {
|
|
62
|
+
const outputData = {
|
|
63
|
+
results,
|
|
64
|
+
summary: { ...summary, executionTime: parseFloat(elapsedTime) }
|
|
65
|
+
};
|
|
66
|
+
if (options.outputFile) {
|
|
67
|
+
writeFileSync(options.outputFile, JSON.stringify(outputData, null, 2));
|
|
68
|
+
console.log(chalk.green(`\u2705 Results saved to ${options.outputFile}`));
|
|
69
|
+
} else {
|
|
70
|
+
console.log(JSON.stringify(outputData, null, 2));
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
console.log(`Pattern Analysis Complete (${elapsedTime}s)`);
|
|
74
|
+
console.log(`Found ${summary.totalPatterns} duplicate patterns`);
|
|
75
|
+
console.log(`Total token cost: ${summary.totalTokenCost} tokens`);
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error(chalk.red("\u274C Pattern analysis failed:"), error);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
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) => {
|
|
83
|
+
console.log(chalk.blue("\u{1F9E0} Analyzing context costs...\n"));
|
|
84
|
+
const startTime = Date.now();
|
|
85
|
+
try {
|
|
86
|
+
const { analyzeContext, generateSummary } = await import("@aiready/context-analyzer");
|
|
87
|
+
const results = await analyzeContext({
|
|
88
|
+
rootDir: directory,
|
|
89
|
+
maxDepth: parseInt(options.maxDepth),
|
|
90
|
+
maxContextBudget: parseInt(options.maxContext),
|
|
91
|
+
include: options.include?.split(","),
|
|
92
|
+
exclude: options.exclude?.split(",")
|
|
93
|
+
});
|
|
94
|
+
const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
95
|
+
const summary = generateSummary(results);
|
|
96
|
+
if (options.output === "json") {
|
|
97
|
+
const outputData = {
|
|
98
|
+
results,
|
|
99
|
+
summary: { ...summary, executionTime: parseFloat(elapsedTime) }
|
|
100
|
+
};
|
|
101
|
+
if (options.outputFile) {
|
|
102
|
+
writeFileSync(options.outputFile, JSON.stringify(outputData, null, 2));
|
|
103
|
+
console.log(chalk.green(`\u2705 Results saved to ${options.outputFile}`));
|
|
104
|
+
} else {
|
|
105
|
+
console.log(JSON.stringify(outputData, null, 2));
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
console.log(`Context Analysis Complete (${elapsedTime}s)`);
|
|
109
|
+
console.log(`Files analyzed: ${summary.totalFiles}`);
|
|
110
|
+
console.log(`Issues found: ${results.length}`);
|
|
111
|
+
console.log(`Average cohesion: ${(summary.avgCohesion * 100).toFixed(1)}%`);
|
|
112
|
+
console.log(`Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(1)}%`);
|
|
113
|
+
}
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error(chalk.red("\u274C Context analysis failed:"), error);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
program.parse();
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ScanOptions, AnalysisResult } from '@aiready/core';
|
|
2
|
+
import { ContextAnalysisResult } from '@aiready/context-analyzer';
|
|
3
|
+
|
|
4
|
+
interface UnifiedAnalysisOptions extends ScanOptions {
|
|
5
|
+
tools?: ('patterns' | 'context')[];
|
|
6
|
+
}
|
|
7
|
+
interface UnifiedAnalysisResult {
|
|
8
|
+
patterns?: AnalysisResult[];
|
|
9
|
+
context?: ContextAnalysisResult[];
|
|
10
|
+
summary: {
|
|
11
|
+
totalIssues: number;
|
|
12
|
+
toolsRun: string[];
|
|
13
|
+
executionTime: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
declare function analyzeUnified(options: UnifiedAnalysisOptions): Promise<UnifiedAnalysisResult>;
|
|
17
|
+
declare function generateUnifiedSummary(result: UnifiedAnalysisResult): string;
|
|
18
|
+
|
|
19
|
+
export { type UnifiedAnalysisOptions, type UnifiedAnalysisResult, analyzeUnified, generateUnifiedSummary };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ScanOptions, AnalysisResult } from '@aiready/core';
|
|
2
|
+
import { ContextAnalysisResult } from '@aiready/context-analyzer';
|
|
3
|
+
|
|
4
|
+
interface UnifiedAnalysisOptions extends ScanOptions {
|
|
5
|
+
tools?: ('patterns' | 'context')[];
|
|
6
|
+
}
|
|
7
|
+
interface UnifiedAnalysisResult {
|
|
8
|
+
patterns?: AnalysisResult[];
|
|
9
|
+
context?: ContextAnalysisResult[];
|
|
10
|
+
summary: {
|
|
11
|
+
totalIssues: number;
|
|
12
|
+
toolsRun: string[];
|
|
13
|
+
executionTime: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
declare function analyzeUnified(options: UnifiedAnalysisOptions): Promise<UnifiedAnalysisResult>;
|
|
17
|
+
declare function generateUnifiedSummary(result: UnifiedAnalysisResult): string;
|
|
18
|
+
|
|
19
|
+
export { type UnifiedAnalysisOptions, type UnifiedAnalysisResult, analyzeUnified, generateUnifiedSummary };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
analyzeUnified: () => analyzeUnified,
|
|
24
|
+
generateUnifiedSummary: () => generateUnifiedSummary
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
var import_pattern_detect = require("@aiready/pattern-detect");
|
|
28
|
+
var import_context_analyzer = require("@aiready/context-analyzer");
|
|
29
|
+
async function analyzeUnified(options) {
|
|
30
|
+
const startTime = Date.now();
|
|
31
|
+
const tools = options.tools || ["patterns", "context"];
|
|
32
|
+
const result = {
|
|
33
|
+
summary: {
|
|
34
|
+
totalIssues: 0,
|
|
35
|
+
toolsRun: tools,
|
|
36
|
+
executionTime: 0
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
if (tools.includes("patterns")) {
|
|
40
|
+
result.patterns = await (0, import_pattern_detect.analyzePatterns)(options);
|
|
41
|
+
result.summary.totalIssues += result.patterns.length;
|
|
42
|
+
}
|
|
43
|
+
if (tools.includes("context")) {
|
|
44
|
+
result.context = await (0, import_context_analyzer.analyzeContext)(options);
|
|
45
|
+
result.summary.totalIssues += result.context?.length || 0;
|
|
46
|
+
}
|
|
47
|
+
result.summary.executionTime = Date.now() - startTime;
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
function generateUnifiedSummary(result) {
|
|
51
|
+
const { summary } = result;
|
|
52
|
+
let output = `\u{1F680} AIReady Analysis Complete
|
|
53
|
+
|
|
54
|
+
`;
|
|
55
|
+
output += `\u{1F4CA} Summary:
|
|
56
|
+
`;
|
|
57
|
+
output += ` Tools run: ${summary.toolsRun.join(", ")}
|
|
58
|
+
`;
|
|
59
|
+
output += ` Total issues found: ${summary.totalIssues}
|
|
60
|
+
`;
|
|
61
|
+
output += ` Execution time: ${(summary.executionTime / 1e3).toFixed(2)}s
|
|
62
|
+
|
|
63
|
+
`;
|
|
64
|
+
if (result.patterns?.length) {
|
|
65
|
+
output += `\u{1F50D} Pattern Analysis: ${result.patterns.length} issues
|
|
66
|
+
`;
|
|
67
|
+
}
|
|
68
|
+
if (result.context?.length) {
|
|
69
|
+
output += `\u{1F9E0} Context Analysis: ${result.context.length} issues
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
return output;
|
|
73
|
+
}
|
|
74
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
75
|
+
0 && (module.exports = {
|
|
76
|
+
analyzeUnified,
|
|
77
|
+
generateUnifiedSummary
|
|
78
|
+
});
|
package/dist/index.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aiready/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Unified CLI for AIReady analysis tools",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"aiready": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"commander": "^12.1.0",
|
|
13
|
+
"chalk": "^5.3.0",
|
|
14
|
+
"@aiready/context-analyzer": "0.1.0",
|
|
15
|
+
"@aiready/core": "0.2.1",
|
|
16
|
+
"@aiready/pattern-detect": "0.5.1"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"tsup": "^8.3.5",
|
|
20
|
+
"@types/node": "^20.0.0"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"aiready",
|
|
24
|
+
"cli",
|
|
25
|
+
"ai-readiness",
|
|
26
|
+
"code-analysis"
|
|
27
|
+
],
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts",
|
|
31
|
+
"dev": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --watch",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"lint": "eslint src",
|
|
34
|
+
"clean": "rm -rf dist"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { analyzeUnified } from '../index';
|
|
3
|
+
|
|
4
|
+
// Mock the individual tools
|
|
5
|
+
vi.mock('@aiready/pattern-detect', () => ({
|
|
6
|
+
analyzePatterns: vi.fn().mockResolvedValue([]),
|
|
7
|
+
generateSummary: vi.fn().mockReturnValue({
|
|
8
|
+
totalDuplicateLines: 0,
|
|
9
|
+
potentialSavings: 0,
|
|
10
|
+
}),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
vi.mock('@aiready/context-analyzer', () => ({
|
|
14
|
+
analyzeContext: vi.fn().mockResolvedValue([]),
|
|
15
|
+
generateSummary: vi.fn().mockReturnValue({
|
|
16
|
+
totalFiles: 0,
|
|
17
|
+
averageCohesion: 0,
|
|
18
|
+
averageFragmentation: 0,
|
|
19
|
+
}),
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
describe('CLI Unified Analysis', () => {
|
|
23
|
+
it('should run unified analysis with both tools', async () => {
|
|
24
|
+
const results = await analyzeUnified({
|
|
25
|
+
rootDir: '/test',
|
|
26
|
+
tools: ['patterns', 'context'],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
expect(results).toHaveProperty('patterns');
|
|
30
|
+
expect(results).toHaveProperty('context');
|
|
31
|
+
expect(results).toHaveProperty('summary');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should run analysis with only patterns tool', async () => {
|
|
35
|
+
const results = await analyzeUnified({
|
|
36
|
+
rootDir: '/test',
|
|
37
|
+
tools: ['patterns'],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
expect(results).toHaveProperty('patterns');
|
|
41
|
+
expect(results).not.toHaveProperty('context');
|
|
42
|
+
expect(results).toHaveProperty('summary');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should run analysis with only context tool', async () => {
|
|
46
|
+
const results = await analyzeUnified({
|
|
47
|
+
rootDir: '/test',
|
|
48
|
+
tools: ['context'],
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
expect(results).not.toHaveProperty('patterns');
|
|
52
|
+
expect(results).toHaveProperty('context');
|
|
53
|
+
expect(results).toHaveProperty('summary');
|
|
54
|
+
});
|
|
55
|
+
});
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { analyzeUnified, generateUnifiedSummary } from './index';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { writeFileSync } from 'fs';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
|
|
9
|
+
const program = new Command();
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.name('aiready')
|
|
13
|
+
.description('AIReady - Unified AI-readiness analysis tools')
|
|
14
|
+
.version('0.1.0');
|
|
15
|
+
|
|
16
|
+
program
|
|
17
|
+
.command('scan')
|
|
18
|
+
.description('Run unified analysis on a codebase')
|
|
19
|
+
.argument('<directory>', 'Directory to analyze')
|
|
20
|
+
.option('-t, --tools <tools>', 'Tools to run (comma-separated: patterns,context)', 'patterns,context')
|
|
21
|
+
.option('--include <patterns>', 'File patterns to include (comma-separated)')
|
|
22
|
+
.option('--exclude <patterns>', 'File patterns to exclude (comma-separated)')
|
|
23
|
+
.option('-o, --output <format>', 'Output format: console, json', 'console')
|
|
24
|
+
.option('--output-file <path>', 'Output file path (for json)')
|
|
25
|
+
.action(async (directory, options) => {
|
|
26
|
+
console.log(chalk.blue('🚀 Starting AIReady unified analysis...\n'));
|
|
27
|
+
|
|
28
|
+
const startTime = Date.now();
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const tools = options.tools.split(',').map((t: string) => t.trim()) as ('patterns' | 'context')[];
|
|
32
|
+
|
|
33
|
+
const results = await analyzeUnified({
|
|
34
|
+
rootDir: directory,
|
|
35
|
+
tools,
|
|
36
|
+
include: options.include?.split(','),
|
|
37
|
+
exclude: options.exclude?.split(','),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
41
|
+
|
|
42
|
+
if (options.output === 'json') {
|
|
43
|
+
const outputData = {
|
|
44
|
+
...results,
|
|
45
|
+
summary: {
|
|
46
|
+
...results.summary,
|
|
47
|
+
executionTime: parseFloat(elapsedTime),
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
if (options.outputFile) {
|
|
52
|
+
writeFileSync(options.outputFile, JSON.stringify(outputData, null, 2));
|
|
53
|
+
console.log(chalk.green(`✅ Results saved to ${options.outputFile}`));
|
|
54
|
+
} else {
|
|
55
|
+
console.log(JSON.stringify(outputData, null, 2));
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
// Console output
|
|
59
|
+
console.log(generateUnifiedSummary(results));
|
|
60
|
+
}
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error(chalk.red('❌ Analysis failed:'), error);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Individual tool commands for convenience
|
|
68
|
+
program
|
|
69
|
+
.command('patterns')
|
|
70
|
+
.description('Run pattern detection analysis')
|
|
71
|
+
.argument('<directory>', 'Directory to analyze')
|
|
72
|
+
.option('-s, --similarity <number>', 'Minimum similarity score (0-1)', '0.40')
|
|
73
|
+
.option('-l, --min-lines <number>', 'Minimum lines to consider', '5')
|
|
74
|
+
.option('--include <patterns>', 'File patterns to include (comma-separated)')
|
|
75
|
+
.option('--exclude <patterns>', 'File patterns to exclude (comma-separated)')
|
|
76
|
+
.option('-o, --output <format>', 'Output format: console, json', 'console')
|
|
77
|
+
.option('--output-file <path>', 'Output file path (for json)')
|
|
78
|
+
.action(async (directory, options) => {
|
|
79
|
+
console.log(chalk.blue('🔍 Analyzing patterns...\n'));
|
|
80
|
+
|
|
81
|
+
const startTime = Date.now();
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const { analyzePatterns, generateSummary } = await import('@aiready/pattern-detect');
|
|
85
|
+
|
|
86
|
+
const results = await analyzePatterns({
|
|
87
|
+
rootDir: directory,
|
|
88
|
+
minSimilarity: parseFloat(options.similarity),
|
|
89
|
+
minLines: parseInt(options.minLines),
|
|
90
|
+
include: options.include?.split(','),
|
|
91
|
+
exclude: options.exclude?.split(','),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
95
|
+
const summary = generateSummary(results);
|
|
96
|
+
|
|
97
|
+
if (options.output === 'json') {
|
|
98
|
+
const outputData = {
|
|
99
|
+
results,
|
|
100
|
+
summary: { ...summary, executionTime: parseFloat(elapsedTime) },
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
if (options.outputFile) {
|
|
104
|
+
writeFileSync(options.outputFile, JSON.stringify(outputData, null, 2));
|
|
105
|
+
console.log(chalk.green(`✅ Results saved to ${options.outputFile}`));
|
|
106
|
+
} else {
|
|
107
|
+
console.log(JSON.stringify(outputData, null, 2));
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
console.log(`Pattern Analysis Complete (${elapsedTime}s)`);
|
|
111
|
+
console.log(`Found ${summary.totalPatterns} duplicate patterns`);
|
|
112
|
+
console.log(`Total token cost: ${summary.totalTokenCost} tokens`);
|
|
113
|
+
}
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error(chalk.red('❌ Pattern analysis failed:'), error);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
program
|
|
121
|
+
.command('context')
|
|
122
|
+
.description('Run context window cost analysis')
|
|
123
|
+
.argument('<directory>', 'Directory to analyze')
|
|
124
|
+
.option('--max-depth <number>', 'Maximum acceptable import depth', '5')
|
|
125
|
+
.option('--max-context <number>', 'Maximum acceptable context budget (tokens)', '10000')
|
|
126
|
+
.option('--include <patterns>', 'File patterns to include (comma-separated)')
|
|
127
|
+
.option('--exclude <patterns>', 'File patterns to exclude (comma-separated)')
|
|
128
|
+
.option('-o, --output <format>', 'Output format: console, json', 'console')
|
|
129
|
+
.option('--output-file <path>', 'Output file path (for json)')
|
|
130
|
+
.action(async (directory, options) => {
|
|
131
|
+
console.log(chalk.blue('🧠 Analyzing context costs...\n'));
|
|
132
|
+
|
|
133
|
+
const startTime = Date.now();
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const { analyzeContext, generateSummary } = await import('@aiready/context-analyzer');
|
|
137
|
+
|
|
138
|
+
const results = await analyzeContext({
|
|
139
|
+
rootDir: directory,
|
|
140
|
+
maxDepth: parseInt(options.maxDepth),
|
|
141
|
+
maxContextBudget: parseInt(options.maxContext),
|
|
142
|
+
include: options.include?.split(','),
|
|
143
|
+
exclude: options.exclude?.split(','),
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
147
|
+
const summary = generateSummary(results);
|
|
148
|
+
|
|
149
|
+
if (options.output === 'json') {
|
|
150
|
+
const outputData = {
|
|
151
|
+
results,
|
|
152
|
+
summary: { ...summary, executionTime: parseFloat(elapsedTime) },
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
if (options.outputFile) {
|
|
156
|
+
writeFileSync(options.outputFile, JSON.stringify(outputData, null, 2));
|
|
157
|
+
console.log(chalk.green(`✅ Results saved to ${options.outputFile}`));
|
|
158
|
+
} else {
|
|
159
|
+
console.log(JSON.stringify(outputData, null, 2));
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
console.log(`Context Analysis Complete (${elapsedTime}s)`);
|
|
163
|
+
console.log(`Files analyzed: ${summary.totalFiles}`);
|
|
164
|
+
console.log(`Issues found: ${results.length}`);
|
|
165
|
+
console.log(`Average cohesion: ${(summary.avgCohesion * 100).toFixed(1)}%`);
|
|
166
|
+
console.log(`Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(1)}%`);
|
|
167
|
+
}
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error(chalk.red('❌ Context analysis failed:'), error);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
program.parse();
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { analyzePatterns } from '@aiready/pattern-detect';
|
|
2
|
+
import { analyzeContext } from '@aiready/context-analyzer';
|
|
3
|
+
import type { AnalysisResult, ScanOptions } from '@aiready/core';
|
|
4
|
+
import type { ContextAnalysisResult } from '@aiready/context-analyzer';
|
|
5
|
+
|
|
6
|
+
export interface UnifiedAnalysisOptions extends ScanOptions {
|
|
7
|
+
tools?: ('patterns' | 'context')[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface UnifiedAnalysisResult {
|
|
11
|
+
patterns?: AnalysisResult[];
|
|
12
|
+
context?: ContextAnalysisResult[];
|
|
13
|
+
summary: {
|
|
14
|
+
totalIssues: number;
|
|
15
|
+
toolsRun: string[];
|
|
16
|
+
executionTime: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function analyzeUnified(
|
|
21
|
+
options: UnifiedAnalysisOptions
|
|
22
|
+
): Promise<UnifiedAnalysisResult> {
|
|
23
|
+
const startTime = Date.now();
|
|
24
|
+
const tools = options.tools || ['patterns', 'context'];
|
|
25
|
+
const result: UnifiedAnalysisResult = {
|
|
26
|
+
summary: {
|
|
27
|
+
totalIssues: 0,
|
|
28
|
+
toolsRun: tools,
|
|
29
|
+
executionTime: 0,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Run pattern detection
|
|
34
|
+
if (tools.includes('patterns')) {
|
|
35
|
+
result.patterns = await analyzePatterns(options);
|
|
36
|
+
result.summary.totalIssues += result.patterns.length;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Run context analysis
|
|
40
|
+
if (tools.includes('context')) {
|
|
41
|
+
result.context = await analyzeContext(options);
|
|
42
|
+
result.summary.totalIssues += result.context?.length || 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
result.summary.executionTime = Date.now() - startTime;
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function generateUnifiedSummary(result: UnifiedAnalysisResult): string {
|
|
50
|
+
const { summary } = result;
|
|
51
|
+
let output = `🚀 AIReady Analysis Complete\n\n`;
|
|
52
|
+
output += `📊 Summary:\n`;
|
|
53
|
+
output += ` Tools run: ${summary.toolsRun.join(', ')}\n`;
|
|
54
|
+
output += ` Total issues found: ${summary.totalIssues}\n`;
|
|
55
|
+
output += ` Execution time: ${(summary.executionTime / 1000).toFixed(2)}s\n\n`;
|
|
56
|
+
|
|
57
|
+
if (result.patterns?.length) {
|
|
58
|
+
output += `🔍 Pattern Analysis: ${result.patterns.length} issues\n`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (result.context?.length) {
|
|
62
|
+
output += `🧠 Context Analysis: ${result.context.length} issues\n`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return output;
|
|
66
|
+
}
|