@aiready/cli 0.9.41 → 0.9.45
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/.aiready/aiready-report-20260228-003433.json +7939 -0
- package/.aiready/aiready-report-20260228-003613.json +771 -0
- package/.turbo/turbo-build.log +11 -11
- package/.turbo/turbo-lint.log +5 -0
- package/.turbo/turbo-test.log +4 -4
- package/README.md +22 -1
- package/dist/chunk-LLJMKNBI.mjs +243 -0
- package/dist/cli.js +424 -263
- package/dist/cli.mjs +373 -212
- package/dist/index.js +12 -6
- package/dist/index.mjs +1 -1
- package/package.json +12 -12
- package/src/cli.ts +18 -0
- package/src/commands/ai-signal-clarity.ts +2 -2
- package/src/commands/consistency.ts +1 -1
- package/src/commands/context.ts +1 -1
- package/src/commands/index.ts +1 -0
- package/src/commands/scan.ts +125 -7
- package/src/commands/upload.ts +87 -0
- package/src/index.ts +6 -0
package/dist/index.js
CHANGED
|
@@ -126,7 +126,8 @@ async function analyzeUnified(options) {
|
|
|
126
126
|
const report = await analyzeDocDrift({
|
|
127
127
|
rootDir: options.rootDir,
|
|
128
128
|
include: options.include,
|
|
129
|
-
exclude: options.exclude
|
|
129
|
+
exclude: options.exclude,
|
|
130
|
+
onProgress: options.onProgress
|
|
130
131
|
});
|
|
131
132
|
if (options.progressCallback) {
|
|
132
133
|
options.progressCallback({ tool: "doc-drift", data: report });
|
|
@@ -139,7 +140,8 @@ async function analyzeUnified(options) {
|
|
|
139
140
|
const report = await analyzeDeps({
|
|
140
141
|
rootDir: options.rootDir,
|
|
141
142
|
include: options.include,
|
|
142
|
-
exclude: options.exclude
|
|
143
|
+
exclude: options.exclude,
|
|
144
|
+
onProgress: options.onProgress
|
|
143
145
|
});
|
|
144
146
|
if (options.progressCallback) {
|
|
145
147
|
options.progressCallback({ tool: "deps-health", data: report });
|
|
@@ -152,7 +154,8 @@ async function analyzeUnified(options) {
|
|
|
152
154
|
const report = await analyzeAiSignalClarity({
|
|
153
155
|
rootDir: options.rootDir,
|
|
154
156
|
include: options.include,
|
|
155
|
-
exclude: options.exclude
|
|
157
|
+
exclude: options.exclude,
|
|
158
|
+
onProgress: options.onProgress
|
|
156
159
|
});
|
|
157
160
|
if (options.progressCallback) {
|
|
158
161
|
options.progressCallback({ tool: "aiSignalClarity", data: report });
|
|
@@ -168,7 +171,8 @@ async function analyzeUnified(options) {
|
|
|
168
171
|
const report = await analyzeAgentGrounding({
|
|
169
172
|
rootDir: options.rootDir,
|
|
170
173
|
include: options.include,
|
|
171
|
-
exclude: options.exclude
|
|
174
|
+
exclude: options.exclude,
|
|
175
|
+
onProgress: options.onProgress
|
|
172
176
|
});
|
|
173
177
|
if (options.progressCallback) {
|
|
174
178
|
options.progressCallback({ tool: "grounding", data: report });
|
|
@@ -181,7 +185,8 @@ async function analyzeUnified(options) {
|
|
|
181
185
|
const report = await analyzeTestability({
|
|
182
186
|
rootDir: options.rootDir,
|
|
183
187
|
include: options.include,
|
|
184
|
-
exclude: options.exclude
|
|
188
|
+
exclude: options.exclude,
|
|
189
|
+
onProgress: options.onProgress
|
|
185
190
|
});
|
|
186
191
|
if (options.progressCallback) {
|
|
187
192
|
options.progressCallback({ tool: "testability", data: report });
|
|
@@ -194,7 +199,8 @@ async function analyzeUnified(options) {
|
|
|
194
199
|
const report = await analyzeChangeAmplification({
|
|
195
200
|
rootDir: options.rootDir,
|
|
196
201
|
include: options.include,
|
|
197
|
-
exclude: options.exclude
|
|
202
|
+
exclude: options.exclude,
|
|
203
|
+
onProgress: options.onProgress
|
|
198
204
|
});
|
|
199
205
|
if (options.progressCallback) {
|
|
200
206
|
options.progressCallback({ tool: "changeAmplification", data: report });
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.45",
|
|
4
4
|
"description": "Unified CLI for AIReady analysis tools",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"chalk": "^5.3.0",
|
|
13
13
|
"commander": "^14.0.0",
|
|
14
|
-
"@aiready/
|
|
15
|
-
"@aiready/
|
|
16
|
-
"@aiready/
|
|
17
|
-
"@aiready/
|
|
18
|
-
"@aiready/
|
|
19
|
-
"@aiready/
|
|
20
|
-
"@aiready/
|
|
21
|
-
"@aiready/
|
|
22
|
-
"@aiready/
|
|
23
|
-
"@aiready/
|
|
24
|
-
"@aiready/
|
|
14
|
+
"@aiready/core": "0.9.37",
|
|
15
|
+
"@aiready/deps": "0.1.10",
|
|
16
|
+
"@aiready/doc-drift": "0.1.10",
|
|
17
|
+
"@aiready/agent-grounding": "0.1.10",
|
|
18
|
+
"@aiready/ai-signal-clarity": "0.1.10",
|
|
19
|
+
"@aiready/visualizer": "0.1.42",
|
|
20
|
+
"@aiready/consistency": "0.8.36",
|
|
21
|
+
"@aiready/context-analyzer": "0.9.40",
|
|
22
|
+
"@aiready/testability": "0.1.10",
|
|
23
|
+
"@aiready/pattern-detect": "0.11.36",
|
|
24
|
+
"@aiready/change-amplification": "0.1.10"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^24.0.0",
|
package/src/cli.ts
CHANGED
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
visualizeHelpText,
|
|
17
17
|
visualiseHelpText,
|
|
18
18
|
changeAmplificationAction,
|
|
19
|
+
uploadAction,
|
|
20
|
+
uploadHelpText,
|
|
19
21
|
} from './commands';
|
|
20
22
|
|
|
21
23
|
const getDirname = () => {
|
|
@@ -111,6 +113,9 @@ program
|
|
|
111
113
|
'Fail on issues: critical, major, any',
|
|
112
114
|
'critical'
|
|
113
115
|
)
|
|
116
|
+
.option('--api-key <key>', 'Platform API key for automatic upload')
|
|
117
|
+
.option('--upload', 'Automatically upload results to the platform')
|
|
118
|
+
.option('--server <url>', 'Custom platform URL')
|
|
114
119
|
.addHelpText('after', scanHelpText)
|
|
115
120
|
.action(async (directory, options) => {
|
|
116
121
|
await scanAction(directory, options);
|
|
@@ -274,4 +279,17 @@ program
|
|
|
274
279
|
await changeAmplificationAction(directory, options);
|
|
275
280
|
});
|
|
276
281
|
|
|
282
|
+
// Upload command - Upload report JSON to platform
|
|
283
|
+
program
|
|
284
|
+
.command('upload')
|
|
285
|
+
.description('Upload an AIReady report JSON to the platform')
|
|
286
|
+
.argument('<file>', 'Report JSON file to upload')
|
|
287
|
+
.option('--api-key <key>', 'Platform API key')
|
|
288
|
+
.option('--repo-id <id>', 'Platform repository ID (optional)')
|
|
289
|
+
.option('--server <url>', 'Custom platform URL')
|
|
290
|
+
.addHelpText('after', uploadHelpText)
|
|
291
|
+
.action(async (file, options) => {
|
|
292
|
+
await uploadAction(file, options);
|
|
293
|
+
});
|
|
294
|
+
|
|
277
295
|
program.parse();
|
|
@@ -10,7 +10,7 @@ export async function aiSignalClarityAction(
|
|
|
10
10
|
directory: string,
|
|
11
11
|
options: any
|
|
12
12
|
): Promise<ToolScoringOutput | undefined> {
|
|
13
|
-
const { analyzeAiSignalClarity,
|
|
13
|
+
const { analyzeAiSignalClarity, calculateAiSignalClarityScore } =
|
|
14
14
|
await import('@aiready/ai-signal-clarity');
|
|
15
15
|
|
|
16
16
|
const config = await loadConfig(directory);
|
|
@@ -25,7 +25,7 @@ export async function aiSignalClarityAction(
|
|
|
25
25
|
exclude: options.exclude,
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
const scoring =
|
|
28
|
+
const scoring = calculateAiSignalClarityScore(report);
|
|
29
29
|
|
|
30
30
|
if (options.output === 'json') {
|
|
31
31
|
return scoring;
|
package/src/commands/context.ts
CHANGED
package/src/commands/index.ts
CHANGED
|
@@ -15,3 +15,4 @@ export { aiSignalClarityAction } from './ai-signal-clarity';
|
|
|
15
15
|
export { agentGroundingAction } from './agent-grounding';
|
|
16
16
|
export { testabilityAction } from './testability';
|
|
17
17
|
export { changeAmplificationAction } from './change-amplification';
|
|
18
|
+
export { uploadAction, uploadHelpText } from './upload';
|
package/src/commands/scan.ts
CHANGED
|
@@ -15,9 +15,13 @@ import {
|
|
|
15
15
|
calculateOverallScore,
|
|
16
16
|
formatScore,
|
|
17
17
|
formatToolScore,
|
|
18
|
+
calculateTokenBudget,
|
|
19
|
+
estimateCostFromBudget,
|
|
20
|
+
getModelPreset,
|
|
18
21
|
getRating,
|
|
19
22
|
getRatingDisplay,
|
|
20
23
|
parseWeightString,
|
|
24
|
+
getRepoMetadata,
|
|
21
25
|
type ToolScoringOutput,
|
|
22
26
|
} from '@aiready/core';
|
|
23
27
|
import { analyzeUnified } from '../index';
|
|
@@ -26,6 +30,7 @@ import {
|
|
|
26
30
|
warnIfGraphCapExceeded,
|
|
27
31
|
truncateArray,
|
|
28
32
|
} from '../utils/helpers';
|
|
33
|
+
import { uploadAction } from './upload';
|
|
29
34
|
|
|
30
35
|
interface ScanOptions {
|
|
31
36
|
tools?: string;
|
|
@@ -41,6 +46,10 @@ interface ScanOptions {
|
|
|
41
46
|
threshold?: string;
|
|
42
47
|
ci?: boolean;
|
|
43
48
|
failOn?: string;
|
|
49
|
+
model?: string;
|
|
50
|
+
apiKey?: string;
|
|
51
|
+
upload?: boolean;
|
|
52
|
+
server?: string;
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
export async function scanAction(directory: string, options: ScanOptions) {
|
|
@@ -50,6 +59,9 @@ export async function scanAction(directory: string, options: ScanOptions) {
|
|
|
50
59
|
// Resolve directory to absolute path to ensure .aiready/ is created in the right location
|
|
51
60
|
const resolvedDir = resolvePath(process.cwd(), directory || '.');
|
|
52
61
|
|
|
62
|
+
// Extract repo metadata for linkage
|
|
63
|
+
const repoMetadata = getRepoMetadata(resolvedDir);
|
|
64
|
+
|
|
53
65
|
try {
|
|
54
66
|
// Define defaults
|
|
55
67
|
const defaults = {
|
|
@@ -74,11 +86,11 @@ export async function scanAction(directory: string, options: ScanOptions) {
|
|
|
74
86
|
|
|
75
87
|
let profileTools = options.tools
|
|
76
88
|
? options.tools.split(',').map((t: string) => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
const tool = t.trim();
|
|
90
|
+
if (tool === 'hallucination' || tool === 'hallucination-risk')
|
|
91
|
+
return 'aiSignalClarity';
|
|
92
|
+
return tool;
|
|
93
|
+
})
|
|
82
94
|
: undefined;
|
|
83
95
|
if (options.profile) {
|
|
84
96
|
switch (options.profile.toLowerCase()) {
|
|
@@ -424,9 +436,21 @@ export async function scanAction(directory: string, options: ScanOptions) {
|
|
|
424
436
|
const results = await analyzeUnified({
|
|
425
437
|
...finalOptions,
|
|
426
438
|
progressCallback,
|
|
439
|
+
onProgress: (processed: number, total: number, message: string) => {
|
|
440
|
+
// Clear line and print progress
|
|
441
|
+
process.stdout.write(
|
|
442
|
+
`\r\x1b[K [${processed}/${total}] ${message}...`
|
|
443
|
+
);
|
|
444
|
+
if (processed === total) {
|
|
445
|
+
process.stdout.write('\n'); // Move to next line when done
|
|
446
|
+
}
|
|
447
|
+
},
|
|
427
448
|
suppressToolConfig: true,
|
|
428
449
|
});
|
|
429
450
|
|
|
451
|
+
// Determine if we need to print a trailing newline because the last tool didn't finish normally or had 0 files
|
|
452
|
+
// But progressCallback already outputs `\n--- TOOL RESULTS ---` so it's fine.
|
|
453
|
+
|
|
430
454
|
// Summarize tools and results to console
|
|
431
455
|
console.log(chalk.cyan('\n=== AIReady Run Summary ==='));
|
|
432
456
|
console.log(
|
|
@@ -477,6 +501,18 @@ export async function scanAction(directory: string, options: ScanOptions) {
|
|
|
477
501
|
results.duplicates,
|
|
478
502
|
results.patterns?.length || 0
|
|
479
503
|
);
|
|
504
|
+
|
|
505
|
+
// Calculate token budget for patterns (waste = duplication)
|
|
506
|
+
const wastedTokens = results.duplicates.reduce((sum: number, d: any) => sum + (d.tokenCost || 0), 0);
|
|
507
|
+
patternScore.tokenBudget = calculateTokenBudget({
|
|
508
|
+
totalContextTokens: wastedTokens * 2, // Estimated context
|
|
509
|
+
wastedTokens: {
|
|
510
|
+
duplication: wastedTokens,
|
|
511
|
+
fragmentation: 0,
|
|
512
|
+
chattiness: 0
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
|
|
480
516
|
toolScores.set('pattern-detect', patternScore);
|
|
481
517
|
} catch (err) {
|
|
482
518
|
void err;
|
|
@@ -490,6 +526,17 @@ export async function scanAction(directory: string, options: ScanOptions) {
|
|
|
490
526
|
try {
|
|
491
527
|
const ctxSummary = genContextSummary(results.context);
|
|
492
528
|
const contextScore = calculateContextScore(ctxSummary);
|
|
529
|
+
|
|
530
|
+
// Calculate token budget for context (waste = fragmentation + depth overhead)
|
|
531
|
+
contextScore.tokenBudget = calculateTokenBudget({
|
|
532
|
+
totalContextTokens: ctxSummary.totalTokens,
|
|
533
|
+
wastedTokens: {
|
|
534
|
+
duplication: 0,
|
|
535
|
+
fragmentation: ctxSummary.totalPotentialSavings || 0,
|
|
536
|
+
chattiness: 0
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
|
|
493
540
|
toolScores.set('context-analyzer', contextScore);
|
|
494
541
|
} catch (err) {
|
|
495
542
|
void err;
|
|
@@ -676,6 +723,49 @@ export async function scanAction(directory: string, options: ScanOptions) {
|
|
|
676
723
|
}
|
|
677
724
|
}
|
|
678
725
|
|
|
726
|
+
// Unified Token Budget Analysis
|
|
727
|
+
const totalWastedDuplication = Array.from(toolScores.values())
|
|
728
|
+
.reduce((sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.duplication || 0), 0);
|
|
729
|
+
const totalWastedFragmentation = Array.from(toolScores.values())
|
|
730
|
+
.reduce((sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.fragmentation || 0), 0);
|
|
731
|
+
const totalContext = Math.max(...Array.from(toolScores.values()).map(s => s.tokenBudget?.totalContextTokens || 0));
|
|
732
|
+
|
|
733
|
+
if (totalContext > 0) {
|
|
734
|
+
const unifiedBudget = calculateTokenBudget({
|
|
735
|
+
totalContextTokens: totalContext,
|
|
736
|
+
wastedTokens: {
|
|
737
|
+
duplication: totalWastedDuplication,
|
|
738
|
+
fragmentation: totalWastedFragmentation,
|
|
739
|
+
chattiness: 0
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
const targetModel = options.model || 'claude-4.6';
|
|
744
|
+
const modelPreset = getModelPreset(targetModel);
|
|
745
|
+
const costEstimate = estimateCostFromBudget(unifiedBudget, modelPreset);
|
|
746
|
+
|
|
747
|
+
const barWidth = 20;
|
|
748
|
+
const filled = Math.round(unifiedBudget.efficiencyRatio * barWidth);
|
|
749
|
+
const bar = chalk.green('█'.repeat(filled)) + chalk.dim('░'.repeat(barWidth - filled));
|
|
750
|
+
|
|
751
|
+
console.log(chalk.bold('\n📊 AI Token Budget Analysis (v0.13)'));
|
|
752
|
+
console.log(` Efficiency: [${bar}] ${(unifiedBudget.efficiencyRatio * 100).toFixed(0)}%`);
|
|
753
|
+
console.log(` Total Context: ${chalk.bold(unifiedBudget.totalContextTokens.toLocaleString())} tokens`);
|
|
754
|
+
console.log(` Wasted Tokens: ${chalk.red(unifiedBudget.wastedTokens.total.toLocaleString())} (${((unifiedBudget.wastedTokens.total / unifiedBudget.totalContextTokens) * 100).toFixed(1)}%)`);
|
|
755
|
+
console.log(` Waste Breakdown:`);
|
|
756
|
+
console.log(` • Duplication: ${unifiedBudget.wastedTokens.bySource.duplication.toLocaleString()} tokens`);
|
|
757
|
+
console.log(` • Fragmentation: ${unifiedBudget.wastedTokens.bySource.fragmentation.toLocaleString()} tokens`);
|
|
758
|
+
console.log(` Potential Savings: ${chalk.green(unifiedBudget.potentialRetrievableTokens.toLocaleString())} tokens retrievable`);
|
|
759
|
+
console.log(`\n Est. Monthly Cost (${modelPreset.name}): ${chalk.bold('$' + costEstimate.total)} [range: $${costEstimate.range[0]}-$${costEstimate.range[1]}]`);
|
|
760
|
+
|
|
761
|
+
// Attach unified budget to report for JSON persistence
|
|
762
|
+
(scoringResult as any).tokenBudget = unifiedBudget;
|
|
763
|
+
(scoringResult as any).costEstimate = {
|
|
764
|
+
model: modelPreset.name,
|
|
765
|
+
...costEstimate
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
|
|
679
769
|
// Show concise breakdown; detailed breakdown only if config requests it
|
|
680
770
|
if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
|
|
681
771
|
console.log(chalk.bold('\nTool breakdown:'));
|
|
@@ -711,13 +801,26 @@ export async function scanAction(directory: string, options: ScanOptions) {
|
|
|
711
801
|
defaultFilename,
|
|
712
802
|
resolvedDir
|
|
713
803
|
);
|
|
714
|
-
const outputData = {
|
|
804
|
+
const outputData = {
|
|
805
|
+
...results,
|
|
806
|
+
scoring: scoringResult,
|
|
807
|
+
repository: repoMetadata,
|
|
808
|
+
};
|
|
715
809
|
handleJSONOutput(
|
|
716
810
|
outputData,
|
|
717
811
|
outputPath,
|
|
718
812
|
`✅ Report saved to ${outputPath}`
|
|
719
813
|
);
|
|
720
814
|
|
|
815
|
+
// Automatic Upload
|
|
816
|
+
if (options.upload) {
|
|
817
|
+
console.log(chalk.blue('\n📤 Automatic upload triggered...'));
|
|
818
|
+
await uploadAction(outputPath, {
|
|
819
|
+
apiKey: options.apiKey,
|
|
820
|
+
server: options.server,
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
|
|
721
824
|
// Warn if graph caps may be exceeded
|
|
722
825
|
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
723
826
|
} else {
|
|
@@ -729,11 +832,24 @@ export async function scanAction(directory: string, options: ScanOptions) {
|
|
|
729
832
|
defaultFilename,
|
|
730
833
|
resolvedDir
|
|
731
834
|
);
|
|
732
|
-
const outputData = {
|
|
835
|
+
const outputData = {
|
|
836
|
+
...results,
|
|
837
|
+
scoring: scoringResult,
|
|
838
|
+
repository: repoMetadata,
|
|
839
|
+
};
|
|
733
840
|
|
|
734
841
|
try {
|
|
735
842
|
writeFileSync(outputPath, JSON.stringify(outputData, null, 2));
|
|
736
843
|
console.log(chalk.dim(`✅ Report auto-persisted to ${outputPath}`));
|
|
844
|
+
|
|
845
|
+
// Automatic Upload (from auto-persistent report)
|
|
846
|
+
if (options.upload) {
|
|
847
|
+
console.log(chalk.blue('\n📤 Automatic upload triggered...'));
|
|
848
|
+
await uploadAction(outputPath, {
|
|
849
|
+
apiKey: options.apiKey,
|
|
850
|
+
server: options.server,
|
|
851
|
+
});
|
|
852
|
+
}
|
|
737
853
|
// Warn if graph caps may be exceeded
|
|
738
854
|
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
739
855
|
} catch (err) {
|
|
@@ -885,6 +1001,8 @@ EXAMPLES:
|
|
|
885
1001
|
$ aiready scan --ci --threshold 70 # GitHub Actions gatekeeper
|
|
886
1002
|
$ aiready scan --ci --fail-on major # Fail on major+ issues
|
|
887
1003
|
$ aiready scan --output json --output-file report.json
|
|
1004
|
+
$ aiready scan --upload --api-key ar_... # Automatic platform upload
|
|
1005
|
+
$ aiready scan --upload --server custom-url.com # Upload to custom platform
|
|
888
1006
|
|
|
889
1007
|
PROFILES:
|
|
890
1008
|
agentic: aiSignalClarity, grounding, testability
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path, { resolve as resolvePath } from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import {
|
|
5
|
+
handleCLIError,
|
|
6
|
+
} from '@aiready/core';
|
|
7
|
+
|
|
8
|
+
interface UploadOptions {
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
repoId?: string;
|
|
11
|
+
server?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function uploadAction(file: string, options: UploadOptions) {
|
|
15
|
+
const startTime = Date.now();
|
|
16
|
+
const filePath = resolvePath(process.cwd(), file);
|
|
17
|
+
const serverUrl = options.server || process.env.AIREADY_SERVER || 'https://dev.platform.getaiready.dev';
|
|
18
|
+
const apiKey = options.apiKey || process.env.AIREADY_API_KEY;
|
|
19
|
+
|
|
20
|
+
if (!apiKey) {
|
|
21
|
+
console.error(chalk.red('❌ API Key is required for upload.'));
|
|
22
|
+
console.log(chalk.dim(' Set AIREADY_API_KEY environment variable or use --api-key flag.'));
|
|
23
|
+
console.log(chalk.dim(' Get an API key from https://getaiready.dev/dashboard'));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!fs.existsSync(filePath)) {
|
|
28
|
+
console.error(chalk.red(`❌ File not found: ${filePath}`));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
console.log(chalk.blue(`🚀 Uploading report to ${serverUrl}...`));
|
|
34
|
+
|
|
35
|
+
// Read the report file
|
|
36
|
+
const reportData = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
37
|
+
|
|
38
|
+
// Prepare upload payload
|
|
39
|
+
// Note: repoId is optional if the metadata contains it, but for now we'll require it or infer from metadata
|
|
40
|
+
const repoId = options.repoId || reportData.repository?.repoId;
|
|
41
|
+
|
|
42
|
+
const res = await fetch(`${serverUrl}/api/analysis/upload`, {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: {
|
|
45
|
+
'Content-Type': 'application/json',
|
|
46
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
47
|
+
},
|
|
48
|
+
body: JSON.stringify({
|
|
49
|
+
data: reportData,
|
|
50
|
+
repoId, // Might be null, server will handle mapping
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const result = (await res.json()) as any;
|
|
55
|
+
|
|
56
|
+
if (!res.ok) {
|
|
57
|
+
console.error(chalk.red(`❌ Upload failed: ${result.error || res.statusText}`));
|
|
58
|
+
if (res.status === 401) {
|
|
59
|
+
console.log(chalk.dim(' Hint: Your API key may be invalid or expired.'));
|
|
60
|
+
}
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
65
|
+
console.log(chalk.green(`\n✅ Upload successful! (${duration}s)`));
|
|
66
|
+
console.log(chalk.cyan(` View results: ${serverUrl}/dashboard`));
|
|
67
|
+
|
|
68
|
+
if (result.analysis) {
|
|
69
|
+
console.log(chalk.dim(` Analysis ID: ${result.analysis.id}`));
|
|
70
|
+
console.log(chalk.dim(` Score: ${result.analysis.aiScore}/100`));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
} catch (error) {
|
|
74
|
+
handleCLIError(error, 'Upload');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const uploadHelpText = `
|
|
79
|
+
EXAMPLES:
|
|
80
|
+
$ aiready upload report.json --api-key ar_...
|
|
81
|
+
$ aiready upload .aiready/latest.json
|
|
82
|
+
$ AIREADY_API_KEY=ar_... aiready upload report.json
|
|
83
|
+
|
|
84
|
+
ENVIRONMENT VARIABLES:
|
|
85
|
+
AIREADY_API_KEY Your platform API key
|
|
86
|
+
AIREADY_SERVER Custom platform URL (default: https://dev.platform.getaiready.dev)
|
|
87
|
+
`;
|
package/src/index.ts
CHANGED
|
@@ -169,6 +169,7 @@ export async function analyzeUnified(
|
|
|
169
169
|
rootDir: options.rootDir,
|
|
170
170
|
include: options.include,
|
|
171
171
|
exclude: options.exclude,
|
|
172
|
+
onProgress: options.onProgress,
|
|
172
173
|
});
|
|
173
174
|
if (options.progressCallback) {
|
|
174
175
|
options.progressCallback({ tool: 'doc-drift', data: report });
|
|
@@ -184,6 +185,7 @@ export async function analyzeUnified(
|
|
|
184
185
|
rootDir: options.rootDir,
|
|
185
186
|
include: options.include,
|
|
186
187
|
exclude: options.exclude,
|
|
188
|
+
onProgress: options.onProgress,
|
|
187
189
|
});
|
|
188
190
|
if (options.progressCallback) {
|
|
189
191
|
options.progressCallback({ tool: 'deps-health', data: report });
|
|
@@ -200,6 +202,7 @@ export async function analyzeUnified(
|
|
|
200
202
|
rootDir: options.rootDir,
|
|
201
203
|
include: options.include,
|
|
202
204
|
exclude: options.exclude,
|
|
205
|
+
onProgress: options.onProgress,
|
|
203
206
|
});
|
|
204
207
|
if (options.progressCallback) {
|
|
205
208
|
options.progressCallback({ tool: 'aiSignalClarity', data: report });
|
|
@@ -219,6 +222,7 @@ export async function analyzeUnified(
|
|
|
219
222
|
rootDir: options.rootDir,
|
|
220
223
|
include: options.include,
|
|
221
224
|
exclude: options.exclude,
|
|
225
|
+
onProgress: options.onProgress,
|
|
222
226
|
});
|
|
223
227
|
if (options.progressCallback) {
|
|
224
228
|
options.progressCallback({ tool: 'grounding', data: report });
|
|
@@ -234,6 +238,7 @@ export async function analyzeUnified(
|
|
|
234
238
|
rootDir: options.rootDir,
|
|
235
239
|
include: options.include,
|
|
236
240
|
exclude: options.exclude,
|
|
241
|
+
onProgress: options.onProgress,
|
|
237
242
|
});
|
|
238
243
|
if (options.progressCallback) {
|
|
239
244
|
options.progressCallback({ tool: 'testability', data: report });
|
|
@@ -250,6 +255,7 @@ export async function analyzeUnified(
|
|
|
250
255
|
rootDir: options.rootDir,
|
|
251
256
|
include: options.include,
|
|
252
257
|
exclude: options.exclude,
|
|
258
|
+
onProgress: options.onProgress,
|
|
253
259
|
});
|
|
254
260
|
if (options.progressCallback) {
|
|
255
261
|
options.progressCallback({ tool: 'changeAmplification', data: report });
|