infra-cost 0.2.0 → 0.2.2
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/bin/index.js +1 -1
- package/dist/demo/{test-enhanced-ui.js → test-enhanced-ui.cjs} +126 -91
- package/dist/demo/test-enhanced-ui.cjs.map +1 -0
- package/dist/demo/{test-multi-cloud-dashboard.js → test-multi-cloud-dashboard.cjs} +176 -160
- package/dist/demo/test-multi-cloud-dashboard.cjs.map +1 -0
- package/dist/{index.js → index.cjs} +4495 -4523
- package/dist/index.cjs.map +1 -0
- package/package.json +1 -1
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
9
24
|
|
|
10
25
|
// src/visualization/multi-cloud-dashboard.ts
|
|
11
|
-
|
|
26
|
+
var import_chalk4 = __toESM(require("chalk"), 1);
|
|
12
27
|
|
|
13
28
|
// src/types/providers.ts
|
|
14
29
|
var CloudProviderAdapter = class {
|
|
@@ -87,23 +102,23 @@ var ResourceType = /* @__PURE__ */ ((ResourceType2) => {
|
|
|
87
102
|
})(ResourceType || {});
|
|
88
103
|
|
|
89
104
|
// src/providers/aws.ts
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
var import_client_cost_explorer = require("@aws-sdk/client-cost-explorer");
|
|
106
|
+
var import_client_iam = require("@aws-sdk/client-iam");
|
|
107
|
+
var import_client_sts = require("@aws-sdk/client-sts");
|
|
108
|
+
var import_client_ec2 = require("@aws-sdk/client-ec2");
|
|
109
|
+
var import_client_s3 = require("@aws-sdk/client-s3");
|
|
110
|
+
var import_client_rds = require("@aws-sdk/client-rds");
|
|
111
|
+
var import_client_lambda = require("@aws-sdk/client-lambda");
|
|
112
|
+
var import_client_budgets = require("@aws-sdk/client-budgets");
|
|
113
|
+
var import_dayjs = __toESM(require("dayjs"), 1);
|
|
99
114
|
|
|
100
115
|
// src/logger.ts
|
|
101
|
-
|
|
102
|
-
|
|
116
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
117
|
+
var import_ora = __toESM(require("ora"), 1);
|
|
103
118
|
var spinner;
|
|
104
119
|
function showSpinner(text) {
|
|
105
120
|
if (!spinner) {
|
|
106
|
-
spinner =
|
|
121
|
+
spinner = (0, import_ora.default)({ text: "" }).start();
|
|
107
122
|
}
|
|
108
123
|
spinner.text = text;
|
|
109
124
|
}
|
|
@@ -409,11 +424,11 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
409
424
|
}
|
|
410
425
|
async validateCredentials() {
|
|
411
426
|
try {
|
|
412
|
-
const sts = new STSClient({
|
|
427
|
+
const sts = new import_client_sts.STSClient({
|
|
413
428
|
credentials: this.getCredentials(),
|
|
414
429
|
region: this.getRegion()
|
|
415
430
|
});
|
|
416
|
-
await sts.send(new GetCallerIdentityCommand({}));
|
|
431
|
+
await sts.send(new import_client_sts.GetCallerIdentityCommand({}));
|
|
417
432
|
return true;
|
|
418
433
|
} catch {
|
|
419
434
|
return false;
|
|
@@ -423,11 +438,11 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
423
438
|
var _a;
|
|
424
439
|
showSpinner("Getting AWS account information");
|
|
425
440
|
try {
|
|
426
|
-
const iam = new IAMClient({
|
|
441
|
+
const iam = new import_client_iam.IAMClient({
|
|
427
442
|
credentials: this.getCredentials(),
|
|
428
443
|
region: this.getRegion()
|
|
429
444
|
});
|
|
430
|
-
const accountAliases = await iam.send(new ListAccountAliasesCommand({}));
|
|
445
|
+
const accountAliases = await iam.send(new import_client_iam.ListAccountAliasesCommand({}));
|
|
431
446
|
const foundAlias = (_a = accountAliases == null ? void 0 : accountAliases.AccountAliases) == null ? void 0 : _a[0];
|
|
432
447
|
if (foundAlias) {
|
|
433
448
|
return {
|
|
@@ -436,11 +451,11 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
436
451
|
provider: "aws" /* AWS */
|
|
437
452
|
};
|
|
438
453
|
}
|
|
439
|
-
const sts = new STSClient({
|
|
454
|
+
const sts = new import_client_sts.STSClient({
|
|
440
455
|
credentials: this.getCredentials(),
|
|
441
456
|
region: this.getRegion()
|
|
442
457
|
});
|
|
443
|
-
const accountInfo = await sts.send(new GetCallerIdentityCommand({}));
|
|
458
|
+
const accountInfo = await sts.send(new import_client_sts.GetCallerIdentityCommand({}));
|
|
444
459
|
return {
|
|
445
460
|
id: accountInfo.Account || "unknown",
|
|
446
461
|
name: accountInfo.Account || "unknown",
|
|
@@ -454,13 +469,13 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
454
469
|
var _a, _b, _c, _d;
|
|
455
470
|
showSpinner("Getting AWS pricing data");
|
|
456
471
|
try {
|
|
457
|
-
const costExplorer = new CostExplorerClient({
|
|
472
|
+
const costExplorer = new import_client_cost_explorer.CostExplorerClient({
|
|
458
473
|
credentials: this.getCredentials(),
|
|
459
474
|
region: this.getRegion()
|
|
460
475
|
});
|
|
461
|
-
const endDate =
|
|
476
|
+
const endDate = (0, import_dayjs.default)().subtract(1, "day");
|
|
462
477
|
const startDate = endDate.subtract(65, "day");
|
|
463
|
-
const pricingData = await costExplorer.send(new GetCostAndUsageCommand({
|
|
478
|
+
const pricingData = await costExplorer.send(new import_client_cost_explorer.GetCostAndUsageCommand({
|
|
464
479
|
TimePeriod: {
|
|
465
480
|
Start: startDate.format("YYYY-MM-DD"),
|
|
466
481
|
End: endDate.format("YYYY-MM-DD")
|
|
@@ -577,11 +592,11 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
577
592
|
async discoverEC2Instances(region, includeCosts) {
|
|
578
593
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
579
594
|
try {
|
|
580
|
-
const ec2Client = new EC2Client({
|
|
595
|
+
const ec2Client = new import_client_ec2.EC2Client({
|
|
581
596
|
credentials: this.getCredentials(),
|
|
582
597
|
region
|
|
583
598
|
});
|
|
584
|
-
const command = new DescribeInstancesCommand({});
|
|
599
|
+
const command = new import_client_ec2.DescribeInstancesCommand({});
|
|
585
600
|
const result = await ec2Client.send(command);
|
|
586
601
|
const instances = [];
|
|
587
602
|
for (const reservation of result.Reservations || []) {
|
|
@@ -632,11 +647,11 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
632
647
|
}
|
|
633
648
|
async discoverS3Buckets(region, includeCosts) {
|
|
634
649
|
try {
|
|
635
|
-
const s3Client = new S3Client({
|
|
650
|
+
const s3Client = new import_client_s3.S3Client({
|
|
636
651
|
credentials: this.getCredentials(),
|
|
637
652
|
region
|
|
638
653
|
});
|
|
639
|
-
const command = new ListBucketsCommand({});
|
|
654
|
+
const command = new import_client_s3.ListBucketsCommand({});
|
|
640
655
|
const result = await s3Client.send(command);
|
|
641
656
|
const buckets = [];
|
|
642
657
|
for (const bucket of result.Buckets || []) {
|
|
@@ -668,11 +683,11 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
668
683
|
async discoverEBSVolumes(region, includeCosts) {
|
|
669
684
|
var _a, _b, _c, _d;
|
|
670
685
|
try {
|
|
671
|
-
const ec2Client = new EC2Client({
|
|
686
|
+
const ec2Client = new import_client_ec2.EC2Client({
|
|
672
687
|
credentials: this.getCredentials(),
|
|
673
688
|
region
|
|
674
689
|
});
|
|
675
|
-
const command = new DescribeVolumesCommand({});
|
|
690
|
+
const command = new import_client_ec2.DescribeVolumesCommand({});
|
|
676
691
|
const result = await ec2Client.send(command);
|
|
677
692
|
const volumes = [];
|
|
678
693
|
for (const volume of result.Volumes || []) {
|
|
@@ -717,11 +732,11 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
717
732
|
async discoverRDSInstances(region, includeCosts) {
|
|
718
733
|
var _a, _b;
|
|
719
734
|
try {
|
|
720
|
-
const rdsClient = new RDSClient({
|
|
735
|
+
const rdsClient = new import_client_rds.RDSClient({
|
|
721
736
|
credentials: this.getCredentials(),
|
|
722
737
|
region
|
|
723
738
|
});
|
|
724
|
-
const command = new DescribeDBInstancesCommand({});
|
|
739
|
+
const command = new import_client_rds.DescribeDBInstancesCommand({});
|
|
725
740
|
const result = await rdsClient.send(command);
|
|
726
741
|
const instances = [];
|
|
727
742
|
for (const dbInstance of result.DBInstances || []) {
|
|
@@ -761,11 +776,11 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
761
776
|
}
|
|
762
777
|
async discoverLambdaFunctions(region, includeCosts) {
|
|
763
778
|
try {
|
|
764
|
-
const lambdaClient = new LambdaClient({
|
|
779
|
+
const lambdaClient = new import_client_lambda.LambdaClient({
|
|
765
780
|
credentials: this.getCredentials(),
|
|
766
781
|
region
|
|
767
782
|
});
|
|
768
|
-
const command = new ListFunctionsCommand({});
|
|
783
|
+
const command = new import_client_lambda.ListFunctionsCommand({});
|
|
769
784
|
const result = await lambdaClient.send(command);
|
|
770
785
|
const functions = [];
|
|
771
786
|
for (const func of result.Functions || []) {
|
|
@@ -802,11 +817,11 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
802
817
|
async discoverVPCs(region, includeCosts) {
|
|
803
818
|
var _a, _b, _c;
|
|
804
819
|
try {
|
|
805
|
-
const ec2Client = new EC2Client({
|
|
820
|
+
const ec2Client = new import_client_ec2.EC2Client({
|
|
806
821
|
credentials: this.getCredentials(),
|
|
807
822
|
region
|
|
808
823
|
});
|
|
809
|
-
const command = new DescribeVpcsCommand({});
|
|
824
|
+
const command = new import_client_ec2.DescribeVpcsCommand({});
|
|
810
825
|
const result = await ec2Client.send(command);
|
|
811
826
|
const vpcs = [];
|
|
812
827
|
for (const vpc of result.Vpcs || []) {
|
|
@@ -844,11 +859,11 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
844
859
|
async discoverSubnets(region, includeCosts) {
|
|
845
860
|
var _a, _b, _c;
|
|
846
861
|
try {
|
|
847
|
-
const ec2Client = new EC2Client({
|
|
862
|
+
const ec2Client = new import_client_ec2.EC2Client({
|
|
848
863
|
credentials: this.getCredentials(),
|
|
849
864
|
region
|
|
850
865
|
});
|
|
851
|
-
const command = new DescribeSubnetsCommand({});
|
|
866
|
+
const command = new import_client_ec2.DescribeSubnetsCommand({});
|
|
852
867
|
const result = await ec2Client.send(command);
|
|
853
868
|
const subnets = [];
|
|
854
869
|
for (const subnet of result.Subnets || []) {
|
|
@@ -907,20 +922,20 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
907
922
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
908
923
|
showSpinner("Getting AWS budgets");
|
|
909
924
|
try {
|
|
910
|
-
const budgetsClient = new BudgetsClient({
|
|
925
|
+
const budgetsClient = new import_client_budgets.BudgetsClient({
|
|
911
926
|
credentials: this.getCredentials(),
|
|
912
927
|
region: this.getRegion()
|
|
913
928
|
});
|
|
914
|
-
const sts = new STSClient({
|
|
929
|
+
const sts = new import_client_sts.STSClient({
|
|
915
930
|
credentials: this.getCredentials(),
|
|
916
931
|
region: this.getRegion()
|
|
917
932
|
});
|
|
918
|
-
const accountInfo = await sts.send(new GetCallerIdentityCommand({}));
|
|
933
|
+
const accountInfo = await sts.send(new import_client_sts.GetCallerIdentityCommand({}));
|
|
919
934
|
const accountId = accountInfo.Account;
|
|
920
935
|
if (!accountId) {
|
|
921
936
|
throw new Error("Unable to determine AWS account ID");
|
|
922
937
|
}
|
|
923
|
-
const budgetsResponse = await budgetsClient.send(new DescribeBudgetsCommand({
|
|
938
|
+
const budgetsResponse = await budgetsClient.send(new import_client_budgets.DescribeBudgetsCommand({
|
|
924
939
|
AccountId: accountId
|
|
925
940
|
}));
|
|
926
941
|
const budgets = [];
|
|
@@ -998,13 +1013,13 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
998
1013
|
var _a, _b, _c, _d, _e;
|
|
999
1014
|
showSpinner("Analyzing cost trends");
|
|
1000
1015
|
try {
|
|
1001
|
-
const costExplorer = new CostExplorerClient({
|
|
1016
|
+
const costExplorer = new import_client_cost_explorer.CostExplorerClient({
|
|
1002
1017
|
credentials: this.getCredentials(),
|
|
1003
1018
|
region: this.getRegion()
|
|
1004
1019
|
});
|
|
1005
|
-
const endDate =
|
|
1020
|
+
const endDate = (0, import_dayjs.default)();
|
|
1006
1021
|
const startDate = endDate.subtract(months, "month");
|
|
1007
|
-
const monthlyData = await costExplorer.send(new GetCostAndUsageCommand({
|
|
1022
|
+
const monthlyData = await costExplorer.send(new import_client_cost_explorer.GetCostAndUsageCommand({
|
|
1008
1023
|
TimePeriod: {
|
|
1009
1024
|
Start: startDate.format("YYYY-MM-DD"),
|
|
1010
1025
|
End: endDate.format("YYYY-MM-DD")
|
|
@@ -1359,8 +1374,8 @@ var AWSProvider = class extends CloudProviderAdapter {
|
|
|
1359
1374
|
calculateTimeRemaining(timePeriod) {
|
|
1360
1375
|
if (!timePeriod.end)
|
|
1361
1376
|
return "Unknown";
|
|
1362
|
-
const endDate =
|
|
1363
|
-
const now =
|
|
1377
|
+
const endDate = (0, import_dayjs.default)(timePeriod.end);
|
|
1378
|
+
const now = (0, import_dayjs.default)();
|
|
1364
1379
|
const daysRemaining = endDate.diff(now, "day");
|
|
1365
1380
|
if (daysRemaining <= 0)
|
|
1366
1381
|
return "Period ended";
|
|
@@ -2339,20 +2354,20 @@ var CloudProviderFactory = class {
|
|
|
2339
2354
|
};
|
|
2340
2355
|
|
|
2341
2356
|
// src/discovery/profile-discovery.ts
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2357
|
+
var import_fs = require("fs");
|
|
2358
|
+
var import_path = require("path");
|
|
2359
|
+
var import_os = require("os");
|
|
2360
|
+
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
2346
2361
|
var CloudProfileDiscovery = class {
|
|
2347
2362
|
constructor() {
|
|
2348
2363
|
this.warnings = [];
|
|
2349
|
-
this.homeDirectory = homedir();
|
|
2364
|
+
this.homeDirectory = (0, import_os.homedir)();
|
|
2350
2365
|
}
|
|
2351
2366
|
/**
|
|
2352
2367
|
* Discover all available cloud provider profiles
|
|
2353
2368
|
*/
|
|
2354
2369
|
async discoverAllProfiles() {
|
|
2355
|
-
console.log(
|
|
2370
|
+
console.log(import_chalk2.default.yellow("\u{1F50D} Discovering cloud provider profiles..."));
|
|
2356
2371
|
const results = {
|
|
2357
2372
|
totalFound: 0,
|
|
2358
2373
|
byProvider: {
|
|
@@ -2385,14 +2400,14 @@ var CloudProfileDiscovery = class {
|
|
|
2385
2400
|
*/
|
|
2386
2401
|
async discoverAWSProfiles() {
|
|
2387
2402
|
const profiles = [];
|
|
2388
|
-
const credentialsPath = join(this.homeDirectory, ".aws", "credentials");
|
|
2389
|
-
const configPath = join(this.homeDirectory, ".aws", "config");
|
|
2390
|
-
if (!existsSync(credentialsPath) && !existsSync(configPath)) {
|
|
2403
|
+
const credentialsPath = (0, import_path.join)(this.homeDirectory, ".aws", "credentials");
|
|
2404
|
+
const configPath = (0, import_path.join)(this.homeDirectory, ".aws", "config");
|
|
2405
|
+
if (!(0, import_fs.existsSync)(credentialsPath) && !(0, import_fs.existsSync)(configPath)) {
|
|
2391
2406
|
return profiles;
|
|
2392
2407
|
}
|
|
2393
2408
|
try {
|
|
2394
|
-
const credentialsProfiles = existsSync(credentialsPath) ? this.parseIniFile(credentialsPath) : {};
|
|
2395
|
-
const configProfiles = existsSync(configPath) ? this.parseAWSConfigFile(configPath) : {};
|
|
2409
|
+
const credentialsProfiles = (0, import_fs.existsSync)(credentialsPath) ? this.parseIniFile(credentialsPath) : {};
|
|
2410
|
+
const configProfiles = (0, import_fs.existsSync)(configPath) ? this.parseAWSConfigFile(configPath) : {};
|
|
2396
2411
|
const allProfileNames = /* @__PURE__ */ new Set([
|
|
2397
2412
|
...Object.keys(credentialsProfiles),
|
|
2398
2413
|
...Object.keys(configProfiles)
|
|
@@ -2408,8 +2423,8 @@ var CloudProfileDiscovery = class {
|
|
|
2408
2423
|
provider: "aws" /* AWS */,
|
|
2409
2424
|
region: fileConfig.region || credConfig.region || "us-east-1",
|
|
2410
2425
|
isDefault: profileName === "default",
|
|
2411
|
-
credentialsPath: existsSync(credentialsPath) ? credentialsPath : void 0,
|
|
2412
|
-
configPath: existsSync(configPath) ? configPath : void 0,
|
|
2426
|
+
credentialsPath: (0, import_fs.existsSync)(credentialsPath) ? credentialsPath : void 0,
|
|
2427
|
+
configPath: (0, import_fs.existsSync)(configPath) ? configPath : void 0,
|
|
2413
2428
|
status: this.validateAWSProfile(credConfig, fileConfig),
|
|
2414
2429
|
lastUsed: this.getLastUsedDate(credentialsPath)
|
|
2415
2430
|
});
|
|
@@ -2424,18 +2439,18 @@ var CloudProfileDiscovery = class {
|
|
|
2424
2439
|
*/
|
|
2425
2440
|
async discoverGCPProfiles() {
|
|
2426
2441
|
const profiles = [];
|
|
2427
|
-
const gcpConfigDir = join(this.homeDirectory, ".config", "gcloud");
|
|
2428
|
-
if (!existsSync(gcpConfigDir)) {
|
|
2442
|
+
const gcpConfigDir = (0, import_path.join)(this.homeDirectory, ".config", "gcloud");
|
|
2443
|
+
if (!(0, import_fs.existsSync)(gcpConfigDir)) {
|
|
2429
2444
|
return profiles;
|
|
2430
2445
|
}
|
|
2431
2446
|
try {
|
|
2432
|
-
const configurationsPath = join(gcpConfigDir, "configurations");
|
|
2433
|
-
if (existsSync(configurationsPath)) {
|
|
2434
|
-
const configFiles =
|
|
2447
|
+
const configurationsPath = (0, import_path.join)(gcpConfigDir, "configurations");
|
|
2448
|
+
if ((0, import_fs.existsSync)(configurationsPath)) {
|
|
2449
|
+
const configFiles = require("fs").readdirSync(configurationsPath);
|
|
2435
2450
|
for (const configFile of configFiles) {
|
|
2436
2451
|
if (configFile.startsWith("config_")) {
|
|
2437
2452
|
const profileName = configFile.replace("config_", "");
|
|
2438
|
-
const configPath = join(configurationsPath, configFile);
|
|
2453
|
+
const configPath = (0, import_path.join)(configurationsPath, configFile);
|
|
2439
2454
|
profiles.push({
|
|
2440
2455
|
name: profileName,
|
|
2441
2456
|
provider: "gcp" /* GOOGLE_CLOUD */,
|
|
@@ -2447,8 +2462,8 @@ var CloudProfileDiscovery = class {
|
|
|
2447
2462
|
}
|
|
2448
2463
|
}
|
|
2449
2464
|
}
|
|
2450
|
-
const adcPath = join(gcpConfigDir, "application_default_credentials.json");
|
|
2451
|
-
if (existsSync(adcPath)) {
|
|
2465
|
+
const adcPath = (0, import_path.join)(gcpConfigDir, "application_default_credentials.json");
|
|
2466
|
+
if ((0, import_fs.existsSync)(adcPath)) {
|
|
2452
2467
|
profiles.push({
|
|
2453
2468
|
name: "application-default",
|
|
2454
2469
|
provider: "gcp" /* GOOGLE_CLOUD */,
|
|
@@ -2467,14 +2482,14 @@ var CloudProfileDiscovery = class {
|
|
|
2467
2482
|
*/
|
|
2468
2483
|
async discoverAzureProfiles() {
|
|
2469
2484
|
const profiles = [];
|
|
2470
|
-
const azureConfigDir = join(this.homeDirectory, ".azure");
|
|
2471
|
-
if (!existsSync(azureConfigDir)) {
|
|
2485
|
+
const azureConfigDir = (0, import_path.join)(this.homeDirectory, ".azure");
|
|
2486
|
+
if (!(0, import_fs.existsSync)(azureConfigDir)) {
|
|
2472
2487
|
return profiles;
|
|
2473
2488
|
}
|
|
2474
2489
|
try {
|
|
2475
|
-
const profilesFile = join(azureConfigDir, "azureProfile.json");
|
|
2476
|
-
if (existsSync(profilesFile)) {
|
|
2477
|
-
const profilesData = JSON.parse(readFileSync(profilesFile, "utf8"));
|
|
2490
|
+
const profilesFile = (0, import_path.join)(azureConfigDir, "azureProfile.json");
|
|
2491
|
+
if ((0, import_fs.existsSync)(profilesFile)) {
|
|
2492
|
+
const profilesData = JSON.parse((0, import_fs.readFileSync)(profilesFile, "utf8"));
|
|
2478
2493
|
if (profilesData.subscriptions && Array.isArray(profilesData.subscriptions)) {
|
|
2479
2494
|
profilesData.subscriptions.forEach((sub, index) => {
|
|
2480
2495
|
profiles.push({
|
|
@@ -2497,12 +2512,12 @@ var CloudProfileDiscovery = class {
|
|
|
2497
2512
|
*/
|
|
2498
2513
|
async discoverAlibabaCloudProfiles() {
|
|
2499
2514
|
const profiles = [];
|
|
2500
|
-
const alicloudConfigPath = join(this.homeDirectory, ".aliyun", "config.json");
|
|
2501
|
-
if (!existsSync(alicloudConfigPath)) {
|
|
2515
|
+
const alicloudConfigPath = (0, import_path.join)(this.homeDirectory, ".aliyun", "config.json");
|
|
2516
|
+
if (!(0, import_fs.existsSync)(alicloudConfigPath)) {
|
|
2502
2517
|
return profiles;
|
|
2503
2518
|
}
|
|
2504
2519
|
try {
|
|
2505
|
-
const configData = JSON.parse(readFileSync(alicloudConfigPath, "utf8"));
|
|
2520
|
+
const configData = JSON.parse((0, import_fs.readFileSync)(alicloudConfigPath, "utf8"));
|
|
2506
2521
|
if (configData.profiles && Array.isArray(configData.profiles)) {
|
|
2507
2522
|
configData.profiles.forEach((profile) => {
|
|
2508
2523
|
profiles.push({
|
|
@@ -2525,8 +2540,8 @@ var CloudProfileDiscovery = class {
|
|
|
2525
2540
|
*/
|
|
2526
2541
|
async discoverOracleCloudProfiles() {
|
|
2527
2542
|
const profiles = [];
|
|
2528
|
-
const ociConfigPath = join(this.homeDirectory, ".oci", "config");
|
|
2529
|
-
if (!existsSync(ociConfigPath)) {
|
|
2543
|
+
const ociConfigPath = (0, import_path.join)(this.homeDirectory, ".oci", "config");
|
|
2544
|
+
if (!(0, import_fs.existsSync)(ociConfigPath)) {
|
|
2530
2545
|
return profiles;
|
|
2531
2546
|
}
|
|
2532
2547
|
try {
|
|
@@ -2550,43 +2565,43 @@ var CloudProfileDiscovery = class {
|
|
|
2550
2565
|
* Display discovered profiles in a formatted table
|
|
2551
2566
|
*/
|
|
2552
2567
|
displayDiscoveryResults(results) {
|
|
2553
|
-
console.log("\n" +
|
|
2568
|
+
console.log("\n" + import_chalk2.default.bold.cyan("\u{1F3AF} Profile Discovery Results"));
|
|
2554
2569
|
console.log("\u2550".repeat(60));
|
|
2555
2570
|
if (results.totalFound === 0) {
|
|
2556
|
-
console.log(
|
|
2557
|
-
console.log(
|
|
2571
|
+
console.log(import_chalk2.default.yellow("\u26A0\uFE0F No cloud provider profiles found"));
|
|
2572
|
+
console.log(import_chalk2.default.gray(" Make sure you have configured at least one cloud provider CLI"));
|
|
2558
2573
|
return;
|
|
2559
2574
|
}
|
|
2560
|
-
console.log(
|
|
2575
|
+
console.log(import_chalk2.default.green(`\u2705 Found ${results.totalFound} profiles across ${Object.keys(results.byProvider).length} providers`));
|
|
2561
2576
|
for (const [provider, profiles] of Object.entries(results.byProvider)) {
|
|
2562
2577
|
if (profiles.length > 0) {
|
|
2563
2578
|
console.log(`
|
|
2564
|
-
${this.getProviderIcon(provider)} ${
|
|
2579
|
+
${this.getProviderIcon(provider)} ${import_chalk2.default.bold(provider.toUpperCase())}: ${profiles.length} profiles`);
|
|
2565
2580
|
profiles.forEach((profile, index) => {
|
|
2566
2581
|
const statusIcon = profile.status === "available" ? "\u2705" : profile.status === "invalid" ? "\u274C" : "\u26A0\uFE0F";
|
|
2567
|
-
const defaultBadge = profile.isDefault ?
|
|
2582
|
+
const defaultBadge = profile.isDefault ? import_chalk2.default.green(" (default)") : "";
|
|
2568
2583
|
console.log(` ${index + 1}. ${profile.name}${defaultBadge} ${statusIcon}`);
|
|
2569
2584
|
if (profile.region) {
|
|
2570
|
-
console.log(` Region: ${
|
|
2585
|
+
console.log(` Region: ${import_chalk2.default.gray(profile.region)}`);
|
|
2571
2586
|
}
|
|
2572
2587
|
});
|
|
2573
2588
|
}
|
|
2574
2589
|
}
|
|
2575
2590
|
if (results.recommended) {
|
|
2576
|
-
console.log("\n" +
|
|
2591
|
+
console.log("\n" + import_chalk2.default.bold.green("\u{1F31F} Recommended Profile:"));
|
|
2577
2592
|
console.log(` ${results.recommended.provider.toUpperCase()}: ${results.recommended.name}`);
|
|
2578
|
-
console.log(
|
|
2593
|
+
console.log(import_chalk2.default.gray(` Use: --provider ${results.recommended.provider} --profile ${results.recommended.name}`));
|
|
2579
2594
|
}
|
|
2580
2595
|
if (results.warnings.length > 0) {
|
|
2581
|
-
console.log("\n" +
|
|
2596
|
+
console.log("\n" + import_chalk2.default.bold.yellow("\u26A0\uFE0F Warnings:"));
|
|
2582
2597
|
results.warnings.forEach((warning) => {
|
|
2583
|
-
console.log(
|
|
2598
|
+
console.log(import_chalk2.default.yellow(` \u2022 ${warning}`));
|
|
2584
2599
|
});
|
|
2585
2600
|
}
|
|
2586
|
-
console.log("\n" +
|
|
2587
|
-
console.log(
|
|
2588
|
-
console.log(
|
|
2589
|
-
console.log(
|
|
2601
|
+
console.log("\n" + import_chalk2.default.bold.cyan("\u{1F4A1} Usage Examples:"));
|
|
2602
|
+
console.log(import_chalk2.default.gray(" infra-cost --provider aws --profile production"));
|
|
2603
|
+
console.log(import_chalk2.default.gray(" infra-cost --provider gcp --profile my-project"));
|
|
2604
|
+
console.log(import_chalk2.default.gray(" infra-cost --all-profiles # Use all available profiles"));
|
|
2590
2605
|
}
|
|
2591
2606
|
/**
|
|
2592
2607
|
* Auto-select best profile based on discovery results
|
|
@@ -2609,7 +2624,7 @@ ${this.getProviderIcon(provider)} ${chalk2.bold(provider.toUpperCase())}: ${prof
|
|
|
2609
2624
|
}
|
|
2610
2625
|
// Helper methods
|
|
2611
2626
|
parseIniFile(filePath) {
|
|
2612
|
-
const content = readFileSync(filePath, "utf8");
|
|
2627
|
+
const content = (0, import_fs.readFileSync)(filePath, "utf8");
|
|
2613
2628
|
const profiles = {};
|
|
2614
2629
|
let currentProfile = "";
|
|
2615
2630
|
content.split("\n").forEach((line) => {
|
|
@@ -2625,7 +2640,7 @@ ${this.getProviderIcon(provider)} ${chalk2.bold(provider.toUpperCase())}: ${prof
|
|
|
2625
2640
|
return profiles;
|
|
2626
2641
|
}
|
|
2627
2642
|
parseAWSConfigFile(filePath) {
|
|
2628
|
-
const content = readFileSync(filePath, "utf8");
|
|
2643
|
+
const content = (0, import_fs.readFileSync)(filePath, "utf8");
|
|
2629
2644
|
const profiles = {};
|
|
2630
2645
|
let currentProfile = "";
|
|
2631
2646
|
content.split("\n").forEach((line) => {
|
|
@@ -2654,7 +2669,7 @@ ${this.getProviderIcon(provider)} ${chalk2.bold(provider.toUpperCase())}: ${prof
|
|
|
2654
2669
|
}
|
|
2655
2670
|
getLastUsedDate(filePath) {
|
|
2656
2671
|
try {
|
|
2657
|
-
const stats =
|
|
2672
|
+
const stats = require("fs").statSync(filePath);
|
|
2658
2673
|
return stats.mtime;
|
|
2659
2674
|
} catch {
|
|
2660
2675
|
return void 0;
|
|
@@ -2692,10 +2707,10 @@ ${this.getProviderIcon(provider)} ${chalk2.bold(provider.toUpperCase())}: ${prof
|
|
|
2692
2707
|
};
|
|
2693
2708
|
|
|
2694
2709
|
// src/visualization/terminal-ui.ts
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2710
|
+
var import_cli_table3 = __toESM(require("cli-table3"), 1);
|
|
2711
|
+
var import_chalk3 = __toESM(require("chalk"), 1);
|
|
2712
|
+
var import_cli_progress = __toESM(require("cli-progress"), 1);
|
|
2713
|
+
var import_moment = __toESM(require("moment"), 1);
|
|
2699
2714
|
var TerminalUIEngine = class {
|
|
2700
2715
|
constructor() {
|
|
2701
2716
|
this.progressBar = null;
|
|
@@ -2704,8 +2719,8 @@ var TerminalUIEngine = class {
|
|
|
2704
2719
|
* Creates a formatted table with enhanced styling
|
|
2705
2720
|
*/
|
|
2706
2721
|
createTable(columns, rows) {
|
|
2707
|
-
const table = new
|
|
2708
|
-
head: columns.map((col) =>
|
|
2722
|
+
const table = new import_cli_table3.default({
|
|
2723
|
+
head: columns.map((col) => import_chalk3.default.bold(col.header)),
|
|
2709
2724
|
colWidths: columns.map((col) => col.width || 20),
|
|
2710
2725
|
colAligns: columns.map((col) => col.align || "left"),
|
|
2711
2726
|
style: {
|
|
@@ -2736,7 +2751,7 @@ var TerminalUIEngine = class {
|
|
|
2736
2751
|
const value = Object.values(row)[index];
|
|
2737
2752
|
const colorKey = col.color;
|
|
2738
2753
|
if (colorKey && typeof value === "string") {
|
|
2739
|
-
return
|
|
2754
|
+
return import_chalk3.default[colorKey](value);
|
|
2740
2755
|
}
|
|
2741
2756
|
return String(value);
|
|
2742
2757
|
});
|
|
@@ -2755,7 +2770,7 @@ var TerminalUIEngine = class {
|
|
|
2755
2770
|
compact: false
|
|
2756
2771
|
}) {
|
|
2757
2772
|
const { totals, totalsByService } = costBreakdown;
|
|
2758
|
-
let output = "\n" +
|
|
2773
|
+
let output = "\n" + import_chalk3.default.bold.cyan("\u{1F4B0} Cost Analysis Summary") + "\n";
|
|
2759
2774
|
output += "\u2550".repeat(50) + "\n\n";
|
|
2760
2775
|
const summaryColumns = [
|
|
2761
2776
|
{ header: "Period", width: 15, align: "left", color: "cyan" },
|
|
@@ -2785,7 +2800,7 @@ var TerminalUIEngine = class {
|
|
|
2785
2800
|
}
|
|
2786
2801
|
];
|
|
2787
2802
|
output += this.createTable(summaryColumns, summaryRows) + "\n\n";
|
|
2788
|
-
output +=
|
|
2803
|
+
output += import_chalk3.default.bold.cyan("\u{1F4CA} Service Breakdown (This Month)") + "\n";
|
|
2789
2804
|
output += "\u2550".repeat(50) + "\n\n";
|
|
2790
2805
|
const allServiceEntries = Object.entries(totalsByService.thisMonth);
|
|
2791
2806
|
const significantServices = allServiceEntries.filter(([_, cost]) => cost > 0.01).sort(([, a], [, b]) => b - a);
|
|
@@ -2795,7 +2810,7 @@ var TerminalUIEngine = class {
|
|
|
2795
2810
|
const hiddenServices = allServiceEntries.length - maxDisplay;
|
|
2796
2811
|
const hiddenCost = significantServices.slice(maxDisplay).reduce((sum, [_, cost]) => sum + cost, 0);
|
|
2797
2812
|
if (hiddenCost > 0) {
|
|
2798
|
-
output +=
|
|
2813
|
+
output += import_chalk3.default.gray(`Showing top ${maxDisplay} of ${allServiceEntries.length} services `) + import_chalk3.default.gray(`(${hiddenServices} services with $${hiddenCost.toFixed(2)} hidden)
|
|
2799
2814
|
|
|
2800
2815
|
`);
|
|
2801
2816
|
}
|
|
@@ -2829,9 +2844,9 @@ var TerminalUIEngine = class {
|
|
|
2829
2844
|
currency: "USD"
|
|
2830
2845
|
}) {
|
|
2831
2846
|
if (!trendData || trendData.length === 0) {
|
|
2832
|
-
return
|
|
2847
|
+
return import_chalk3.default.red("No trend data available");
|
|
2833
2848
|
}
|
|
2834
|
-
let output = "\n" +
|
|
2849
|
+
let output = "\n" + import_chalk3.default.bold.cyan("\u{1F4C8} Cost Trend Analysis") + "\n";
|
|
2835
2850
|
output += "\u2550".repeat(50) + "\n\n";
|
|
2836
2851
|
const maxCost = Math.max(...trendData.map((d) => d.actualCost));
|
|
2837
2852
|
const minCost = Math.min(...trendData.map((d) => d.actualCost));
|
|
@@ -2841,7 +2856,7 @@ var TerminalUIEngine = class {
|
|
|
2841
2856
|
const barLength = Math.round(normalizedValue * options.width);
|
|
2842
2857
|
const bar = "\u2588".repeat(barLength) + "\u2591".repeat(options.width - barLength);
|
|
2843
2858
|
const coloredBar = this.colorizeBar(bar, normalizedValue, options.colorThreshold);
|
|
2844
|
-
const period =
|
|
2859
|
+
const period = (0, import_moment.default)(data.period).format("MMM YYYY");
|
|
2845
2860
|
const cost = this.formatCurrency(data.actualCost, options.currency);
|
|
2846
2861
|
const change = data.changeFromPrevious ? this.formatChangeIndicator(data.changeFromPrevious.percentage) : "";
|
|
2847
2862
|
output += `${period.padEnd(10)} ${coloredBar} ${cost.padStart(10)} ${change}
|
|
@@ -2859,8 +2874,8 @@ var TerminalUIEngine = class {
|
|
|
2859
2874
|
if (this.progressBar) {
|
|
2860
2875
|
this.progressBar.stop();
|
|
2861
2876
|
}
|
|
2862
|
-
this.progressBar = new
|
|
2863
|
-
format: `${
|
|
2877
|
+
this.progressBar = new import_cli_progress.default.SingleBar({
|
|
2878
|
+
format: `${import_chalk3.default.cyan(label)} ${import_chalk3.default.cyan("[")}${import_chalk3.default.yellow("{bar}")}${import_chalk3.default.cyan("]")} {percentage}% | ETA: {eta}s | {value}/{total}`,
|
|
2864
2879
|
barCompleteChar: "\u2588",
|
|
2865
2880
|
barIncompleteChar: "\u2591",
|
|
2866
2881
|
hideCursor: true
|
|
@@ -2889,14 +2904,14 @@ var TerminalUIEngine = class {
|
|
|
2889
2904
|
*/
|
|
2890
2905
|
createAnomalyAlert(anomalies) {
|
|
2891
2906
|
if (anomalies.length === 0) {
|
|
2892
|
-
return
|
|
2907
|
+
return import_chalk3.default.green("\u2705 No cost anomalies detected");
|
|
2893
2908
|
}
|
|
2894
|
-
let output = "\n" +
|
|
2909
|
+
let output = "\n" + import_chalk3.default.bold.red("\u{1F6A8} Cost Anomalies Detected") + "\n";
|
|
2895
2910
|
output += "\u2550".repeat(50) + "\n\n";
|
|
2896
2911
|
anomalies.forEach((anomaly) => {
|
|
2897
2912
|
const severityColor = this.getSeverityColor(anomaly.severity);
|
|
2898
2913
|
const icon = this.getSeverityIcon(anomaly.severity);
|
|
2899
|
-
output +=
|
|
2914
|
+
output += import_chalk3.default[severityColor](`${icon} ${anomaly.date}
|
|
2900
2915
|
`);
|
|
2901
2916
|
output += ` Expected: ${this.formatCurrency(anomaly.expectedCost, "USD")}
|
|
2902
2917
|
`;
|
|
@@ -2905,7 +2920,7 @@ var TerminalUIEngine = class {
|
|
|
2905
2920
|
output += ` Deviation: ${anomaly.deviation > 0 ? "+" : ""}${anomaly.deviation.toFixed(1)}%
|
|
2906
2921
|
`;
|
|
2907
2922
|
if (anomaly.description) {
|
|
2908
|
-
output += ` ${
|
|
2923
|
+
output += ` ${import_chalk3.default.gray(anomaly.description)}
|
|
2909
2924
|
`;
|
|
2910
2925
|
}
|
|
2911
2926
|
output += "\n";
|
|
@@ -2918,14 +2933,14 @@ var TerminalUIEngine = class {
|
|
|
2918
2933
|
createHeader(title, subtitle) {
|
|
2919
2934
|
const width = 60;
|
|
2920
2935
|
let output = "\n";
|
|
2921
|
-
output +=
|
|
2936
|
+
output += import_chalk3.default.cyan("\u250C" + "\u2500".repeat(width - 2) + "\u2510") + "\n";
|
|
2922
2937
|
const titlePadding = Math.floor((width - title.length - 4) / 2);
|
|
2923
|
-
output +=
|
|
2938
|
+
output += import_chalk3.default.cyan("\u2502") + " ".repeat(titlePadding) + import_chalk3.default.bold.white(title) + " ".repeat(width - title.length - titlePadding - 2) + import_chalk3.default.cyan("\u2502") + "\n";
|
|
2924
2939
|
if (subtitle) {
|
|
2925
2940
|
const subtitlePadding = Math.floor((width - subtitle.length - 4) / 2);
|
|
2926
|
-
output +=
|
|
2941
|
+
output += import_chalk3.default.cyan("\u2502") + " ".repeat(subtitlePadding) + import_chalk3.default.gray(subtitle) + " ".repeat(width - subtitle.length - subtitlePadding - 2) + import_chalk3.default.cyan("\u2502") + "\n";
|
|
2927
2942
|
}
|
|
2928
|
-
output +=
|
|
2943
|
+
output += import_chalk3.default.cyan("\u2514" + "\u2500".repeat(width - 2) + "\u2518") + "\n\n";
|
|
2929
2944
|
return output;
|
|
2930
2945
|
}
|
|
2931
2946
|
// Helper methods
|
|
@@ -2943,42 +2958,42 @@ var TerminalUIEngine = class {
|
|
|
2943
2958
|
const change = (current - previous) / previous * 100;
|
|
2944
2959
|
const changeStr = `${change >= 0 ? "+" : ""}${change.toFixed(1)}%`;
|
|
2945
2960
|
if (change > 0) {
|
|
2946
|
-
return
|
|
2961
|
+
return import_chalk3.default.red(`\u2197 ${changeStr}`);
|
|
2947
2962
|
} else if (change < 0) {
|
|
2948
|
-
return
|
|
2963
|
+
return import_chalk3.default.green(`\u2198 ${changeStr}`);
|
|
2949
2964
|
} else {
|
|
2950
|
-
return
|
|
2965
|
+
return import_chalk3.default.gray("\u2192 0.0%");
|
|
2951
2966
|
}
|
|
2952
2967
|
}
|
|
2953
2968
|
getTrendIndicator(current, previous) {
|
|
2954
2969
|
if (previous === 0)
|
|
2955
|
-
return
|
|
2970
|
+
return import_chalk3.default.gray("\u2500");
|
|
2956
2971
|
const change = (current - previous) / previous * 100;
|
|
2957
2972
|
if (change > 10)
|
|
2958
|
-
return
|
|
2973
|
+
return import_chalk3.default.red("\u2197\u2197");
|
|
2959
2974
|
if (change > 0)
|
|
2960
|
-
return
|
|
2975
|
+
return import_chalk3.default.yellow("\u2197");
|
|
2961
2976
|
if (change < -10)
|
|
2962
|
-
return
|
|
2977
|
+
return import_chalk3.default.green("\u2198\u2198");
|
|
2963
2978
|
if (change < 0)
|
|
2964
|
-
return
|
|
2965
|
-
return
|
|
2979
|
+
return import_chalk3.default.green("\u2198");
|
|
2980
|
+
return import_chalk3.default.gray("\u2192");
|
|
2966
2981
|
}
|
|
2967
2982
|
colorizeBar(bar, normalizedValue, threshold) {
|
|
2968
2983
|
const thresholdValue = threshold || 0.7;
|
|
2969
2984
|
if (normalizedValue > thresholdValue) {
|
|
2970
|
-
return
|
|
2985
|
+
return import_chalk3.default.red(bar);
|
|
2971
2986
|
} else if (normalizedValue > 0.4) {
|
|
2972
|
-
return
|
|
2987
|
+
return import_chalk3.default.yellow(bar);
|
|
2973
2988
|
} else {
|
|
2974
|
-
return
|
|
2989
|
+
return import_chalk3.default.green(bar);
|
|
2975
2990
|
}
|
|
2976
2991
|
}
|
|
2977
2992
|
formatChangeIndicator(percentage) {
|
|
2978
2993
|
const indicator = percentage >= 0 ? "\u2197" : "\u2198";
|
|
2979
2994
|
const color = percentage >= 0 ? "red" : "green";
|
|
2980
2995
|
const sign = percentage >= 0 ? "+" : "";
|
|
2981
|
-
return
|
|
2996
|
+
return import_chalk3.default[color](`${indicator} ${sign}${percentage.toFixed(1)}%`);
|
|
2982
2997
|
}
|
|
2983
2998
|
getSeverityColor(severity) {
|
|
2984
2999
|
switch (severity.toLowerCase()) {
|
|
@@ -3021,7 +3036,7 @@ var MultiCloudDashboard = class {
|
|
|
3021
3036
|
* Create comprehensive multi-cloud inventory dashboard
|
|
3022
3037
|
*/
|
|
3023
3038
|
async generateMultiCloudInventoryDashboard(providers) {
|
|
3024
|
-
console.log(
|
|
3039
|
+
console.log(import_chalk4.default.yellow("\u{1F310} Gathering multi-cloud inventory..."));
|
|
3025
3040
|
const summary = await this.collectMultiCloudInventory(providers);
|
|
3026
3041
|
return this.renderMultiCloudDashboard(summary);
|
|
3027
3042
|
}
|
|
@@ -3065,7 +3080,7 @@ var MultiCloudDashboard = class {
|
|
|
3065
3080
|
summary.providerBreakdown[provider].status = "unavailable";
|
|
3066
3081
|
continue;
|
|
3067
3082
|
}
|
|
3068
|
-
console.log(
|
|
3083
|
+
console.log(import_chalk4.default.gray(` Scanning ${provider.toUpperCase()} resources...`));
|
|
3069
3084
|
const providerAdapter = this.createProviderAdapter(provider, profile);
|
|
3070
3085
|
if (!providerAdapter) {
|
|
3071
3086
|
summary.providerBreakdown[provider].status = "error";
|
|
@@ -3089,7 +3104,7 @@ var MultiCloudDashboard = class {
|
|
|
3089
3104
|
summary.consolidatedResourcesByType[type] += count;
|
|
3090
3105
|
});
|
|
3091
3106
|
} catch (error) {
|
|
3092
|
-
console.warn(
|
|
3107
|
+
console.warn(import_chalk4.default.yellow(`\u26A0\uFE0F Failed to scan ${provider}: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
3093
3108
|
summary.providerBreakdown[provider].status = "error";
|
|
3094
3109
|
summary.providerBreakdown[provider].errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
3095
3110
|
}
|
|
@@ -3106,7 +3121,7 @@ var MultiCloudDashboard = class {
|
|
|
3106
3121
|
"\u{1F310} Multi-Cloud Infrastructure Dashboard",
|
|
3107
3122
|
`Comprehensive view across ${summary.totalProviders} cloud providers`
|
|
3108
3123
|
);
|
|
3109
|
-
output +=
|
|
3124
|
+
output += import_chalk4.default.bold.cyan("\u{1F4CA} Executive Summary") + "\n";
|
|
3110
3125
|
output += "\u2550".repeat(60) + "\n\n";
|
|
3111
3126
|
const summaryTable = this.ui.createTable([
|
|
3112
3127
|
{ header: "Metric", width: 25, align: "left", color: "cyan" },
|
|
@@ -3130,38 +3145,38 @@ var MultiCloudDashboard = class {
|
|
|
3130
3145
|
}
|
|
3131
3146
|
]);
|
|
3132
3147
|
output += summaryTable + "\n\n";
|
|
3133
|
-
output +=
|
|
3148
|
+
output += import_chalk4.default.bold.cyan("\u2601\uFE0F Provider Breakdown") + "\n";
|
|
3134
3149
|
output += "\u2550".repeat(60) + "\n\n";
|
|
3135
3150
|
for (const [provider, data] of Object.entries(summary.providerBreakdown)) {
|
|
3136
3151
|
const providerName = this.getProviderDisplayName(provider);
|
|
3137
3152
|
const statusIcon = this.getStatusIcon(data.status);
|
|
3138
3153
|
const statusColor = this.getStatusColor(data.status);
|
|
3139
|
-
output += `${statusIcon} ${
|
|
3154
|
+
output += `${statusIcon} ${import_chalk4.default.bold[statusColor](providerName)}
|
|
3140
3155
|
`;
|
|
3141
3156
|
if (data.status === "active" && data.inventory) {
|
|
3142
|
-
output += ` Resources: ${
|
|
3157
|
+
output += ` Resources: ${import_chalk4.default.yellow(data.resourceCount.toLocaleString())}
|
|
3143
3158
|
`;
|
|
3144
|
-
output += ` Cost: ${
|
|
3159
|
+
output += ` Cost: ${import_chalk4.default.green(`$${data.cost.toFixed(2)}`)}
|
|
3145
3160
|
`;
|
|
3146
|
-
output += ` Regions: ${
|
|
3161
|
+
output += ` Regions: ${import_chalk4.default.blue(data.inventory.region)}
|
|
3147
3162
|
`;
|
|
3148
|
-
output += ` Last Updated: ${
|
|
3163
|
+
output += ` Last Updated: ${import_chalk4.default.gray(data.inventory.lastUpdated.toLocaleString())}
|
|
3149
3164
|
`;
|
|
3150
3165
|
const topTypes = Object.entries(data.inventory.resourcesByType).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a).slice(0, 3).map(([type, count]) => `${count} ${type}`).join(", ");
|
|
3151
3166
|
if (topTypes) {
|
|
3152
|
-
output += ` Top Types: ${
|
|
3167
|
+
output += ` Top Types: ${import_chalk4.default.gray(topTypes)}
|
|
3153
3168
|
`;
|
|
3154
3169
|
}
|
|
3155
3170
|
} else if (data.status === "error") {
|
|
3156
|
-
output += ` ${
|
|
3171
|
+
output += ` ${import_chalk4.default.red("Error: " + (data.errorMessage || "Unknown error"))}
|
|
3157
3172
|
`;
|
|
3158
3173
|
} else if (data.status === "unavailable") {
|
|
3159
|
-
output += ` ${
|
|
3174
|
+
output += ` ${import_chalk4.default.gray("No credentials or profiles configured")}
|
|
3160
3175
|
`;
|
|
3161
3176
|
}
|
|
3162
3177
|
output += "\n";
|
|
3163
3178
|
}
|
|
3164
|
-
output +=
|
|
3179
|
+
output += import_chalk4.default.bold.cyan("\u{1F4C8} Consolidated Resource Analysis") + "\n";
|
|
3165
3180
|
output += "\u2550".repeat(60) + "\n\n";
|
|
3166
3181
|
const resourceTypeTable = this.ui.createTable([
|
|
3167
3182
|
{ header: "Resource Type", width: 20, align: "left", color: "blue" },
|
|
@@ -3171,7 +3186,7 @@ var MultiCloudDashboard = class {
|
|
|
3171
3186
|
], this.createResourceTypeRows(summary));
|
|
3172
3187
|
output += resourceTypeTable + "\n\n";
|
|
3173
3188
|
output += this.generateMultiCloudInsights(summary);
|
|
3174
|
-
output +=
|
|
3189
|
+
output += import_chalk4.default.bold.cyan("\u{1F4A1} Multi-Cloud Recommendations") + "\n";
|
|
3175
3190
|
output += "\u2550".repeat(60) + "\n";
|
|
3176
3191
|
output += this.generateMultiCloudRecommendations(summary);
|
|
3177
3192
|
return output;
|
|
@@ -3180,7 +3195,7 @@ var MultiCloudDashboard = class {
|
|
|
3180
3195
|
* Generate actionable multi-cloud insights
|
|
3181
3196
|
*/
|
|
3182
3197
|
generateMultiCloudInsights(summary) {
|
|
3183
|
-
let output =
|
|
3198
|
+
let output = import_chalk4.default.bold.cyan("\u{1F9E0} Multi-Cloud Insights") + "\n";
|
|
3184
3199
|
output += "\u2550".repeat(60) + "\n\n";
|
|
3185
3200
|
const insights = [];
|
|
3186
3201
|
const activeProviders = Object.values(summary.providerBreakdown).filter((p) => p.status === "active").length;
|
|
@@ -3231,13 +3246,13 @@ var MultiCloudDashboard = class {
|
|
|
3231
3246
|
recommendations.push("\u{1F3F7}\uFE0F Implement consistent tagging strategy across all cloud providers");
|
|
3232
3247
|
recommendations.push("\u{1F512} Use --dependency-mapping to understand cross-cloud resource relationships");
|
|
3233
3248
|
recommendations.forEach((rec, index) => {
|
|
3234
|
-
output +=
|
|
3249
|
+
output += import_chalk4.default.gray(`${index + 1}. ${rec}
|
|
3235
3250
|
`);
|
|
3236
3251
|
});
|
|
3237
|
-
output += "\n" +
|
|
3238
|
-
output +=
|
|
3239
|
-
output +=
|
|
3240
|
-
output +=
|
|
3252
|
+
output += "\n" + import_chalk4.default.bold.yellow("\u26A1 Quick Actions:") + "\n";
|
|
3253
|
+
output += import_chalk4.default.gray("\u2022 infra-cost --all-profiles --combine-profiles # Aggregate view\n");
|
|
3254
|
+
output += import_chalk4.default.gray("\u2022 infra-cost --compare-clouds aws,gcp,azure # Cost comparison\n");
|
|
3255
|
+
output += import_chalk4.default.gray("\u2022 infra-cost --inventory --group-by provider # Detailed inventory\n");
|
|
3241
3256
|
return output;
|
|
3242
3257
|
}
|
|
3243
3258
|
// Helper methods
|
|
@@ -3339,6 +3354,7 @@ var MultiCloudDashboard = class {
|
|
|
3339
3354
|
};
|
|
3340
3355
|
|
|
3341
3356
|
// src/demo/test-multi-cloud-dashboard.ts
|
|
3357
|
+
var import_meta = {};
|
|
3342
3358
|
async function testMultiCloudDashboard() {
|
|
3343
3359
|
console.log("\u{1F680} Testing Multi-Cloud Dashboard...\n");
|
|
3344
3360
|
try {
|
|
@@ -3364,7 +3380,7 @@ async function testMultiCloudDashboard() {
|
|
|
3364
3380
|
console.error("\u274C Error testing multi-cloud dashboard:", error instanceof Error ? error.message : error);
|
|
3365
3381
|
}
|
|
3366
3382
|
}
|
|
3367
|
-
if (
|
|
3383
|
+
if (import_meta.url === `file://${process.argv[1]}`) {
|
|
3368
3384
|
testMultiCloudDashboard();
|
|
3369
3385
|
}
|
|
3370
|
-
//# sourceMappingURL=test-multi-cloud-dashboard.
|
|
3386
|
+
//# sourceMappingURL=test-multi-cloud-dashboard.cjs.map
|