@supatest/cli 0.0.30 → 0.0.31

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 +97 -14
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5522,7 +5522,7 @@ var CLI_VERSION;
5522
5522
  var init_version = __esm({
5523
5523
  "src/version.ts"() {
5524
5524
  "use strict";
5525
- CLI_VERSION = "0.0.30";
5525
+ CLI_VERSION = "0.0.31";
5526
5526
  }
5527
5527
  });
5528
5528
 
@@ -6466,6 +6466,7 @@ var init_agent = __esm({
6466
6466
  await init_config();
6467
6467
  init_command_discovery();
6468
6468
  init_error_logger();
6469
+ init_logger();
6469
6470
  init_mcp_loader();
6470
6471
  init_project_instructions();
6471
6472
  CoreAgent = class {
@@ -6531,6 +6532,7 @@ ${projectInstructions}`,
6531
6532
  "ANTHROPIC_BASE_URL",
6532
6533
  "ANTHROPIC_AUTH_TOKEN",
6533
6534
  "CLAUDE_CODE_AUTH_TOKEN",
6535
+ "CLAUDE_CODE_OAUTH_TOKEN",
6534
6536
  "CLAUDE_API_KEY"
6535
6537
  ]);
6536
6538
  for (const [key, value] of Object.entries(process.env)) {
@@ -6538,12 +6540,32 @@ ${projectInstructions}`,
6538
6540
  cleanEnv[key] = value;
6539
6541
  }
6540
6542
  }
6541
- const internalConfigDir = join6(homedir2(), ".supatest", "claude-internal");
6542
- cleanEnv.CLAUDE_CONFIG_DIR = internalConfigDir;
6543
- cleanEnv.ANTHROPIC_API_KEY = config2.supatestApiKey || "";
6544
- cleanEnv.ANTHROPIC_BASE_URL = process.env.ANTHROPIC_BASE_URL || "";
6543
+ logger.debug("[agent] Setting up authentication", {
6544
+ useClaudeMax: !!config2.oauthToken,
6545
+ hasSupatestApiKey: !!config2.supatestApiKey,
6546
+ supatestApiKeyPrefix: config2.supatestApiKey ? config2.supatestApiKey.slice(0, 15) + "..." : null,
6547
+ anthropicBaseUrl: process.env.ANTHROPIC_BASE_URL
6548
+ });
6549
+ if (config2.oauthToken) {
6550
+ cleanEnv.ANTHROPIC_API_KEY = "";
6551
+ cleanEnv.ANTHROPIC_BASE_URL = "";
6552
+ this.presenter.onLog(`Auth: Using Claude Max (default Claude Code credentials)`);
6553
+ logger.debug("[agent] Claude Max mode: Using default ~/.claude/ config, cleared ANTHROPIC_API_KEY and ANTHROPIC_BASE_URL");
6554
+ } else {
6555
+ const internalConfigDir = join6(homedir2(), ".supatest", "claude-internal");
6556
+ cleanEnv.CLAUDE_CONFIG_DIR = internalConfigDir;
6557
+ cleanEnv.ANTHROPIC_API_KEY = config2.supatestApiKey || "";
6558
+ cleanEnv.ANTHROPIC_BASE_URL = process.env.ANTHROPIC_BASE_URL || "";
6559
+ this.presenter.onLog(`Auth: Using Supatest API key${process.env.ANTHROPIC_BASE_URL ? ` (base: ${process.env.ANTHROPIC_BASE_URL})` : ""}`);
6560
+ logger.debug("[agent] API key mode: Set ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL, and CLAUDE_CONFIG_DIR");
6561
+ }
6545
6562
  cleanEnv.ANTHROPIC_AUTH_TOKEN = "";
6546
6563
  cleanEnv.CLAUDE_CODE_AUTH_TOKEN = "";
6564
+ logger.debug("[agent] Final auth env vars", {
6565
+ ANTHROPIC_API_KEY: cleanEnv.ANTHROPIC_API_KEY ? cleanEnv.ANTHROPIC_API_KEY.slice(0, 15) + "..." : "(not set)",
6566
+ ANTHROPIC_BASE_URL: cleanEnv.ANTHROPIC_BASE_URL || "(not set)",
6567
+ CLAUDE_CONFIG_DIR: cleanEnv.CLAUDE_CONFIG_DIR || "(using default ~/.claude/)"
6568
+ });
6547
6569
  cleanEnv.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = "1";
6548
6570
  const queryOptions = {
6549
6571
  // AbortController for cancellation support
@@ -6616,6 +6638,13 @@ ${projectInstructions}`,
6616
6638
  return expiredPatterns.some((pattern) => lowerError.includes(pattern));
6617
6639
  };
6618
6640
  const runQuery = async (options) => {
6641
+ logger.debug("[agent] Starting query", {
6642
+ model: options.model,
6643
+ maxTurns: options.maxTurns,
6644
+ permissionMode: options.permissionMode,
6645
+ hasResume: !!options.resume,
6646
+ cwd: options.cwd
6647
+ });
6619
6648
  const queryIterator = query({ prompt, options });
6620
6649
  if (this.messageBridge) {
6621
6650
  queryIterator.streamInput(this.messageBridge).catch((err) => {
@@ -6738,16 +6767,24 @@ ${projectInstructions}`,
6738
6767
  };
6739
6768
  try {
6740
6769
  await runQuery(queryOptions);
6770
+ logger.debug("[agent] Query completed successfully");
6741
6771
  } catch (error) {
6742
6772
  const errorMessage = error instanceof Error ? error.message : String(error);
6773
+ logger.debug("[agent] Query error caught", {
6774
+ errorName: error instanceof Error ? error.name : "unknown",
6775
+ errorMessage,
6776
+ stack: error instanceof Error ? error.stack?.slice(0, 500) : void 0
6777
+ });
6743
6778
  const isAbortError = error instanceof Error && error.name === "AbortError" || errorMessage.toLowerCase().includes("aborted");
6744
6779
  if (isAbortError) {
6745
6780
  wasInterrupted = true;
6781
+ logger.debug("[agent] Query was aborted by user");
6746
6782
  } else if (config2.providerSessionId && isSessionExpiredError(errorMessage)) {
6747
6783
  const expiredMessage = "Can't continue conversation older than 30 days. Please start a new session.";
6748
6784
  this.presenter.onError(expiredMessage, true);
6749
6785
  hasError = true;
6750
6786
  errors.push(expiredMessage);
6787
+ logger.debug("[agent] Session expired error");
6751
6788
  } else {
6752
6789
  logError(error, {
6753
6790
  source: "CoreAgent.run",
@@ -6759,6 +6796,7 @@ ${projectInstructions}`,
6759
6796
  this.presenter.onError(errorMessage, true);
6760
6797
  hasError = true;
6761
6798
  errors.push(errorMessage);
6799
+ logger.debug("[agent] General error, logged to error-logger");
6762
6800
  }
6763
6801
  } finally {
6764
6802
  this.messageBridge?.close();
@@ -10960,7 +10998,7 @@ var init_useOverlayEscapeGuard = __esm({
10960
10998
  });
10961
10999
 
10962
11000
  // src/ui/App.tsx
10963
- import { execSync as execSync5 } from "child_process";
11001
+ import { execSync as execSync6 } from "child_process";
10964
11002
  import { homedir as homedir5 } from "os";
10965
11003
  import { Box as Box23, Text as Text21, useApp as useApp2, useStdout as useStdout2 } from "ink";
10966
11004
  import Spinner3 from "ink-spinner";
@@ -10994,7 +11032,7 @@ var init_App = __esm({
10994
11032
  init_theme();
10995
11033
  getGitBranch2 = () => {
10996
11034
  try {
10997
- return execSync5("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
11035
+ return execSync6("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
10998
11036
  } catch {
10999
11037
  return "";
11000
11038
  }
@@ -12369,12 +12407,43 @@ Updating Supatest CLI ${CLI_VERSION} \u2192 ${latest}...`);
12369
12407
 
12370
12408
  // src/index.ts
12371
12409
  init_banner();
12410
+
12411
+ // src/utils/claude-max.ts
12412
+ init_logger();
12413
+ import { execSync as execSync4 } from "child_process";
12414
+ function isClaudeMaxAvailable() {
12415
+ logger.debug("[claude-max] Checking if Claude Code credentials exist in keychain");
12416
+ try {
12417
+ const credentialsJson = execSync4(
12418
+ 'security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null',
12419
+ { encoding: "utf-8" }
12420
+ ).trim();
12421
+ if (!credentialsJson) {
12422
+ logger.debug("[claude-max] No credentials found in keychain");
12423
+ return false;
12424
+ }
12425
+ const credentials = JSON.parse(credentialsJson);
12426
+ const hasOauth = !!credentials.claudeAiOauth?.accessToken;
12427
+ logger.debug("[claude-max] Credentials check", {
12428
+ hasOauth,
12429
+ hasRefreshToken: !!credentials.claudeAiOauth?.refreshToken
12430
+ });
12431
+ return hasOauth;
12432
+ } catch (error) {
12433
+ logger.debug("[claude-max] Error checking keychain", {
12434
+ error: error instanceof Error ? error.message : String(error)
12435
+ });
12436
+ return false;
12437
+ }
12438
+ }
12439
+
12440
+ // src/index.ts
12372
12441
  init_error_logger();
12373
12442
  init_logger();
12374
12443
 
12375
12444
  // src/utils/node-version.ts
12376
12445
  init_logger();
12377
- import { execSync as execSync4 } from "child_process";
12446
+ import { execSync as execSync5 } from "child_process";
12378
12447
  var MINIMUM_NODE_VERSION2 = 18;
12379
12448
  function parseVersion2(versionString) {
12380
12449
  const cleaned = versionString.trim().replace(/^v/, "");
@@ -12391,7 +12460,7 @@ function parseVersion2(versionString) {
12391
12460
  }
12392
12461
  function getNodeVersion2() {
12393
12462
  try {
12394
- const versionOutput = execSync4("node --version", {
12463
+ const versionOutput = execSync5("node --version", {
12395
12464
  encoding: "utf-8",
12396
12465
  stdio: ["ignore", "pipe", "ignore"]
12397
12466
  });
@@ -12505,10 +12574,10 @@ var program = new Command();
12505
12574
  program.name("supatest").description(
12506
12575
  "AI-powered task automation CLI for CI/CD - fix tests, lint issues, and more"
12507
12576
  ).version(CLI_VERSION).argument("[task]", "Task description or prompt for the AI agent").option("-l, --logs <file>", "Path to log file to analyze").option("--stdin", "Read logs from stdin").option("-C, --cwd <path>", "Working directory for the agent", process.cwd()).option(
12508
- "-m, --max-iterations <number>",
12577
+ "-m, --claude-max-iterations <number>",
12509
12578
  "Maximum number of iterations",
12510
12579
  "100"
12511
- ).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) => {
12580
+ ).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)").option("--claude-max", "Use Claude Max subscription (requires Claude Code to be logged in)").action(async (task, options) => {
12512
12581
  try {
12513
12582
  checkNodeVersion2();
12514
12583
  await checkAndAutoUpdate();
@@ -12543,7 +12612,19 @@ program.name("supatest").description(
12543
12612
  process.exit(1);
12544
12613
  }
12545
12614
  let supatestApiKey;
12615
+ let oauthToken;
12546
12616
  const supatestApiUrl = options.supatestApiUrl || config.supatestApiUrl;
12617
+ if (options.claudeMax) {
12618
+ if (!isClaudeMaxAvailable()) {
12619
+ logger.error("Claude Max not available. Please ensure:");
12620
+ logger.error(" 1. Claude Code is installed");
12621
+ logger.error(" 2. You are logged in with a Claude Max subscription");
12622
+ logger.error(" 3. Run 'claude' and authenticate if needed");
12623
+ process.exit(1);
12624
+ }
12625
+ oauthToken = "use-claude-max";
12626
+ logger.info("Using Claude Max subscription for LLM calls");
12627
+ }
12547
12628
  if (isHeadlessMode) {
12548
12629
  supatestApiKey = normalizeSupatestKey(
12549
12630
  options.supatestApiKey || config.supatestApiKey,
@@ -12551,7 +12632,7 @@ program.name("supatest").description(
12551
12632
  );
12552
12633
  if (!supatestApiKey) {
12553
12634
  logger.error(
12554
- "API key required in CI/headless mode. Please either:"
12635
+ "Supatest API key required in CI/headless mode. Please either:"
12555
12636
  );
12556
12637
  logger.error(" 1. Set SUPATEST_API_KEY environment variable");
12557
12638
  logger.error(" 2. Use --supatest-api-key option");
@@ -12593,7 +12674,8 @@ program.name("supatest").description(
12593
12674
  verbose: options.verbose || false,
12594
12675
  cwd: options.cwd,
12595
12676
  systemPromptAppend: config.headlessSystemPrompt,
12596
- selectedModel
12677
+ selectedModel,
12678
+ oauthToken
12597
12679
  });
12598
12680
  process.exit(result.success ? 0 : 1);
12599
12681
  } else {
@@ -12608,7 +12690,8 @@ program.name("supatest").description(
12608
12690
  verbose: options.verbose || false,
12609
12691
  cwd: options.cwd,
12610
12692
  systemPromptAppend: config.interactiveSystemPrompt,
12611
- selectedModel
12693
+ selectedModel,
12694
+ oauthToken
12612
12695
  });
12613
12696
  }
12614
12697
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supatest/cli",
3
- "version": "0.0.30",
3
+ "version": "0.0.31",
4
4
  "description": "Supatest CLI - AI-powered task automation for CI/CD",
5
5
  "type": "module",
6
6
  "bin": {