@supatest/cli 0.0.22 → 0.0.24
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/index.js +149 -18
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -3817,6 +3817,34 @@ function installChromium() {
|
|
|
3817
3817
|
};
|
|
3818
3818
|
}
|
|
3819
3819
|
}
|
|
3820
|
+
function createSupatestConfig(cwd) {
|
|
3821
|
+
const supatestDir = path.join(cwd, ".supatest");
|
|
3822
|
+
const mcpJsonPath = path.join(supatestDir, "mcp.json");
|
|
3823
|
+
try {
|
|
3824
|
+
if (fs.existsSync(mcpJsonPath)) {
|
|
3825
|
+
return {
|
|
3826
|
+
ok: true,
|
|
3827
|
+
message: "mcp.json already exists",
|
|
3828
|
+
created: false
|
|
3829
|
+
};
|
|
3830
|
+
}
|
|
3831
|
+
if (!fs.existsSync(supatestDir)) {
|
|
3832
|
+
fs.mkdirSync(supatestDir, { recursive: true });
|
|
3833
|
+
}
|
|
3834
|
+
fs.writeFileSync(mcpJsonPath, JSON.stringify(DEFAULT_MCP_CONFIG, null, 2) + "\n", "utf-8");
|
|
3835
|
+
return {
|
|
3836
|
+
ok: true,
|
|
3837
|
+
message: "Created .supatest/mcp.json with Playwright MCP server configuration",
|
|
3838
|
+
created: true
|
|
3839
|
+
};
|
|
3840
|
+
} catch (error) {
|
|
3841
|
+
return {
|
|
3842
|
+
ok: false,
|
|
3843
|
+
message: `Failed to create mcp.json: ${error instanceof Error ? error.message : String(error)}`,
|
|
3844
|
+
created: false
|
|
3845
|
+
};
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3820
3848
|
function getVersionSummary() {
|
|
3821
3849
|
const nodeVersion = getNodeVersion();
|
|
3822
3850
|
const playwrightVersion = getPlaywrightVersion();
|
|
@@ -3828,7 +3856,7 @@ function getVersionSummary() {
|
|
|
3828
3856
|
lines.push(` Chromium: ${chromiumVersion ? `build ${chromiumVersion}` : "Not installed"}`);
|
|
3829
3857
|
return lines.join("\n");
|
|
3830
3858
|
}
|
|
3831
|
-
async function setupCommand() {
|
|
3859
|
+
async function setupCommand(options) {
|
|
3832
3860
|
const output = [];
|
|
3833
3861
|
const log = (msg) => {
|
|
3834
3862
|
output.push(msg);
|
|
@@ -3876,6 +3904,18 @@ async function setupCommand() {
|
|
|
3876
3904
|
result.errors.push(chromiumResult.message);
|
|
3877
3905
|
}
|
|
3878
3906
|
}
|
|
3907
|
+
log("\n3. Setting up MCP configuration...");
|
|
3908
|
+
const configResult = createSupatestConfig(options.cwd);
|
|
3909
|
+
if (configResult.ok) {
|
|
3910
|
+
if (configResult.created) {
|
|
3911
|
+
log(` \u2705 ${configResult.message}`);
|
|
3912
|
+
} else {
|
|
3913
|
+
log(` \u2705 ${configResult.message}`);
|
|
3914
|
+
}
|
|
3915
|
+
} else {
|
|
3916
|
+
log(` \u274C ${configResult.message}`);
|
|
3917
|
+
result.errors.push(configResult.message);
|
|
3918
|
+
}
|
|
3879
3919
|
const versionSummary = getVersionSummary();
|
|
3880
3920
|
log(versionSummary);
|
|
3881
3921
|
log("\n" + "\u2500".repeat(50));
|
|
@@ -3891,11 +3931,19 @@ async function setupCommand() {
|
|
|
3891
3931
|
result.output = output.join("\n");
|
|
3892
3932
|
return result;
|
|
3893
3933
|
}
|
|
3894
|
-
var MINIMUM_NODE_VERSION;
|
|
3934
|
+
var MINIMUM_NODE_VERSION, DEFAULT_MCP_CONFIG;
|
|
3895
3935
|
var init_setup = __esm({
|
|
3896
3936
|
"src/commands/setup.ts"() {
|
|
3897
3937
|
"use strict";
|
|
3898
3938
|
MINIMUM_NODE_VERSION = 18;
|
|
3939
|
+
DEFAULT_MCP_CONFIG = {
|
|
3940
|
+
mcpServers: {
|
|
3941
|
+
playwright: {
|
|
3942
|
+
command: "npx",
|
|
3943
|
+
args: ["@playwright/mcp@latest"]
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
};
|
|
3899
3947
|
}
|
|
3900
3948
|
});
|
|
3901
3949
|
|
|
@@ -3904,7 +3952,7 @@ var CLI_VERSION;
|
|
|
3904
3952
|
var init_version = __esm({
|
|
3905
3953
|
"src/version.ts"() {
|
|
3906
3954
|
"use strict";
|
|
3907
|
-
CLI_VERSION = "0.0.
|
|
3955
|
+
CLI_VERSION = "0.0.24";
|
|
3908
3956
|
}
|
|
3909
3957
|
});
|
|
3910
3958
|
|
|
@@ -4956,11 +5004,23 @@ ${projectInstructions}`,
|
|
|
4956
5004
|
resultText = msg.result || resultText;
|
|
4957
5005
|
} else {
|
|
4958
5006
|
hasError = true;
|
|
4959
|
-
if (
|
|
5007
|
+
if (msg.subtype === "error_max_turns") {
|
|
5008
|
+
const maxTurnsError = `Agent stopped after ${msg.num_turns} turns (max iterations reached). Use --max-iterations to increase the limit.`;
|
|
5009
|
+
errors.push(maxTurnsError);
|
|
5010
|
+
this.presenter.onError(maxTurnsError);
|
|
5011
|
+
} else if (msg.subtype === "error_max_budget_usd") {
|
|
5012
|
+
const budgetError = "Agent stopped: budget limit exceeded.";
|
|
5013
|
+
errors.push(budgetError);
|
|
5014
|
+
this.presenter.onError(budgetError);
|
|
5015
|
+
} else if ("errors" in msg && Array.isArray(msg.errors)) {
|
|
4960
5016
|
errors.push(...msg.errors);
|
|
4961
5017
|
for (const error of msg.errors) {
|
|
4962
5018
|
this.presenter.onError(error);
|
|
4963
5019
|
}
|
|
5020
|
+
} else {
|
|
5021
|
+
const unknownError = `Agent stopped unexpectedly (${msg.subtype || "unknown reason"})`;
|
|
5022
|
+
errors.push(unknownError);
|
|
5023
|
+
this.presenter.onError(unknownError);
|
|
4964
5024
|
}
|
|
4965
5025
|
}
|
|
4966
5026
|
} else if (msg.type === "user") {
|
|
@@ -5253,7 +5313,7 @@ var init_react = __esm({
|
|
|
5253
5313
|
}
|
|
5254
5314
|
onUsageUpdate(usage) {
|
|
5255
5315
|
const contextWindow = CONTEXT_WINDOWS[usage.model] || 2e5;
|
|
5256
|
-
const contextTokens = usage.inputTokens + usage.cacheReadTokens
|
|
5316
|
+
const contextTokens = usage.inputTokens + usage.cacheReadTokens;
|
|
5257
5317
|
const contextPct = contextTokens / contextWindow * 100;
|
|
5258
5318
|
this.callbacks.setUsageStats((prev) => {
|
|
5259
5319
|
if (prev && prev.inputTokens > contextTokens) {
|
|
@@ -5298,7 +5358,7 @@ var init_react = __esm({
|
|
|
5298
5358
|
if (result.usage) {
|
|
5299
5359
|
const usage = result.usage;
|
|
5300
5360
|
const contextWindow = CONTEXT_WINDOWS[usage.model] || 2e5;
|
|
5301
|
-
const contextTokens = usage.inputTokens + usage.cacheReadTokens
|
|
5361
|
+
const contextTokens = usage.inputTokens + usage.cacheReadTokens;
|
|
5302
5362
|
const contextPct = contextTokens / contextWindow * 100;
|
|
5303
5363
|
this.callbacks.setUsageStats((prev) => {
|
|
5304
5364
|
if (prev && prev.inputTokens > contextTokens) {
|
|
@@ -5415,6 +5475,9 @@ var init_SessionContext = __esm({
|
|
|
5415
5475
|
});
|
|
5416
5476
|
setStaticRemountKey((prev) => prev + 1);
|
|
5417
5477
|
}, []);
|
|
5478
|
+
const refreshStatic = useCallback(() => {
|
|
5479
|
+
setStaticRemountKey((prev) => prev + 1);
|
|
5480
|
+
}, []);
|
|
5418
5481
|
const updateStats = useCallback((updates) => {
|
|
5419
5482
|
setStats((prev) => ({ ...prev, ...updates }));
|
|
5420
5483
|
}, []);
|
|
@@ -5460,7 +5523,8 @@ var init_SessionContext = __esm({
|
|
|
5460
5523
|
setPlanFilePath,
|
|
5461
5524
|
selectedModel,
|
|
5462
5525
|
setSelectedModel,
|
|
5463
|
-
staticRemountKey
|
|
5526
|
+
staticRemountKey,
|
|
5527
|
+
refreshStatic
|
|
5464
5528
|
};
|
|
5465
5529
|
return /* @__PURE__ */ React.createElement(SessionContext.Provider, { value }, children);
|
|
5466
5530
|
};
|
|
@@ -6734,7 +6798,7 @@ var init_message_bridge = __esm({
|
|
|
6734
6798
|
});
|
|
6735
6799
|
|
|
6736
6800
|
// src/commands/login.ts
|
|
6737
|
-
import { spawn } from "child_process";
|
|
6801
|
+
import { spawn as spawn2 } from "child_process";
|
|
6738
6802
|
import crypto2 from "crypto";
|
|
6739
6803
|
import http from "http";
|
|
6740
6804
|
import { platform } from "os";
|
|
@@ -6770,7 +6834,7 @@ function openBrowser(url) {
|
|
|
6770
6834
|
default:
|
|
6771
6835
|
command = "xdg-open";
|
|
6772
6836
|
}
|
|
6773
|
-
|
|
6837
|
+
spawn2(command, [url], { detached: true, stdio: "ignore" }).unref();
|
|
6774
6838
|
}
|
|
6775
6839
|
function startCallbackServer(port, expectedState) {
|
|
6776
6840
|
return new Promise((resolve2, reject) => {
|
|
@@ -8681,9 +8745,9 @@ var init_useOverlayEscapeGuard = __esm({
|
|
|
8681
8745
|
});
|
|
8682
8746
|
|
|
8683
8747
|
// src/ui/App.tsx
|
|
8684
|
-
import { execSync as
|
|
8748
|
+
import { execSync as execSync5 } from "child_process";
|
|
8685
8749
|
import { homedir as homedir5 } from "os";
|
|
8686
|
-
import { Box as Box20, Text as Text18, useApp as useApp2 } from "ink";
|
|
8750
|
+
import { Box as Box20, Text as Text18, useApp as useApp2, useStdout as useStdout2 } from "ink";
|
|
8687
8751
|
import Spinner3 from "ink-spinner";
|
|
8688
8752
|
import React23, { useEffect as useEffect10, useRef as useRef4, useState as useState10 } from "react";
|
|
8689
8753
|
var getGitBranch2, getCurrentFolder2, AppContent, App;
|
|
@@ -8713,7 +8777,7 @@ var init_App = __esm({
|
|
|
8713
8777
|
init_theme();
|
|
8714
8778
|
getGitBranch2 = () => {
|
|
8715
8779
|
try {
|
|
8716
|
-
return
|
|
8780
|
+
return execSync5("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
|
|
8717
8781
|
} catch {
|
|
8718
8782
|
return "";
|
|
8719
8783
|
}
|
|
@@ -8728,7 +8792,8 @@ var init_App = __esm({
|
|
|
8728
8792
|
};
|
|
8729
8793
|
AppContent = ({ config: config2, sessionId, webUrl, queuedTasks = [], onExit, onSubmitTask, apiClient, onResumeSession, onClearSession }) => {
|
|
8730
8794
|
const { exit } = useApp2();
|
|
8731
|
-
const {
|
|
8795
|
+
const { stdout } = useStdout2();
|
|
8796
|
+
const { addMessage, clearMessages, isAgentRunning, messages, setSessionId, setWebUrl, setShouldInterruptAgent, setIsAgentRunning, toggleAllToolOutputs, allToolsExpanded, selectedModel, setSelectedModel, refreshStatic } = useSession();
|
|
8732
8797
|
useModeToggle();
|
|
8733
8798
|
const [terminalWidth, setTerminalWidth] = useState10(process.stdout.columns || 80);
|
|
8734
8799
|
const [showHelp, setShowHelp] = useState10(false);
|
|
@@ -8881,7 +8946,7 @@ var init_App = __esm({
|
|
|
8881
8946
|
content: "Running setup..."
|
|
8882
8947
|
});
|
|
8883
8948
|
try {
|
|
8884
|
-
const result = await setupCommand();
|
|
8949
|
+
const result = await setupCommand({ cwd: config2.cwd || process.cwd() });
|
|
8885
8950
|
addMessage({
|
|
8886
8951
|
type: "assistant",
|
|
8887
8952
|
content: result.output
|
|
@@ -9005,6 +9070,7 @@ var init_App = __esm({
|
|
|
9005
9070
|
markOverlayClosed();
|
|
9006
9071
|
setShowHelp(false);
|
|
9007
9072
|
};
|
|
9073
|
+
const isInitialMount = useRef4(true);
|
|
9008
9074
|
useEffect10(() => {
|
|
9009
9075
|
const handleResize = () => {
|
|
9010
9076
|
setTerminalWidth(process.stdout.columns || 80);
|
|
@@ -9014,6 +9080,19 @@ var init_App = __esm({
|
|
|
9014
9080
|
process.stdout.off("resize", handleResize);
|
|
9015
9081
|
};
|
|
9016
9082
|
}, []);
|
|
9083
|
+
useEffect10(() => {
|
|
9084
|
+
if (isInitialMount.current) {
|
|
9085
|
+
isInitialMount.current = false;
|
|
9086
|
+
return;
|
|
9087
|
+
}
|
|
9088
|
+
const handler = setTimeout(() => {
|
|
9089
|
+
stdout?.write("\x1B[3J\x1B[H\x1B[2J");
|
|
9090
|
+
refreshStatic();
|
|
9091
|
+
}, 300);
|
|
9092
|
+
return () => {
|
|
9093
|
+
clearTimeout(handler);
|
|
9094
|
+
};
|
|
9095
|
+
}, [terminalWidth, refreshStatic, stdout]);
|
|
9017
9096
|
useKeypress(
|
|
9018
9097
|
(key) => {
|
|
9019
9098
|
if (key.name === "escape" && isAgentRunning && !isOverlayOpen) {
|
|
@@ -9941,6 +10020,57 @@ async function runAgent(config2) {
|
|
|
9941
10020
|
});
|
|
9942
10021
|
}
|
|
9943
10022
|
|
|
10023
|
+
// src/utils/auto-update.ts
|
|
10024
|
+
init_error_logger();
|
|
10025
|
+
init_version();
|
|
10026
|
+
import { execSync as execSync3, spawn } from "child_process";
|
|
10027
|
+
import latestVersion from "latest-version";
|
|
10028
|
+
import { gt as gt2 } from "semver";
|
|
10029
|
+
var UPDATE_CHECK_TIMEOUT = 3e3;
|
|
10030
|
+
var INSTALL_TIMEOUT = 6e4;
|
|
10031
|
+
async function checkAndAutoUpdate() {
|
|
10032
|
+
if (process.env.NODE_ENV === "development") {
|
|
10033
|
+
return;
|
|
10034
|
+
}
|
|
10035
|
+
if (process.env.SUPATEST_SKIP_UPDATE === "1") {
|
|
10036
|
+
return;
|
|
10037
|
+
}
|
|
10038
|
+
try {
|
|
10039
|
+
const latest = await Promise.race([
|
|
10040
|
+
latestVersion("@supatest/cli"),
|
|
10041
|
+
new Promise(
|
|
10042
|
+
(_2, reject) => setTimeout(() => reject(new Error("timeout")), UPDATE_CHECK_TIMEOUT)
|
|
10043
|
+
)
|
|
10044
|
+
]);
|
|
10045
|
+
if (!gt2(latest, CLI_VERSION)) {
|
|
10046
|
+
return;
|
|
10047
|
+
}
|
|
10048
|
+
console.log(`
|
|
10049
|
+
Updating Supatest CLI ${CLI_VERSION} \u2192 ${latest}...`);
|
|
10050
|
+
try {
|
|
10051
|
+
execSync3("npm install -g @supatest/cli@latest", {
|
|
10052
|
+
stdio: "inherit",
|
|
10053
|
+
timeout: INSTALL_TIMEOUT
|
|
10054
|
+
});
|
|
10055
|
+
console.log("\u2713 Updated successfully\n");
|
|
10056
|
+
const child = spawn(process.argv[0], process.argv.slice(1), {
|
|
10057
|
+
stdio: "inherit",
|
|
10058
|
+
detached: false
|
|
10059
|
+
});
|
|
10060
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
10061
|
+
await new Promise(() => {
|
|
10062
|
+
});
|
|
10063
|
+
} catch (installError) {
|
|
10064
|
+
logError(installError, { source: "auto-update", action: "install" });
|
|
10065
|
+
const errMsg = installError instanceof Error ? installError.message : String(installError);
|
|
10066
|
+
console.error("Failed to update:", errMsg);
|
|
10067
|
+
console.log("Continuing with current version...\n");
|
|
10068
|
+
}
|
|
10069
|
+
} catch (error) {
|
|
10070
|
+
logError(error, { source: "auto-update", action: "check" });
|
|
10071
|
+
}
|
|
10072
|
+
}
|
|
10073
|
+
|
|
9944
10074
|
// src/index.ts
|
|
9945
10075
|
init_banner();
|
|
9946
10076
|
init_error_logger();
|
|
@@ -9948,7 +10078,7 @@ init_logger();
|
|
|
9948
10078
|
|
|
9949
10079
|
// src/utils/node-version.ts
|
|
9950
10080
|
init_logger();
|
|
9951
|
-
import { execSync as
|
|
10081
|
+
import { execSync as execSync4 } from "child_process";
|
|
9952
10082
|
var MINIMUM_NODE_VERSION2 = 18;
|
|
9953
10083
|
function parseVersion2(versionString) {
|
|
9954
10084
|
const cleaned = versionString.trim().replace(/^v/, "");
|
|
@@ -9965,7 +10095,7 @@ function parseVersion2(versionString) {
|
|
|
9965
10095
|
}
|
|
9966
10096
|
function getNodeVersion2() {
|
|
9967
10097
|
try {
|
|
9968
|
-
const versionOutput =
|
|
10098
|
+
const versionOutput = execSync4("node --version", {
|
|
9969
10099
|
encoding: "utf-8",
|
|
9970
10100
|
stdio: ["ignore", "pipe", "ignore"]
|
|
9971
10101
|
});
|
|
@@ -10085,6 +10215,7 @@ program.name("supatest").description(
|
|
|
10085
10215
|
).option("--supatest-api-key <key>", "Supatest API key (or use SUPATEST_API_KEY env)").option("--supatest-api-url <url>", "Supatest API URL (or use SUPATEST_API_URL env, defaults to https://code-api.supatest.ai)").option("--headless", "Run in headless mode (for CI/CD, minimal output)").option("--verbose", "Enable verbose logging").option("--model <model>", "Claude model to use (or use ANTHROPIC_MODEL_NAME env)").action(async (task, options) => {
|
|
10086
10216
|
try {
|
|
10087
10217
|
checkNodeVersion2();
|
|
10218
|
+
await checkAndAutoUpdate();
|
|
10088
10219
|
const isHeadlessMode = options.headless || process.stdin.isTTY === false;
|
|
10089
10220
|
if (options.verbose) {
|
|
10090
10221
|
logger.setVerbose(true);
|
|
@@ -10193,9 +10324,9 @@ program.name("supatest").description(
|
|
|
10193
10324
|
process.exit(1);
|
|
10194
10325
|
}
|
|
10195
10326
|
});
|
|
10196
|
-
program.command("setup").description("Check prerequisites and set up required tools (Node.js, Playwright MCP)").action(async () => {
|
|
10327
|
+
program.command("setup").description("Check prerequisites and set up required tools (Node.js, Playwright MCP)").option("-C, --cwd <path>", "Working directory for setup", process.cwd()).action(async (options) => {
|
|
10197
10328
|
try {
|
|
10198
|
-
const result = await setupCommand();
|
|
10329
|
+
const result = await setupCommand({ cwd: options.cwd });
|
|
10199
10330
|
process.exit(result.errors.length === 0 ? 0 : 1);
|
|
10200
10331
|
} catch (error) {
|
|
10201
10332
|
logError(error, { source: "setup" });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supatest/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"description": "Supatest CLI - AI-powered task automation for CI/CD",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -64,10 +64,13 @@
|
|
|
64
64
|
"string-width": "^8.1.0",
|
|
65
65
|
"strip-ansi": "^7.1.2",
|
|
66
66
|
"undici": "^7.16.0",
|
|
67
|
-
"wrap-ansi": "^9.0.2"
|
|
67
|
+
"wrap-ansi": "^9.0.2",
|
|
68
|
+
"latest-version": "^9.0.0",
|
|
69
|
+
"semver": "^7.6.0"
|
|
68
70
|
},
|
|
69
71
|
"devDependencies": {
|
|
70
72
|
"@types/node": "^20.12.12",
|
|
73
|
+
"@types/semver": "^7.5.8",
|
|
71
74
|
"@types/react": "^19.0.0",
|
|
72
75
|
"nodemon": "^3.1.11",
|
|
73
76
|
"tsup": "^8.5.1",
|