@ganakailabs/cloudeval-cli 0.22.0 → 0.24.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
@@ -24,7 +24,7 @@ import {
24
24
  searchSessions,
25
25
  unsetCliConfigValue,
26
26
  writeCliConfigValue
27
- } from "./chunk-RCRNSEQS.js";
27
+ } from "./chunk-QSBGUI25.js";
28
28
  import {
29
29
  getBundledAgentProfile,
30
30
  getBundledAgentProfiles,
@@ -33,10 +33,10 @@ import {
33
33
  normalizeApiBase,
34
34
  redactSensitiveSecrets,
35
35
  redactSensitiveText
36
- } from "./chunk-LDDHLUZH.js";
36
+ } from "./chunk-KBHRBGSX.js";
37
37
  import {
38
38
  CLI_VERSION
39
- } from "./chunk-AF6Z5VZD.js";
39
+ } from "./chunk-MK3L4LRF.js";
40
40
 
41
41
  // src/runtime/prepareInk.ts
42
42
  import fs from "fs";
@@ -136,7 +136,7 @@ ensureInkRuntimeEnvironment();
136
136
  import React from "react";
137
137
  import { Command } from "commander";
138
138
  import { promises as fs12 } from "fs";
139
- import os4 from "os";
139
+ import os6 from "os";
140
140
  import path9 from "path";
141
141
 
142
142
  // src/shellCompletion.ts
@@ -507,6 +507,16 @@ var cliCommands = [
507
507
  "--template-file",
508
508
  "--parameters-file",
509
509
  "--parameters-url",
510
+ "--workspace-dir",
511
+ "--workspace-entry",
512
+ "--workspace-parameters",
513
+ "--cloud-sync",
514
+ "--azure-tenant-id",
515
+ "--azure-client-id",
516
+ "--azure-client-secret",
517
+ "--azure-subscription-id",
518
+ "--resource-group",
519
+ "--resource-groups",
510
520
  "--name",
511
521
  "--description",
512
522
  "--provider",
@@ -1604,7 +1614,7 @@ var resolveReportProjectId = async ({
1604
1614
  if (!token) {
1605
1615
  throw new Error("No project specified. Use --project <id> for report access.");
1606
1616
  }
1607
- const resolvedWorkspace = workspace ?? await import("./dist-AGQQPJUD.js").then((core) => ({
1617
+ const resolvedWorkspace = workspace ?? await import("./dist-CFLR5FML.js").then((core) => ({
1608
1618
  checkUserStatus: core.checkUserStatus,
1609
1619
  getProjects: core.getProjects
1610
1620
  }));
@@ -1633,7 +1643,7 @@ var warnIfAccessKeyFromCliOption = (options, command) => {
1633
1643
  };
1634
1644
  var resolveAuthContext = async (options, command, deps) => {
1635
1645
  const baseUrl = await deps.resolveBaseUrl(options, command);
1636
- const core = await import("./dist-AGQQPJUD.js");
1646
+ const core = await import("./dist-CFLR5FML.js");
1637
1647
  core.assertSecureBaseUrl(baseUrl);
1638
1648
  warnIfAccessKeyFromCliOption(options, command);
1639
1649
  let accessKey = options.accessKey;
@@ -1719,7 +1729,7 @@ var resolveToken = async (options, baseUrl, deps, command) => {
1719
1729
  if (options.accessKey) {
1720
1730
  return options.accessKey;
1721
1731
  }
1722
- const { getAuthToken } = await import("./dist-AGQQPJUD.js");
1732
+ const { getAuthToken } = await import("./dist-CFLR5FML.js");
1723
1733
  try {
1724
1734
  return await getAuthToken({
1725
1735
  accessKey: options.accessKey,
@@ -1730,7 +1740,7 @@ var resolveToken = async (options, baseUrl, deps, command) => {
1730
1740
  if (!canLogin) {
1731
1741
  throw error;
1732
1742
  }
1733
- const { login } = await import("./dist-AGQQPJUD.js");
1743
+ const { login } = await import("./dist-CFLR5FML.js");
1734
1744
  process.stderr.write("Authentication required. Starting login flow...\n");
1735
1745
  const token = await login(baseUrl, {
1736
1746
  headless: Boolean(process.env.SSH_TTY || process.env.CLOUDEVAL_HEADLESS_LOGIN)
@@ -1896,7 +1906,7 @@ var registerReportsCommand = (program2, deps) => {
1896
1906
  token,
1897
1907
  requestedProjectId: options.project
1898
1908
  });
1899
- const core = await import("./dist-AGQQPJUD.js");
1909
+ const core = await import("./dist-CFLR5FML.js");
1900
1910
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
1901
1911
  const reports2 = await core.listReports({
1902
1912
  baseUrl,
@@ -1918,7 +1928,7 @@ var registerReportsCommand = (program2, deps) => {
1918
1928
  try {
1919
1929
  const baseUrl = await deps.resolveBaseUrl(options, command);
1920
1930
  const token = await resolveToken(options, baseUrl, deps, command);
1921
- const core = await import("./dist-AGQQPJUD.js");
1931
+ const core = await import("./dist-CFLR5FML.js");
1922
1932
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
1923
1933
  const projectId = await resolveReportProjectId({
1924
1934
  baseUrl,
@@ -2021,7 +2031,7 @@ var registerReportsCommand = (program2, deps) => {
2021
2031
  try {
2022
2032
  const baseUrl = await deps.resolveBaseUrl(options, command);
2023
2033
  const token = await resolveToken(options, baseUrl, deps, command);
2024
- const core = await import("./dist-AGQQPJUD.js");
2034
+ const core = await import("./dist-CFLR5FML.js");
2025
2035
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
2026
2036
  const projectId = await resolveReportProjectId({
2027
2037
  baseUrl,
@@ -2091,7 +2101,7 @@ var registerReportsCommand = (program2, deps) => {
2091
2101
  token,
2092
2102
  requestedProjectId: options.project
2093
2103
  });
2094
- const core = await import("./dist-AGQQPJUD.js");
2104
+ const core = await import("./dist-CFLR5FML.js");
2095
2105
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
2096
2106
  const report = await core.getWafReport({
2097
2107
  baseUrl,
@@ -2130,7 +2140,7 @@ var registerReportsCommand = (program2, deps) => {
2130
2140
  token,
2131
2141
  requestedProjectId: options.project
2132
2142
  });
2133
- const core = await import("./dist-AGQQPJUD.js");
2143
+ const core = await import("./dist-CFLR5FML.js");
2134
2144
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
2135
2145
  const report = await core.getReport({
2136
2146
  baseUrl,
@@ -2158,7 +2168,7 @@ var registerReportsCommand = (program2, deps) => {
2158
2168
  token,
2159
2169
  requestedProjectId: options.project
2160
2170
  });
2161
- const core = await import("./dist-AGQQPJUD.js");
2171
+ const core = await import("./dist-CFLR5FML.js");
2162
2172
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
2163
2173
  const report = await core.getCostReport({
2164
2174
  baseUrl,
@@ -2187,7 +2197,7 @@ var registerReportsCommand = (program2, deps) => {
2187
2197
  token,
2188
2198
  requestedProjectId: options.project
2189
2199
  });
2190
- const core = await import("./dist-AGQQPJUD.js");
2200
+ const core = await import("./dist-CFLR5FML.js");
2191
2201
  const status = token ? await core.checkUserStatus(baseUrl, token) : void 0;
2192
2202
  const report = await core.getWafReport({
2193
2203
  baseUrl,
@@ -3529,7 +3539,7 @@ var runChatRecipe = async (recipe, prompt2, options, command, deps) => {
3529
3539
  });
3530
3540
  progressWriter.write({ type: "auth", step: "auth", message: "Resolving authentication" });
3531
3541
  const context = await resolveAuthContext(options, command, deps);
3532
- const core = await import("./dist-AGQQPJUD.js");
3542
+ const core = await import("./dist-CFLR5FML.js");
3533
3543
  progressWriter.write({
3534
3544
  type: "request",
3535
3545
  step: "project",
@@ -4266,6 +4276,8 @@ var registerOpenCommand = (program2, deps) => {
4266
4276
  // src/projectsCommand.ts
4267
4277
  import path3 from "path";
4268
4278
  import fs5 from "fs/promises";
4279
+ import os from "os";
4280
+ import { spawn } from "child_process";
4269
4281
 
4270
4282
  // src/projectDiagramImage.ts
4271
4283
  var trimTrailingSlash = (value) => value.replace(/\/+$/, "");
@@ -4640,6 +4652,268 @@ var fileBlob = async (filePath) => {
4640
4652
  name: path3.basename(filePath)
4641
4653
  };
4642
4654
  };
4655
+ var normalizeWorkspacePath = (value) => value.replace(/\\/g, "/").replace(/^\/+/, "").replace(/^\.\//, "").split("/").filter((part) => part && part !== ".").join("/");
4656
+ var isIgnoredWorkspacePath = (relativePath) => {
4657
+ const normalized = normalizeWorkspacePath(relativePath);
4658
+ return normalized === ".DS_Store" || normalized.endsWith("/.DS_Store") || normalized.startsWith(".git/") || normalized.startsWith("node_modules/") || normalized.startsWith(".cloudeval/bundles/") || normalized.startsWith(".cloudeval/connections/") || normalized.startsWith(".cloudeval/reports/") || normalized.startsWith(".cloudeval/share/") || normalized.startsWith(".cloudeval/shares/") || normalized.startsWith(".cloudeval/snapshots/") || normalized.startsWith(".cloudeval/template-cache/") || normalized === ".cloudeval/ps-rule.yaml";
4659
+ };
4660
+ var readWorkspaceConfig = (content) => {
4661
+ const entryMatch = content.match(/^\s*entry:\s*["']?([^"'\n#]+)["']?\s*(?:#.*)?$/m);
4662
+ const parametersMatch = content.match(
4663
+ /^\s*parameters:\s*["']?([^"'\n#]+)["']?\s*(?:#.*)?$/m
4664
+ );
4665
+ return {
4666
+ entry: entryMatch ? normalizeWorkspacePath(entryMatch[1].trim()) : void 0,
4667
+ parameters: parametersMatch ? normalizeWorkspacePath(parametersMatch[1].trim()) : void 0
4668
+ };
4669
+ };
4670
+ var generateWorkspaceConfig = (entry, parameters, sourceEntry) => {
4671
+ const parameterLine = parameters ? ` parameters: ${parameters}
4672
+ ` : "";
4673
+ const sourceEntryLine = sourceEntry ? ` source_entry: ${sourceEntry}` : "";
4674
+ return [
4675
+ "version: 1",
4676
+ "stacks:",
4677
+ " - id: main",
4678
+ ` entry: ${entry}`,
4679
+ sourceEntryLine,
4680
+ parameterLine.trimEnd(),
4681
+ "resolve:",
4682
+ " linked_templates: true",
4683
+ "analysis:",
4684
+ " auto_resolve_on_import: true",
4685
+ " auto_refresh_on_resolve: true",
4686
+ ""
4687
+ ].filter((line) => line.length > 0).join("\n");
4688
+ };
4689
+ var runCommand = (command, args) => new Promise((resolve, reject) => {
4690
+ const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] });
4691
+ const stdout = [];
4692
+ const stderr = [];
4693
+ child.stdout.on("data", (chunk) => stdout.push(Buffer.from(chunk)));
4694
+ child.stderr.on("data", (chunk) => stderr.push(Buffer.from(chunk)));
4695
+ child.on("error", reject);
4696
+ child.on("exit", (code) => {
4697
+ const output = {
4698
+ stdout: Buffer.concat(stdout).toString("utf8"),
4699
+ stderr: Buffer.concat(stderr).toString("utf8")
4700
+ };
4701
+ if (code === 0) {
4702
+ resolve(output);
4703
+ return;
4704
+ }
4705
+ reject(
4706
+ new Error(
4707
+ `${command} ${args.join(" ")} failed with exit code ${code ?? "unknown"}${output.stderr ? `: ${output.stderr.trim()}` : ""}`
4708
+ )
4709
+ );
4710
+ });
4711
+ });
4712
+ var isBicepPath = (filePath) => /\.bicep$/i.test(filePath);
4713
+ var compiledBicepPathFor = (entry) => {
4714
+ const parsed = path3.posix.parse(entry);
4715
+ return normalizeWorkspacePath(
4716
+ path3.posix.join(
4717
+ ".cloudeval/template-cache/compiled",
4718
+ parsed.dir,
4719
+ `${parsed.name}.json`
4720
+ )
4721
+ );
4722
+ };
4723
+ var compileBicepEntry = async (root, entry) => {
4724
+ const tempDir = await fs5.mkdtemp(path3.join(os.tmpdir(), "cloudeval-bicep-"));
4725
+ const outputPath = path3.join(tempDir, "compiled.json");
4726
+ try {
4727
+ await runCommand("az", [
4728
+ "bicep",
4729
+ "build",
4730
+ "--file",
4731
+ path3.join(root, entry),
4732
+ "--outfile",
4733
+ outputPath
4734
+ ]);
4735
+ const bytes = await fs5.readFile(outputPath);
4736
+ return {
4737
+ path: compiledBicepPathFor(entry),
4738
+ blob: new Blob([bytes], { type: "application/json" })
4739
+ };
4740
+ } catch (error) {
4741
+ const message = error instanceof Error ? error.message : "Bicep compilation failed.";
4742
+ if (error?.code === "ENOENT") {
4743
+ throw new Error(
4744
+ "Bicep workspace entries require Azure CLI with `az bicep` available. Install Azure CLI or upload a compiled ARM JSON entry."
4745
+ );
4746
+ }
4747
+ throw new Error(`Failed to compile Bicep workspace entry '${entry}': ${message}`);
4748
+ } finally {
4749
+ await fs5.rm(tempDir, { recursive: true, force: true });
4750
+ }
4751
+ };
4752
+ var collectWorkspacePaths = async (root) => {
4753
+ const paths = [];
4754
+ const visit = async (directory) => {
4755
+ const entries = await fs5.readdir(directory, { withFileTypes: true });
4756
+ for (const entry of entries) {
4757
+ const absolute = path3.join(directory, entry.name);
4758
+ const relative = normalizeWorkspacePath(path3.relative(root, absolute));
4759
+ if (!relative || isIgnoredWorkspacePath(relative)) {
4760
+ continue;
4761
+ }
4762
+ if (entry.isDirectory()) {
4763
+ await visit(absolute);
4764
+ } else if (entry.isFile()) {
4765
+ paths.push(relative);
4766
+ }
4767
+ }
4768
+ };
4769
+ await visit(root);
4770
+ return paths.sort((left, right) => left.localeCompare(right));
4771
+ };
4772
+ var findFirstPath = (paths, candidates) => {
4773
+ const lowerToPath = new Map(paths.map((filePath) => [filePath.toLowerCase(), filePath]));
4774
+ for (const candidate of candidates) {
4775
+ const found = lowerToPath.get(candidate.toLowerCase());
4776
+ if (found) {
4777
+ return found;
4778
+ }
4779
+ }
4780
+ return void 0;
4781
+ };
4782
+ var detectWorkspaceEntry = (paths, explicitEntry, config) => {
4783
+ if (explicitEntry) {
4784
+ const normalized = normalizeWorkspacePath(explicitEntry);
4785
+ if (!paths.includes(normalized)) {
4786
+ throw new Error(`--workspace-entry '${explicitEntry}' was not found in --workspace-dir.`);
4787
+ }
4788
+ return normalized;
4789
+ }
4790
+ if (config?.entry && paths.includes(config.entry)) {
4791
+ return config.entry;
4792
+ }
4793
+ const rootCandidate = findFirstPath(paths, ["azuredeploy.json", "main.json", "deploy.json"]);
4794
+ if (rootCandidate) {
4795
+ return rootCandidate;
4796
+ }
4797
+ const recursiveAzureDeploy = paths.find(
4798
+ (filePath) => /(^|\/)azuredeploy\.json$/i.test(filePath)
4799
+ );
4800
+ if (recursiveAzureDeploy) {
4801
+ return recursiveAzureDeploy;
4802
+ }
4803
+ const armCandidate = paths.find((filePath) => /\.json$/i.test(filePath));
4804
+ if (armCandidate) {
4805
+ return armCandidate;
4806
+ }
4807
+ throw new Error(
4808
+ "Could not detect a workspace entry file. Pass --workspace-entry or add .cloudeval/config.yaml."
4809
+ );
4810
+ };
4811
+ var resolveWorkspaceParameters = (paths, explicitParameters, config) => {
4812
+ if (explicitParameters) {
4813
+ const normalized = normalizeWorkspacePath(explicitParameters);
4814
+ if (!paths.includes(normalized)) {
4815
+ throw new Error(`--workspace-parameters '${explicitParameters}' was not found in --workspace-dir.`);
4816
+ }
4817
+ return normalized;
4818
+ }
4819
+ if (config?.parameters && paths.includes(config.parameters)) {
4820
+ return config.parameters;
4821
+ }
4822
+ return findFirstPath(paths, ["azuredeploy.parameters.json", "parameters.json"]);
4823
+ };
4824
+ var collectWorkspaceFiles = async (workspaceDir, options) => {
4825
+ const root = path3.resolve(workspaceDir);
4826
+ const stat = await fs5.stat(root).catch(() => void 0);
4827
+ if (!stat?.isDirectory()) {
4828
+ throw new Error(`--workspace-dir '${workspaceDir}' is not a directory.`);
4829
+ }
4830
+ const paths = await collectWorkspacePaths(root);
4831
+ const existingConfigPath = paths.find(
4832
+ (filePath) => filePath.toLowerCase() === ".cloudeval/config.yaml"
4833
+ );
4834
+ const config = existingConfigPath ? readWorkspaceConfig(await fs5.readFile(path3.join(root, existingConfigPath), "utf8")) : void 0;
4835
+ const entry = detectWorkspaceEntry(paths, options.workspaceEntry, config);
4836
+ const parameters = resolveWorkspaceParameters(paths, options.workspaceParameters, config);
4837
+ const compiledEntry = isBicepPath(entry) ? await compileBicepEntry(root, entry) : void 0;
4838
+ const analysisEntry = compiledEntry?.path ?? entry;
4839
+ const finalPaths = [...paths];
4840
+ const generatedConfig = existingConfigPath && !compiledEntry ? void 0 : generateWorkspaceConfig(analysisEntry, parameters, compiledEntry ? entry : void 0);
4841
+ if (generatedConfig) {
4842
+ finalPaths.push(".cloudeval/config.yaml");
4843
+ }
4844
+ const files = [];
4845
+ if (compiledEntry) {
4846
+ files.push(compiledEntry);
4847
+ }
4848
+ for (const relativePath of finalPaths.sort((left, right) => left.localeCompare(right))) {
4849
+ if (relativePath === ".cloudeval/config.yaml" && generatedConfig) {
4850
+ files.push({
4851
+ path: relativePath,
4852
+ blob: new Blob([generatedConfig], { type: "text/yaml" })
4853
+ });
4854
+ continue;
4855
+ }
4856
+ const bytes = await fs5.readFile(path3.join(root, relativePath));
4857
+ files.push({
4858
+ path: relativePath,
4859
+ blob: new Blob([bytes], {
4860
+ type: /\.ya?ml$/i.test(relativePath) ? "text/yaml" : "application/octet-stream"
4861
+ })
4862
+ });
4863
+ }
4864
+ return { files, entry: analysisEntry };
4865
+ };
4866
+ var collectResourceGroups = (options) => {
4867
+ const repeated = Array.isArray(options.resourceGroup) ? options.resourceGroup : [];
4868
+ const commaSeparated = options.resourceGroups ? options.resourceGroups.split(",").map((value) => value.trim()) : [];
4869
+ return [...repeated, ...commaSeparated].map((value) => value.trim()).filter(Boolean);
4870
+ };
4871
+ var resolveAzureCloudSyncInput = (options) => {
4872
+ if (!options.cloudSync) {
4873
+ return void 0;
4874
+ }
4875
+ const tenantId = options.azureTenantId || process.env.AZURE_TENANT_ID;
4876
+ const clientId = options.azureClientId || process.env.AZURE_CLIENT_ID;
4877
+ const clientSecret = options.azureClientSecret || process.env.AZURE_CLIENT_SECRET;
4878
+ const subscriptionId = options.azureSubscriptionId || process.env.AZURE_SUBSCRIPTION_ID;
4879
+ const missing = [
4880
+ ["--azure-tenant-id or AZURE_TENANT_ID", tenantId],
4881
+ ["--azure-client-id or AZURE_CLIENT_ID", clientId],
4882
+ ["--azure-client-secret or AZURE_CLIENT_SECRET", clientSecret],
4883
+ ["--azure-subscription-id or AZURE_SUBSCRIPTION_ID", subscriptionId]
4884
+ ].filter(([, value]) => !value).map(([label]) => label);
4885
+ if (missing.length) {
4886
+ throw new Error(`Missing Cloud sync credential value(s): ${missing.join(", ")}.`);
4887
+ }
4888
+ return {
4889
+ tenantId,
4890
+ clientId,
4891
+ clientSecret,
4892
+ subscriptionId,
4893
+ resourceGroups: collectResourceGroups(options)
4894
+ };
4895
+ };
4896
+ var assertSingleProjectSource = (options) => {
4897
+ const sources = [
4898
+ options.templateUrl ? "--template-url" : void 0,
4899
+ options.templateFile ? "--template-file" : void 0,
4900
+ options.workspaceDir ? "--workspace-dir" : void 0,
4901
+ options.cloudSync ? "--cloud-sync" : void 0
4902
+ ].filter(Boolean);
4903
+ if (sources.length > 1) {
4904
+ throw new Error(`Choose one project source: ${sources.join(", ")} cannot be combined.`);
4905
+ }
4906
+ if ((options.parametersFile || options.parametersUrl) && !options.templateFile && !options.templateUrl) {
4907
+ throw new Error("--parameters-file and --parameters-url require --template-file or --template-url.");
4908
+ }
4909
+ if (options.cloudSync && options.provider && options.provider !== "azure") {
4910
+ throw new Error("--cloud-sync currently supports --provider azure.");
4911
+ }
4912
+ };
4913
+ var appendOptionValue = (value, previous = []) => [
4914
+ ...previous,
4915
+ value
4916
+ ];
4643
4917
  var writeDiagramImageHeaders = async (outputPath, headers) => {
4644
4918
  await fs5.mkdir(path3.dirname(outputPath), { recursive: true });
4645
4919
  const text = Object.entries(headers).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key}: ${value}`).join("\n");
@@ -4778,7 +5052,7 @@ var configureDiagramExportCommand = (command, deps) => addAuthOptions(command, d
4778
5052
  const context = requireAuthUser(
4779
5053
  await resolveAuthContext(options, actionCommand, deps)
4780
5054
  );
4781
- const core = await import("./dist-AGQQPJUD.js");
5055
+ const core = await import("./dist-CFLR5FML.js");
4782
5056
  const projects = await core.getProjects(
4783
5057
  context.baseUrl,
4784
5058
  context.token,
@@ -4855,7 +5129,7 @@ var registerProjectsCommand = (program2, deps) => {
4855
5129
  addCommon(addAuthOptions(projects.command("list").description("List projects"), deps.defaultBaseUrl)).action(async (options, command) => {
4856
5130
  try {
4857
5131
  const context = await resolveAuthContext(options, command, deps);
4858
- const core = await import("./dist-AGQQPJUD.js");
5132
+ const core = await import("./dist-CFLR5FML.js");
4859
5133
  const data = await listProjectsForContext(core, context);
4860
5134
  const url = buildFrontendUrl({ baseUrl: frontendBase(context, options), target: "projects" });
4861
5135
  await writeProjectListOutput({ data, options, frontendUrl: url });
@@ -4873,7 +5147,7 @@ var registerProjectsCommand = (program2, deps) => {
4873
5147
  ).action(async (id, options, command) => {
4874
5148
  try {
4875
5149
  const context = await resolveAuthContext(options, command, deps);
4876
- const core = await import("./dist-AGQQPJUD.js");
5150
+ const core = await import("./dist-CFLR5FML.js");
4877
5151
  const list = await listProjectsForContext(core, context);
4878
5152
  const data = list.find((project) => project.id === id);
4879
5153
  if (!data) {
@@ -4934,13 +5208,16 @@ var registerProjectsCommand = (program2, deps) => {
4934
5208
  deps
4935
5209
  );
4936
5210
  configureGraphCommands(projects, deps);
4937
- addCommon(addAuthOptions(projects.command("create").description("Create a quick template project"), deps.defaultBaseUrl)).option("--template-url <url>", "Template URL").option("--template-file <path>", "Local JSON template file").option("--parameters-file <path>", "Local JSON parameters file").option("--parameters-url <url>", "Parameters file URL").option("--name <name>", "Project name").option("--description <text>", "Project description").option("--provider <provider>", "Cloud provider: azure, aws, gcp").action(async (options, command) => {
5211
+ addCommon(addAuthOptions(projects.command("create").description("Create a CloudEval project"), deps.defaultBaseUrl)).option("--template-url <url>", "Template URL").option("--template-file <path>", "Local JSON template file").option("--parameters-file <path>", "Local JSON parameters file").option("--parameters-url <url>", "Parameters file URL").option("--workspace-dir <path>", "Upload an Infrastructure as code folder").option("--workspace-entry <path>", "Workspace visualization entry file").option("--workspace-parameters <path>", "Workspace parameters file").option("--cloud-sync", "Create a Cloud sync project from Azure credentials", false).option("--azure-tenant-id <id>", "Azure tenant id for Cloud sync").option("--azure-client-id <id>", "Azure service principal client id for Cloud sync").option("--azure-client-secret <secret>", "Azure service principal client secret for Cloud sync").option("--azure-subscription-id <id>", "Azure subscription id for Cloud sync").option("--resource-group <name>", "Azure resource group scope for Cloud sync", appendOptionValue, []).option("--resource-groups <list>", "Comma-separated Azure resource group scopes for Cloud sync").option("--name <name>", "Project name").option("--description <text>", "Project description").option("--provider <provider>", "Cloud provider: azure, aws, gcp").action(async (options, command) => {
4938
5212
  try {
5213
+ assertSingleProjectSource(options);
4939
5214
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
4940
- const core = await import("./dist-AGQQPJUD.js");
5215
+ const core = await import("./dist-CFLR5FML.js");
4941
5216
  const template = await fileBlob(options.templateFile);
4942
5217
  const parameters = await fileBlob(options.parametersFile);
4943
- const inferredName = options.name || (options.templateFile ? path3.basename(options.templateFile, path3.extname(options.templateFile)) : void 0);
5218
+ const workspace = options.workspaceDir ? await collectWorkspaceFiles(options.workspaceDir, options) : void 0;
5219
+ const cloudSync = resolveAzureCloudSyncInput(options);
5220
+ const inferredName = options.name || (options.workspaceDir ? path3.basename(path3.resolve(options.workspaceDir)) : void 0) || (cloudSync ? "Cloud sync" : void 0) || (options.templateFile ? path3.basename(options.templateFile, path3.extname(options.templateFile)) : void 0);
4944
5221
  const result = await core.createQuickProject({
4945
5222
  baseUrl: context.baseUrl,
4946
5223
  authToken: context.token,
@@ -4951,9 +5228,12 @@ var registerProjectsCommand = (program2, deps) => {
4951
5228
  parametersFile: parameters?.blob,
4952
5229
  parametersFileName: parameters?.name,
4953
5230
  parametersUrl: options.parametersUrl,
5231
+ workspaceFiles: workspace?.files,
5232
+ workspaceEntry: workspace?.entry,
5233
+ cloudSync,
4954
5234
  name: inferredName,
4955
5235
  description: options.description,
4956
- provider: options.provider
5236
+ provider: options.provider ?? "azure"
4957
5237
  });
4958
5238
  const projectId = String(result.project.id);
4959
5239
  const url = buildFrontendUrl({
@@ -4968,7 +5248,8 @@ var registerProjectsCommand = (program2, deps) => {
4968
5248
  connection: result.connection,
4969
5249
  syncStatus: result.syncStatus,
4970
5250
  normalizedTemplateUrl: result.normalizedTemplateUrl,
4971
- inferred: result.inferred
5251
+ inferred: result.inferred,
5252
+ iacPipeline: result.iacPipeline
4972
5253
  },
4973
5254
  format: options.format,
4974
5255
  output: options.output,
@@ -5060,7 +5341,7 @@ var registerConnectionsCommand = (program2, deps) => {
5060
5341
  addCommon2(addAuthOptions(connections.command("list").description("List connections"), deps.defaultBaseUrl)).action(async (options, command) => {
5061
5342
  try {
5062
5343
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
5063
- const core = await import("./dist-AGQQPJUD.js");
5344
+ const core = await import("./dist-CFLR5FML.js");
5064
5345
  const data = await core.listConnections({
5065
5346
  baseUrl: context.baseUrl,
5066
5347
  authToken: context.token,
@@ -5085,7 +5366,7 @@ var registerConnectionsCommand = (program2, deps) => {
5085
5366
  ).action(async (id, options, command) => {
5086
5367
  try {
5087
5368
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
5088
- const core = await import("./dist-AGQQPJUD.js");
5369
+ const core = await import("./dist-CFLR5FML.js");
5089
5370
  const data = await core.getConnection({
5090
5371
  baseUrl: context.baseUrl,
5091
5372
  authToken: context.token,
@@ -5423,7 +5704,7 @@ var checkoutReturnUrl = (context, options) => options.returnTo || billingUrl(con
5423
5704
  var runTopUpCheckout = async (commandName, packId, options, command, deps) => {
5424
5705
  try {
5425
5706
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
5426
- const core = await import("./dist-AGQQPJUD.js");
5707
+ const core = await import("./dist-CFLR5FML.js");
5427
5708
  const returnTo = checkoutReturnUrl(context, options);
5428
5709
  const session = await core.createTopUpCheckoutSession({
5429
5710
  baseUrl: context.baseUrl,
@@ -5463,7 +5744,7 @@ var registerBillingCommands = (program2, deps) => {
5463
5744
  ).action(async (options, command) => {
5464
5745
  try {
5465
5746
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
5466
- const core = await import("./dist-AGQQPJUD.js");
5747
+ const core = await import("./dist-CFLR5FML.js");
5467
5748
  const range = rangeToDates("30d");
5468
5749
  const [entitlement, usageSummary] = await Promise.all([
5469
5750
  core.getBillingEntitlement({
@@ -5493,7 +5774,7 @@ var registerBillingCommands = (program2, deps) => {
5493
5774
  addCommon3(addAuthOptions(billing.command("summary").description("Show billing summary"), deps.defaultBaseUrl)).action(async (options, command) => {
5494
5775
  try {
5495
5776
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
5496
- const core = await import("./dist-AGQQPJUD.js");
5777
+ const core = await import("./dist-CFLR5FML.js");
5497
5778
  const range = rangeToDates("30d");
5498
5779
  const [entitlement, subscriptionStatus, usageSummary] = await Promise.all([
5499
5780
  core.getBillingEntitlement({ baseUrl: context.baseUrl, authToken: context.token }),
@@ -5529,7 +5810,7 @@ var registerBillingCommands = (program2, deps) => {
5529
5810
  addCommon3(addAuthOptions(billing.command("plans").description("Show billing plans"), deps.defaultBaseUrl)).action(async (options, command) => {
5530
5811
  try {
5531
5812
  const context = await resolveAuthContext(options, command, deps);
5532
- const core = await import("./dist-AGQQPJUD.js");
5813
+ const core = await import("./dist-CFLR5FML.js");
5533
5814
  const data = await core.getBillingConfig({ baseUrl: context.baseUrl, authToken: context.token });
5534
5815
  const url = billingUrl(context, { ...options, tab: "plans" });
5535
5816
  await write("billing plans", data, options, url);
@@ -5541,7 +5822,7 @@ var registerBillingCommands = (program2, deps) => {
5541
5822
  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) => {
5542
5823
  try {
5543
5824
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
5544
- const core = await import("./dist-AGQQPJUD.js");
5825
+ const core = await import("./dist-CFLR5FML.js");
5545
5826
  const range = rangeToDates(options.range);
5546
5827
  const data = await core.getBillingUsageSummary({
5547
5828
  baseUrl: context.baseUrl,
@@ -5564,7 +5845,7 @@ var registerBillingCommands = (program2, deps) => {
5564
5845
  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) => {
5565
5846
  try {
5566
5847
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
5567
- const core = await import("./dist-AGQQPJUD.js");
5848
+ const core = await import("./dist-CFLR5FML.js");
5568
5849
  const range = rangeToDates(options.range);
5569
5850
  const data = await core.getBillingUsageLedger({
5570
5851
  baseUrl: context.baseUrl,
@@ -5592,7 +5873,7 @@ var registerBillingCommands = (program2, deps) => {
5592
5873
  addCommon3(addAuthOptions(billing.command(name).description(`Show billing ${name}`), deps.defaultBaseUrl)).option("--limit <n>", "Result limit", "25").action(async (options, command) => {
5593
5874
  try {
5594
5875
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
5595
- const core = await import("./dist-AGQQPJUD.js");
5876
+ const core = await import("./dist-CFLR5FML.js");
5596
5877
  const data = await core[getter]({
5597
5878
  baseUrl: context.baseUrl,
5598
5879
  authToken: context.token,
@@ -5610,7 +5891,7 @@ var registerBillingCommands = (program2, deps) => {
5610
5891
  addCommon3(addAuthOptions(topups, deps.defaultBaseUrl)).option("--limit <n>", "Result limit", "25").action(async (options, command) => {
5611
5892
  try {
5612
5893
  const context = requireAuthUser(await resolveAuthContext(options, command, deps));
5613
- const core = await import("./dist-AGQQPJUD.js");
5894
+ const core = await import("./dist-CFLR5FML.js");
5614
5895
  const data = await core.getTopUpPacks({
5615
5896
  baseUrl: context.baseUrl,
5616
5897
  authToken: context.token
@@ -5651,7 +5932,7 @@ import { randomUUID as randomUUID2 } from "crypto";
5651
5932
 
5652
5933
  // src/mcpSetupCommand.ts
5653
5934
  import fs6 from "fs/promises";
5654
- import os from "os";
5935
+ import os2 from "os";
5655
5936
  import path4 from "path";
5656
5937
  var MCP_SETUP_CLIENTS = ["codex", "claude", "cursor", "vscode", "generic"];
5657
5938
  var CLIENTS = new Set(MCP_SETUP_CLIENTS);
@@ -5679,7 +5960,7 @@ var normalizeMcpSetupToolset = (value) => {
5679
5960
  var defaultConfigPath = (client) => {
5680
5961
  if (client === "claude") {
5681
5962
  return path4.join(
5682
- os.homedir(),
5963
+ os2.homedir(),
5683
5964
  "Library",
5684
5965
  "Application Support",
5685
5966
  "Claude",
@@ -5687,7 +5968,7 @@ var defaultConfigPath = (client) => {
5687
5968
  );
5688
5969
  }
5689
5970
  if (client === "cursor") {
5690
- return path4.join(os.homedir(), ".cursor", "mcp.json");
5971
+ return path4.join(os2.homedir(), ".cursor", "mcp.json");
5691
5972
  }
5692
5973
  if (client === "vscode") {
5693
5974
  return path4.join(process.cwd(), ".vscode", "mcp.json");
@@ -6137,6 +6418,273 @@ var getRule = async (input) => fetchCloudEvalJson({
6137
6418
  path: `/rule/rules/${encodeURIComponent(input.ruleId)}`
6138
6419
  });
6139
6420
 
6421
+ // src/telemetry.ts
6422
+ import os3 from "os";
6423
+
6424
+ // src/telemetryConnectionString.generated.ts
6425
+ var PACKAGED_APPLICATIONINSIGHTS_CONNECTION_STRING = "";
6426
+
6427
+ // src/telemetry.ts
6428
+ var TELEMETRY_SCHEMA_VERSION = "1";
6429
+ var TRUE_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
6430
+ var FALSE_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
6431
+ var PROPERTY_ALLOWLIST = /* @__PURE__ */ new Set([
6432
+ "alias",
6433
+ "aliases",
6434
+ "arch",
6435
+ "authMode",
6436
+ "cliVersion",
6437
+ "command",
6438
+ "completionShell",
6439
+ "completions",
6440
+ "email",
6441
+ "errorCategory",
6442
+ "exitCode",
6443
+ "firstName",
6444
+ "format",
6445
+ "fullName",
6446
+ "installSource",
6447
+ "installerResult",
6448
+ "installerType",
6449
+ "interactive",
6450
+ "lastName",
6451
+ "mcpSetup",
6452
+ "nodeVersion",
6453
+ "os",
6454
+ "osVersionMajor",
6455
+ "previousCliVersion",
6456
+ "requestedVersion",
6457
+ "resolvedVersion",
6458
+ "runtime",
6459
+ "subcommand",
6460
+ "success",
6461
+ "platform",
6462
+ "telemetrySchemaVersion",
6463
+ "toolName",
6464
+ "toolset",
6465
+ "targetCliVersion",
6466
+ "tuiInitialTab",
6467
+ "updateAction"
6468
+ ]);
6469
+ var MEASUREMENT_ALLOWLIST = /* @__PURE__ */ new Set(["durationMs"]);
6470
+ var trimString = (value) => {
6471
+ if (typeof value !== "string") {
6472
+ return void 0;
6473
+ }
6474
+ const trimmed = value.trim();
6475
+ return trimmed || void 0;
6476
+ };
6477
+ var parseTelemetryBoolean = (value) => {
6478
+ const normalized = trimString(value)?.toLowerCase();
6479
+ if (!normalized) {
6480
+ return void 0;
6481
+ }
6482
+ if (TRUE_VALUES.has(normalized)) {
6483
+ return true;
6484
+ }
6485
+ if (FALSE_VALUES.has(normalized)) {
6486
+ return false;
6487
+ }
6488
+ return void 0;
6489
+ };
6490
+ var resolveTelemetryEnabled = (config, env = process.env) => {
6491
+ if (parseTelemetryBoolean(env.CLOUDEVAL_TELEMETRY_DISABLED) === true) {
6492
+ return false;
6493
+ }
6494
+ const envOverride = parseTelemetryBoolean(env.CLOUDEVAL_TELEMETRY);
6495
+ if (typeof envOverride === "boolean") {
6496
+ return envOverride;
6497
+ }
6498
+ if (typeof config.telemetry?.enabled === "boolean") {
6499
+ return config.telemetry.enabled;
6500
+ }
6501
+ return true;
6502
+ };
6503
+ var resolveTelemetryConnectionString = (env = process.env) => {
6504
+ return trimString(env.CLOUDEVAL_APPLICATIONINSIGHTS_CONNECTION_STRING) || trimString(env.APPLICATIONINSIGHTS_CONNECTION_STRING) || trimString(env.NEXT_PUBLIC_APPLICATIONINSIGHTS_CONNECTION_STRING) || trimString(PACKAGED_APPLICATIONINSIGHTS_CONNECTION_STRING);
6505
+ };
6506
+ var sanitizeTelemetryProperties = (properties) => {
6507
+ const sanitizedProperties = {};
6508
+ const measurements = {};
6509
+ for (const [key, value] of Object.entries(properties)) {
6510
+ if (MEASUREMENT_ALLOWLIST.has(key)) {
6511
+ const numberValue2 = typeof value === "number" ? value : typeof value === "string" ? Number(value) : Number.NaN;
6512
+ if (Number.isFinite(numberValue2)) {
6513
+ measurements[key] = numberValue2;
6514
+ }
6515
+ continue;
6516
+ }
6517
+ if (!PROPERTY_ALLOWLIST.has(key)) {
6518
+ continue;
6519
+ }
6520
+ if (typeof value === "string") {
6521
+ const trimmed = value.trim();
6522
+ if (trimmed) {
6523
+ sanitizedProperties[key] = trimmed.slice(0, 256);
6524
+ }
6525
+ } else if (typeof value === "boolean" || typeof value === "number") {
6526
+ sanitizedProperties[key] = String(value);
6527
+ }
6528
+ }
6529
+ return { properties: sanitizedProperties, measurements };
6530
+ };
6531
+ var buildTelemetryUserProperties = (user) => {
6532
+ if (!user || typeof user !== "object") {
6533
+ return {};
6534
+ }
6535
+ const email = trimString(user.email);
6536
+ const fullName = trimString(user.fullName) || trimString(user.full_name) || trimString(user.name);
6537
+ const firstName = trimString(user.firstName);
6538
+ const lastName = trimString(user.lastName);
6539
+ const nameParts = fullName?.split(/\s+/).filter(Boolean) || [];
6540
+ return {
6541
+ ...email ? { email } : {},
6542
+ ...firstName || nameParts[0] ? { firstName: firstName || nameParts[0] } : {},
6543
+ ...lastName || nameParts.length > 1 ? { lastName: lastName || nameParts[nameParts.length - 1] } : {},
6544
+ ...fullName ? { fullName } : {}
6545
+ };
6546
+ };
6547
+ var classifyTelemetryError = (error) => {
6548
+ const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
6549
+ const normalized = message.toLowerCase();
6550
+ if (normalized.includes("no authentication") || normalized.includes("not authenticated")) {
6551
+ return "auth_unavailable";
6552
+ }
6553
+ if (normalized.includes("403") || normalized.includes("forbidden")) {
6554
+ return "forbidden";
6555
+ }
6556
+ if (normalized.includes("401") || normalized.includes("unauthorized")) {
6557
+ return "unauthorized";
6558
+ }
6559
+ if (normalized.includes("429") || normalized.includes("rate limit")) {
6560
+ return "rate_limited";
6561
+ }
6562
+ if (normalized.includes("fetch failed") || normalized.includes("econnrefused") || normalized.includes("enotfound") || normalized.includes("etimedout") || normalized.includes("network")) {
6563
+ return "network";
6564
+ }
6565
+ if (normalized.includes("abort") || normalized.includes("cancel")) {
6566
+ return "interrupted";
6567
+ }
6568
+ if (normalized.includes("invalid") || normalized.includes("required")) {
6569
+ return "validation";
6570
+ }
6571
+ return "error";
6572
+ };
6573
+ var getCommonTelemetryProperties = (overrides = {}) => {
6574
+ const release = os3.release();
6575
+ return {
6576
+ cliVersion: CLI_VERSION,
6577
+ telemetrySchemaVersion: TELEMETRY_SCHEMA_VERSION,
6578
+ os: os3.platform(),
6579
+ osVersionMajor: release.split(".")[0],
6580
+ arch: os3.arch(),
6581
+ nodeVersion: process.versions.node,
6582
+ runtime: process.versions.bun ? "bun" : "node",
6583
+ installSource: process.env.CLOUDEVAL_INSTALL_SOURCE || "unknown",
6584
+ ...overrides
6585
+ };
6586
+ };
6587
+ var createNoopTelemetry = () => ({
6588
+ enabled: false,
6589
+ setUserProperties: () => {
6590
+ },
6591
+ track: async () => {
6592
+ },
6593
+ flush: async () => {
6594
+ }
6595
+ });
6596
+ var createApplicationInsightsClient = async (connectionString) => {
6597
+ const appInsights = await import("applicationinsights");
6598
+ const client = new appInsights.TelemetryClient(connectionString, {
6599
+ useGlobalProviders: false
6600
+ });
6601
+ client.setUseDiskRetryCaching(false);
6602
+ return client;
6603
+ };
6604
+ var flushClient = async (client) => {
6605
+ try {
6606
+ const flush = client.flush;
6607
+ if (!flush) {
6608
+ return;
6609
+ }
6610
+ await new Promise((resolve) => {
6611
+ let settled = false;
6612
+ const settle = () => {
6613
+ if (!settled) {
6614
+ settled = true;
6615
+ resolve();
6616
+ }
6617
+ };
6618
+ const timeout = setTimeout(settle, 1500);
6619
+ timeout.unref?.();
6620
+ try {
6621
+ const result = flush.call(client, () => {
6622
+ clearTimeout(timeout);
6623
+ settle();
6624
+ });
6625
+ if (result && typeof result.then === "function") {
6626
+ result.catch(() => {
6627
+ }).finally(() => {
6628
+ clearTimeout(timeout);
6629
+ settle();
6630
+ });
6631
+ } else if (flush.length === 0) {
6632
+ clearTimeout(timeout);
6633
+ settle();
6634
+ }
6635
+ } catch {
6636
+ clearTimeout(timeout);
6637
+ settle();
6638
+ }
6639
+ });
6640
+ } catch {
6641
+ }
6642
+ };
6643
+ var createCliTelemetry = async (options) => {
6644
+ if (!resolveTelemetryEnabled(options.config, options.env)) {
6645
+ return createNoopTelemetry();
6646
+ }
6647
+ const connectionString = resolveTelemetryConnectionString(options.env);
6648
+ if (!connectionString) {
6649
+ return createNoopTelemetry();
6650
+ }
6651
+ let client;
6652
+ try {
6653
+ client = options.clientFactory ? options.clientFactory(connectionString) : await createApplicationInsightsClient(connectionString);
6654
+ } catch {
6655
+ return createNoopTelemetry();
6656
+ }
6657
+ let userProperties = {};
6658
+ const commonProperties = options.commonProperties || {};
6659
+ return {
6660
+ enabled: true,
6661
+ setUserProperties(properties) {
6662
+ userProperties = {
6663
+ ...userProperties,
6664
+ ...sanitizeTelemetryProperties(buildTelemetryUserProperties(properties)).properties
6665
+ };
6666
+ },
6667
+ async track(eventName, properties = {}) {
6668
+ try {
6669
+ const sanitized = sanitizeTelemetryProperties({
6670
+ ...commonProperties,
6671
+ ...userProperties,
6672
+ ...properties
6673
+ });
6674
+ client.trackEvent({
6675
+ name: eventName,
6676
+ properties: sanitized.properties,
6677
+ measurements: sanitized.measurements
6678
+ });
6679
+ } catch {
6680
+ }
6681
+ },
6682
+ async flush() {
6683
+ await flushClient(client);
6684
+ }
6685
+ };
6686
+ };
6687
+
6140
6688
  // src/mcpCommand.ts
6141
6689
  var MCP_PROTOCOL_VERSION = "2025-06-18";
6142
6690
  var SUPPORTED_PROTOCOL_VERSIONS = ["2025-06-18", "2025-03-26", "2024-11-05"];
@@ -8008,7 +8556,7 @@ var reportsFrontendUrl = (config, input) => buildFrontendUrl({
8008
8556
  reportVerbosity: input.reportVerbosity
8009
8557
  });
8010
8558
  var resolveAuth = async (config, options = {}) => {
8011
- const core = await import("./dist-AGQQPJUD.js");
8559
+ const core = await import("./dist-CFLR5FML.js");
8012
8560
  core.assertSecureBaseUrl(config.baseUrl);
8013
8561
  let token;
8014
8562
  try {
@@ -8108,7 +8656,7 @@ var assertModelAvailable = async (config, token) => {
8108
8656
  if (!config.model) {
8109
8657
  return;
8110
8658
  }
8111
- const core = await import("./dist-AGQQPJUD.js");
8659
+ const core = await import("./dist-CFLR5FML.js");
8112
8660
  try {
8113
8661
  const response = await fetch(
8114
8662
  `${core.normalizeApiBase(config.baseUrl)}/models`,
@@ -8365,7 +8913,7 @@ var buildToolHandlers = (serverOptions) => {
8365
8913
  });
8366
8914
  handlers.set("agent_profiles_list", async (args) => {
8367
8915
  const config = await resolveInvocationConfig(serverOptions, args);
8368
- const core = await import("./dist-AGQQPJUD.js");
8916
+ const core = await import("./dist-CFLR5FML.js");
8369
8917
  const data = await listProfilesForDiscovery(core, config.baseUrl);
8370
8918
  return withEnvelope({
8371
8919
  command: "agents list",
@@ -8378,7 +8926,7 @@ var buildToolHandlers = (serverOptions) => {
8378
8926
  throw new Error("profileId is required.");
8379
8927
  }
8380
8928
  const config = await resolveInvocationConfig(serverOptions, args);
8381
- const core = await import("./dist-AGQQPJUD.js");
8929
+ const core = await import("./dist-CFLR5FML.js");
8382
8930
  const data = await getProfileForDiscovery(core, config.baseUrl, profileId);
8383
8931
  return withEnvelope({
8384
8932
  command: "agents show",
@@ -9015,7 +9563,7 @@ var buildToolHandlers = (serverOptions) => {
9015
9563
  });
9016
9564
  handlers.set("auth_status", async (args) => {
9017
9565
  const config = await resolveInvocationConfig(serverOptions, args);
9018
- const core = await import("./dist-AGQQPJUD.js");
9566
+ const core = await import("./dist-CFLR5FML.js");
9019
9567
  const data = await core.getAuthStatus(config.baseUrl, { validate: true });
9020
9568
  return withEnvelope({
9021
9569
  command: "auth status",
@@ -9024,7 +9572,7 @@ var buildToolHandlers = (serverOptions) => {
9024
9572
  });
9025
9573
  handlers.set("status", async (args) => {
9026
9574
  const config = await resolveInvocationConfig(serverOptions, args);
9027
- const core = await import("./dist-AGQQPJUD.js");
9575
+ const core = await import("./dist-CFLR5FML.js");
9028
9576
  const auth = await core.getAuthStatus(config.baseUrl, { validate: true });
9029
9577
  return withEnvelope({
9030
9578
  command: "status",
@@ -9055,7 +9603,7 @@ var buildToolHandlers = (serverOptions) => {
9055
9603
  }
9056
9604
  ];
9057
9605
  try {
9058
- const core = await import("./dist-AGQQPJUD.js");
9606
+ const core = await import("./dist-CFLR5FML.js");
9059
9607
  core.assertSecureBaseUrl(config.baseUrl);
9060
9608
  checks.push({
9061
9609
  id: "base-url-secure",
@@ -9575,7 +10123,7 @@ var buildToolHandlers = (serverOptions) => {
9575
10123
  } catch {
9576
10124
  token = config.accessKey;
9577
10125
  }
9578
- const core = await import("./dist-AGQQPJUD.js");
10126
+ const core = await import("./dist-CFLR5FML.js");
9579
10127
  const data = await core.getBillingConfig({
9580
10128
  baseUrl: config.baseUrl,
9581
10129
  authToken: token
@@ -10037,9 +10585,18 @@ var serveMcpServer = async (options) => {
10037
10585
  `Tool has no handler: ${name}`
10038
10586
  );
10039
10587
  }
10588
+ const startedAt = Date.now();
10040
10589
  try {
10041
10590
  const envelope = await handler(args);
10042
10591
  debug("tool call completed", { tool: name, ok: envelope.ok });
10592
+ await options.telemetry?.track("cli.mcp.tool", {
10593
+ command: "mcp",
10594
+ subcommand: "serve",
10595
+ toolName: name,
10596
+ toolset,
10597
+ durationMs: Date.now() - startedAt,
10598
+ success: true
10599
+ });
10043
10600
  return jsonRpcResult(
10044
10601
  request.id,
10045
10602
  toToolResult(envelope)
@@ -10049,6 +10606,15 @@ var serveMcpServer = async (options) => {
10049
10606
  tool: name,
10050
10607
  message: error instanceof Error ? error.message : String(error)
10051
10608
  });
10609
+ await options.telemetry?.track("cli.mcp.tool", {
10610
+ command: "mcp",
10611
+ subcommand: "serve",
10612
+ toolName: name,
10613
+ toolset,
10614
+ durationMs: Date.now() - startedAt,
10615
+ success: false,
10616
+ errorCategory: classifyTelemetryError(error)
10617
+ });
10052
10618
  return jsonRpcResult(
10053
10619
  request.id,
10054
10620
  toToolError(name, error)
@@ -10329,8 +10895,10 @@ var registerMcpCommand = (program2, deps) => {
10329
10895
  profile: normalizeConfigProfile(command.optsWithGlobals?.().profile),
10330
10896
  accessKey: stringValue(options.accessKey),
10331
10897
  toolset: normalizeMcpToolset(options.toolset),
10332
- verbose: Boolean(options.verbose)
10898
+ verbose: Boolean(options.verbose),
10899
+ telemetry: deps.getTelemetry?.()
10333
10900
  });
10901
+ await deps.finishTelemetry?.(0);
10334
10902
  process.exit(0);
10335
10903
  });
10336
10904
  };
@@ -10409,7 +10977,7 @@ var registerCapabilitiesCommand = (program2, deps) => {
10409
10977
  warnIfAccessKeyFromCliOption(options, command);
10410
10978
  let data = capabilities;
10411
10979
  if (options.live) {
10412
- const core = await import("./dist-AGQQPJUD.js");
10980
+ const core = await import("./dist-CFLR5FML.js");
10413
10981
  const baseUrl = await deps.resolveBaseUrl(options, command);
10414
10982
  const accessKey = options.accessKeyStdin ? await deps.readStdinValue() : options.accessKey;
10415
10983
  const token = await core.getAuthToken({ accessKey, baseUrl });
@@ -10547,7 +11115,7 @@ var writeCredentialOutput = async (input) => {
10547
11115
  };
10548
11116
  var resolveCoreAuth = async (options, command, deps) => {
10549
11117
  const context = await resolveAuthContext(options, command, deps);
10550
- const core = await import("./dist-AGQQPJUD.js");
11118
+ const core = await import("./dist-CFLR5FML.js");
10551
11119
  return { ...context, core };
10552
11120
  };
10553
11121
  var parseCapabilities = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean);
@@ -10655,7 +11223,7 @@ import { randomUUID as randomUUID4 } from "crypto";
10655
11223
  import { exec } from "child_process";
10656
11224
  import { randomUUID as randomUUID3 } from "crypto";
10657
11225
  import fs9 from "fs/promises";
10658
- import os2 from "os";
11226
+ import os4 from "os";
10659
11227
  import path6 from "path";
10660
11228
  var normalizeHooks = (config, event) => {
10661
11229
  if (config.hooks?.enabled !== true) {
@@ -10668,7 +11236,7 @@ var normalizeHooks = (config, event) => {
10668
11236
  };
10669
11237
  var writeHookPayload = async (input, hook) => {
10670
11238
  const filePath = path6.join(
10671
- os2.tmpdir(),
11239
+ os4.tmpdir(),
10672
11240
  `cloudeval-hook-${process.pid}-${randomUUID3()}.json`
10673
11241
  );
10674
11242
  await fs9.writeFile(
@@ -10864,7 +11432,7 @@ var registerAgentsCommand = (program2, deps) => {
10864
11432
  const agents = program2.command("agents").description("CloudEval Agent Profile utilities");
10865
11433
  addAgentOutputOptions(agents.command("list").description("List Agent Profiles"), deps).action(async (options, command) => {
10866
11434
  const baseUrl = await deps.resolveBaseUrl(options, command);
10867
- const core = await import("./dist-AGQQPJUD.js");
11435
+ const core = await import("./dist-CFLR5FML.js");
10868
11436
  core.assertSecureBaseUrl(baseUrl);
10869
11437
  const data = await listProfilesForDiscovery2(core, baseUrl);
10870
11438
  await writeProfiles({
@@ -10880,7 +11448,7 @@ var registerAgentsCommand = (program2, deps) => {
10880
11448
  deps
10881
11449
  ).action(async (profileId, options, command) => {
10882
11450
  const baseUrl = await deps.resolveBaseUrl(options, command);
10883
- const core = await import("./dist-AGQQPJUD.js");
11451
+ const core = await import("./dist-CFLR5FML.js");
10884
11452
  core.assertSecureBaseUrl(baseUrl);
10885
11453
  const data = await getProfileForDiscovery2(core, baseUrl, profileId);
10886
11454
  await writeProfiles({
@@ -10899,7 +11467,7 @@ var registerAgentsCommand = (program2, deps) => {
10899
11467
  const cliProfile = getActiveConfigProfile(command);
10900
11468
  const cliConfig = await loadCliConfig(cliProfile);
10901
11469
  const auth = await resolveAuthContext(options, command, deps);
10902
- const core = await import("./dist-AGQQPJUD.js");
11470
+ const core = await import("./dist-CFLR5FML.js");
10903
11471
  const profileResponse = await core.getAgentProfile({
10904
11472
  baseUrl: auth.baseUrl,
10905
11473
  authToken: auth.token,
@@ -11397,7 +11965,7 @@ var registerDiagnosticsCommands = (program2, deps) => {
11397
11965
  const baseUrl = await deps.resolveBaseUrl(options, command);
11398
11966
  const profile = getActiveConfigProfile(command);
11399
11967
  const config = await loadCliConfig(profile);
11400
- const core = await import("./dist-AGQQPJUD.js");
11968
+ const core = await import("./dist-CFLR5FML.js");
11401
11969
  const auth = await core.getAuthStatus(baseUrl, { validate: true });
11402
11970
  if (options.format === "text" || !options.format) {
11403
11971
  process.stdout.write(
@@ -11447,7 +12015,7 @@ var registerDiagnosticsCommands = (program2, deps) => {
11447
12015
  detail: getCliConfigPath(profile)
11448
12016
  });
11449
12017
  try {
11450
- const core = await import("./dist-AGQQPJUD.js");
12018
+ const core = await import("./dist-CFLR5FML.js");
11451
12019
  core.assertSecureBaseUrl(baseUrl);
11452
12020
  checks.push({
11453
12021
  id: "base-url-secure",
@@ -11547,7 +12115,7 @@ var resolveToken2 = async (options, deps, baseUrl, command) => {
11547
12115
  return options.accessKey;
11548
12116
  }
11549
12117
  try {
11550
- const core = await import("./dist-AGQQPJUD.js");
12118
+ const core = await import("./dist-CFLR5FML.js");
11551
12119
  return await core.getAuthToken({
11552
12120
  baseUrl
11553
12121
  });
@@ -11631,7 +12199,7 @@ var registerModelsCommand = (program2, deps) => {
11631
12199
  let source = "fallback";
11632
12200
  let modelList = fallbackModels;
11633
12201
  try {
11634
- const core = await import("./dist-AGQQPJUD.js");
12202
+ const core = await import("./dist-CFLR5FML.js");
11635
12203
  const response = await fetch(`${core.normalizeApiBase(baseUrl)}/models`, {
11636
12204
  headers: {
11637
12205
  Accept: "application/json",
@@ -11911,7 +12479,7 @@ var registerSetupCommand = (program2, defaultBaseUrl = CLOUD_BASE_URL) => {
11911
12479
  };
11912
12480
 
11913
12481
  // src/updateCommand.ts
11914
- import { spawn } from "child_process";
12482
+ import { spawn as spawn2 } from "child_process";
11915
12483
  import fs10 from "fs/promises";
11916
12484
  import path7 from "path";
11917
12485
  import { createInterface as createInterface2 } from "readline/promises";
@@ -12030,7 +12598,7 @@ var runInstaller = async ({
12030
12598
  installerUrl,
12031
12599
  targetTag,
12032
12600
  fetchImpl = fetch,
12033
- spawnImpl = spawn,
12601
+ spawnImpl = spawn2,
12034
12602
  output = process.stderr,
12035
12603
  platform = process.platform,
12036
12604
  env = process.env,
@@ -12337,13 +12905,19 @@ var maybeShowUpdateNudge = async (input, deps = {}) => {
12337
12905
  } catch {
12338
12906
  }
12339
12907
  };
12340
- var registerUpdateCommand = (program2) => {
12908
+ var registerUpdateCommand = (program2, registerOptions = {}) => {
12341
12909
  program2.command("update").description("Update CloudEval CLI to the latest published version").option("-c, --check", "Check for the latest version without installing", false).option("-y, --yes", "Install without prompting for confirmation", false).option(
12342
12910
  "-f, --format <format>",
12343
12911
  "Output format: text, json, ndjson, markdown",
12344
12912
  "text"
12345
12913
  ).option("-o, --output <file>", "Output file").action(async (options) => {
12346
12914
  const result = await handleUpdateCommand(options);
12915
+ await registerOptions.getTelemetry?.()?.track("cli.update", {
12916
+ previousCliVersion: result.currentVersion,
12917
+ targetCliVersion: result.latestVersion,
12918
+ updateAction: result.action,
12919
+ success: true
12920
+ });
12347
12921
  if (options.format === "text" || !options.format) {
12348
12922
  const text = formatUpdateStatusText(result);
12349
12923
  if (options.output) {
@@ -12364,7 +12938,7 @@ var registerUpdateCommand = (program2) => {
12364
12938
 
12365
12939
  // src/uninstallCommand.ts
12366
12940
  import fs11 from "fs/promises";
12367
- import os3 from "os";
12941
+ import os5 from "os";
12368
12942
  import path8 from "path";
12369
12943
  import { createInterface as createInterface3 } from "readline/promises";
12370
12944
  var pathExists = async (candidate) => {
@@ -12521,7 +13095,7 @@ var confirmUninstall = async ({
12521
13095
  }
12522
13096
  };
12523
13097
  var handleUninstallCommand = async (options, deps = {}) => {
12524
- const home = deps.home ?? os3.homedir();
13098
+ const home = deps.home ?? os5.homedir();
12525
13099
  const platform = deps.platform ?? process.platform;
12526
13100
  const dryRun = Boolean(options.dryRun);
12527
13101
  const removeConfig = Boolean(options.removeConfig);
@@ -12756,7 +13330,7 @@ var assertNoLegacyApiKeyUsage = () => {
12756
13330
  };
12757
13331
  assertNoLegacyApiKeyUsage();
12758
13332
  var completionScriptPath = (shell) => {
12759
- const home = os4.homedir();
13333
+ const home = os6.homedir();
12760
13334
  switch (shell) {
12761
13335
  case "bash":
12762
13336
  return path9.join(home, ".local", "share", "bash-completion", "completions", "cloudeval");
@@ -12770,7 +13344,7 @@ var completionScriptPath = (shell) => {
12770
13344
  };
12771
13345
  var ZSH_FPATH_MARKER = "CloudEval CLI completions";
12772
13346
  var ensureZshCompletionFpath = async () => {
12773
- const zshrc = path9.join(os4.homedir(), ".zshrc");
13347
+ const zshrc = path9.join(os6.homedir(), ".zshrc");
12774
13348
  let existing = "";
12775
13349
  try {
12776
13350
  existing = await fs12.readFile(zshrc, "utf8");
@@ -12803,7 +13377,7 @@ var uninstallCompletionScript = async (shell) => {
12803
13377
  var runInteractiveLoginOnboarding = async (baseUrl, token) => {
12804
13378
  const [{ render }, { Onboarding }] = await Promise.all([
12805
13379
  import("ink"),
12806
- import("./Onboarding-4N4WIORR.js")
13380
+ import("./Onboarding-QV5RTUCR.js")
12807
13381
  ]);
12808
13382
  await new Promise((resolve) => {
12809
13383
  let app;
@@ -13016,6 +13590,94 @@ var sanitizeHeaders = (headers) => {
13016
13590
  }
13017
13591
  return sanitized;
13018
13592
  };
13593
+ var activeTelemetry;
13594
+ var activeTelemetryStartedAt = 0;
13595
+ var activeTelemetryProperties = {};
13596
+ var activeTelemetryFinished = false;
13597
+ var enumLikeValue = (value) => {
13598
+ if (typeof value !== "string") {
13599
+ return void 0;
13600
+ }
13601
+ const normalized = value.trim().toLowerCase();
13602
+ return /^[a-z][a-z0-9_-]{0,48}$/.test(normalized) ? normalized : void 0;
13603
+ };
13604
+ var versionLikeValue = (value) => {
13605
+ if (typeof value !== "string") {
13606
+ return void 0;
13607
+ }
13608
+ const normalized = value.trim();
13609
+ if (normalized.toLowerCase() === "latest") {
13610
+ return "latest";
13611
+ }
13612
+ return /^v?[0-9][0-9A-Za-z._-]{0,64}$/.test(normalized) ? normalized : void 0;
13613
+ };
13614
+ var commandPathParts = (command) => {
13615
+ const parts = [];
13616
+ let current = command;
13617
+ while (current) {
13618
+ const name = current.name();
13619
+ if (name && name !== "cloudeval") {
13620
+ parts.unshift(name);
13621
+ }
13622
+ current = current.parent;
13623
+ }
13624
+ return parts;
13625
+ };
13626
+ var telemetryPropertiesForCommand = (command, options) => {
13627
+ const [commandName = "root", ...subcommands] = commandPathParts(command);
13628
+ const format = options.json ? "json" : enumLikeValue(options.format) ?? void 0;
13629
+ const authMode = options.accessKey || options.accessKeyStdin ? "access_key" : options.headless ? "device_code" : "stored";
13630
+ return {
13631
+ command: commandName,
13632
+ subcommand: subcommands.join(" ") || void 0,
13633
+ format,
13634
+ interactive: Boolean(
13635
+ !options.nonInteractive && process.stdin.isTTY && process.stdout.isTTY
13636
+ ),
13637
+ authMode,
13638
+ tuiInitialTab: enumLikeValue(options.tab),
13639
+ toolset: enumLikeValue(options.toolset)
13640
+ };
13641
+ };
13642
+ var getActiveCliTelemetry = () => activeTelemetry;
13643
+ var initializeCommandTelemetry = async (actionCommand, options) => {
13644
+ activeTelemetryStartedAt = Date.now();
13645
+ activeTelemetryFinished = false;
13646
+ activeTelemetryProperties = telemetryPropertiesForCommand(actionCommand, options);
13647
+ const config = await resolveCliConfig(actionCommand);
13648
+ activeTelemetry = await createCliTelemetry({
13649
+ config,
13650
+ commonProperties: getCommonTelemetryProperties(activeTelemetryProperties)
13651
+ });
13652
+ };
13653
+ var finishCommandTelemetry = async (exitCode, error) => {
13654
+ if (!activeTelemetry || activeTelemetryFinished) {
13655
+ return;
13656
+ }
13657
+ activeTelemetryFinished = true;
13658
+ const durationMs = Math.max(0, Date.now() - activeTelemetryStartedAt);
13659
+ if (error) {
13660
+ await activeTelemetry.track("cli.error", {
13661
+ ...activeTelemetryProperties,
13662
+ durationMs,
13663
+ exitCode,
13664
+ success: false,
13665
+ errorCategory: classifyTelemetryError(error)
13666
+ });
13667
+ }
13668
+ await activeTelemetry.track("cli.command", {
13669
+ ...activeTelemetryProperties,
13670
+ durationMs,
13671
+ exitCode,
13672
+ success: exitCode === 0,
13673
+ ...error ? { errorCategory: classifyTelemetryError(error) } : {}
13674
+ });
13675
+ await activeTelemetry.flush();
13676
+ };
13677
+ var exitCli = async (exitCode, error) => {
13678
+ await finishCommandTelemetry(exitCode, error);
13679
+ process.exit(exitCode);
13680
+ };
13019
13681
  var program = new Command();
13020
13682
  var resolveBaseUrl = async (options, command) => {
13021
13683
  const configuredBaseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
@@ -13037,7 +13699,7 @@ var resolveBaseUrl = async (options, command) => {
13037
13699
  });
13038
13700
  }
13039
13701
  try {
13040
- const { getAuthStatus } = await import("./dist-AGQQPJUD.js");
13702
+ const { getAuthStatus } = await import("./dist-CFLR5FML.js");
13041
13703
  const status = await getAuthStatus();
13042
13704
  const storedBaseUrl = status.baseUrl;
13043
13705
  if (storedBaseUrl && shouldUseStoredBaseUrl(storedBaseUrl)) {
@@ -13079,6 +13741,7 @@ Examples:
13079
13741
  `
13080
13742
  ).option("--profile <name>", "Configuration profile", process.env.CLOUDEVAL_PROFILE).option("-v, --verbose", "Enable verbose logging", false).option("--show-sensitive-ids", "Show full account/session identifiers in command output", false).hook("preAction", async (thisCommand, actionCommand) => {
13081
13743
  const opts = typeof actionCommand.optsWithGlobals === "function" ? actionCommand.optsWithGlobals() : thisCommand.opts();
13744
+ await initializeCommandTelemetry(actionCommand, opts);
13082
13745
  setShowSensitiveIds(Boolean(opts.showSensitiveIds || opts.verbose));
13083
13746
  if (opts.verbose) {
13084
13747
  setVerbose(true);
@@ -13089,6 +13752,8 @@ Examples:
13089
13752
  args: process.argv.slice(2),
13090
13753
  options: opts
13091
13754
  });
13755
+ }).hook("postAction", async () => {
13756
+ await finishCommandTelemetry(0);
13092
13757
  });
13093
13758
  program.addHelpCommand(false);
13094
13759
  program.command("login").description("Authenticate with Cloudeval").option(
@@ -13108,7 +13773,7 @@ program.command("login").description("Authenticate with Cloudeval").option(
13108
13773
  checkUserStatus,
13109
13774
  ensurePlaygroundProject,
13110
13775
  login
13111
- } = await import("./dist-AGQQPJUD.js");
13776
+ } = await import("./dist-CFLR5FML.js");
13112
13777
  assertSecureBaseUrl(options.baseUrl);
13113
13778
  const headlessEnvironment = isHeadlessEnvironment();
13114
13779
  const headlessLogin = options.headless || headlessEnvironment;
@@ -13116,6 +13781,7 @@ program.command("login").description("Authenticate with Cloudeval").option(
13116
13781
  headless: headlessLogin
13117
13782
  });
13118
13783
  const userStatus = await checkUserStatus(options.baseUrl, token);
13784
+ getActiveCliTelemetry()?.setUserProperties(userStatus.user || {});
13119
13785
  if (userStatus.user?.id && userStatus.user.email) {
13120
13786
  const shouldRunQuickOnboard = !userStatus.onboardingCompleted;
13121
13787
  if (shouldRunQuickOnboard) {
@@ -13159,11 +13825,21 @@ program.command("login").description("Authenticate with Cloudeval").option(
13159
13825
  } else {
13160
13826
  verboseLog("Skipping Playground setup because authenticated user details were unavailable");
13161
13827
  }
13828
+ await getActiveCliTelemetry()?.track("cli.auth", {
13829
+ command: "login",
13830
+ authMode: headlessLogin ? "device_code" : "browser",
13831
+ success: true
13832
+ });
13162
13833
  console.log("\u2705 Login successful.");
13163
- process.exit(0);
13834
+ await exitCli(0);
13164
13835
  } catch (error) {
13836
+ await getActiveCliTelemetry()?.track("cli.auth", {
13837
+ command: "login",
13838
+ success: false,
13839
+ errorCategory: classifyTelemetryError(error)
13840
+ });
13165
13841
  console.error(`\u274C Login failed: ${error?.message || "Unknown error"}`);
13166
- process.exit(1);
13842
+ await exitCli(1, error);
13167
13843
  }
13168
13844
  });
13169
13845
  program.command("logout").description("Log out and clear stored authentication state").option(
@@ -13172,7 +13848,7 @@ program.command("logout").description("Log out and clear stored authentication s
13172
13848
  DEFAULT_BASE_URL
13173
13849
  ).option("--all-devices", "Revoke sessions on all devices", false).action(async (options) => {
13174
13850
  try {
13175
- const { assertSecureBaseUrl, logout } = await import("./dist-AGQQPJUD.js");
13851
+ const { assertSecureBaseUrl, logout } = await import("./dist-CFLR5FML.js");
13176
13852
  assertSecureBaseUrl(options.baseUrl);
13177
13853
  const result = await logout({
13178
13854
  baseUrl: options.baseUrl,
@@ -13183,10 +13859,20 @@ program.command("logout").description("Log out and clear stored authentication s
13183
13859
  } else {
13184
13860
  console.log("\u2705 Logged out locally.");
13185
13861
  }
13186
- process.exit(0);
13862
+ await getActiveCliTelemetry()?.track("cli.auth", {
13863
+ command: "logout",
13864
+ authMode: "stored",
13865
+ success: true
13866
+ });
13867
+ await exitCli(0);
13187
13868
  } catch (error) {
13869
+ await getActiveCliTelemetry()?.track("cli.auth", {
13870
+ command: "logout",
13871
+ success: false,
13872
+ errorCategory: classifyTelemetryError(error)
13873
+ });
13188
13874
  console.error("\u274C Logout failed:", error.message);
13189
- process.exit(1);
13875
+ await exitCli(1, error);
13190
13876
  }
13191
13877
  });
13192
13878
  var authCommand = program.command("auth").description("Authentication utilities");
@@ -13196,7 +13882,7 @@ authCommand.command("status").description("Show current authentication status").
13196
13882
  DEFAULT_BASE_URL
13197
13883
  ).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) => {
13198
13884
  try {
13199
- const { assertSecureBaseUrl, getAuthStatus } = await import("./dist-AGQQPJUD.js");
13885
+ const { assertSecureBaseUrl, getAuthStatus } = await import("./dist-CFLR5FML.js");
13200
13886
  const effectiveBaseUrl = await resolveBaseUrl(options, command);
13201
13887
  assertSecureBaseUrl(effectiveBaseUrl);
13202
13888
  const status = await getAuthStatus(effectiveBaseUrl, { validate: true });
@@ -13232,9 +13918,21 @@ authCommand.command("status").description("Show current authentication status").
13232
13918
  data: options.format === "text" || !options.format ? textData : machineData,
13233
13919
  format: options.format
13234
13920
  });
13921
+ await getActiveCliTelemetry()?.track("cli.auth", {
13922
+ command: "auth",
13923
+ subcommand: "status",
13924
+ authMode: "stored",
13925
+ success: true
13926
+ });
13235
13927
  } catch (error) {
13928
+ await getActiveCliTelemetry()?.track("cli.auth", {
13929
+ command: "auth",
13930
+ subcommand: "status",
13931
+ success: false,
13932
+ errorCategory: classifyTelemetryError(error)
13933
+ });
13236
13934
  console.error(`\u274C Failed to fetch auth status: ${error?.message || "Unknown error"}`);
13237
- process.exit(1);
13935
+ await exitCli(1, error);
13238
13936
  }
13239
13937
  });
13240
13938
  registerReportsCommand(program, {
@@ -13320,10 +14018,26 @@ registerCapabilitiesCommand(program, {
13320
14018
  });
13321
14019
  registerMcpCommand(program, {
13322
14020
  defaultBaseUrl: DEFAULT_BASE_URL,
13323
- resolveBaseUrl
14021
+ resolveBaseUrl,
14022
+ getTelemetry: getActiveCliTelemetry,
14023
+ finishTelemetry: finishCommandTelemetry
13324
14024
  });
13325
- registerUpdateCommand(program);
14025
+ registerUpdateCommand(program, { getTelemetry: getActiveCliTelemetry });
13326
14026
  registerUninstallCommand(program);
14027
+ var telemetryCommand = program.command("__telemetry", { hidden: true }).description("Internal telemetry utilities");
14028
+ telemetryCommand.command("install").description("Track a completed installer run").option("--installer-type <type>", "Installer type").option("--requested-version <version>", "Requested version").option("--resolved-version <version>", "Resolved version").option("--platform <platform>", "Target platform").option("--aliases <state>", "Alias setup state").option("--completions <state>", "Completion setup state").option("--mcp-setup <state>", "MCP setup state").option("--result <result>", "Installer result", "success").action(async (options) => {
14029
+ await getActiveCliTelemetry()?.track("cli.install", {
14030
+ installerType: enumLikeValue(options.installerType),
14031
+ requestedVersion: versionLikeValue(options.requestedVersion),
14032
+ resolvedVersion: versionLikeValue(options.resolvedVersion),
14033
+ platform: enumLikeValue(options.platform),
14034
+ aliases: enumLikeValue(options.aliases),
14035
+ completions: enumLikeValue(options.completions),
14036
+ mcpSetup: enumLikeValue(options.mcpSetup),
14037
+ installerResult: enumLikeValue(options.result) ?? "success",
14038
+ success: options.result !== "failure"
14039
+ });
14040
+ });
13327
14041
  program.command("__complete").description("Internal completion endpoint").argument("[words...]", "Completion words").action((words = []) => {
13328
14042
  const candidates = completeCliWords(words);
13329
14043
  for (const candidate of candidates) {
@@ -13333,14 +14047,14 @@ program.command("__complete").description("Internal completion endpoint").argume
13333
14047
  );
13334
14048
  }
13335
14049
  });
13336
- var completionCommand = program.command("completion").description("Print or install shell completion scripts").argument("[shell]", "Shell to generate completions for: bash, zsh, fish, powershell").option("--bin <name>", "Primary binary name", "cloudeval").action((shellName, options) => {
14050
+ var completionCommand = program.command("completion").description("Print or install shell completion scripts").argument("[shell]", "Shell to generate completions for: bash, zsh, fish, powershell").option("--bin <name>", "Primary binary name", "cloudeval").action(async (shellName, options) => {
13337
14051
  const detectedShell = process.env.SHELL?.split("/").pop();
13338
14052
  const shell = normalizeCompletionShell(shellName || detectedShell);
13339
14053
  if (!shell) {
13340
14054
  console.error(
13341
14055
  "Unsupported shell. Usage: cloudeval completion <bash|zsh|fish|powershell>"
13342
14056
  );
13343
- process.exit(1);
14057
+ return await exitCli(1, new Error("unsupported_completion_shell"));
13344
14058
  }
13345
14059
  process.stdout.write(buildCompletionScript(shell, options.bin));
13346
14060
  });
@@ -13351,7 +14065,7 @@ completionCommand.command("install").description("Install shell completion scrip
13351
14065
  console.error(
13352
14066
  "Unsupported shell. Usage: cloudeval completion install --shell <bash|zsh|fish|powershell>"
13353
14067
  );
13354
- process.exit(1);
14068
+ return await exitCli(1, new Error("unsupported_completion_shell"));
13355
14069
  }
13356
14070
  const scriptPath = await installCompletionScript(shell, options.bin);
13357
14071
  process.stdout.write(`Installed ${shell} completion at ${scriptPath}
@@ -13364,7 +14078,7 @@ completionCommand.command("uninstall").description("Remove installed shell compl
13364
14078
  console.error(
13365
14079
  "Unsupported shell. Usage: cloudeval completion uninstall --shell <bash|zsh|fish|powershell>"
13366
14080
  );
13367
- process.exit(1);
14081
+ return await exitCli(1, new Error("unsupported_completion_shell"));
13368
14082
  }
13369
14083
  const scriptPath = await uninstallCompletionScript(shell);
13370
14084
  process.stdout.write(`Removed ${shell} completion at ${scriptPath}
@@ -13379,10 +14093,10 @@ program.command("tui").description("Open the CloudEval Terminal UI").option(
13379
14093
  "Access key for automation",
13380
14094
  process.env.CLOUDEVAL_ACCESS_KEY
13381
14095
  ).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) => {
13382
- const { assertSecureBaseUrl } = await import("./dist-AGQQPJUD.js");
14096
+ const { assertSecureBaseUrl } = await import("./dist-CFLR5FML.js");
13383
14097
  const [{ render }, { App }] = await Promise.all([
13384
14098
  import("ink"),
13385
- import("./App-7ZEWM5DC.js")
14099
+ import("./App-TJ2EHBBT.js")
13386
14100
  ]);
13387
14101
  const baseUrl = await resolveBaseUrl(options, command);
13388
14102
  assertSecureBaseUrl(baseUrl);
@@ -13400,7 +14114,12 @@ program.command("tui").description("Open the CloudEval Terminal UI").option(
13400
14114
  `
13401
14115
  );
13402
14116
  }
13403
- render(
14117
+ await getActiveCliTelemetry()?.track("cli.tui", {
14118
+ command: "tui",
14119
+ tuiInitialTab: enumLikeValue(options.tab) ?? "chat",
14120
+ success: true
14121
+ });
14122
+ const app = render(
13404
14123
  /* @__PURE__ */ jsx(
13405
14124
  App,
13406
14125
  {
@@ -13421,6 +14140,7 @@ program.command("tui").description("Open the CloudEval Terminal UI").option(
13421
14140
  }
13422
14141
  )
13423
14142
  );
14143
+ await app.waitUntilExit();
13424
14144
  });
13425
14145
  program.command("chat").description("Start an interactive chat session").option(
13426
14146
  "--base-url <url>",
@@ -13431,10 +14151,10 @@ program.command("chat").description("Start an interactive chat session").option(
13431
14151
  "Access key for automation",
13432
14152
  process.env.CLOUDEVAL_ACCESS_KEY
13433
14153
  ).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) => {
13434
- const { assertSecureBaseUrl } = await import("./dist-AGQQPJUD.js");
14154
+ const { assertSecureBaseUrl } = await import("./dist-CFLR5FML.js");
13435
14155
  const [{ render }, { App }] = await Promise.all([
13436
14156
  import("ink"),
13437
- import("./App-7ZEWM5DC.js")
14157
+ import("./App-TJ2EHBBT.js")
13438
14158
  ]);
13439
14159
  const baseUrl = await resolveBaseUrl(options, command);
13440
14160
  assertSecureBaseUrl(baseUrl);
@@ -13470,7 +14190,12 @@ program.command("chat").description("Start an interactive chat session").option(
13470
14190
  throw new Error("No local sessions are available to continue.");
13471
14191
  }
13472
14192
  }
13473
- render(
14193
+ await getActiveCliTelemetry()?.track("cli.tui", {
14194
+ command: "chat",
14195
+ tuiInitialTab: "chat",
14196
+ success: true
14197
+ });
14198
+ const app = render(
13474
14199
  /* @__PURE__ */ jsx(
13475
14200
  App,
13476
14201
  {
@@ -13490,6 +14215,7 @@ program.command("chat").description("Start an interactive chat session").option(
13490
14215
  }
13491
14216
  )
13492
14217
  );
14218
+ await app.waitUntilExit();
13493
14219
  });
13494
14220
  program.command("ask").alias("agent").description("Ask a single question or run an agent task (non-interactive)").argument("<question...>", "The question to ask").option(
13495
14221
  "--base-url <url>",
@@ -13503,7 +14229,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
13503
14229
  const question = Array.isArray(questionParts) ? questionParts.join(" ") : String(questionParts);
13504
14230
  const commandName = command.parent?.args?.[0] === "agent" ? "agent" : "ask";
13505
14231
  const selectedMode = commandName === "agent" ? "agent" : "ask";
13506
- const { assertSecureBaseUrl } = await import("./dist-AGQQPJUD.js");
14232
+ const { assertSecureBaseUrl } = await import("./dist-CFLR5FML.js");
13507
14233
  const baseUrl = await resolveBaseUrl(options, command);
13508
14234
  assertSecureBaseUrl(baseUrl);
13509
14235
  const selectedProfile = getActiveConfigProfile(command);
@@ -13544,7 +14270,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
13544
14270
  const fs13 = await import("fs");
13545
14271
  const fsPromises = await import("fs/promises");
13546
14272
  const { randomUUID: randomUUID5 } = await import("crypto");
13547
- const core = await import("./dist-AGQQPJUD.js");
14273
+ const core = await import("./dist-CFLR5FML.js");
13548
14274
  const {
13549
14275
  streamChat,
13550
14276
  reduceChunk,
@@ -13602,7 +14328,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
13602
14328
  console.error("Authentication required. Starting login process...\n");
13603
14329
  }
13604
14330
  try {
13605
- const { login } = await import("./dist-AGQQPJUD.js");
14331
+ const { login } = await import("./dist-CFLR5FML.js");
13606
14332
  verboseLog("Calling interactive login", { baseUrl });
13607
14333
  token = await login(baseUrl, {
13608
14334
  headless: isHeadlessEnvironment()
@@ -13619,7 +14345,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
13619
14345
  });
13620
14346
  progressWriter.clear();
13621
14347
  console.error(`Login failed: ${loginError.message}`);
13622
- process.exit(1);
14348
+ await exitCli(1, loginError);
13623
14349
  }
13624
14350
  } else {
13625
14351
  verboseLog("Authentication error (not recoverable):", {
@@ -13628,12 +14354,15 @@ program.command("ask").alias("agent").description("Ask a single question or run
13628
14354
  });
13629
14355
  progressWriter.clear();
13630
14356
  console.error(`Authentication failed: ${error.message}`);
13631
- process.exit(1);
14357
+ await exitCli(1, error);
13632
14358
  }
13633
14359
  }
13634
14360
  } else {
13635
14361
  verboseLog("Using provided access key for authentication");
13636
14362
  }
14363
+ if (!token) {
14364
+ return await exitCli(1, new Error("auth_unavailable"));
14365
+ }
13637
14366
  await assertModelAvailable2({
13638
14367
  baseUrl,
13639
14368
  authToken: token,
@@ -13652,6 +14381,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
13652
14381
  verboseLog("Using provided project ID:", selectedProjectId);
13653
14382
  try {
13654
14383
  const userStatus = await checkUserStatus(baseUrl, token);
14384
+ getActiveCliTelemetry()?.setUserProperties(userStatus.user || {});
13655
14385
  authenticatedUserId = userStatus.user?.id;
13656
14386
  } catch {
13657
14387
  }
@@ -13666,6 +14396,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
13666
14396
  try {
13667
14397
  verboseLog("Checking user status", { baseUrl });
13668
14398
  const userStatus = await checkUserStatus(baseUrl, token);
14399
+ getActiveCliTelemetry()?.setUserProperties(userStatus.user || {});
13669
14400
  authenticatedUserId = userStatus.user?.id;
13670
14401
  verboseLog("User status:", {
13671
14402
  hasUser: !!userStatus.user,
@@ -13703,7 +14434,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
13703
14434
  "No project is available for this account. Run `cloudeval chat` to complete onboarding, then retry."
13704
14435
  );
13705
14436
  process.stderr.write("\n");
13706
- process.exit(1);
14437
+ await exitCli(1, new Error("no_project_available"));
13707
14438
  }
13708
14439
  }
13709
14440
  let userName = "You";
@@ -13983,7 +14714,7 @@ Error: ${errorMsg}
13983
14714
  await closeOutputStream();
13984
14715
  process.stderr.write(summary);
13985
14716
  }
13986
- process.exit(HITL_REQUIRED_EXIT_CODE);
14717
+ await exitCli(HITL_REQUIRED_EXIT_CODE, new Error("hitl_required"));
13987
14718
  }
13988
14719
  const responses = await promptForHitlResponses(questions);
13989
14720
  if (responses.length === 0) {
@@ -14055,7 +14786,7 @@ Error: ${errorMsg}
14055
14786
  process.stderr.write(`Error: ${noResponseMessage}
14056
14787
  `);
14057
14788
  }
14058
- process.exit(1);
14789
+ await exitCli(1, new Error(noResponseMessage));
14059
14790
  }
14060
14791
  if (streamTextOutput) {
14061
14792
  if (emittedTextLength === 0) {
@@ -14158,7 +14889,7 @@ Error: ${errorMsg}
14158
14889
  })
14159
14890
  );
14160
14891
  verboseLog("Command completed successfully");
14161
- process.exit(0);
14892
+ await exitCli(0);
14162
14893
  } catch (error) {
14163
14894
  try {
14164
14895
  writeHookWarnings(
@@ -14185,22 +14916,22 @@ Error: ${errorMsg}
14185
14916
  if (options.debug || options.verbose) {
14186
14917
  console.error(error.stack);
14187
14918
  }
14188
- process.exit(1);
14919
+ await exitCli(1, error);
14189
14920
  }
14190
14921
  });
14191
14922
  program.command("banner").description("Preview the startup banner and terminal capabilities").action(async () => {
14192
14923
  const { render } = await import("ink");
14193
14924
  const BannerPreview = React.lazy(async () => ({
14194
- default: (await import("./Banner-Z2XN5FGK.js")).Banner
14925
+ default: (await import("./Banner-HTYBWNZ3.js")).Banner
14195
14926
  }));
14196
14927
  render(
14197
14928
  /* @__PURE__ */ jsx(React.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(BannerPreview, { disable: false }) })
14198
14929
  );
14199
14930
  });
14200
14931
  var argv = !process.argv.slice(2).length ? ["node", "cloudeval", "tui", ...process.argv.slice(2)] : process.argv;
14201
- void program.parseAsync(argv).catch((error) => {
14932
+ void program.parseAsync(argv).catch(async (error) => {
14202
14933
  console.error(`\u274C ${error.message}`);
14203
- process.exit(1);
14934
+ await exitCli(1, error);
14204
14935
  });
14205
14936
  export {
14206
14937
  isVerbose,