@supatest/cli 0.0.22 → 0.0.23

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.
Files changed (2) hide show
  1. package/dist/index.js +134 -15
  2. 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.22";
3955
+ CLI_VERSION = "0.0.23";
3908
3956
  }
3909
3957
  });
3910
3958
 
@@ -5415,6 +5463,9 @@ var init_SessionContext = __esm({
5415
5463
  });
5416
5464
  setStaticRemountKey((prev) => prev + 1);
5417
5465
  }, []);
5466
+ const refreshStatic = useCallback(() => {
5467
+ setStaticRemountKey((prev) => prev + 1);
5468
+ }, []);
5418
5469
  const updateStats = useCallback((updates) => {
5419
5470
  setStats((prev) => ({ ...prev, ...updates }));
5420
5471
  }, []);
@@ -5460,7 +5511,8 @@ var init_SessionContext = __esm({
5460
5511
  setPlanFilePath,
5461
5512
  selectedModel,
5462
5513
  setSelectedModel,
5463
- staticRemountKey
5514
+ staticRemountKey,
5515
+ refreshStatic
5464
5516
  };
5465
5517
  return /* @__PURE__ */ React.createElement(SessionContext.Provider, { value }, children);
5466
5518
  };
@@ -6734,7 +6786,7 @@ var init_message_bridge = __esm({
6734
6786
  });
6735
6787
 
6736
6788
  // src/commands/login.ts
6737
- import { spawn } from "child_process";
6789
+ import { spawn as spawn2 } from "child_process";
6738
6790
  import crypto2 from "crypto";
6739
6791
  import http from "http";
6740
6792
  import { platform } from "os";
@@ -6770,7 +6822,7 @@ function openBrowser(url) {
6770
6822
  default:
6771
6823
  command = "xdg-open";
6772
6824
  }
6773
- spawn(command, [url], { detached: true, stdio: "ignore" }).unref();
6825
+ spawn2(command, [url], { detached: true, stdio: "ignore" }).unref();
6774
6826
  }
6775
6827
  function startCallbackServer(port, expectedState) {
6776
6828
  return new Promise((resolve2, reject) => {
@@ -8681,9 +8733,9 @@ var init_useOverlayEscapeGuard = __esm({
8681
8733
  });
8682
8734
 
8683
8735
  // src/ui/App.tsx
8684
- import { execSync as execSync4 } from "child_process";
8736
+ import { execSync as execSync5 } from "child_process";
8685
8737
  import { homedir as homedir5 } from "os";
8686
- import { Box as Box20, Text as Text18, useApp as useApp2 } from "ink";
8738
+ import { Box as Box20, Text as Text18, useApp as useApp2, useStdout as useStdout2 } from "ink";
8687
8739
  import Spinner3 from "ink-spinner";
8688
8740
  import React23, { useEffect as useEffect10, useRef as useRef4, useState as useState10 } from "react";
8689
8741
  var getGitBranch2, getCurrentFolder2, AppContent, App;
@@ -8713,7 +8765,7 @@ var init_App = __esm({
8713
8765
  init_theme();
8714
8766
  getGitBranch2 = () => {
8715
8767
  try {
8716
- return execSync4("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
8768
+ return execSync5("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
8717
8769
  } catch {
8718
8770
  return "";
8719
8771
  }
@@ -8728,7 +8780,8 @@ var init_App = __esm({
8728
8780
  };
8729
8781
  AppContent = ({ config: config2, sessionId, webUrl, queuedTasks = [], onExit, onSubmitTask, apiClient, onResumeSession, onClearSession }) => {
8730
8782
  const { exit } = useApp2();
8731
- const { addMessage, clearMessages, isAgentRunning, messages, setSessionId, setWebUrl, setShouldInterruptAgent, setIsAgentRunning, toggleAllToolOutputs, allToolsExpanded, selectedModel, setSelectedModel } = useSession();
8783
+ const { stdout } = useStdout2();
8784
+ const { addMessage, clearMessages, isAgentRunning, messages, setSessionId, setWebUrl, setShouldInterruptAgent, setIsAgentRunning, toggleAllToolOutputs, allToolsExpanded, selectedModel, setSelectedModel, refreshStatic } = useSession();
8732
8785
  useModeToggle();
8733
8786
  const [terminalWidth, setTerminalWidth] = useState10(process.stdout.columns || 80);
8734
8787
  const [showHelp, setShowHelp] = useState10(false);
@@ -8881,7 +8934,7 @@ var init_App = __esm({
8881
8934
  content: "Running setup..."
8882
8935
  });
8883
8936
  try {
8884
- const result = await setupCommand();
8937
+ const result = await setupCommand({ cwd: config2.cwd || process.cwd() });
8885
8938
  addMessage({
8886
8939
  type: "assistant",
8887
8940
  content: result.output
@@ -9005,6 +9058,7 @@ var init_App = __esm({
9005
9058
  markOverlayClosed();
9006
9059
  setShowHelp(false);
9007
9060
  };
9061
+ const isInitialMount = useRef4(true);
9008
9062
  useEffect10(() => {
9009
9063
  const handleResize = () => {
9010
9064
  setTerminalWidth(process.stdout.columns || 80);
@@ -9014,6 +9068,19 @@ var init_App = __esm({
9014
9068
  process.stdout.off("resize", handleResize);
9015
9069
  };
9016
9070
  }, []);
9071
+ useEffect10(() => {
9072
+ if (isInitialMount.current) {
9073
+ isInitialMount.current = false;
9074
+ return;
9075
+ }
9076
+ const handler = setTimeout(() => {
9077
+ stdout?.write("\x1B[3J\x1B[H\x1B[2J");
9078
+ refreshStatic();
9079
+ }, 300);
9080
+ return () => {
9081
+ clearTimeout(handler);
9082
+ };
9083
+ }, [terminalWidth, refreshStatic, stdout]);
9017
9084
  useKeypress(
9018
9085
  (key) => {
9019
9086
  if (key.name === "escape" && isAgentRunning && !isOverlayOpen) {
@@ -9941,6 +10008,57 @@ async function runAgent(config2) {
9941
10008
  });
9942
10009
  }
9943
10010
 
10011
+ // src/utils/auto-update.ts
10012
+ init_error_logger();
10013
+ init_version();
10014
+ import { execSync as execSync3, spawn } from "child_process";
10015
+ import latestVersion from "latest-version";
10016
+ import { gt as gt2 } from "semver";
10017
+ var UPDATE_CHECK_TIMEOUT = 3e3;
10018
+ var INSTALL_TIMEOUT = 6e4;
10019
+ async function checkAndAutoUpdate() {
10020
+ if (process.env.NODE_ENV === "development") {
10021
+ return;
10022
+ }
10023
+ if (process.env.SUPATEST_SKIP_UPDATE === "1") {
10024
+ return;
10025
+ }
10026
+ try {
10027
+ const latest = await Promise.race([
10028
+ latestVersion("@supatest/cli"),
10029
+ new Promise(
10030
+ (_2, reject) => setTimeout(() => reject(new Error("timeout")), UPDATE_CHECK_TIMEOUT)
10031
+ )
10032
+ ]);
10033
+ if (!gt2(latest, CLI_VERSION)) {
10034
+ return;
10035
+ }
10036
+ console.log(`
10037
+ Updating Supatest CLI ${CLI_VERSION} \u2192 ${latest}...`);
10038
+ try {
10039
+ execSync3("npm install -g @supatest/cli@latest", {
10040
+ stdio: "inherit",
10041
+ timeout: INSTALL_TIMEOUT
10042
+ });
10043
+ console.log("\u2713 Updated successfully\n");
10044
+ const child = spawn(process.argv[0], process.argv.slice(1), {
10045
+ stdio: "inherit",
10046
+ detached: false
10047
+ });
10048
+ child.on("exit", (code) => process.exit(code ?? 0));
10049
+ await new Promise(() => {
10050
+ });
10051
+ } catch (installError) {
10052
+ logError(installError, { source: "auto-update", action: "install" });
10053
+ const errMsg = installError instanceof Error ? installError.message : String(installError);
10054
+ console.error("Failed to update:", errMsg);
10055
+ console.log("Continuing with current version...\n");
10056
+ }
10057
+ } catch (error) {
10058
+ logError(error, { source: "auto-update", action: "check" });
10059
+ }
10060
+ }
10061
+
9944
10062
  // src/index.ts
9945
10063
  init_banner();
9946
10064
  init_error_logger();
@@ -9948,7 +10066,7 @@ init_logger();
9948
10066
 
9949
10067
  // src/utils/node-version.ts
9950
10068
  init_logger();
9951
- import { execSync as execSync3 } from "child_process";
10069
+ import { execSync as execSync4 } from "child_process";
9952
10070
  var MINIMUM_NODE_VERSION2 = 18;
9953
10071
  function parseVersion2(versionString) {
9954
10072
  const cleaned = versionString.trim().replace(/^v/, "");
@@ -9965,7 +10083,7 @@ function parseVersion2(versionString) {
9965
10083
  }
9966
10084
  function getNodeVersion2() {
9967
10085
  try {
9968
- const versionOutput = execSync3("node --version", {
10086
+ const versionOutput = execSync4("node --version", {
9969
10087
  encoding: "utf-8",
9970
10088
  stdio: ["ignore", "pipe", "ignore"]
9971
10089
  });
@@ -10085,6 +10203,7 @@ program.name("supatest").description(
10085
10203
  ).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
10204
  try {
10087
10205
  checkNodeVersion2();
10206
+ await checkAndAutoUpdate();
10088
10207
  const isHeadlessMode = options.headless || process.stdin.isTTY === false;
10089
10208
  if (options.verbose) {
10090
10209
  logger.setVerbose(true);
@@ -10193,9 +10312,9 @@ program.name("supatest").description(
10193
10312
  process.exit(1);
10194
10313
  }
10195
10314
  });
10196
- program.command("setup").description("Check prerequisites and set up required tools (Node.js, Playwright MCP)").action(async () => {
10315
+ 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
10316
  try {
10198
- const result = await setupCommand();
10317
+ const result = await setupCommand({ cwd: options.cwd });
10199
10318
  process.exit(result.errors.length === 0 ? 0 : 1);
10200
10319
  } catch (error) {
10201
10320
  logError(error, { source: "setup" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supatest/cli",
3
- "version": "0.0.22",
3
+ "version": "0.0.23",
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",