@ganakailabs/cloudeval-cli 0.18.5 → 0.19.1
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/README.md +56 -0
- package/dist/{App-ZAC2LGZ4.js → App-ITRXW4R6.js} +2 -2
- package/dist/{Banner-RPE5HIBA.js → Banner-GMH566I3.js} +2 -2
- package/dist/{chunk-NF3ETGO7.js → chunk-3JC653QP.js} +1 -1
- package/dist/{chunk-Z5AYM56N.js → chunk-QJFZ5ESD.js} +1 -1
- package/dist/cli.js +346 -56
- package/package.json +2 -2
- package/sbom.spdx.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# CloudEval CLI
|
|
2
2
|
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/ganakailabs/cloudeval-cli/main/docs/assets/images/cli/tui-chat.png" alt="CloudEval CLI terminal UI" width="100%">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/@ganakailabs/cloudeval-cli"><img alt="npm" src="https://img.shields.io/npm/v/@ganakailabs/cloudeval-cli?style=flat-square"></a>
|
|
9
|
+
<a href="https://github.com/ganakailabs/cloudeval-cli/releases"><img alt="release" src="https://img.shields.io/github/v/release/ganakailabs/cloudeval-cli?sort=semver&style=flat-square"></a>
|
|
10
|
+
<a href="https://github.com/ganakailabs/cloudeval-cli/blob/main/LICENSE"><img alt="license" src="https://img.shields.io/badge/license-CloudEval%20CLI%20License-blue?style=flat-square"></a>
|
|
11
|
+
<a href="https://docs.cloudeval.ai/reference/cli-overview"><img alt="docs" src="https://img.shields.io/badge/docs-docs.cloudeval.ai-2d6cdf?style=flat-square"></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
3
14
|
CloudEval CLI brings CloudEval into your terminal, scripts, and agent tools. It
|
|
4
15
|
supports cloud chat, Agent mode, Agent Profiles, project and report inspection,
|
|
5
16
|
template validation, recipes, local hooks, and MCP server workflows.
|
|
@@ -26,6 +37,13 @@ the shell installer:
|
|
|
26
37
|
curl -fsSL https://cli.cloudeval.ai/install.sh | bash
|
|
27
38
|
```
|
|
28
39
|
|
|
40
|
+
The shell installer can detect Codex, Claude Desktop, Cursor, and VS Code,
|
|
41
|
+
skip clients where CloudEval MCP is already configured, and offer setup only
|
|
42
|
+
for missing clients that can be configured automatically. Manual-only clients
|
|
43
|
+
are summarized with a follow-up command instead of forcing another prompt.
|
|
44
|
+
When a CLI update exposes new MCP capabilities, restart or reload your MCP
|
|
45
|
+
client when you are ready; CloudEval never restarts those apps automatically.
|
|
46
|
+
|
|
29
47
|
## Common Commands
|
|
30
48
|
|
|
31
49
|
```bash
|
|
@@ -42,6 +60,33 @@ cloudeval mcp serve --toolset readonly
|
|
|
42
60
|
cloudeval capabilities --format json
|
|
43
61
|
```
|
|
44
62
|
|
|
63
|
+
## Uninstall
|
|
64
|
+
|
|
65
|
+
To remove local installer-owned artifacts while keeping CloudEval config,
|
|
66
|
+
sessions, and auth:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cloudeval uninstall --yes
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
To preview cleanup first:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cloudeval uninstall --dry-run
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
To remove local config and session state too:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
cloudeval uninstall --yes --remove-config
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If you installed through npm, remove the npm package as the final step:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm uninstall -g @ganakailabs/cloudeval-cli
|
|
88
|
+
```
|
|
89
|
+
|
|
45
90
|
## What It Covers
|
|
46
91
|
|
|
47
92
|
- Terminal UI for chat, Agent mode, projects, reports, billing, and settings.
|
|
@@ -63,3 +108,14 @@ then provide it as `CLOUDEVAL_ACCESS_KEY`.
|
|
|
63
108
|
- Command reference: <https://docs.cloudeval.ai/reference/cli-command-reference>
|
|
64
109
|
- MCP setup: <https://docs.cloudeval.ai/reference/mcp-client-setup>
|
|
65
110
|
- Release smoke tests: <https://github.com/ganakailabs/cloudeval-cli/blob/main/docs/release-smoke-tests.md>
|
|
111
|
+
|
|
112
|
+
## License And Notices
|
|
113
|
+
|
|
114
|
+
CloudEval CLI first-party code is provided under the
|
|
115
|
+
[CloudEval CLI License](https://github.com/ganakailabs/cloudeval-cli/blob/main/LICENSE).
|
|
116
|
+
Production third-party package attribution is published in
|
|
117
|
+
[THIRD_PARTY_NOTICES.md](https://github.com/ganakailabs/cloudeval-cli/blob/main/THIRD_PARTY_NOTICES.md),
|
|
118
|
+
and the release SBOM is published as
|
|
119
|
+
[sbom.spdx.json](https://github.com/ganakailabs/cloudeval-cli/blob/main/sbom.spdx.json).
|
|
120
|
+
Installer releases also place these notice files under
|
|
121
|
+
`~/.local/share/cloudeval/licenses`.
|
|
@@ -31,10 +31,10 @@ import {
|
|
|
31
31
|
} from "./chunk-4QIKW5TJ.js";
|
|
32
32
|
import {
|
|
33
33
|
Banner
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-QJFZ5ESD.js";
|
|
35
35
|
import {
|
|
36
36
|
CLI_VERSION
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-3JC653QP.js";
|
|
38
38
|
import {
|
|
39
39
|
raisedButtonStyle,
|
|
40
40
|
terminalTheme
|
package/dist/cli.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "./chunk-4QIKW5TJ.js";
|
|
17
17
|
import {
|
|
18
18
|
CLI_VERSION
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-3JC653QP.js";
|
|
20
20
|
|
|
21
21
|
// src/runtime/prepareInk.ts
|
|
22
22
|
import fs from "fs";
|
|
@@ -115,9 +115,9 @@ ensureInkRuntimeEnvironment();
|
|
|
115
115
|
// src/cli.tsx
|
|
116
116
|
import React from "react";
|
|
117
117
|
import { Command } from "commander";
|
|
118
|
-
import { promises as
|
|
119
|
-
import
|
|
120
|
-
import
|
|
118
|
+
import { promises as fs12 } from "fs";
|
|
119
|
+
import os5 from "os";
|
|
120
|
+
import path10 from "path";
|
|
121
121
|
|
|
122
122
|
// src/shellCompletion.ts
|
|
123
123
|
var normalizeCompletionShell = (shell) => {
|
|
@@ -780,6 +780,25 @@ var cliCommands = [
|
|
|
780
780
|
],
|
|
781
781
|
workflows: ["update"]
|
|
782
782
|
},
|
|
783
|
+
{
|
|
784
|
+
name: "uninstall",
|
|
785
|
+
description: "Remove local CloudEval CLI installation artifacts",
|
|
786
|
+
domain: "setup",
|
|
787
|
+
options: [
|
|
788
|
+
"--yes",
|
|
789
|
+
"-y",
|
|
790
|
+
"--dry-run",
|
|
791
|
+
"--keep-config",
|
|
792
|
+
"--remove-config",
|
|
793
|
+
"--format",
|
|
794
|
+
"-f",
|
|
795
|
+
"--output",
|
|
796
|
+
"-o",
|
|
797
|
+
"--profile",
|
|
798
|
+
"--help"
|
|
799
|
+
],
|
|
800
|
+
workflows: ["uninstall"]
|
|
801
|
+
},
|
|
783
802
|
{
|
|
784
803
|
name: "banner",
|
|
785
804
|
description: "Preview the startup banner and terminal capabilities",
|
|
@@ -1371,10 +1390,10 @@ var writeFormattedOutput = async (input) => {
|
|
|
1371
1390
|
process.stdout.write(text);
|
|
1372
1391
|
};
|
|
1373
1392
|
var writePrivateOutputFile = async (output, text) => {
|
|
1374
|
-
const
|
|
1375
|
-
await
|
|
1393
|
+
const fs13 = await import("fs/promises");
|
|
1394
|
+
await fs13.writeFile(output, text, { encoding: "utf8", mode: 384 });
|
|
1376
1395
|
if (process.platform !== "win32") {
|
|
1377
|
-
await
|
|
1396
|
+
await fs13.chmod(output, 384);
|
|
1378
1397
|
}
|
|
1379
1398
|
};
|
|
1380
1399
|
|
|
@@ -1722,8 +1741,8 @@ var writeReport = async (report, options, tuiDefault) => {
|
|
|
1722
1741
|
const textFormat = format === "text" || format === "table" ? "summary" : format;
|
|
1723
1742
|
const text = serializeReportOutput(report, { format: textFormat, mode });
|
|
1724
1743
|
if (options.output) {
|
|
1725
|
-
const
|
|
1726
|
-
await
|
|
1744
|
+
const fs13 = await import("fs/promises");
|
|
1745
|
+
await fs13.writeFile(options.output, text, "utf8");
|
|
1727
1746
|
return;
|
|
1728
1747
|
}
|
|
1729
1748
|
process.stdout.write(text);
|
|
@@ -1758,16 +1777,16 @@ var writeDownloadPayload = async (input) => {
|
|
|
1758
1777
|
);
|
|
1759
1778
|
return [];
|
|
1760
1779
|
}
|
|
1761
|
-
const
|
|
1762
|
-
const
|
|
1763
|
-
await
|
|
1780
|
+
const fs13 = await import("fs/promises");
|
|
1781
|
+
const path11 = await import("path");
|
|
1782
|
+
await fs13.mkdir(path11.dirname(input.output), { recursive: true });
|
|
1764
1783
|
const text = formatOutput({
|
|
1765
1784
|
command: input.command,
|
|
1766
1785
|
data: input.payload,
|
|
1767
1786
|
format: input.format,
|
|
1768
1787
|
frontendUrl: input.frontendUrl
|
|
1769
1788
|
});
|
|
1770
|
-
await
|
|
1789
|
+
await fs13.writeFile(input.output, text, "utf8");
|
|
1771
1790
|
return [input.output];
|
|
1772
1791
|
};
|
|
1773
1792
|
var resolveMachineFormat = (requested) => {
|
|
@@ -1916,14 +1935,14 @@ var registerReportsCommand = (program2, deps) => {
|
|
|
1916
1935
|
);
|
|
1917
1936
|
const data = reportTypes.length === 1 ? payload[reportTypes[0] === "architecture" ? "waf" : reportTypes[0]] : payload;
|
|
1918
1937
|
if (options.output && reportTypes.length > 1) {
|
|
1919
|
-
const
|
|
1920
|
-
const
|
|
1921
|
-
const stat = await
|
|
1922
|
-
if (stat?.isDirectory() || !
|
|
1923
|
-
await
|
|
1938
|
+
const fs13 = await import("fs/promises");
|
|
1939
|
+
const path11 = await import("path");
|
|
1940
|
+
const stat = await fs13.stat(options.output).catch(() => void 0);
|
|
1941
|
+
if (stat?.isDirectory() || !path11.extname(options.output)) {
|
|
1942
|
+
await fs13.mkdir(options.output, { recursive: true });
|
|
1924
1943
|
const files = [];
|
|
1925
1944
|
for (const [key, value] of Object.entries(payload)) {
|
|
1926
|
-
const file =
|
|
1945
|
+
const file = path11.join(options.output, `${projectId}-${key}-report.json`);
|
|
1927
1946
|
files.push(
|
|
1928
1947
|
...await writeDownloadPayload({
|
|
1929
1948
|
command: "reports download",
|
|
@@ -4668,12 +4687,12 @@ var responseErrorMessage = async (response) => {
|
|
|
4668
4687
|
var fetchCloudEvalJson = async ({
|
|
4669
4688
|
baseUrl,
|
|
4670
4689
|
authToken,
|
|
4671
|
-
path:
|
|
4690
|
+
path: path11,
|
|
4672
4691
|
method = "GET",
|
|
4673
4692
|
query = {},
|
|
4674
4693
|
body
|
|
4675
4694
|
}) => {
|
|
4676
|
-
const url = new URL(`${normalizeApiBase(baseUrl)}${
|
|
4695
|
+
const url = new URL(`${normalizeApiBase(baseUrl)}${path11}`);
|
|
4677
4696
|
for (const [key, value] of Object.entries(query)) {
|
|
4678
4697
|
if (value !== void 0 && value !== null && value !== "") {
|
|
4679
4698
|
url.searchParams.set(key, String(value));
|
|
@@ -5264,8 +5283,8 @@ var writeConnectionsListOutput = async ({
|
|
|
5264
5283
|
if (format === "text") {
|
|
5265
5284
|
const text = renderConnectionsListText(data);
|
|
5266
5285
|
if (options.output) {
|
|
5267
|
-
const
|
|
5268
|
-
await
|
|
5286
|
+
const fs13 = await import("fs/promises");
|
|
5287
|
+
await fs13.writeFile(options.output, text, "utf8");
|
|
5269
5288
|
return;
|
|
5270
5289
|
}
|
|
5271
5290
|
process.stdout.write(text);
|
|
@@ -5599,8 +5618,8 @@ var write = async (command, data, options, frontendUrl) => {
|
|
|
5599
5618
|
const text = renderBillingText(command, data);
|
|
5600
5619
|
if (text) {
|
|
5601
5620
|
if (options.output) {
|
|
5602
|
-
const
|
|
5603
|
-
await
|
|
5621
|
+
const fs13 = await import("fs/promises");
|
|
5622
|
+
await fs13.writeFile(options.output, text, "utf8");
|
|
5604
5623
|
return;
|
|
5605
5624
|
}
|
|
5606
5625
|
process.stdout.write(text);
|
|
@@ -11450,10 +11469,10 @@ var registerConfigCommand = (program2) => {
|
|
|
11450
11469
|
const profile = resolveProfile(options, command);
|
|
11451
11470
|
const current = await loadCliConfig(profile);
|
|
11452
11471
|
const next = writeCliConfigValue(current, key, value);
|
|
11453
|
-
const
|
|
11472
|
+
const path11 = await saveCliConfig(next, profile);
|
|
11454
11473
|
await writeFormattedOutput({
|
|
11455
11474
|
command: "config set",
|
|
11456
|
-
data: { profile, path:
|
|
11475
|
+
data: { profile, path: path11, config: next },
|
|
11457
11476
|
format: options.format,
|
|
11458
11477
|
output: options.output
|
|
11459
11478
|
});
|
|
@@ -11464,10 +11483,10 @@ var registerConfigCommand = (program2) => {
|
|
|
11464
11483
|
const profile = resolveProfile(options, command);
|
|
11465
11484
|
const current = await loadCliConfig(profile);
|
|
11466
11485
|
const next = unsetCliConfigValue(current, key);
|
|
11467
|
-
const
|
|
11486
|
+
const path11 = await saveCliConfig(next, profile);
|
|
11468
11487
|
await writeFormattedOutput({
|
|
11469
11488
|
command: "config unset",
|
|
11470
|
-
data: { profile, path:
|
|
11489
|
+
data: { profile, path: path11, config: next },
|
|
11471
11490
|
format: options.format,
|
|
11472
11491
|
output: options.output
|
|
11473
11492
|
});
|
|
@@ -11764,8 +11783,8 @@ var writeModelsListOutput = async (input) => {
|
|
|
11764
11783
|
defaultModel: input.defaultModel
|
|
11765
11784
|
});
|
|
11766
11785
|
if (input.options.output) {
|
|
11767
|
-
const
|
|
11768
|
-
await
|
|
11786
|
+
const fs13 = await import("fs/promises");
|
|
11787
|
+
await fs13.writeFile(input.options.output, text, "utf8");
|
|
11769
11788
|
return;
|
|
11770
11789
|
}
|
|
11771
11790
|
process.stdout.write(text);
|
|
@@ -11831,10 +11850,10 @@ var registerModelsCommand = (program2, deps) => {
|
|
|
11831
11850
|
const profile = options.profile || getActiveConfigProfile(command);
|
|
11832
11851
|
const config = await loadCliConfig(profile);
|
|
11833
11852
|
const next = { ...config, model };
|
|
11834
|
-
const
|
|
11853
|
+
const path11 = await saveCliConfig(next, profile);
|
|
11835
11854
|
await writeFormattedOutput({
|
|
11836
11855
|
command: "models default set",
|
|
11837
|
-
data: { profile, path:
|
|
11856
|
+
data: { profile, path: path11, model },
|
|
11838
11857
|
format: options.format,
|
|
11839
11858
|
output: options.output
|
|
11840
11859
|
});
|
|
@@ -11877,8 +11896,8 @@ var writeSessionTableOutput = async (command, data, options) => {
|
|
|
11877
11896
|
if (format === "text") {
|
|
11878
11897
|
const text = renderSessionsTable(data);
|
|
11879
11898
|
if (options.output) {
|
|
11880
|
-
const
|
|
11881
|
-
await
|
|
11899
|
+
const fs13 = await import("fs/promises");
|
|
11900
|
+
await fs13.writeFile(options.output, text, "utf8");
|
|
11882
11901
|
return;
|
|
11883
11902
|
}
|
|
11884
11903
|
process.stdout.write(text);
|
|
@@ -12050,12 +12069,12 @@ var registerSetupCommand = (program2, defaultBaseUrl = CLOUD_BASE_URL) => {
|
|
|
12050
12069
|
rl.close();
|
|
12051
12070
|
}
|
|
12052
12071
|
}
|
|
12053
|
-
const
|
|
12072
|
+
const path11 = await saveCliConfig(next, profile);
|
|
12054
12073
|
await writeFormattedOutput({
|
|
12055
12074
|
command: "setup",
|
|
12056
12075
|
data: {
|
|
12057
12076
|
profile,
|
|
12058
|
-
path:
|
|
12077
|
+
path: path11,
|
|
12059
12078
|
config: next,
|
|
12060
12079
|
nextSteps: [
|
|
12061
12080
|
"Run `cloudeval auth status` to inspect authentication.",
|
|
@@ -12339,6 +12358,9 @@ var formatUpdateStatusText = (result) => {
|
|
|
12339
12358
|
lines.push(
|
|
12340
12359
|
"MCP onboarding: interactive updates can ask to configure Codex, Claude, Cursor, or VS Code after installation."
|
|
12341
12360
|
);
|
|
12361
|
+
lines.push(
|
|
12362
|
+
"MCP refresh: Restart or reload configured MCP clients when you are ready to load new CloudEval tools. CloudEval does not restart those apps for you."
|
|
12363
|
+
);
|
|
12342
12364
|
}
|
|
12343
12365
|
return `${lines.join("\n")}
|
|
12344
12366
|
`;
|
|
@@ -12380,6 +12402,7 @@ var handleUpdateCommand = async (options, deps = {}) => {
|
|
|
12380
12402
|
};
|
|
12381
12403
|
var suppressedNudgeCommands = /* @__PURE__ */ new Set([
|
|
12382
12404
|
"update",
|
|
12405
|
+
"uninstall",
|
|
12383
12406
|
"completion",
|
|
12384
12407
|
"help",
|
|
12385
12408
|
"capabilities",
|
|
@@ -12470,8 +12493,274 @@ var registerUpdateCommand = (program2) => {
|
|
|
12470
12493
|
});
|
|
12471
12494
|
};
|
|
12472
12495
|
|
|
12473
|
-
// src/
|
|
12496
|
+
// src/uninstallCommand.ts
|
|
12497
|
+
import fs11 from "fs/promises";
|
|
12498
|
+
import os4 from "os";
|
|
12499
|
+
import path9 from "path";
|
|
12474
12500
|
import { createInterface as createInterface3 } from "readline/promises";
|
|
12501
|
+
var pathExists = async (candidate) => {
|
|
12502
|
+
try {
|
|
12503
|
+
await fs11.lstat(candidate);
|
|
12504
|
+
return true;
|
|
12505
|
+
} catch (error) {
|
|
12506
|
+
if (error?.code === "ENOENT") {
|
|
12507
|
+
return false;
|
|
12508
|
+
}
|
|
12509
|
+
throw error;
|
|
12510
|
+
}
|
|
12511
|
+
};
|
|
12512
|
+
var installerBinDir = (home) => path9.join(home, ".local", "bin");
|
|
12513
|
+
var completionPaths = (home) => [
|
|
12514
|
+
path9.join(home, ".local", "share", "bash-completion", "completions", "cloudeval"),
|
|
12515
|
+
path9.join(home, ".zsh", "completions", "_cloudeval"),
|
|
12516
|
+
path9.join(home, ".config", "fish", "completions", "cloudeval.fish"),
|
|
12517
|
+
path9.join(home, ".config", "powershell", "cloudeval-completion.ps1")
|
|
12518
|
+
];
|
|
12519
|
+
var installerArtifactTargets = (home, platform) => {
|
|
12520
|
+
const binDir = installerBinDir(home);
|
|
12521
|
+
const executableName = platform === "win32" ? "cloudeval.exe" : "cloudeval";
|
|
12522
|
+
const targets = [
|
|
12523
|
+
{
|
|
12524
|
+
label: "cloudeval binary",
|
|
12525
|
+
path: path9.join(binDir, executableName),
|
|
12526
|
+
kind: "file",
|
|
12527
|
+
status: "missing"
|
|
12528
|
+
},
|
|
12529
|
+
{
|
|
12530
|
+
label: "cloudeval binary",
|
|
12531
|
+
path: path9.join(binDir, "cloudeval"),
|
|
12532
|
+
kind: "file",
|
|
12533
|
+
status: "missing"
|
|
12534
|
+
},
|
|
12535
|
+
{
|
|
12536
|
+
label: "eva alias",
|
|
12537
|
+
path: path9.join(binDir, "eva"),
|
|
12538
|
+
kind: "file",
|
|
12539
|
+
status: "missing"
|
|
12540
|
+
},
|
|
12541
|
+
{
|
|
12542
|
+
label: "cloud alias",
|
|
12543
|
+
path: path9.join(binDir, "cloud"),
|
|
12544
|
+
kind: "file",
|
|
12545
|
+
status: "missing"
|
|
12546
|
+
},
|
|
12547
|
+
{
|
|
12548
|
+
label: "Ink runtime asset",
|
|
12549
|
+
path: path9.join(binDir, "yoga.wasm"),
|
|
12550
|
+
kind: "file",
|
|
12551
|
+
status: "missing"
|
|
12552
|
+
},
|
|
12553
|
+
{
|
|
12554
|
+
label: "license notices",
|
|
12555
|
+
path: path9.join(home, ".local", "share", "cloudeval", "licenses"),
|
|
12556
|
+
kind: "directory",
|
|
12557
|
+
status: "missing"
|
|
12558
|
+
},
|
|
12559
|
+
...completionPaths(home).map((completionPath) => ({
|
|
12560
|
+
label: "shell completion",
|
|
12561
|
+
path: completionPath,
|
|
12562
|
+
kind: "file",
|
|
12563
|
+
status: "missing"
|
|
12564
|
+
}))
|
|
12565
|
+
];
|
|
12566
|
+
return targets.filter(
|
|
12567
|
+
(target, index) => targets.findIndex((candidate) => candidate.path === target.path) === index
|
|
12568
|
+
);
|
|
12569
|
+
};
|
|
12570
|
+
var shellProfilePaths = (home) => [
|
|
12571
|
+
path9.join(home, ".bashrc"),
|
|
12572
|
+
path9.join(home, ".bash_profile"),
|
|
12573
|
+
path9.join(home, ".zshrc"),
|
|
12574
|
+
path9.join(home, ".profile"),
|
|
12575
|
+
path9.join(home, ".config", "fish", "config.fish")
|
|
12576
|
+
];
|
|
12577
|
+
var removeInstallerPathSnippet = (content, binDir) => {
|
|
12578
|
+
const exportLine = `export PATH="${binDir}:$PATH"`;
|
|
12579
|
+
const fishLine = `set -gx PATH "${binDir}" $PATH`;
|
|
12580
|
+
const lines = content.split(/\r?\n/);
|
|
12581
|
+
let changed = false;
|
|
12582
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
12583
|
+
if (lines[index] === "# Cloudeval CLI" && (lines[index + 1] === exportLine || lines[index + 1] === fishLine)) {
|
|
12584
|
+
const removeFrom = index > 0 && lines[index - 1] === "" ? index - 1 : index;
|
|
12585
|
+
lines.splice(removeFrom, index - removeFrom + 2);
|
|
12586
|
+
changed = true;
|
|
12587
|
+
index = Math.max(removeFrom - 1, -1);
|
|
12588
|
+
}
|
|
12589
|
+
}
|
|
12590
|
+
if (!changed) {
|
|
12591
|
+
return void 0;
|
|
12592
|
+
}
|
|
12593
|
+
return lines.join("\n");
|
|
12594
|
+
};
|
|
12595
|
+
var removeTarget = async (target, dryRun) => {
|
|
12596
|
+
if (!await pathExists(target.path)) {
|
|
12597
|
+
return { ...target, status: "missing" };
|
|
12598
|
+
}
|
|
12599
|
+
if (dryRun) {
|
|
12600
|
+
return { ...target, status: "would_remove" };
|
|
12601
|
+
}
|
|
12602
|
+
await fs11.rm(target.path, { recursive: target.kind === "directory", force: true });
|
|
12603
|
+
return { ...target, status: "removed" };
|
|
12604
|
+
};
|
|
12605
|
+
var updateShellProfile = async (profilePath, home, dryRun) => {
|
|
12606
|
+
if (!await pathExists(profilePath)) {
|
|
12607
|
+
return {
|
|
12608
|
+
label: "shell profile PATH entry",
|
|
12609
|
+
path: profilePath,
|
|
12610
|
+
kind: "shell-profile",
|
|
12611
|
+
status: "missing"
|
|
12612
|
+
};
|
|
12613
|
+
}
|
|
12614
|
+
const content = await fs11.readFile(profilePath, "utf8");
|
|
12615
|
+
const updated = removeInstallerPathSnippet(content, installerBinDir(home));
|
|
12616
|
+
if (updated === void 0) {
|
|
12617
|
+
return {
|
|
12618
|
+
label: "shell profile PATH entry",
|
|
12619
|
+
path: profilePath,
|
|
12620
|
+
kind: "shell-profile",
|
|
12621
|
+
status: "missing"
|
|
12622
|
+
};
|
|
12623
|
+
}
|
|
12624
|
+
if (dryRun) {
|
|
12625
|
+
return {
|
|
12626
|
+
label: "shell profile PATH entry",
|
|
12627
|
+
path: profilePath,
|
|
12628
|
+
kind: "shell-profile",
|
|
12629
|
+
status: "would_update"
|
|
12630
|
+
};
|
|
12631
|
+
}
|
|
12632
|
+
await fs11.writeFile(profilePath, updated, "utf8");
|
|
12633
|
+
return {
|
|
12634
|
+
label: "shell profile PATH entry",
|
|
12635
|
+
path: profilePath,
|
|
12636
|
+
kind: "shell-profile",
|
|
12637
|
+
status: "updated"
|
|
12638
|
+
};
|
|
12639
|
+
};
|
|
12640
|
+
var confirmUninstall = async ({
|
|
12641
|
+
input = process.stdin,
|
|
12642
|
+
output = process.stderr
|
|
12643
|
+
}) => {
|
|
12644
|
+
const rl = createInterface3({ input, output });
|
|
12645
|
+
try {
|
|
12646
|
+
const answer = await rl.question(
|
|
12647
|
+
"Remove CloudEval CLI local installation artifacts? Config is kept unless --remove-config is set. [y/N] "
|
|
12648
|
+
);
|
|
12649
|
+
return /^(y|yes)$/i.test(answer.trim());
|
|
12650
|
+
} finally {
|
|
12651
|
+
rl.close();
|
|
12652
|
+
}
|
|
12653
|
+
};
|
|
12654
|
+
var handleUninstallCommand = async (options, deps = {}) => {
|
|
12655
|
+
const home = deps.home ?? os4.homedir();
|
|
12656
|
+
const platform = deps.platform ?? process.platform;
|
|
12657
|
+
const dryRun = Boolean(options.dryRun);
|
|
12658
|
+
const removeConfig = Boolean(options.removeConfig);
|
|
12659
|
+
const input = deps.input ?? process.stdin;
|
|
12660
|
+
const output = deps.output ?? process.stderr;
|
|
12661
|
+
const inputIsTTY = deps.inputIsTTY ?? ("isTTY" in input ? Boolean(input.isTTY) : false);
|
|
12662
|
+
if (!dryRun && !options.yes) {
|
|
12663
|
+
if (!inputIsTTY) {
|
|
12664
|
+
throw new Error(
|
|
12665
|
+
"CloudEval uninstall requires confirmation. Re-run with --yes for non-interactive removal."
|
|
12666
|
+
);
|
|
12667
|
+
}
|
|
12668
|
+
const confirmed = await confirmUninstall({ input, output });
|
|
12669
|
+
if (!confirmed) {
|
|
12670
|
+
throw new Error("CloudEval uninstall cancelled.");
|
|
12671
|
+
}
|
|
12672
|
+
}
|
|
12673
|
+
const actions = [];
|
|
12674
|
+
for (const target of installerArtifactTargets(home, platform)) {
|
|
12675
|
+
actions.push(await removeTarget(target, dryRun));
|
|
12676
|
+
}
|
|
12677
|
+
for (const profilePath of shellProfilePaths(home)) {
|
|
12678
|
+
const action = await updateShellProfile(profilePath, home, dryRun);
|
|
12679
|
+
if (action.status !== "missing") {
|
|
12680
|
+
actions.push(action);
|
|
12681
|
+
}
|
|
12682
|
+
}
|
|
12683
|
+
const configTarget = {
|
|
12684
|
+
label: "config",
|
|
12685
|
+
path: path9.join(home, ".config", "cloudeval"),
|
|
12686
|
+
kind: "directory",
|
|
12687
|
+
status: "kept"
|
|
12688
|
+
};
|
|
12689
|
+
if (removeConfig) {
|
|
12690
|
+
actions.push(await removeTarget(configTarget, dryRun));
|
|
12691
|
+
} else {
|
|
12692
|
+
actions.push(configTarget);
|
|
12693
|
+
}
|
|
12694
|
+
return {
|
|
12695
|
+
dryRun,
|
|
12696
|
+
removeConfig,
|
|
12697
|
+
actions,
|
|
12698
|
+
notes: [
|
|
12699
|
+
"If you installed the npm package globally, finish with `npm uninstall -g @ganakailabs/cloudeval-cli`.",
|
|
12700
|
+
"MCP client configuration is left untouched. Update or remove MCP entries from each client if needed."
|
|
12701
|
+
]
|
|
12702
|
+
};
|
|
12703
|
+
};
|
|
12704
|
+
var formatUninstallResultText = (result) => {
|
|
12705
|
+
const lines = [
|
|
12706
|
+
"CloudEval CLI Uninstall",
|
|
12707
|
+
`Mode: ${result.dryRun ? "dry run" : "applied"}`,
|
|
12708
|
+
`Config: ${result.removeConfig ? "removed when present" : "kept"}`
|
|
12709
|
+
];
|
|
12710
|
+
const changed = result.actions.filter(
|
|
12711
|
+
(action) => ["removed", "updated", "would_remove", "would_update"].includes(action.status)
|
|
12712
|
+
);
|
|
12713
|
+
const kept = result.actions.filter((action) => action.status === "kept");
|
|
12714
|
+
if (changed.length) {
|
|
12715
|
+
lines.push("", result.dryRun ? "Would clean:" : "Cleaned:");
|
|
12716
|
+
for (const action of changed) {
|
|
12717
|
+
lines.push(`- ${action.label}: ${action.path}`);
|
|
12718
|
+
}
|
|
12719
|
+
} else {
|
|
12720
|
+
lines.push("", "Cleaned: nothing found");
|
|
12721
|
+
}
|
|
12722
|
+
if (kept.length) {
|
|
12723
|
+
lines.push("", "Kept:");
|
|
12724
|
+
for (const action of kept) {
|
|
12725
|
+
lines.push(`- ${action.label}: ${action.path}`);
|
|
12726
|
+
}
|
|
12727
|
+
}
|
|
12728
|
+
if (result.notes.length) {
|
|
12729
|
+
lines.push("", "Notes:");
|
|
12730
|
+
for (const note of result.notes) {
|
|
12731
|
+
lines.push(`- ${note}`);
|
|
12732
|
+
}
|
|
12733
|
+
}
|
|
12734
|
+
return `${lines.join("\n")}
|
|
12735
|
+
`;
|
|
12736
|
+
};
|
|
12737
|
+
var registerUninstallCommand = (program2) => {
|
|
12738
|
+
program2.command("uninstall").description("Remove local CloudEval CLI installation artifacts").option("-y, --yes", "Remove without prompting for confirmation", false).option("--dry-run", "Show what would be removed without deleting files", false).option("--keep-config", "Keep ~/.config/cloudeval settings, sessions, and auth (default)", true).option("--remove-config", "Also remove ~/.config/cloudeval settings, sessions, and auth", false).option(
|
|
12739
|
+
"-f, --format <format>",
|
|
12740
|
+
"Output format: text, json, ndjson, markdown",
|
|
12741
|
+
"text"
|
|
12742
|
+
).option("-o, --output <file>", "Output file").action(async (options) => {
|
|
12743
|
+
const result = await handleUninstallCommand(options);
|
|
12744
|
+
if (options.format === "text" || !options.format) {
|
|
12745
|
+
const text = formatUninstallResultText(result);
|
|
12746
|
+
if (options.output) {
|
|
12747
|
+
await fs11.writeFile(options.output, text, "utf8");
|
|
12748
|
+
return;
|
|
12749
|
+
}
|
|
12750
|
+
process.stdout.write(text);
|
|
12751
|
+
return;
|
|
12752
|
+
}
|
|
12753
|
+
await writeFormattedOutput({
|
|
12754
|
+
command: "uninstall",
|
|
12755
|
+
data: result,
|
|
12756
|
+
format: options.format,
|
|
12757
|
+
output: options.output
|
|
12758
|
+
});
|
|
12759
|
+
});
|
|
12760
|
+
};
|
|
12761
|
+
|
|
12762
|
+
// src/hitlPrompt.ts
|
|
12763
|
+
import { createInterface as createInterface4 } from "readline/promises";
|
|
12475
12764
|
var HITL_REQUIRED_EXIT_CODE = 6;
|
|
12476
12765
|
var recommendedOption = (question) => question.options?.find((option) => option.id === question.recommended_option_id) ?? question.options?.find((option) => option.recommended) ?? question.options?.[0];
|
|
12477
12766
|
var optionLines = (question) => (question.options ?? []).map((option, index) => {
|
|
@@ -12540,7 +12829,7 @@ var answerHitlQuestions = async (questions, ask) => {
|
|
|
12540
12829
|
return responses;
|
|
12541
12830
|
};
|
|
12542
12831
|
var promptForHitlResponses = async (questions, input = process.stdin, output = process.stderr) => {
|
|
12543
|
-
const rl =
|
|
12832
|
+
const rl = createInterface4({ input, output });
|
|
12544
12833
|
try {
|
|
12545
12834
|
return await answerHitlQuestions(questions, (prompt2) => rl.question(prompt2));
|
|
12546
12835
|
} finally {
|
|
@@ -12598,24 +12887,24 @@ var assertNoLegacyApiKeyUsage = () => {
|
|
|
12598
12887
|
};
|
|
12599
12888
|
assertNoLegacyApiKeyUsage();
|
|
12600
12889
|
var completionScriptPath = (shell) => {
|
|
12601
|
-
const home =
|
|
12890
|
+
const home = os5.homedir();
|
|
12602
12891
|
switch (shell) {
|
|
12603
12892
|
case "bash":
|
|
12604
|
-
return
|
|
12893
|
+
return path10.join(home, ".local", "share", "bash-completion", "completions", "cloudeval");
|
|
12605
12894
|
case "zsh":
|
|
12606
|
-
return
|
|
12895
|
+
return path10.join(home, ".zsh", "completions", "_cloudeval");
|
|
12607
12896
|
case "fish":
|
|
12608
|
-
return
|
|
12897
|
+
return path10.join(home, ".config", "fish", "completions", "cloudeval.fish");
|
|
12609
12898
|
case "powershell":
|
|
12610
|
-
return
|
|
12899
|
+
return path10.join(home, ".config", "powershell", "cloudeval-completion.ps1");
|
|
12611
12900
|
}
|
|
12612
12901
|
};
|
|
12613
12902
|
var ZSH_FPATH_MARKER = "CloudEval CLI completions";
|
|
12614
12903
|
var ensureZshCompletionFpath = async () => {
|
|
12615
|
-
const zshrc =
|
|
12904
|
+
const zshrc = path10.join(os5.homedir(), ".zshrc");
|
|
12616
12905
|
let existing = "";
|
|
12617
12906
|
try {
|
|
12618
|
-
existing = await
|
|
12907
|
+
existing = await fs12.readFile(zshrc, "utf8");
|
|
12619
12908
|
} catch {
|
|
12620
12909
|
existing = "";
|
|
12621
12910
|
}
|
|
@@ -12626,12 +12915,12 @@ var ensureZshCompletionFpath = async () => {
|
|
|
12626
12915
|
# ${ZSH_FPATH_MARKER}
|
|
12627
12916
|
fpath=("$HOME/.zsh/completions" $fpath)
|
|
12628
12917
|
`;
|
|
12629
|
-
await
|
|
12918
|
+
await fs12.appendFile(zshrc, snippet, "utf8");
|
|
12630
12919
|
};
|
|
12631
12920
|
var installCompletionScript = async (shell, binaryName) => {
|
|
12632
12921
|
const scriptPath = completionScriptPath(shell);
|
|
12633
|
-
await
|
|
12634
|
-
await
|
|
12922
|
+
await fs12.mkdir(path10.dirname(scriptPath), { recursive: true });
|
|
12923
|
+
await fs12.writeFile(scriptPath, buildCompletionScript(shell, binaryName), "utf8");
|
|
12635
12924
|
if (shell === "zsh") {
|
|
12636
12925
|
await ensureZshCompletionFpath();
|
|
12637
12926
|
}
|
|
@@ -12639,7 +12928,7 @@ var installCompletionScript = async (shell, binaryName) => {
|
|
|
12639
12928
|
};
|
|
12640
12929
|
var uninstallCompletionScript = async (shell) => {
|
|
12641
12930
|
const scriptPath = completionScriptPath(shell);
|
|
12642
|
-
await
|
|
12931
|
+
await fs12.rm(scriptPath, { force: true });
|
|
12643
12932
|
return scriptPath;
|
|
12644
12933
|
};
|
|
12645
12934
|
var runInteractiveLoginOnboarding = async (baseUrl, token) => {
|
|
@@ -13164,6 +13453,7 @@ registerMcpCommand(program, {
|
|
|
13164
13453
|
resolveBaseUrl
|
|
13165
13454
|
});
|
|
13166
13455
|
registerUpdateCommand(program);
|
|
13456
|
+
registerUninstallCommand(program);
|
|
13167
13457
|
program.command("__complete").description("Internal completion endpoint").argument("[words...]", "Completion words").action((words = []) => {
|
|
13168
13458
|
const candidates = completeCliWords(words);
|
|
13169
13459
|
for (const candidate of candidates) {
|
|
@@ -13222,7 +13512,7 @@ program.command("tui").description("Open the CloudEval Terminal UI").option(
|
|
|
13222
13512
|
const { assertSecureBaseUrl } = await import("./dist-I4IPYCRC.js");
|
|
13223
13513
|
const [{ render }, { App }] = await Promise.all([
|
|
13224
13514
|
import("ink"),
|
|
13225
|
-
import("./App-
|
|
13515
|
+
import("./App-ITRXW4R6.js")
|
|
13226
13516
|
]);
|
|
13227
13517
|
const baseUrl = await resolveBaseUrl(options, command);
|
|
13228
13518
|
assertSecureBaseUrl(baseUrl);
|
|
@@ -13272,7 +13562,7 @@ program.command("chat").description("Start an interactive chat session").option(
|
|
|
13272
13562
|
const { assertSecureBaseUrl } = await import("./dist-I4IPYCRC.js");
|
|
13273
13563
|
const [{ render }, { App }] = await Promise.all([
|
|
13274
13564
|
import("ink"),
|
|
13275
|
-
import("./App-
|
|
13565
|
+
import("./App-ITRXW4R6.js")
|
|
13276
13566
|
]);
|
|
13277
13567
|
const baseUrl = await resolveBaseUrl(options, command);
|
|
13278
13568
|
assertSecureBaseUrl(baseUrl);
|
|
@@ -13378,7 +13668,7 @@ program.command("ask").alias("agent").description("Ask a single question or run
|
|
|
13378
13668
|
});
|
|
13379
13669
|
}
|
|
13380
13670
|
try {
|
|
13381
|
-
const
|
|
13671
|
+
const fs13 = await import("fs");
|
|
13382
13672
|
const fsPromises = await import("fs/promises");
|
|
13383
13673
|
const { randomUUID: randomUUID5 } = await import("crypto");
|
|
13384
13674
|
const core = await import("./dist-I4IPYCRC.js");
|
|
@@ -13568,11 +13858,11 @@ program.command("ask").alias("agent").description("Ask a single question or run
|
|
|
13568
13858
|
console.error(`[${commandName}] Thread ID: ${threadId}`);
|
|
13569
13859
|
}
|
|
13570
13860
|
if (streamTextOutput && options.output) {
|
|
13571
|
-
fileOutputStream =
|
|
13861
|
+
fileOutputStream = fs13.createWriteStream(options.output, { encoding: "utf-8" });
|
|
13572
13862
|
outputStream = fileOutputStream;
|
|
13573
13863
|
}
|
|
13574
13864
|
if (ndjsonOutput && options.output) {
|
|
13575
|
-
ndjsonOutputStream =
|
|
13865
|
+
ndjsonOutputStream = fs13.createWriteStream(options.output, { encoding: "utf-8" });
|
|
13576
13866
|
}
|
|
13577
13867
|
const writeAskDataEvent = (event) => {
|
|
13578
13868
|
const line = `${JSON.stringify(event)}
|
|
@@ -14006,7 +14296,7 @@ Error: ${errorMsg}
|
|
|
14006
14296
|
program.command("banner").description("Preview the startup banner and terminal capabilities").action(async () => {
|
|
14007
14297
|
const { render } = await import("ink");
|
|
14008
14298
|
const BannerPreview = React.lazy(async () => ({
|
|
14009
|
-
default: (await import("./Banner-
|
|
14299
|
+
default: (await import("./Banner-GMH566I3.js")).Banner
|
|
14010
14300
|
}));
|
|
14011
14301
|
render(
|
|
14012
14302
|
/* @__PURE__ */ jsx(React.Suspense, { fallback: null, children: /* @__PURE__ */ jsx(BannerPreview, { disable: false }) })
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ganakailabs/cloudeval-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "CloudEval CLI for cloud architecture, cost, report, automation, and MCP workflows.",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"run": "node dist/cli.js",
|
|
64
64
|
"dev": "tsx src/cli.tsx",
|
|
65
65
|
"lint": "pnpm -C ../shared build && pnpm -C ../core build && tsc --noEmit -p tsconfig.json",
|
|
66
|
-
"test": "pnpm -C ../shared build && pnpm -C ../core build && tsx --test src/askProgress.test.ts src/hitlPrompt.test.ts src/baseUrl.test.ts src/frontendLinks.test.ts src/outputFormatter.test.ts src/localHooks.test.ts src/projectDiagramImage.test.ts src/loginOnboardingMode.test.ts src/runtime/prepareInk.test.ts src/ui/animationPolicy.test.ts src/ui/components/Banner.test.ts src/ui/components/InputBox.test.ts src/ui/components/Transcript.test.ts src/ui/billingSummary.test.ts src/ui/inputSanitizer.test.ts src/ui/inputViewport.test.ts src/ui/keyBindings.test.ts src/ui/layout.test.ts src/ui/scrollBehavior.test.ts src/ui/promptSuggestions.test.ts src/ui/commandCompletion.test.ts src/ui/interactionModel.test.ts src/ui/userDisplayName.test.ts src/ui/workspaceTabs.test.ts src/ui/workspaceDataStore.test.ts src/ui/overviewDashboard.test.ts src/ui/reportsDashboard.test.ts src/completionEngine.test.ts src/shellCompletion.test.ts src/updateCommand.test.ts src/mcpSetupCommand.test.ts src/mcpCommand.test.ts src/sessionsStore.test.ts src/recipes/catalog.test.ts src/reports/reportRender.test.ts src/reports/reportCommand.test.ts",
|
|
66
|
+
"test": "pnpm -C ../shared build && pnpm -C ../core build && tsx --test src/askProgress.test.ts src/hitlPrompt.test.ts src/baseUrl.test.ts src/frontendLinks.test.ts src/outputFormatter.test.ts src/localHooks.test.ts src/projectDiagramImage.test.ts src/loginOnboardingMode.test.ts src/runtime/prepareInk.test.ts src/ui/animationPolicy.test.ts src/ui/components/Banner.test.ts src/ui/components/InputBox.test.ts src/ui/components/Transcript.test.ts src/ui/billingSummary.test.ts src/ui/inputSanitizer.test.ts src/ui/inputViewport.test.ts src/ui/keyBindings.test.ts src/ui/layout.test.ts src/ui/scrollBehavior.test.ts src/ui/promptSuggestions.test.ts src/ui/commandCompletion.test.ts src/ui/interactionModel.test.ts src/ui/userDisplayName.test.ts src/ui/workspaceTabs.test.ts src/ui/workspaceDataStore.test.ts src/ui/overviewDashboard.test.ts src/ui/reportsDashboard.test.ts src/completionEngine.test.ts src/shellCompletion.test.ts src/updateCommand.test.ts src/uninstallCommand.test.ts src/mcpSetupCommand.test.ts src/mcpCommand.test.ts src/sessionsStore.test.ts src/recipes/catalog.test.ts src/reports/reportRender.test.ts src/reports/reportCommand.test.ts",
|
|
67
67
|
"test:cli:noninteractive": "pnpm -C ../shared build && pnpm -C ../core build && tsx --test src/nonInteractiveCli.test.ts",
|
|
68
68
|
"test:cli:noninteractive:packaged": "pnpm build:executable:current && CLOUDEVAL_CLI_BIN=./dist/bin/cloudeval pnpm test:cli:noninteractive",
|
|
69
69
|
"test:cli:noninteractive:live": "pnpm build:executable:current && CLOUDEVAL_CLI_BIN=./dist/bin/cloudeval tsx --test src/liveNonInteractiveCli.test.ts",
|
package/sbom.spdx.json
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
{
|
|
15
15
|
"SPDXID": "SPDXRef-Package-CloudEval-CLI",
|
|
16
16
|
"name": "CloudEval CLI",
|
|
17
|
-
"versionInfo": "0.
|
|
17
|
+
"versionInfo": "0.19.1",
|
|
18
18
|
"downloadLocation": "https://github.com/ganakailabs/cloudeval-cli",
|
|
19
19
|
"filesAnalyzed": false,
|
|
20
20
|
"licenseConcluded": "LicenseRef-CloudEval-CLI",
|