@ganakailabs/cloudeval-cli 0.26.11 → 0.27.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/dist/cli.js CHANGED
@@ -26,17 +26,20 @@ import {
26
26
  writeCliConfigValue
27
27
  } from "./chunk-QSBGUI25.js";
28
28
  import {
29
+ clearActiveCLITraceContext,
30
+ createCLITraceContext,
29
31
  getBundledAgentProfile,
30
32
  getBundledAgentProfiles,
31
33
  getCLIHeaders,
32
34
  isSensitiveSecretKey,
33
35
  normalizeApiBase,
34
36
  redactSensitiveSecrets,
35
- redactSensitiveText
36
- } from "./chunk-2OLI5VOG.js";
37
+ redactSensitiveText,
38
+ setActiveCLITraceContext
39
+ } from "./chunk-USSCB2ZU.js";
37
40
  import {
38
41
  CLI_VERSION
39
- } from "./chunk-Y5L2F7X3.js";
42
+ } from "./chunk-YW5JWFYV.js";
40
43
 
41
44
  // src/runtime/prepareInk.ts
42
45
  import fs from "fs";
@@ -1649,7 +1652,7 @@ var resolveReportProjectId = async ({
1649
1652
  if (!token) {
1650
1653
  throw new Error("No project specified. Use --project <id> for report access.");
1651
1654
  }
1652
- const resolvedWorkspace = workspace ?? await import("./dist-MQQKC6DZ.js").then((core) => ({
1655
+ const resolvedWorkspace = workspace ?? await import("./dist-PEYJDO7A.js").then((core) => ({
1653
1656
  checkUserStatus: core.checkUserStatus,
1654
1657
  getProjects: core.getProjects
1655
1658
  }));
@@ -1678,7 +1681,7 @@ var warnIfAccessKeyFromCliOption = (options, command) => {
1678
1681
  };
1679
1682
  var resolveAuthContext = async (options, command, deps) => {
1680
1683
  const baseUrl = await deps.resolveBaseUrl(options, command);
1681
- const core = await import("./dist-MQQKC6DZ.js");
1684
+ const core = await import("./dist-PEYJDO7A.js");
1682
1685
  core.assertSecureBaseUrl(baseUrl);
1683
1686
  warnIfAccessKeyFromCliOption(options, command);
1684
1687
  let accessKey = options.accessKey;
@@ -1764,7 +1767,7 @@ var resolveToken = async (options, baseUrl, deps, command) => {
1764
1767
  if (options.accessKey) {
1765
1768
  return options.accessKey;
1766
1769
  }
1767
- const { getAuthToken } = await import("./dist-MQQKC6DZ.js");
1770
+ const { getAuthToken } = await import("./dist-PEYJDO7A.js");
1768
1771
  try {
1769
1772
  return await getAuthToken({
1770
1773
  accessKey: options.accessKey,
@@ -1775,7 +1778,7 @@ var resolveToken = async (options, baseUrl, deps, command) => {
1775
1778
  if (!canLogin) {
1776
1779
  throw error;
1777
1780
  }
1778
- const { login } = await import("./dist-MQQKC6DZ.js");
1781
+ const { login } = await import("./dist-PEYJDO7A.js");
1779
1782
  process.stderr.write("Authentication required. Starting login flow...\n");
1780
1783
  const token = await login(baseUrl, {
1781
1784
  headless: Boolean(process.env.SSH_TTY || process.env.CLOUDEVAL_HEADLESS_LOGIN)
@@ -1941,7 +1944,7 @@ var registerReportsCommand = (program2, deps) => {
1941
1944
  token,
1942
1945
  requestedProjectId: options.project
1943
1946
  });
1944
- const core = await import("./dist-MQQKC6DZ.js");
1947
+ const core = await import("./dist-PEYJDO7A.js");
1945
1948
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
1946
1949
  const reports2 = await core.listReports({
1947
1950
  baseUrl,
@@ -1963,7 +1966,7 @@ var registerReportsCommand = (program2, deps) => {
1963
1966
  try {
1964
1967
  const baseUrl = await deps.resolveBaseUrl(options, command);
1965
1968
  const token = await resolveToken(options, baseUrl, deps, command);
1966
- const core = await import("./dist-MQQKC6DZ.js");
1969
+ const core = await import("./dist-PEYJDO7A.js");
1967
1970
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
1968
1971
  const projectId = await resolveReportProjectId({
1969
1972
  baseUrl,
@@ -2066,7 +2069,7 @@ var registerReportsCommand = (program2, deps) => {
2066
2069
  try {
2067
2070
  const baseUrl = await deps.resolveBaseUrl(options, command);
2068
2071
  const token = await resolveToken(options, baseUrl, deps, command);
2069
- const core = await import("./dist-MQQKC6DZ.js");
2072
+ const core = await import("./dist-PEYJDO7A.js");
2070
2073
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
2071
2074
  const projectId = await resolveReportProjectId({
2072
2075
  baseUrl,
@@ -2136,7 +2139,7 @@ var registerReportsCommand = (program2, deps) => {
2136
2139
  token,
2137
2140
  requestedProjectId: options.project
2138
2141
  });
2139
- const core = await import("./dist-MQQKC6DZ.js");
2142
+ const core = await import("./dist-PEYJDO7A.js");
2140
2143
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
2141
2144
  const report = await core.getWafReport({
2142
2145
  baseUrl,
@@ -2175,7 +2178,7 @@ var registerReportsCommand = (program2, deps) => {
2175
2178
  token,
2176
2179
  requestedProjectId: options.project
2177
2180
  });
2178
- const core = await import("./dist-MQQKC6DZ.js");
2181
+ const core = await import("./dist-PEYJDO7A.js");
2179
2182
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
2180
2183
  const report = await core.getReport({
2181
2184
  baseUrl,
@@ -2203,7 +2206,7 @@ var registerReportsCommand = (program2, deps) => {
2203
2206
  token,
2204
2207
  requestedProjectId: options.project
2205
2208
  });
2206
- const core = await import("./dist-MQQKC6DZ.js");
2209
+ const core = await import("./dist-PEYJDO7A.js");
2207
2210
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
2208
2211
  const report = await core.getCostReport({
2209
2212
  baseUrl,
@@ -2232,7 +2235,7 @@ var registerReportsCommand = (program2, deps) => {
2232
2235
  token,
2233
2236
  requestedProjectId: options.project
2234
2237
  });
2235
- const core = await import("./dist-MQQKC6DZ.js");
2238
+ const core = await import("./dist-PEYJDO7A.js");
2236
2239
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
2237
2240
  const report = await core.getWafReport({
2238
2241
  baseUrl,
@@ -2410,14 +2413,41 @@ var parseGateConfig = (configText) => {
2410
2413
  const match = configText.match(new RegExp(`^\\s*${key}\\s*:\\s*([^\\s#]+)`, "m"));
2411
2414
  return match ? match[1].trim() : void 0;
2412
2415
  };
2416
+ const firstStringValue = (...keys) => {
2417
+ for (const key of keys) {
2418
+ const value = stringValue2(key);
2419
+ if (value !== void 0) {
2420
+ return value;
2421
+ }
2422
+ }
2423
+ return void 0;
2424
+ };
2413
2425
  const numberValue2 = (key) => {
2414
2426
  const match = configText.match(new RegExp(`^\\s*${key}\\s*:\\s*([0-9]+(?:\\.[0-9]+)?)`, "m"));
2415
2427
  return match ? Number(match[1]) : void 0;
2416
2428
  };
2429
+ const firstNumberValue = (...keys) => {
2430
+ for (const key of keys) {
2431
+ const value = numberValue2(key);
2432
+ if (value !== void 0) {
2433
+ return value;
2434
+ }
2435
+ }
2436
+ return void 0;
2437
+ };
2417
2438
  const booleanValue2 = (key) => {
2418
2439
  const match = configText.match(new RegExp(`^\\s*${key}\\s*:\\s*(true|false)`, "im"));
2419
2440
  return match ? match[1].toLowerCase() === "true" : void 0;
2420
2441
  };
2442
+ const firstBooleanValue = (...keys) => {
2443
+ for (const key of keys) {
2444
+ const value = booleanValue2(key);
2445
+ if (value !== void 0) {
2446
+ return value;
2447
+ }
2448
+ }
2449
+ return void 0;
2450
+ };
2421
2451
  const pillarScoreMins = {};
2422
2452
  const pillarBlock = configText.match(/^(\s*)pillars\s*:\s*$(?<body>(?:\n\s+[-\w]+\s*:\s*[0-9]+(?:\.[0-9]+)?\s*)+)/m);
2423
2453
  const pillarBody = pillarBlock?.groups?.body ?? "";
@@ -2439,15 +2469,21 @@ var parseGateConfig = (configText) => {
2439
2469
  pillarScoreMins[key] = value;
2440
2470
  }
2441
2471
  }
2442
- const enforcement = stringValue2("enforcement")?.toLowerCase();
2472
+ const enforcement = firstStringValue("enforcement", "mode")?.toLowerCase();
2443
2473
  return {
2444
- enforcement: enforcement === "warn" ? "warn" : "required",
2445
- overallScoreMin: numberValue2("overall_score_min") ?? 80,
2446
- pillarScoreMin: numberValue2("pillar_score_min"),
2474
+ enforcement: enforcement === "warn" || enforcement === "comment_only" ? "warn" : "required",
2475
+ overallScoreMin: firstNumberValue("overall_score_min", "minimum_well_architected_score") ?? 80,
2476
+ pillarScoreMin: firstNumberValue("pillar_score_min", "minimum_pillar_score"),
2447
2477
  pillarScoreMins,
2448
- failOnHighRisk: booleanValue2("fail_on_high_risk") ?? true,
2449
- failOnValidationErrors: booleanValue2("fail_on_validation_errors") ?? true,
2450
- maxMonthlyCost: numberValue2("max_monthly_cost")
2478
+ failOnHighRisk: firstBooleanValue(
2479
+ "fail_on_high_risk",
2480
+ "fail_when_high_risk_findings_exist"
2481
+ ) ?? true,
2482
+ failOnValidationErrors: firstBooleanValue(
2483
+ "fail_on_validation_errors",
2484
+ "fail_when_validation_fails"
2485
+ ) ?? true,
2486
+ maxMonthlyCost: firstNumberValue("max_monthly_cost", "max_monthly_cost_usd")
2451
2487
  };
2452
2488
  };
2453
2489
  var numberFrom = (...values) => {
@@ -2493,11 +2529,13 @@ var reviewReportStatus = (report) => ({
2493
2529
  var reviewReportStatuses = ({
2494
2530
  cost,
2495
2531
  waf,
2496
- preload
2532
+ preload,
2533
+ graph
2497
2534
  }) => ({
2498
2535
  cost: reviewReportStatus(cost),
2499
2536
  wellArchitected: reviewReportStatus(waf),
2500
- preload: reviewReportStatus(preload)
2537
+ preload: reviewReportStatus(preload),
2538
+ graph: reviewReportStatus(graph)
2501
2539
  });
2502
2540
  var publicJobStatus = (value) => {
2503
2541
  const record = firstRecord(value);
@@ -2534,18 +2572,198 @@ var formatMoney = (amount, currency, fallback = "not available") => {
2534
2572
  }
2535
2573
  return currency ? `${numericAmount} ${currency}` : String(numericAmount);
2536
2574
  };
2537
- var formatValidation = (validation) => {
2538
- const policyFailed = displayNumber(validation?.policyChecks?.failed);
2539
- const unitFailed = displayNumber(validation?.unitTests?.failed);
2540
- return `Policy checks ${policyFailed} failed, unit tests ${unitFailed} failed`;
2575
+ var trimNumber = (value, fractionDigits = 2) => Number.isInteger(value) ? String(value) : String(Number(value.toFixed(fractionDigits)));
2576
+ var formatScore = (value, fallback = "unknown") => {
2577
+ const numericValue = numberFrom(value);
2578
+ return numericValue === void 0 ? fallback : `${trimNumber(numericValue)}/100`;
2579
+ };
2580
+ var scoreRating = (value) => {
2581
+ const numericValue = numberFrom(value);
2582
+ if (numericValue === void 0) {
2583
+ return void 0;
2584
+ }
2585
+ if (numericValue >= 90) {
2586
+ return "EXCELLENT";
2587
+ }
2588
+ if (numericValue >= 75) {
2589
+ return "GOOD";
2590
+ }
2591
+ if (numericValue >= 50) {
2592
+ return "FAIR";
2593
+ }
2594
+ if (numericValue >= 30) {
2595
+ return "POOR";
2596
+ }
2597
+ return "CRITICAL";
2541
2598
  };
2542
- var compactValidation = (validation) => {
2599
+ var scoreRatingIcon = (rating) => {
2600
+ switch (rating) {
2601
+ case "EXCELLENT":
2602
+ return "\u{1F7E2}";
2603
+ case "GOOD":
2604
+ return "\u{1F535}";
2605
+ case "FAIR":
2606
+ return "\u{1F7E1}";
2607
+ case "POOR":
2608
+ return "\u{1F7E0}";
2609
+ case "CRITICAL":
2610
+ return "\u{1F534}";
2611
+ default:
2612
+ return "\u26AA";
2613
+ }
2614
+ };
2615
+ var formatMonthlyMoney = (amount, currency, fallback = "not available") => {
2616
+ const value = formatMoney(amount, currency, fallback);
2617
+ return value === fallback ? value : `${value}/mo`;
2618
+ };
2619
+ var compactBudgetLabel = (amount, currency) => {
2620
+ if (amount === void 0 || !Number.isFinite(amount)) {
2621
+ return void 0;
2622
+ }
2623
+ if (Math.abs(amount) >= 1e6) {
2624
+ return `${trimNumber(amount / 1e6, 1)}M`;
2625
+ }
2626
+ if (Math.abs(amount) >= 1e3) {
2627
+ return `${trimNumber(amount / 1e3, 1)}K`;
2628
+ }
2629
+ return formatMonthlyMoney(amount, currency);
2630
+ };
2631
+ var costSummaryLine = (cost) => {
2632
+ const amount = numberFrom(cost?.amount);
2633
+ if (amount === void 0) {
2634
+ return "\u26AA Cost: not available";
2635
+ }
2636
+ const formattedCost = formatMonthlyMoney(amount, cost?.currency);
2637
+ const threshold = numberFrom(cost?.threshold);
2638
+ if (threshold === void 0) {
2639
+ return `\u26AA Cost: ${formattedCost} (not gated)`;
2640
+ }
2641
+ const budget = compactBudgetLabel(threshold, cost?.currency) ?? "configured";
2642
+ return String(cost?.status ?? "").toLowerCase() === "fail" ? `\u{1F534} Cost: ${formattedCost} (over ${budget} budget)` : `\u{1F7E2} Cost: ${formattedCost} (under ${budget} budget)`;
2643
+ };
2644
+ var statusIcon = (status) => {
2645
+ switch (String(status ?? "").toLowerCase()) {
2646
+ case "pass":
2647
+ case "passed":
2648
+ case "success":
2649
+ case "succeeded":
2650
+ return "\u{1F7E2}";
2651
+ case "warn":
2652
+ case "warning":
2653
+ return "\u{1F7E1}";
2654
+ case "fail":
2655
+ case "failed":
2656
+ case "error":
2657
+ return "\u{1F534}";
2658
+ default:
2659
+ return "\u26AA";
2660
+ }
2661
+ };
2662
+ var formatValidation = (validation) => {
2543
2663
  const policyFailed = numberFrom(validation?.policyChecks?.failed);
2544
2664
  const unitFailed = numberFrom(validation?.unitTests?.failed);
2545
2665
  if (policyFailed === 0 && unitFailed === 0) {
2546
- return "validation clean";
2666
+ return "Validation clean";
2547
2667
  }
2548
- return formatValidation(validation);
2668
+ const parts = [];
2669
+ if (unitFailed !== void 0) {
2670
+ parts.push(unitFailed === 0 ? "unit tests clean" : `${unitFailed} unit tests failed`);
2671
+ }
2672
+ if (policyFailed !== void 0) {
2673
+ parts.push(policyFailed === 0 ? "policy checks clean" : `${policyFailed} policy checks failed`);
2674
+ }
2675
+ return parts.length ? parts.join(", ") : "Validation not available";
2676
+ };
2677
+ var validationSummaryLine = (validation) => {
2678
+ const unitFailed = numberFrom(validation?.unitTests?.failed);
2679
+ if (unitFailed === void 0) {
2680
+ return "\u26AA Validation: not available";
2681
+ }
2682
+ return unitFailed > 0 ? `\u{1F534} Validation: ${unitFailed} unit tests failed` : "\u{1F7E2} Validation: GOOD";
2683
+ };
2684
+ var policySummaryLine = (validation) => {
2685
+ const policyFailed = numberFrom(validation?.policyChecks?.failed);
2686
+ if (policyFailed === void 0) {
2687
+ return "\u26AA Policy checks: not available";
2688
+ }
2689
+ return policyFailed > 0 ? `\u{1F534} Policy checks: ${policyFailed} failed` : "\u{1F7E2} Policy checks: GOOD";
2690
+ };
2691
+ var validationDetailLines = (validation) => {
2692
+ if (!validation) {
2693
+ return ["- Validation data was not available."];
2694
+ }
2695
+ const lines = [];
2696
+ const unitTotal = numberFrom(validation.unitTests?.total);
2697
+ const unitPassed = numberFrom(validation.unitTests?.passed);
2698
+ const unitFailed = numberFrom(validation.unitTests?.failed);
2699
+ if (unitTotal !== void 0 || unitPassed !== void 0 || unitFailed !== void 0) {
2700
+ const parts = [];
2701
+ if (unitPassed !== void 0) parts.push(`**${unitPassed} passed**`);
2702
+ if (unitFailed !== void 0) parts.push(`**${unitFailed} failed**`);
2703
+ if (unitTotal !== void 0) parts.push(`${unitTotal} total`);
2704
+ lines.push(`- Unit tests: ${parts.join(", ")}`);
2705
+ }
2706
+ const policyTotal = numberFrom(validation.policyChecks?.total);
2707
+ const policyPassed = numberFrom(validation.policyChecks?.passed);
2708
+ const policyFailed = numberFrom(validation.policyChecks?.failed);
2709
+ if (policyTotal !== void 0 || policyPassed !== void 0 || policyFailed !== void 0) {
2710
+ const parts = [];
2711
+ if (policyPassed !== void 0) parts.push(`**${policyPassed} passed**`);
2712
+ if (policyFailed !== void 0) parts.push(`**${policyFailed} failed**`);
2713
+ if (policyTotal !== void 0) parts.push(`${policyTotal} total`);
2714
+ lines.push(`- Policy checks: ${parts.join(", ")}`);
2715
+ }
2716
+ return lines.length ? lines : ["- Validation data was not available."];
2717
+ };
2718
+ var namedAmount = (record) => numberFrom(
2719
+ record.amount,
2720
+ record.monthly_cost,
2721
+ record.monthlyCost,
2722
+ record.cost,
2723
+ record.value
2724
+ );
2725
+ var namedLabel = (record, fallback) => String(record.name ?? record.service ?? record.label ?? record.category ?? fallback);
2726
+ var mermaidLabel = (value) => value.replace(/"/g, "'");
2727
+ var costServiceRows = (services, currency) => (Array.isArray(services) ? services : []).map((service, index) => {
2728
+ const record = asRecord(service);
2729
+ const amount = namedAmount(record);
2730
+ if (amount === void 0) {
2731
+ return void 0;
2732
+ }
2733
+ const rowCurrency = String(record.currency ?? currency ?? "") || void 0;
2734
+ return {
2735
+ name: namedLabel(record, `Service ${index + 1}`),
2736
+ amount,
2737
+ ...rowCurrency ? { currency: rowCurrency } : {}
2738
+ };
2739
+ }).filter((service) => service !== void 0);
2740
+ var reconcileCostServiceRows = (services, totalAmount, currency) => {
2741
+ const total = numberFrom(totalAmount);
2742
+ if (total === void 0 || services.length === 0) {
2743
+ return services;
2744
+ }
2745
+ const serviceSum = services.reduce((sum, service) => sum + service.amount, 0);
2746
+ if (serviceSum > total + 1e-3) {
2747
+ return [
2748
+ {
2749
+ name: "Reported total",
2750
+ amount: total,
2751
+ ...currency ? { currency } : {}
2752
+ }
2753
+ ];
2754
+ }
2755
+ const delta = Number((total - serviceSum).toFixed(3));
2756
+ if (delta > 1e-3) {
2757
+ return [
2758
+ ...services,
2759
+ {
2760
+ name: "Other",
2761
+ amount: delta,
2762
+ ...currency ? { currency } : {}
2763
+ }
2764
+ ];
2765
+ }
2766
+ return services;
2549
2767
  };
2550
2768
  var markdownLink = (label, url) => url ? `[${label}](${url})` : label;
2551
2769
  var extractPillars = (waf) => {
@@ -2615,11 +2833,65 @@ var extractValidation = ({
2615
2833
  }
2616
2834
  };
2617
2835
  };
2836
+ var extractArchitectureInsights = ({
2837
+ waf,
2838
+ preload,
2839
+ graph,
2840
+ project
2841
+ }) => {
2842
+ const graphNodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
2843
+ const graphEdges = Array.isArray(graph?.edges) ? graph.edges : [];
2844
+ const graphResourceTypes = new Set(
2845
+ graphNodes.map((node) => asRecord(node).type).filter((type) => typeof type === "string" && type.trim().length > 0)
2846
+ );
2847
+ const metrics = firstRecord(
2848
+ preload?.reports?.architecture?.metrics,
2849
+ preload?.latest_payloads?.architecture?.summary,
2850
+ waf?.architecture,
2851
+ waf?.parsed?.architecture,
2852
+ project?.architecture,
2853
+ project?.graph
2854
+ );
2855
+ const resources = numberFrom(
2856
+ metrics?.resource_count,
2857
+ metrics?.resourceCount,
2858
+ metrics?.resources,
2859
+ metrics?.node_count,
2860
+ metrics?.nodeCount,
2861
+ graphNodes.length || void 0
2862
+ );
2863
+ const relationships = numberFrom(
2864
+ metrics?.relationship_count,
2865
+ metrics?.relationshipCount,
2866
+ metrics?.relationships,
2867
+ metrics?.edge_count,
2868
+ metrics?.edgeCount,
2869
+ graphEdges.length || void 0
2870
+ );
2871
+ const resourceTypes = numberFrom(
2872
+ metrics?.resource_type_count,
2873
+ metrics?.resourceTypeCount,
2874
+ metrics?.types,
2875
+ metrics?.resource_types,
2876
+ metrics?.resourceTypes,
2877
+ graphResourceTypes.size || void 0
2878
+ );
2879
+ if (resources === void 0 && relationships === void 0 && resourceTypes === void 0) {
2880
+ return void 0;
2881
+ }
2882
+ return {
2883
+ resources,
2884
+ relationships,
2885
+ resourceTypes,
2886
+ relationshipDensity: resources !== void 0 && resources > 0 && relationships !== void 0 ? relationships / resources : void 0
2887
+ };
2888
+ };
2618
2889
  var evaluateGate = ({
2619
2890
  configText,
2620
2891
  waf,
2621
2892
  cost,
2622
2893
  preload,
2894
+ graph,
2623
2895
  project
2624
2896
  }) => {
2625
2897
  const gateConfig = parseGateConfig(configText);
@@ -2672,6 +2944,7 @@ var evaluateGate = ({
2672
2944
  };
2673
2945
  });
2674
2946
  const validation = extractValidation({ waf, preload, project });
2947
+ const architecture = extractArchitectureInsights({ waf, preload, graph, project });
2675
2948
  const wellArchitected = {
2676
2949
  overall: {
2677
2950
  score: overallScore,
@@ -2710,7 +2983,8 @@ var evaluateGate = ({
2710
2983
  monthlyCost,
2711
2984
  wellArchitected,
2712
2985
  cost: costSummary,
2713
- validation
2986
+ validation,
2987
+ architecture
2714
2988
  };
2715
2989
  }
2716
2990
  const failures = [];
@@ -2749,7 +3023,8 @@ var evaluateGate = ({
2749
3023
  monthlyCost,
2750
3024
  wellArchitected,
2751
3025
  cost: costSummary,
2752
- validation
3026
+ validation,
3027
+ architecture
2753
3028
  };
2754
3029
  };
2755
3030
  var safeFetch = async (input) => {
@@ -2865,7 +3140,7 @@ var fetchReviewReports = async ({
2865
3140
  projectId,
2866
3141
  userId
2867
3142
  }) => {
2868
- const [cost, waf, preload] = await Promise.all([
3143
+ const [cost, waf, preload, graph] = await Promise.all([
2869
3144
  safeFetch({
2870
3145
  baseUrl,
2871
3146
  authToken: token,
@@ -2880,9 +3155,14 @@ var fetchReviewReports = async ({
2880
3155
  baseUrl,
2881
3156
  authToken: token,
2882
3157
  path: `/reports/preload/${encodeURIComponent(projectId)}?user_id=${encodeURIComponent(userId)}&include_payload=true`
3158
+ }) : Promise.resolve(void 0),
3159
+ userId ? safeFetch({
3160
+ baseUrl,
3161
+ authToken: token,
3162
+ path: `/projects/${encodeURIComponent(projectId)}/graph?user_id=${encodeURIComponent(userId)}`
2883
3163
  }) : Promise.resolve(void 0)
2884
3164
  ]);
2885
- return { cost, waf, preload };
3165
+ return { cost, waf, preload, graph };
2886
3166
  };
2887
3167
  var waitForReviewReports = async ({
2888
3168
  baseUrl,
@@ -2906,8 +3186,11 @@ var waitForReviewReports = async ({
2906
3186
  };
2907
3187
  var buildAiSummaryPrompt = (data) => [
2908
3188
  "Write a concise CloudEval pull request review summary in Markdown.",
2909
- "Focus on gate status, Well-Architected posture, cost posture, and security/operational risks.",
2910
- "Keep it under 160 words. Do not invent facts not present below.",
3189
+ "Return exactly two sections: Short Summary and Details.",
3190
+ "Short Summary: one dense paragraph under 45 words with gate status, Well-Architected posture, validation, and cost.",
3191
+ "Details: short bullets with bold labels only when useful, such as **Key risks:**, **Cost posture:**, and **Recommended next step:**.",
3192
+ "Keep the full response under 180 words. Do not invent facts not present below.",
3193
+ "Do not include citations, source markers, hidden tool ids, or HTML comments.",
2911
3194
  "",
2912
3195
  `Project: ${data.projectId}`,
2913
3196
  `Repository: ${data.repo ?? "unknown"}`,
@@ -2924,10 +3207,81 @@ var isTransientAiSummaryText = (text) => {
2924
3207
  if (!text?.trim()) {
2925
3208
  return false;
2926
3209
  }
2927
- return /too many requests|rate[- ]?limit|try again in a moment|temporarily unavailable/i.test(
3210
+ return /too many requests|rate[- ]?limit|try again in a moment|temporarily unavailable|something went wrong while processing|please try again or ask a different question|did not complete within/i.test(
2928
3211
  text
2929
3212
  );
2930
3213
  };
3214
+ var normalizeAiSummaryMarkdown = (text) => {
3215
+ return normalizeAiSummarySections(text).markdown;
3216
+ };
3217
+ var normalizeAiSummarySections = (text) => {
3218
+ const trimmed = String(text ?? "").trim();
3219
+ if (!trimmed) {
3220
+ return { shortSummary: "", detailsMarkdown: "", markdown: "" };
3221
+ }
3222
+ const withNewlines = sanitizeAiSummaryMarkdown(trimmed.replace(/\\n/g, "\n"));
3223
+ const requestMatch = /\bRequest:\s*/i.exec(withNewlines);
3224
+ const sourceText = requestMatch ? withNewlines.slice(requestMatch.index + requestMatch[0].length).split(/\n\s*\nThe request reached\b/i)[0].trim() || withNewlines : withNewlines;
3225
+ const sections = splitAiSummarySections(sourceText);
3226
+ return {
3227
+ ...sections,
3228
+ markdown: renderAiSummarySections(sections.shortSummary, sections.detailsMarkdown)
3229
+ };
3230
+ };
3231
+ var sanitizeAiSummaryMarkdown = (text) => text.replace(/<!--[\s\S]*?-->/g, "").replace(/\s*\[S_[A-Za-z0-9_:-]+\]/g, "").replace(/\n{3,}/g, "\n\n").trim();
3232
+ var stripAiSectionLabel = (text, label) => text.replace(new RegExp(`^\\s*#{0,6}\\s*\\*\\*?${label}\\*\\*?\\s*:?\\s*`, "i"), "").replace(new RegExp(`^\\s*${label}\\s*:?\\s*`, "i"), "").trim();
3233
+ var normalizeAiDetailHeadings = (text) => text.split("\n").map((line) => {
3234
+ const cleaned = line.replace(/^\s*#{1,6}\s*/, "").replace(/^\s*[-*]\s+/, "").trimEnd();
3235
+ const labelMatch = cleaned.match(/^\*\*(Key risks|Cost posture|Recommended next step|Recommendation|Validation|Impact):\*\*\s*(.*)$/i) ?? cleaned.match(/^\*\*(Key risks|Cost posture|Recommended next step|Recommendation|Validation|Impact)\*\*\s*:\s*(.*)$/i) ?? cleaned.match(/^(Key risks|Cost posture|Recommended next step|Recommendation|Validation|Impact)\s*:\s*(.*)$/i);
3236
+ if (!labelMatch) {
3237
+ return cleaned;
3238
+ }
3239
+ return `- **${labelMatch[1]}:** ${labelMatch[2]}`.trimEnd();
3240
+ }).join("\n").trim();
3241
+ var splitAiSummarySections = (text) => {
3242
+ const cleaned = sanitizeAiSummaryMarkdown(text).replace(/^\s*#{1,6}\s*AI summary\s*$/gim, "").trim();
3243
+ const shortMatch = /\bShort Summary\s*:\s*/i.exec(cleaned);
3244
+ const detailsMatch = /\bDetails\s*:\s*/i.exec(cleaned);
3245
+ if (shortMatch && detailsMatch && shortMatch.index < detailsMatch.index) {
3246
+ const shortSummary2 = stripAiSectionLabel(
3247
+ cleaned.slice(shortMatch.index, detailsMatch.index).trim(),
3248
+ "Short Summary"
3249
+ );
3250
+ const detailsMarkdown2 = normalizeAiDetailHeadings(
3251
+ stripAiSectionLabel(cleaned.slice(detailsMatch.index).trim(), "Details")
3252
+ );
3253
+ return { shortSummary: shortSummary2, detailsMarkdown: detailsMarkdown2 };
3254
+ }
3255
+ const paragraphs = cleaned.split(/\n\s*\n/).map((paragraph) => paragraph.trim()).filter(Boolean);
3256
+ const shortSummary = stripAiSectionLabel(paragraphs[0] ?? cleaned, "Short Summary");
3257
+ const detailsMarkdown = normalizeAiDetailHeadings(paragraphs.slice(1).join("\n\n"));
3258
+ return { shortSummary, detailsMarkdown };
3259
+ };
3260
+ var renderAiSummarySections = (shortSummary, detailsMarkdown) => {
3261
+ const lines = [`**Short summary:** ${shortSummary.trim()}`];
3262
+ if (detailsMarkdown.trim()) {
3263
+ lines.push(
3264
+ "",
3265
+ "<details>",
3266
+ "<summary>AI details</summary>",
3267
+ "",
3268
+ detailsMarkdown.trim(),
3269
+ "",
3270
+ "</details>"
3271
+ );
3272
+ }
3273
+ return lines.join("\n");
3274
+ };
3275
+ var aiSummaryAttemptTimeoutMs = () => {
3276
+ const raw = process.env.CLOUDEVAL_REVIEW_AI_ATTEMPT_TIMEOUT_MS;
3277
+ if (raw?.trim()) {
3278
+ const parsed = Number.parseInt(raw.trim(), 10);
3279
+ if (Number.isFinite(parsed) && parsed > 0) {
3280
+ return parsed;
3281
+ }
3282
+ }
3283
+ return 18e4;
3284
+ };
2931
3285
  var aiSummaryRetryDelaysMs = () => {
2932
3286
  const raw = process.env.CLOUDEVAL_REVIEW_AI_RETRY_DELAYS_MS;
2933
3287
  if (raw?.trim()) {
@@ -2945,11 +3299,23 @@ var generateAiSummaryAttempt = async ({
2945
3299
  agentProfileId,
2946
3300
  data
2947
3301
  }) => {
2948
- const core = await import("./dist-MQQKC6DZ.js");
3302
+ const core = await import("./dist-PEYJDO7A.js");
2949
3303
  const threadId = `review-${data.projectId}-${Date.now()}`;
2950
3304
  let markdown = "";
2951
3305
  let chatState = { ...core.initialChatState, threadId };
2952
- for await (const chunk of core.streamChat({
3306
+ const attemptTimeoutMs = aiSummaryAttemptTimeoutMs();
3307
+ let timedOut = false;
3308
+ let timeoutId;
3309
+ const timeoutPromise = new Promise((_, reject) => {
3310
+ timeoutId = setTimeout(() => {
3311
+ timedOut = true;
3312
+ reject(
3313
+ new Error(`AI summary did not complete within ${attemptTimeoutMs}ms.`)
3314
+ );
3315
+ }, attemptTimeoutMs);
3316
+ timeoutId.unref?.();
3317
+ });
3318
+ const iterator = core.streamChat({
2953
3319
  baseUrl,
2954
3320
  authToken: token,
2955
3321
  message: buildAiSummaryPrompt(data),
@@ -2977,35 +3343,94 @@ var generateAiSummaryAttempt = async ({
2977
3343
  completeAfterResponse: true,
2978
3344
  responseCompletionGraceMs: 250,
2979
3345
  streamIdleTimeoutMs: 12e4
2980
- })) {
2981
- chatState = core.reduceChunk(chatState, chunk);
2982
- const latestMessage = [...chatState.messages ?? []].reverse().find((message) => message.role === "assistant");
2983
- const chunkAssistantMessage = Array.isArray(chunk?.messages) ? [...chunk.messages].reverse().find((message) => message?.role === "assistant" && typeof message?.content === "string")?.content : void 0;
2984
- const content = chunk?.content;
2985
- if (typeof chunkAssistantMessage === "string" && chunkAssistantMessage.trim()) {
2986
- markdown = chunkAssistantMessage;
3346
+ });
3347
+ try {
3348
+ while (true) {
3349
+ const next = await Promise.race([iterator.next(), timeoutPromise]);
3350
+ if (next.done) {
3351
+ break;
3352
+ }
3353
+ const chunk = next.value;
3354
+ chatState = core.reduceChunk(chatState, chunk);
3355
+ const latestMessage = [...chatState.messages ?? []].reverse().find((message) => message.role === "assistant");
3356
+ const chunkAssistantMessage = Array.isArray(chunk?.messages) ? [...chunk.messages].reverse().find((message) => message?.role === "assistant" && typeof message?.content === "string")?.content : void 0;
3357
+ const content = chunk?.content;
3358
+ if (typeof chunkAssistantMessage === "string" && chunkAssistantMessage.trim()) {
3359
+ markdown = chunkAssistantMessage;
3360
+ }
3361
+ if (chunk.type === "responding" && typeof content === "string") {
3362
+ markdown = latestMessage?.content || `${markdown}${content}`;
3363
+ }
3364
+ }
3365
+ } finally {
3366
+ if (timeoutId) {
3367
+ clearTimeout(timeoutId);
2987
3368
  }
2988
- if (chunk.type === "responding" && typeof content === "string") {
2989
- markdown = latestMessage?.content || `${markdown}${content}`;
3369
+ if (timedOut) {
3370
+ await iterator.return?.(void 0).catch(() => void 0);
2990
3371
  }
2991
3372
  }
2992
3373
  const finalMessage = [...chatState.messages ?? []].reverse().find((message) => message.role === "assistant");
3374
+ const rawMarkdown = String(finalMessage?.content || markdown).trim();
3375
+ const normalized = normalizeAiSummarySections(rawMarkdown);
2993
3376
  return {
2994
3377
  enabled: true,
2995
3378
  status: "ok",
2996
3379
  mode,
2997
3380
  ...mode === "agent" ? { agentProfileId: agentProfileId ?? "architecture" } : {},
2998
3381
  ...model ? { model } : {},
2999
- markdown: String(finalMessage?.content || markdown).trim(),
3382
+ ...normalized,
3000
3383
  threadId
3001
3384
  };
3002
3385
  };
3003
3386
  var generateAiSummary = async (input) => {
3004
3387
  const retryDelays = aiSummaryRetryDelaysMs();
3005
3388
  let lastResult;
3389
+ let activeInput = input;
3390
+ let fallbackFromMode;
3006
3391
  for (let attemptIndex = 0; attemptIndex <= retryDelays.length; attemptIndex += 1) {
3007
- const result = await generateAiSummaryAttempt(input);
3392
+ let result;
3393
+ try {
3394
+ result = await generateAiSummaryAttempt(activeInput);
3395
+ } catch (error) {
3396
+ const message = error?.message ?? "AI summary failed";
3397
+ if (!isTransientAiSummaryText(message)) {
3398
+ throw error;
3399
+ }
3400
+ result = {
3401
+ enabled: true,
3402
+ status: "transient_error",
3403
+ mode: activeInput.mode,
3404
+ ...activeInput.mode === "agent" ? { agentProfileId: activeInput.agentProfileId ?? "architecture" } : {},
3405
+ ...activeInput.model ? { model: activeInput.model } : {},
3406
+ markdown: message,
3407
+ error: message
3408
+ };
3409
+ }
3008
3410
  result.attempts = attemptIndex + 1;
3411
+ if (fallbackFromMode) {
3412
+ result.fallbackFromMode = fallbackFromMode;
3413
+ }
3414
+ const normalizedSummary = typeof result.shortSummary === "string" || typeof result.detailsMarkdown === "string" ? {
3415
+ shortSummary: String(result.shortSummary ?? "").trim(),
3416
+ detailsMarkdown: String(result.detailsMarkdown ?? "").trim(),
3417
+ markdown: renderAiSummarySections(
3418
+ String(result.shortSummary ?? "").trim(),
3419
+ String(result.detailsMarkdown ?? "").trim()
3420
+ )
3421
+ } : normalizeAiSummarySections(result.markdown);
3422
+ result = { ...result, ...normalizedSummary };
3423
+ if (isTransientAiSummaryText(result.markdown)) {
3424
+ const normalizedError = normalizeAiSummaryMarkdown(result.error);
3425
+ if (normalizedError && !isTransientAiSummaryText(normalizedError)) {
3426
+ result = {
3427
+ ...result,
3428
+ ...normalizeAiSummarySections(normalizedError)
3429
+ };
3430
+ result.status = "ok";
3431
+ delete result.error;
3432
+ }
3433
+ }
3009
3434
  lastResult = result;
3010
3435
  if (!isTransientAiSummaryText(result.markdown)) {
3011
3436
  return result;
@@ -3015,14 +3440,23 @@ var generateAiSummary = async (input) => {
3015
3440
  break;
3016
3441
  }
3017
3442
  await sleep2(retryDelay);
3443
+ if (activeInput.mode === "agent") {
3444
+ fallbackFromMode = "agent";
3445
+ activeInput = {
3446
+ ...input,
3447
+ mode: "ask",
3448
+ agentProfileId: void 0
3449
+ };
3450
+ }
3018
3451
  }
3019
3452
  return {
3020
3453
  ...lastResult ?? {},
3021
3454
  enabled: true,
3022
3455
  status: "unavailable",
3023
- mode: input.mode,
3024
- ...input.mode === "agent" ? { agentProfileId: input.agentProfileId ?? "architecture" } : {},
3456
+ mode: activeInput.mode,
3457
+ ...activeInput.mode === "agent" ? { agentProfileId: activeInput.agentProfileId ?? "architecture" } : {},
3025
3458
  ...input.model ? { model: input.model } : {},
3459
+ ...fallbackFromMode ? { fallbackFromMode } : {},
3026
3460
  attempts: lastResult?.attempts ?? retryDelays.length + 1,
3027
3461
  error: lastResult?.markdown || "AI summary unavailable",
3028
3462
  markdown: "AI summary unavailable: CloudEval AI was rate-limited. Retry the workflow or rerun `cloudeval review`."
@@ -3030,18 +3464,55 @@ var generateAiSummary = async (input) => {
3030
3464
  };
3031
3465
  var buildMarkdownSummary = (data) => {
3032
3466
  const gateStatus = String(data.gate?.status ?? "unknown").toUpperCase();
3033
- const score = data.gate?.overallScore ?? "unknown";
3467
+ const score = data.gate?.overallScore ?? data.gate?.wellArchitected?.overall?.score;
3034
3468
  const cost = data.gate?.cost?.monthly;
3035
3469
  const validation = data.gate?.validation;
3470
+ const architecture = data.gate?.architecture;
3036
3471
  const projectLabel = String(data.project?.name ?? data.projectName ?? data.projectId);
3037
3472
  const projectDisplay = markdownLink(projectLabel, data.project?.url ?? data.projectUrl);
3038
3473
  const source = data.repo ? `${data.repo}${data.ref ? ` @ ${data.ref}` : ""}` : data.ref ?? "unknown source";
3039
3474
  const commit = String(data.commitSha ?? "unknown").slice(0, 12);
3040
- const pillarLines = Array.isArray(data.gate?.wellArchitected?.pillars) ? data.gate.wellArchitected.pillars.map(
3041
- (pillar) => `- ${pillar.label}: ${pillar.score} - ${String(pillar.status ?? "unknown").toUpperCase()}`
3042
- ) : [];
3475
+ const pillarLines = Array.isArray(data.gate?.wellArchitected?.pillars) ? data.gate.wellArchitected.pillars.map((pillar) => {
3476
+ const rating = scoreRating(pillar.score);
3477
+ return `| ${pillar.label} | **${formatScore(pillar.score)}** | ${scoreRatingIcon(rating)} ${rating ?? "UNKNOWN"} |`;
3478
+ }) : [];
3479
+ const riskLines = [
3480
+ ["High-risk findings", data.gate?.wellArchitected?.risks?.high],
3481
+ ["Medium-risk findings", data.gate?.wellArchitected?.risks?.medium],
3482
+ ["Critical findings", data.gate?.wellArchitected?.risks?.critical]
3483
+ ].filter(([, value]) => numberFrom(value) !== void 0).map(([label, value]) => `- ${label}: **${displayNumber(value)}**`);
3484
+ const costServices = reconcileCostServiceRows(
3485
+ costServiceRows(data.gate?.cost?.topServices, cost?.currency),
3486
+ cost?.amount,
3487
+ cost?.currency
3488
+ );
3489
+ const positiveCostServices = costServices.filter((service) => service.amount > 0);
3490
+ const architectureLines = [
3491
+ ["Resources", architecture?.resources],
3492
+ ["Relationships", architecture?.relationships],
3493
+ ["Resource types", architecture?.resourceTypes]
3494
+ ].filter(([, value]) => numberFrom(value) !== void 0).map(([label, value]) => `- ${label}: **${displayNumber(value)}**`);
3495
+ const density = numberFrom(architecture?.relationshipDensity);
3496
+ if (density !== void 0) {
3497
+ architectureLines.push(
3498
+ `- Graph connectivity: **${trimNumber(density, 2)} relationships per resource**`
3499
+ );
3500
+ }
3501
+ const resourceCount = numberFrom(architecture?.resources);
3502
+ const resourceTypeCount = numberFrom(architecture?.resourceTypes);
3503
+ if (resourceCount !== void 0 && resourceTypeCount !== void 0) {
3504
+ architectureLines.push(
3505
+ `- Resource diversity: **${displayNumber(resourceTypeCount)} types across ${displayNumber(resourceCount)} resources**`
3506
+ );
3507
+ }
3508
+ const overallRating = scoreRating(score);
3043
3509
  const lines = [
3044
- `**${gateStatus}** for ${projectDisplay}: Well-Architected ${score}, cost ${formatMoney(cost?.amount, cost?.currency)}, ${compactValidation(validation)}.`,
3510
+ `${statusIcon(data.gate?.status)} **Overall** : ${gateStatus}`,
3511
+ `${scoreRatingIcon(overallRating)} Well-Architected Posture: ${formatScore(score)} (${overallRating ?? "UNKNOWN"})`,
3512
+ validationSummaryLine(validation),
3513
+ policySummaryLine(validation),
3514
+ costSummaryLine(cost),
3515
+ `**Cloudeval Project**: ${projectDisplay}`,
3045
3516
  "",
3046
3517
  `Source: \`${source}\` \xB7 commit \`${commit}\``
3047
3518
  ];
@@ -3055,38 +3526,75 @@ var buildMarkdownSummary = (data) => {
3055
3526
  lines.push(
3056
3527
  "",
3057
3528
  "<details>",
3058
- "<summary>Well-Architected details</summary>",
3529
+ "<summary>Well-Architected drilldown</summary>",
3530
+ "",
3531
+ ...riskLines,
3059
3532
  "",
3060
- `- Overall score: ${score}`,
3533
+ "| Pillar | Score | Rating |",
3534
+ "| --- | ---: | --- |",
3061
3535
  ...pillarLines,
3062
3536
  "",
3063
3537
  "</details>"
3064
3538
  );
3065
3539
  }
3066
3540
  if (cost?.amount !== void 0 || cost?.threshold !== void 0) {
3067
- const costLines = [`- Monthly estimate: ${formatMoney(cost?.amount, cost?.currency)}`];
3541
+ const costLines = [];
3068
3542
  if (data.gate?.cost?.estimatedSavings?.amount !== void 0) {
3069
3543
  costLines.push(
3070
- `- Estimated savings: ${formatMoney(data.gate.cost.estimatedSavings.amount, data.gate.cost.estimatedSavings.currency)}`
3544
+ `- Estimated savings: **${formatMonthlyMoney(data.gate.cost.estimatedSavings.amount, data.gate.cost.estimatedSavings.currency)}**`
3545
+ );
3546
+ }
3547
+ if (costServices.length) {
3548
+ costLines.push(
3549
+ "",
3550
+ "| Service | Monthly cost |",
3551
+ "| --- | ---: |",
3552
+ ...costServices.map(
3553
+ (service) => `| ${service.name} | **${formatMonthlyMoney(service.amount, service.currency)}** |`
3554
+ )
3555
+ );
3556
+ }
3557
+ if (positiveCostServices.length) {
3558
+ costLines.push(
3559
+ "",
3560
+ "```mermaid",
3561
+ "pie title Monthly cost by service",
3562
+ ...positiveCostServices.map(
3563
+ (service) => ` "${mermaidLabel(service.name)}" : ${trimNumber(service.amount, 3)}`
3564
+ ),
3565
+ "```"
3071
3566
  );
3072
3567
  }
3568
+ if (costLines.length) {
3569
+ lines.push(
3570
+ "",
3571
+ "<details>",
3572
+ "<summary>Cost drilldown</summary>",
3573
+ "",
3574
+ ...costLines,
3575
+ "",
3576
+ "</details>"
3577
+ );
3578
+ }
3579
+ }
3580
+ if (validation) {
3073
3581
  lines.push(
3074
3582
  "",
3075
3583
  "<details>",
3076
- "<summary>Cost details</summary>",
3584
+ "<summary>Validation details</summary>",
3077
3585
  "",
3078
- ...costLines,
3586
+ ...validationDetailLines(validation),
3079
3587
  "",
3080
3588
  "</details>"
3081
3589
  );
3082
3590
  }
3083
- if (validation) {
3591
+ if (architectureLines.length) {
3084
3592
  lines.push(
3085
3593
  "",
3086
3594
  "<details>",
3087
- "<summary>Validation details</summary>",
3595
+ "<summary>Architecture insights</summary>",
3088
3596
  "",
3089
- `- ${formatValidation(validation)}`,
3597
+ ...architectureLines,
3090
3598
  "",
3091
3599
  "</details>"
3092
3600
  );
@@ -3150,7 +3658,7 @@ var registerReviewCommand = (program2, deps) => {
3150
3658
  9e5
3151
3659
  )
3152
3660
  }) : void 0;
3153
- const [{ cost, waf, preload }, configText] = await Promise.all([
3661
+ const [{ cost, waf, preload, graph }, configText] = await Promise.all([
3154
3662
  waitForReviewReports({
3155
3663
  baseUrl: context.baseUrl,
3156
3664
  token: context.token,
@@ -3188,8 +3696,8 @@ var registerReviewCommand = (program2, deps) => {
3188
3696
  commitSha,
3189
3697
  sourceRoot,
3190
3698
  sync: reviewSyncStatus(sync, finalStatus),
3191
- reports: reviewReportStatuses({ cost, waf, preload }),
3192
- gate: evaluateGate({ configText, waf, cost, preload, project })
3699
+ reports: reviewReportStatuses({ cost, waf, preload, graph }),
3700
+ gate: evaluateGate({ configText, waf, cost, preload, graph, project })
3193
3701
  };
3194
3702
  if (options.aiSummary !== false) {
3195
3703
  try {
@@ -4567,7 +5075,7 @@ var runChatRecipe = async (recipe, prompt2, options, command, deps) => {
4567
5075
  });
4568
5076
  progressWriter.write({ type: "auth", step: "auth", message: "Resolving authentication" });
4569
5077
  const context = await resolveAuthContext(options, command, deps);
4570
- const core = await import("./dist-MQQKC6DZ.js");
5078
+ const core = await import("./dist-PEYJDO7A.js");
4571
5079
  progressWriter.write({
4572
5080
  type: "request",
4573
5081
  step: "project",
@@ -5652,21 +6160,36 @@ var readWorkspaceConfig = (content) => {
5652
6160
  };
5653
6161
  };
5654
6162
  var generateWorkspaceConfig = (entry, parameters, sourceEntry) => {
5655
- const parameterLine = parameters ? ` parameters: ${parameters}
5656
- ` : "";
6163
+ const parameterLine = parameters ? ` parameters: ${parameters}` : "";
5657
6164
  const sourceEntryLine = sourceEntry ? ` source_entry: ${sourceEntry}` : "";
5658
6165
  return [
6166
+ "# CloudEval config v1. Paths are relative to this workspace root.",
6167
+ "# Visualization source for diagrams and reports.",
5659
6168
  "version: 1",
5660
6169
  "stacks:",
5661
- " - id: main",
6170
+ " - id: primary-architecture",
6171
+ " name: Primary architecture",
5662
6172
  ` entry: ${entry}`,
5663
6173
  sourceEntryLine,
5664
- parameterLine.trimEnd(),
6174
+ parameterLine,
5665
6175
  "resolve:",
6176
+ " # Follow relative ARM templateLink files when building the analysis bundle.",
5666
6177
  " linked_templates: true",
5667
6178
  "analysis:",
6179
+ " # Run the normal import -> resolve -> report refresh pipeline after upload.",
5668
6180
  " auto_resolve_on_import: true",
5669
6181
  " auto_refresh_on_resolve: true",
6182
+ "",
6183
+ "# Optional CI gates for `cloudeval review` and GitHub Actions.",
6184
+ "# Uncomment and tune these when pull requests should be blocked by CloudEval.",
6185
+ "# ci:",
6186
+ "# gates:",
6187
+ "# enforcement: block_pull_request",
6188
+ "# minimum_well_architected_score: 80",
6189
+ "# minimum_pillar_score: 75",
6190
+ "# fail_when_high_risk_findings_exist: true",
6191
+ "# fail_when_validation_fails: true",
6192
+ "# max_monthly_cost_usd: 500",
5670
6193
  ""
5671
6194
  ].filter((line) => line.length > 0).join("\n");
5672
6195
  };
@@ -6036,7 +6559,7 @@ var configureDiagramExportCommand = (command, deps) => addAuthOptions(command, d
6036
6559
  const context = requireAuthUser(
6037
6560
  await resolveAuthContext(options, actionCommand, deps)
6038
6561
  );
6039
- const core = await import("./dist-MQQKC6DZ.js");
6562
+ const core = await import("./dist-PEYJDO7A.js");
6040
6563
  const projects = await core.getProjects(
6041
6564
  context.baseUrl,
6042
6565
  context.token,
@@ -6113,7 +6636,7 @@ var registerProjectsCommand = (program2, deps) => {
6113
6636
  addCommon(addAuthOptions(projects.command("list").description("List projects"), deps.defaultBaseUrl)).action(async (options, command) => {
6114
6637
  try {
6115
6638
  const context = await resolveAuthContext(options, command, deps);
6116
- const core = await import("./dist-MQQKC6DZ.js");
6639
+ const core = await import("./dist-PEYJDO7A.js");
6117
6640
  const data = await listProjectsForContext(core, context);
6118
6641
  const url = buildFrontendUrl({ baseUrl: frontendBase(context, options), target: "projects" });
6119
6642
  await writeProjectListOutput({ data, options, frontendUrl: url });
@@ -6131,7 +6654,7 @@ var registerProjectsCommand = (program2, deps) => {
6131
6654
  ).action(async (id, options, command) => {
6132
6655
  try {
6133
6656
  const context = await resolveAuthContext(options, command, deps);
6134
- const core = await import("./dist-MQQKC6DZ.js");
6657
+ const core = await import("./dist-PEYJDO7A.js");
6135
6658
  const list = await listProjectsForContext(core, context);
6136
6659
  const data = list.find((project) => project.id === id);
6137
6660
  if (!data) {
@@ -6196,7 +6719,7 @@ var registerProjectsCommand = (program2, deps) => {
6196
6719
  try {
6197
6720
  assertSingleProjectSource(options);
6198
6721
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
6199
- const core = await import("./dist-MQQKC6DZ.js");
6722
+ const core = await import("./dist-PEYJDO7A.js");
6200
6723
  const template = await fileBlob(options.templateFile);
6201
6724
  const parameters = await fileBlob(options.parametersFile);
6202
6725
  const workspace = options.workspaceDir ? await collectWorkspaceFiles(options.workspaceDir, options) : void 0;
@@ -6325,7 +6848,7 @@ var registerConnectionsCommand = (program2, deps) => {
6325
6848
  addCommon2(addAuthOptions(connections.command("list").description("List connections"), deps.defaultBaseUrl)).action(async (options, command) => {
6326
6849
  try {
6327
6850
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
6328
- const core = await import("./dist-MQQKC6DZ.js");
6851
+ const core = await import("./dist-PEYJDO7A.js");
6329
6852
  const data = await core.listConnections({
6330
6853
  baseUrl: context.baseUrl,
6331
6854
  authToken: context.token,
@@ -6350,7 +6873,7 @@ var registerConnectionsCommand = (program2, deps) => {
6350
6873
  ).action(async (id, options, command) => {
6351
6874
  try {
6352
6875
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
6353
- const core = await import("./dist-MQQKC6DZ.js");
6876
+ const core = await import("./dist-PEYJDO7A.js");
6354
6877
  const data = await core.getConnection({
6355
6878
  baseUrl: context.baseUrl,
6356
6879
  authToken: context.token,
@@ -6688,7 +7211,7 @@ var checkoutReturnUrl = (context, options) => options.returnTo || billingUrl(con
6688
7211
  var runTopUpCheckout = async (commandName, packId, options, command, deps) => {
6689
7212
  try {
6690
7213
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
6691
- const core = await import("./dist-MQQKC6DZ.js");
7214
+ const core = await import("./dist-PEYJDO7A.js");
6692
7215
  const returnTo = checkoutReturnUrl(context, options);
6693
7216
  const session = await core.createTopUpCheckoutSession({
6694
7217
  baseUrl: context.baseUrl,
@@ -6728,7 +7251,7 @@ var registerBillingCommands = (program2, deps) => {
6728
7251
  ).action(async (options, command) => {
6729
7252
  try {
6730
7253
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
6731
- const core = await import("./dist-MQQKC6DZ.js");
7254
+ const core = await import("./dist-PEYJDO7A.js");
6732
7255
  const range = rangeToDates("30d");
6733
7256
  const [entitlement, usageSummary] = await Promise.all([
6734
7257
  core.getBillingEntitlement({
@@ -6758,7 +7281,7 @@ var registerBillingCommands = (program2, deps) => {
6758
7281
  addCommon3(addAuthOptions(billing.command("summary").description("Show billing summary"), deps.defaultBaseUrl)).action(async (options, command) => {
6759
7282
  try {
6760
7283
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
6761
- const core = await import("./dist-MQQKC6DZ.js");
7284
+ const core = await import("./dist-PEYJDO7A.js");
6762
7285
  const range = rangeToDates("30d");
6763
7286
  const [entitlement, subscriptionStatus, usageSummary] = await Promise.all([
6764
7287
  core.getBillingEntitlement({ baseUrl: context.baseUrl, authToken: context.token }),
@@ -6794,7 +7317,7 @@ var registerBillingCommands = (program2, deps) => {
6794
7317
  addCommon3(addAuthOptions(billing.command("plans").description("Show billing plans"), deps.defaultBaseUrl)).action(async (options, command) => {
6795
7318
  try {
6796
7319
  const context = await resolveAuthContext(options, command, deps);
6797
- const core = await import("./dist-MQQKC6DZ.js");
7320
+ const core = await import("./dist-PEYJDO7A.js");
6798
7321
  const data = await core.getBillingConfig({ baseUrl: context.baseUrl, authToken: context.token });
6799
7322
  const url = billingUrl(context, { ...options, tab: "plans" });
6800
7323
  await write("billing plans", data, options, url);
@@ -6806,7 +7329,7 @@ var registerBillingCommands = (program2, deps) => {
6806
7329
  addCommon3(addAuthOptions(billing.command("usage").description("Show billing usage summary"), deps.defaultBaseUrl)).option("--range <range>", "Usage range: 7d, 30d, 90d, all", "30d").option("--start-at <iso>", "Start timestamp").option("--end-at <iso>", "End timestamp").option("--granularity <value>", "Granularity: hour, day, month", "day").option("--action-type <type>", "Action type filter").option("--model <name>", "Model filter").option("--outcome <outcome>", "Outcome filter").option("--charge-status <status>", "Charge status filter").action(async (options, command) => {
6807
7330
  try {
6808
7331
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
6809
- const core = await import("./dist-MQQKC6DZ.js");
7332
+ const core = await import("./dist-PEYJDO7A.js");
6810
7333
  const range = rangeToDates(options.range);
6811
7334
  const data = await core.getBillingUsageSummary({
6812
7335
  baseUrl: context.baseUrl,
@@ -6829,7 +7352,7 @@ var registerBillingCommands = (program2, deps) => {
6829
7352
  addCommon3(addAuthOptions(billing.command("ledger").description("Show billing ledger"), deps.defaultBaseUrl)).option("--range <range>", "Usage range: 7d, 30d, 90d, all", "30d").option("--start-at <iso>", "Start timestamp").option("--end-at <iso>", "End timestamp").option("--action-type <type>", "Action type filter").option("--model <name>", "Model filter").option("--outcome <outcome>", "Outcome filter").option("--charge-status <status>", "Charge status filter").option("--limit <n>", "Page size", "25").option("--cursor <cursor>", "Pagination cursor").action(async (options, command) => {
6830
7353
  try {
6831
7354
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
6832
- const core = await import("./dist-MQQKC6DZ.js");
7355
+ const core = await import("./dist-PEYJDO7A.js");
6833
7356
  const range = rangeToDates(options.range);
6834
7357
  const data = await core.getBillingUsageLedger({
6835
7358
  baseUrl: context.baseUrl,
@@ -6857,7 +7380,7 @@ var registerBillingCommands = (program2, deps) => {
6857
7380
  addCommon3(addAuthOptions(billing.command(name).description(`Show billing ${name}`), deps.defaultBaseUrl)).option("--limit <n>", "Result limit", "25").action(async (options, command) => {
6858
7381
  try {
6859
7382
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
6860
- const core = await import("./dist-MQQKC6DZ.js");
7383
+ const core = await import("./dist-PEYJDO7A.js");
6861
7384
  const data = await core[getter]({
6862
7385
  baseUrl: context.baseUrl,
6863
7386
  authToken: context.token,
@@ -6875,7 +7398,7 @@ var registerBillingCommands = (program2, deps) => {
6875
7398
  addCommon3(addAuthOptions(topups, deps.defaultBaseUrl)).option("--limit <n>", "Result limit", "25").action(async (options, command) => {
6876
7399
  try {
6877
7400
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
6878
- const core = await import("./dist-MQQKC6DZ.js");
7401
+ const core = await import("./dist-PEYJDO7A.js");
6879
7402
  const data = await core.getTopUpPacks({
6880
7403
  baseUrl: context.baseUrl,
6881
7404
  authToken: context.token
@@ -7404,12 +7927,13 @@ var getRule = async (input) => fetchCloudEvalJson({
7404
7927
 
7405
7928
  // src/telemetry.ts
7406
7929
  import os3 from "os";
7930
+ import { createHash } from "crypto";
7407
7931
 
7408
7932
  // src/telemetryConnectionString.generated.ts
7409
7933
  var PACKAGED_APPLICATIONINSIGHTS_CONNECTION_STRING = "InstrumentationKey=ca7b6ae2-ce35-4e67-8756-439ebe2da618;IngestionEndpoint=https://westeurope-5.in.applicationinsights.azure.com/;LiveEndpoint=https://westeurope.livediagnostics.monitor.azure.com/;ApplicationId=28327903-cb61-4210-bed7-d4d8f9f65cfe";
7410
7934
 
7411
7935
  // src/telemetry.ts
7412
- var TELEMETRY_SCHEMA_VERSION = "1";
7936
+ var TELEMETRY_SCHEMA_VERSION = "2";
7413
7937
  var TRUE_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
7414
7938
  var FALSE_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
7415
7939
  var PROPERTY_ALLOWLIST = /* @__PURE__ */ new Set([
@@ -7421,23 +7945,20 @@ var PROPERTY_ALLOWLIST = /* @__PURE__ */ new Set([
7421
7945
  "command",
7422
7946
  "completionShell",
7423
7947
  "completions",
7424
- "email",
7425
7948
  "errorCategory",
7426
7949
  "exitCode",
7427
- "firstName",
7428
7950
  "format",
7429
- "fullName",
7430
7951
  "installSource",
7431
7952
  "installerResult",
7432
7953
  "installerType",
7433
7954
  "interactive",
7434
- "lastName",
7435
7955
  "mcpSetup",
7436
7956
  "nodeVersion",
7437
7957
  "os",
7438
7958
  "osVersionMajor",
7439
7959
  "previousCliVersion",
7440
7960
  "requestedVersion",
7961
+ "requestId",
7441
7962
  "resolvedVersion",
7442
7963
  "runtime",
7443
7964
  "subcommand",
@@ -7447,8 +7968,10 @@ var PROPERTY_ALLOWLIST = /* @__PURE__ */ new Set([
7447
7968
  "toolName",
7448
7969
  "toolset",
7449
7970
  "targetCliVersion",
7971
+ "traceId",
7450
7972
  "tuiInitialTab",
7451
- "updateAction"
7973
+ "updateAction",
7974
+ "user_hash"
7452
7975
  ]);
7453
7976
  var MEASUREMENT_ALLOWLIST = /* @__PURE__ */ new Set(["durationMs"]);
7454
7977
  var trimString = (value) => {
@@ -7516,16 +8039,12 @@ var buildTelemetryUserProperties = (user) => {
7516
8039
  if (!user || typeof user !== "object") {
7517
8040
  return {};
7518
8041
  }
7519
- const email = trimString(user.email);
7520
- const fullName = trimString(user.fullName) || trimString(user.full_name) || trimString(user.name);
7521
- const firstName = trimString(user.firstName);
7522
- const lastName = trimString(user.lastName);
7523
- const nameParts = fullName?.split(/\s+/).filter(Boolean) || [];
8042
+ const internalId = trimString(user.id) || trimString(user.userId) || trimString(user.user_id) || trimString(user.accountId) || trimString(user.account_id);
8043
+ if (!internalId) {
8044
+ return {};
8045
+ }
7524
8046
  return {
7525
- ...email ? { email } : {},
7526
- ...firstName || nameParts[0] ? { firstName: firstName || nameParts[0] } : {},
7527
- ...lastName || nameParts.length > 1 ? { lastName: lastName || nameParts[nameParts.length - 1] } : {},
7528
- ...fullName ? { fullName } : {}
8047
+ user_hash: `h_${createHash("sha256").update("cloudeval-cli:user:").update(internalId).digest("hex").slice(0, 32)}`
7529
8048
  };
7530
8049
  };
7531
8050
  var classifyTelemetryError = (error) => {
@@ -7585,6 +8104,16 @@ var createApplicationInsightsClient = async (connectionString) => {
7585
8104
  disableDiskRetryCaching(client);
7586
8105
  return client;
7587
8106
  };
8107
+ var setTelemetryClientRole = (client) => {
8108
+ try {
8109
+ const context = client.context;
8110
+ const cloudRoleKey = context?.keys?.cloudRole;
8111
+ if (cloudRoleKey && context?.tags) {
8112
+ context.tags[cloudRoleKey] = "cloudeval-cli";
8113
+ }
8114
+ } catch {
8115
+ }
8116
+ };
7588
8117
  var disableDiskRetryCaching = (client) => {
7589
8118
  try {
7590
8119
  client.setUseDiskRetryCaching?.(false);
@@ -7641,6 +8170,7 @@ var createCliTelemetry = async (options) => {
7641
8170
  let client;
7642
8171
  try {
7643
8172
  client = options.clientFactory ? options.clientFactory(connectionString) : await createApplicationInsightsClient(connectionString);
8173
+ setTelemetryClientRole(client);
7644
8174
  } catch {
7645
8175
  return createNoopTelemetry();
7646
8176
  }
@@ -9546,7 +10076,7 @@ var reportsFrontendUrl = (config, input) => buildFrontendUrl({
9546
10076
  reportVerbosity: input.reportVerbosity
9547
10077
  });
9548
10078
  var resolveAuth = async (config, options = {}) => {
9549
- const core = await import("./dist-MQQKC6DZ.js");
10079
+ const core = await import("./dist-PEYJDO7A.js");
9550
10080
  core.assertSecureBaseUrl(config.baseUrl);
9551
10081
  let token;
9552
10082
  try {
@@ -9642,7 +10172,7 @@ var assertModelAvailable = async (config, token) => {
9642
10172
  if (!config.model) {
9643
10173
  return;
9644
10174
  }
9645
- const core = await import("./dist-MQQKC6DZ.js");
10175
+ const core = await import("./dist-PEYJDO7A.js");
9646
10176
  try {
9647
10177
  const response = await fetch(
9648
10178
  `${core.normalizeApiBase(config.baseUrl)}/models`,
@@ -9899,7 +10429,7 @@ var buildToolHandlers = (serverOptions) => {
9899
10429
  });
9900
10430
  handlers.set("agent_profiles_list", async (args) => {
9901
10431
  const config = await resolveInvocationConfig(serverOptions, args);
9902
- const core = await import("./dist-MQQKC6DZ.js");
10432
+ const core = await import("./dist-PEYJDO7A.js");
9903
10433
  const data = await listProfilesForDiscovery(core, config.baseUrl);
9904
10434
  return withEnvelope({
9905
10435
  command: "agents list",
@@ -9912,7 +10442,7 @@ var buildToolHandlers = (serverOptions) => {
9912
10442
  throw new Error("profileId is required.");
9913
10443
  }
9914
10444
  const config = await resolveInvocationConfig(serverOptions, args);
9915
- const core = await import("./dist-MQQKC6DZ.js");
10445
+ const core = await import("./dist-PEYJDO7A.js");
9916
10446
  const data = await getProfileForDiscovery(core, config.baseUrl, profileId);
9917
10447
  return withEnvelope({
9918
10448
  command: "agents show",
@@ -10549,7 +11079,7 @@ var buildToolHandlers = (serverOptions) => {
10549
11079
  });
10550
11080
  handlers.set("auth_status", async (args) => {
10551
11081
  const config = await resolveInvocationConfig(serverOptions, args);
10552
- const core = await import("./dist-MQQKC6DZ.js");
11082
+ const core = await import("./dist-PEYJDO7A.js");
10553
11083
  const data = await core.getAuthStatus(config.baseUrl, { validate: true });
10554
11084
  return withEnvelope({
10555
11085
  command: "auth status",
@@ -10558,7 +11088,7 @@ var buildToolHandlers = (serverOptions) => {
10558
11088
  });
10559
11089
  handlers.set("status", async (args) => {
10560
11090
  const config = await resolveInvocationConfig(serverOptions, args);
10561
- const core = await import("./dist-MQQKC6DZ.js");
11091
+ const core = await import("./dist-PEYJDO7A.js");
10562
11092
  const auth = await core.getAuthStatus(config.baseUrl, { validate: true });
10563
11093
  return withEnvelope({
10564
11094
  command: "status",
@@ -10589,7 +11119,7 @@ var buildToolHandlers = (serverOptions) => {
10589
11119
  }
10590
11120
  ];
10591
11121
  try {
10592
- const core = await import("./dist-MQQKC6DZ.js");
11122
+ const core = await import("./dist-PEYJDO7A.js");
10593
11123
  core.assertSecureBaseUrl(config.baseUrl);
10594
11124
  checks.push({
10595
11125
  id: "base-url-secure",
@@ -11109,7 +11639,7 @@ var buildToolHandlers = (serverOptions) => {
11109
11639
  } catch {
11110
11640
  token = config.accessKey;
11111
11641
  }
11112
- const core = await import("./dist-MQQKC6DZ.js");
11642
+ const core = await import("./dist-PEYJDO7A.js");
11113
11643
  const data = await core.getBillingConfig({
11114
11644
  baseUrl: config.baseUrl,
11115
11645
  authToken: token
@@ -11963,7 +12493,7 @@ var registerCapabilitiesCommand = (program2, deps) => {
11963
12493
  warnIfAccessKeyFromCliOption(options, command);
11964
12494
  let data = capabilities;
11965
12495
  if (options.live) {
11966
- const core = await import("./dist-MQQKC6DZ.js");
12496
+ const core = await import("./dist-PEYJDO7A.js");
11967
12497
  const baseUrl = await deps.resolveBaseUrl(options, command);
11968
12498
  const accessKey = options.accessKeyStdin ? await deps.readStdinValue() : options.accessKey;
11969
12499
  const token = await core.getAuthToken({ accessKey, baseUrl });
@@ -12101,7 +12631,7 @@ var writeCredentialOutput = async (input) => {
12101
12631
  };
12102
12632
  var resolveCoreAuth = async (options, command, deps) => {
12103
12633
  const context = await resolveAuthContext(options, command, deps);
12104
- const core = await import("./dist-MQQKC6DZ.js");
12634
+ const core = await import("./dist-PEYJDO7A.js");
12105
12635
  return { ...context, core };
12106
12636
  };
12107
12637
  var parseCapabilities = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean);
@@ -12418,7 +12948,7 @@ var registerAgentsCommand = (program2, deps) => {
12418
12948
  const agents = program2.command("agents").description("CloudEval Agent Profile utilities");
12419
12949
  addAgentOutputOptions(agents.command("list").description("List Agent Profiles"), deps).action(async (options, command) => {
12420
12950
  const baseUrl = await deps.resolveBaseUrl(options, command);
12421
- const core = await import("./dist-MQQKC6DZ.js");
12951
+ const core = await import("./dist-PEYJDO7A.js");
12422
12952
  core.assertSecureBaseUrl(baseUrl);
12423
12953
  const data = await listProfilesForDiscovery2(core, baseUrl);
12424
12954
  await writeProfiles({
@@ -12434,7 +12964,7 @@ var registerAgentsCommand = (program2, deps) => {
12434
12964
  deps
12435
12965
  ).action(async (profileId, options, command) => {
12436
12966
  const baseUrl = await deps.resolveBaseUrl(options, command);
12437
- const core = await import("./dist-MQQKC6DZ.js");
12967
+ const core = await import("./dist-PEYJDO7A.js");
12438
12968
  core.assertSecureBaseUrl(baseUrl);
12439
12969
  const data = await getProfileForDiscovery2(core, baseUrl, profileId);
12440
12970
  await writeProfiles({
@@ -12453,7 +12983,7 @@ var registerAgentsCommand = (program2, deps) => {
12453
12983
  const cliProfile = getActiveConfigProfile(command);
12454
12984
  const cliConfig = await loadCliConfig(cliProfile);
12455
12985
  const auth = await resolveAuthContext(options, command, deps);
12456
- const core = await import("./dist-MQQKC6DZ.js");
12986
+ const core = await import("./dist-PEYJDO7A.js");
12457
12987
  const profileResponse = await core.getAgentProfile({
12458
12988
  baseUrl: auth.baseUrl,
12459
12989
  authToken: auth.token,
@@ -12951,7 +13481,7 @@ var registerDiagnosticsCommands = (program2, deps) => {
12951
13481
  const baseUrl = await deps.resolveBaseUrl(options, command);
12952
13482
  const profile = getActiveConfigProfile(command);
12953
13483
  const config = await loadCliConfig(profile);
12954
- const core = await import("./dist-MQQKC6DZ.js");
13484
+ const core = await import("./dist-PEYJDO7A.js");
12955
13485
  const auth = await core.getAuthStatus(baseUrl, { validate: true });
12956
13486
  if (options.format === "text" || !options.format) {
12957
13487
  process.stdout.write(
@@ -13001,7 +13531,7 @@ var registerDiagnosticsCommands = (program2, deps) => {
13001
13531
  detail: getCliConfigPath(profile)
13002
13532
  });
13003
13533
  try {
13004
- const core = await import("./dist-MQQKC6DZ.js");
13534
+ const core = await import("./dist-PEYJDO7A.js");
13005
13535
  core.assertSecureBaseUrl(baseUrl);
13006
13536
  checks.push({
13007
13537
  id: "base-url-secure",
@@ -13101,7 +13631,7 @@ var resolveToken2 = async (options, deps, baseUrl, command) => {
13101
13631
  return options.accessKey;
13102
13632
  }
13103
13633
  try {
13104
- const core = await import("./dist-MQQKC6DZ.js");
13634
+ const core = await import("./dist-PEYJDO7A.js");
13105
13635
  return await core.getAuthToken({
13106
13636
  baseUrl
13107
13637
  });
@@ -13185,7 +13715,7 @@ var registerModelsCommand = (program2, deps) => {
13185
13715
  let source = "fallback";
13186
13716
  let modelList = fallbackModels;
13187
13717
  try {
13188
- const core = await import("./dist-MQQKC6DZ.js");
13718
+ const core = await import("./dist-PEYJDO7A.js");
13189
13719
  const response = await fetch(`${core.normalizeApiBase(baseUrl)}/models`, {
13190
13720
  headers: {
13191
13721
  Accept: "application/json",
@@ -14364,7 +14894,7 @@ var uninstallCompletionScript = async (shell) => {
14364
14894
  var runInteractiveLoginOnboarding = async (baseUrl, token) => {
14365
14895
  const [{ render }, { Onboarding }] = await Promise.all([
14366
14896
  import("ink"),
14367
- import("./Onboarding-CORIICF5.js")
14897
+ import("./Onboarding-GAN3Q5TS.js")
14368
14898
  ]);
14369
14899
  await new Promise((resolve) => {
14370
14900
  let app;
@@ -14630,7 +15160,13 @@ var getActiveCliTelemetry = () => activeTelemetry;
14630
15160
  var initializeCommandTelemetry = async (actionCommand, options) => {
14631
15161
  activeTelemetryStartedAt = Date.now();
14632
15162
  activeTelemetryFinished = false;
14633
- activeTelemetryProperties = telemetryPropertiesForCommand(actionCommand, options);
15163
+ const traceContext = createCLITraceContext();
15164
+ setActiveCLITraceContext(traceContext);
15165
+ activeTelemetryProperties = {
15166
+ ...telemetryPropertiesForCommand(actionCommand, options),
15167
+ traceId: traceContext.traceId,
15168
+ requestId: traceContext.requestId
15169
+ };
14634
15170
  const config = await resolveCliConfig(actionCommand);
14635
15171
  activeTelemetry = await createCliTelemetry({
14636
15172
  config,
@@ -14639,27 +15175,33 @@ var initializeCommandTelemetry = async (actionCommand, options) => {
14639
15175
  };
14640
15176
  var finishCommandTelemetry = async (exitCode, error) => {
14641
15177
  if (!activeTelemetry || activeTelemetryFinished) {
15178
+ clearActiveCLITraceContext();
14642
15179
  return;
14643
15180
  }
14644
15181
  activeTelemetryFinished = true;
14645
15182
  const durationMs = Math.max(0, Date.now() - activeTelemetryStartedAt);
14646
- if (error) {
14647
- await activeTelemetry.track("cli.error", {
15183
+ try {
15184
+ if (error) {
15185
+ await activeTelemetry.track("cli.error", {
15186
+ ...activeTelemetryProperties,
15187
+ durationMs,
15188
+ exitCode,
15189
+ success: false,
15190
+ errorCategory: classifyTelemetryError(error)
15191
+ });
15192
+ }
15193
+ await activeTelemetry.track("cli.command", {
14648
15194
  ...activeTelemetryProperties,
14649
15195
  durationMs,
14650
15196
  exitCode,
14651
- success: false,
14652
- errorCategory: classifyTelemetryError(error)
15197
+ success: exitCode === 0,
15198
+ ...error ? { errorCategory: classifyTelemetryError(error) } : {}
14653
15199
  });
15200
+ await activeTelemetry.flush();
15201
+ } finally {
15202
+ clearActiveCLITraceContext();
15203
+ activeTelemetry = void 0;
14654
15204
  }
14655
- await activeTelemetry.track("cli.command", {
14656
- ...activeTelemetryProperties,
14657
- durationMs,
14658
- exitCode,
14659
- success: exitCode === 0,
14660
- ...error ? { errorCategory: classifyTelemetryError(error) } : {}
14661
- });
14662
- await activeTelemetry.flush();
14663
15205
  };
14664
15206
  var exitCli = async (exitCode, error) => {
14665
15207
  await finishCommandTelemetry(exitCode, error);
@@ -14686,7 +15228,7 @@ var resolveBaseUrl = async (options, command) => {
14686
15228
  });
14687
15229
  }
14688
15230
  try {
14689
- const { getAuthStatus } = await import("./dist-MQQKC6DZ.js");
15231
+ const { getAuthStatus } = await import("./dist-PEYJDO7A.js");
14690
15232
  const status = await getAuthStatus();
14691
15233
  const storedBaseUrl = status.baseUrl;
14692
15234
  if (storedBaseUrl && shouldUseStoredBaseUrl(storedBaseUrl)) {
@@ -14760,7 +15302,7 @@ program.command("login").description("Authenticate with Cloudeval").option(
14760
15302
  checkUserStatus,
14761
15303
  ensurePlaygroundProject,
14762
15304
  login
14763
- } = await import("./dist-MQQKC6DZ.js");
15305
+ } = await import("./dist-PEYJDO7A.js");
14764
15306
  assertSecureBaseUrl(options.baseUrl);
14765
15307
  const headlessEnvironment = isHeadlessEnvironment();
14766
15308
  const headlessLogin = options.headless || headlessEnvironment;
@@ -14835,7 +15377,7 @@ program.command("logout").description("Log out and clear stored authentication s
14835
15377
  DEFAULT_BASE_URL
14836
15378
  ).option("--all-devices", "Revoke sessions on all devices", false).action(async (options) => {
14837
15379
  try {
14838
- const { assertSecureBaseUrl, logout } = await import("./dist-MQQKC6DZ.js");
15380
+ const { assertSecureBaseUrl, logout } = await import("./dist-PEYJDO7A.js");
14839
15381
  assertSecureBaseUrl(options.baseUrl);
14840
15382
  const result = await logout({
14841
15383
  baseUrl: options.baseUrl,
@@ -14869,7 +15411,7 @@ authCommand.command("status").description("Show current authentication status").
14869
15411
  DEFAULT_BASE_URL
14870
15412
  ).option("--format <format>", "Output format: text, json, ndjson, markdown", "text").option("--show-sensitive-ids", "Show full account/session identifiers in command output", false).option("-v, --verbose", "Enable verbose logging and show full non-token identifiers", false).action(async (options, command) => {
14871
15413
  try {
14872
- const { assertSecureBaseUrl, getAuthStatus } = await import("./dist-MQQKC6DZ.js");
15414
+ const { assertSecureBaseUrl, getAuthStatus } = await import("./dist-PEYJDO7A.js");
14873
15415
  const effectiveBaseUrl = await resolveBaseUrl(options, command);
14874
15416
  assertSecureBaseUrl(effectiveBaseUrl);
14875
15417
  const status = await getAuthStatus(effectiveBaseUrl, { validate: true });
@@ -15086,10 +15628,10 @@ program.command("tui").description("Open the CloudEval Terminal UI").option(
15086
15628
  "Access key for automation",
15087
15629
  process.env.CLOUDEVAL_ACCESS_KEY
15088
15630
  ).option("--access-key-stdin", "Read access key from stdin (recommended for automation)", false).option("--model <name>", "Model name").option("--debug", "Log raw chunks", false).option("--health-check", "Enable health check (disabled by default)").option("--no-banner", "Disable ASCII banner").option("--animate", "Enable TUI animations (default)").option("--no-anim", "Disable TUI animations").option("-v, --verbose", "Enable verbose logging", false).action(async (options, command) => {
15089
- const { assertSecureBaseUrl } = await import("./dist-MQQKC6DZ.js");
15631
+ const { assertSecureBaseUrl } = await import("./dist-PEYJDO7A.js");
15090
15632
  const [{ render }, { App }] = await Promise.all([
15091
15633
  import("ink"),
15092
- import("./App-VZXTX4H7.js")
15634
+ import("./App-GQMIIL3U.js")
15093
15635
  ]);
15094
15636
  const baseUrl = await resolveBaseUrl(options, command);
15095
15637
  assertSecureBaseUrl(baseUrl);
@@ -15144,10 +15686,10 @@ program.command("chat").description("Start an interactive chat session").option(
15144
15686
  "Access key for automation",
15145
15687
  process.env.CLOUDEVAL_ACCESS_KEY
15146
15688
  ).option("--access-key-stdin", "Read access key from stdin (recommended for automation)", false).option("--conversation <id>", "Conversation/thread id to resume").option("--continue", "Resume the most recent local chat session", false).option("--resume <id-or-title>", "Resume a local chat session by thread id or title").option("--model <name>", "Model name").option("--mode <mode>", "Initial chat mode: ask, agent").option("--debug", "Log raw chunks", false).option("--health-check", "Enable health check (disabled by default)").option("--no-banner", "Disable ASCII banner").option("--animate", "Enable TUI animations (default)").option("--no-anim", "Disable TUI animations").option("-v, --verbose", "Enable verbose logging", false).action(async (options, command) => {
15147
- const { assertSecureBaseUrl } = await import("./dist-MQQKC6DZ.js");
15689
+ const { assertSecureBaseUrl } = await import("./dist-PEYJDO7A.js");
15148
15690
  const [{ render }, { App }] = await Promise.all([
15149
15691
  import("ink"),
15150
- import("./App-VZXTX4H7.js")
15692
+ import("./App-GQMIIL3U.js")
15151
15693
  ]);
15152
15694
  const baseUrl = await resolveBaseUrl(options, command);
15153
15695
  assertSecureBaseUrl(baseUrl);
@@ -15222,7 +15764,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
15222
15764
  const question = Array.isArray(questionParts) ? questionParts.join(" ") : String(questionParts);
15223
15765
  const commandName = command.parent?.args?.[0] === "agent" ? "agent" : "ask";
15224
15766
  const selectedMode = commandName === "agent" ? "agent" : "ask";
15225
- const { assertSecureBaseUrl } = await import("./dist-MQQKC6DZ.js");
15767
+ const { assertSecureBaseUrl } = await import("./dist-PEYJDO7A.js");
15226
15768
  const baseUrl = await resolveBaseUrl(options, command);
15227
15769
  assertSecureBaseUrl(baseUrl);
15228
15770
  const selectedProfile = getActiveConfigProfile(command);
@@ -15263,7 +15805,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
15263
15805
  const fs14 = await import("fs");
15264
15806
  const fsPromises = await import("fs/promises");
15265
15807
  const { randomUUID: randomUUID5 } = await import("crypto");
15266
- const core = await import("./dist-MQQKC6DZ.js");
15808
+ const core = await import("./dist-PEYJDO7A.js");
15267
15809
  const {
15268
15810
  streamChat,
15269
15811
  reduceChunk,
@@ -15319,7 +15861,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
15319
15861
  console.error("Authentication required. Starting login process...\n");
15320
15862
  }
15321
15863
  try {
15322
- const { login } = await import("./dist-MQQKC6DZ.js");
15864
+ const { login } = await import("./dist-PEYJDO7A.js");
15323
15865
  verboseLog("Calling interactive login", { baseUrl });
15324
15866
  token = await login(baseUrl, {
15325
15867
  headless: isHeadlessEnvironment()
@@ -15383,7 +15925,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
15383
15925
  message: error.message
15384
15926
  });
15385
15927
  }
15386
- const { resolveAskProject } = await import("./resolveAskProject-KQKI5GRT.js");
15928
+ const { resolveAskProject } = await import("./resolveAskProject-DQJXPS5G.js");
15387
15929
  let project;
15388
15930
  try {
15389
15931
  project = await resolveAskProject({
@@ -15901,7 +16443,7 @@ Error: ${errorMsg}
15901
16443
  program.command("banner").description("Preview the startup banner and terminal capabilities").action(async () => {
15902
16444
  const { render } = await import("ink");
15903
16445
  const BannerPreview = React.lazy(async () => ({
15904
- default: (await import("./Banner-URKZ37H4.js")).Banner
16446
+ default: (await import("./Banner-J2ESX3JN.js")).Banner
15905
16447
  }));
15906
16448
  render(
15907
16449
  /* @__PURE__ */ jsx(React.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(BannerPreview, { disable: false }) })