@validate.qa/runner 1.0.34 → 1.0.35

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 (4) hide show
  1. package/README.md +24 -1
  2. package/dist/cli.js +306 -163
  3. package/dist/cli.mjs +306 -163
  4. package/package.json +2 -1
package/dist/cli.js CHANGED
@@ -1349,11 +1349,13 @@ function escapeEnvValue(value) {
1349
1349
  const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r");
1350
1350
  return `"${escaped}"`;
1351
1351
  }
1352
- var API_PREFIX, AUDIO_CHUNK_DURATION_MS, ACTION_BATCH_INTERVAL_MS, ACTION_BATCH_MAX_SIZE, MOBILE_SCREENSHOT_INTERVAL_MS, MOBILE_ACTION_BATCH_MAX_SIZE, MOBILE_BRIDGE_PORT, MOBILE_SNAPSHOT_MAX_SIZE_BYTES, MOBILE_APP_ID_MAX_LENGTH, MOBILE_APP_ID_PATTERN, MOBILE_FOCUS_SETTLE_MS, MOBILE_DEFAULT_SWIPE_DISTANCE, MOBILE_MAX_SWIPE_DISTANCE, SELECTOR_PRIORITIES, MOBILE_STEP_TYPES, BLOCKED_ENV_VARS, SPAWNED_ENV_ALLOWLIST;
1352
+ var API_PREFIX, SUPPORT_EMAIL, PLATFORM_ADMIN_EMAIL, AUDIO_CHUNK_DURATION_MS, ACTION_BATCH_INTERVAL_MS, ACTION_BATCH_MAX_SIZE, MOBILE_SCREENSHOT_INTERVAL_MS, MOBILE_ACTION_BATCH_MAX_SIZE, MOBILE_BRIDGE_PORT, MOBILE_SNAPSHOT_MAX_SIZE_BYTES, MOBILE_APP_ID_MAX_LENGTH, MOBILE_APP_ID_PATTERN, MOBILE_FOCUS_SETTLE_MS, MOBILE_DEFAULT_SWIPE_DISTANCE, MOBILE_MAX_SWIPE_DISTANCE, SELECTOR_PRIORITIES, MOBILE_STEP_TYPES, BLOCKED_ENV_VARS, SPAWNED_ENV_ALLOWLIST;
1353
1353
  var init_constants = __esm({
1354
1354
  "../shared/dist/constants.js"() {
1355
1355
  "use strict";
1356
1356
  API_PREFIX = "/api";
1357
+ SUPPORT_EMAIL = "support@validate.qa";
1358
+ PLATFORM_ADMIN_EMAIL = "admin@validate.qa";
1357
1359
  AUDIO_CHUNK_DURATION_MS = 3e4;
1358
1360
  ACTION_BATCH_INTERVAL_MS = 2e3;
1359
1361
  ACTION_BATCH_MAX_SIZE = 10;
@@ -2557,6 +2559,8 @@ var init_audit_pricing = __esm({
2557
2559
  // Current defaults
2558
2560
  "grok-build-0.1": { input: 1, output: 2 },
2559
2561
  "claude-opus-4-7": { input: 5, output: 25 },
2562
+ // Introductory pricing through 2026-08-31 ($2/$10); standard is $3/$15.
2563
+ "claude-sonnet-5": { input: 2, output: 10 },
2560
2564
  "claude-sonnet-4-6": { input: 3, output: 15 },
2561
2565
  "claude-haiku-4-5-20251001": { input: 1, output: 5 },
2562
2566
  "gpt-4o": { input: 2.5, output: 10 },
@@ -3593,7 +3597,7 @@ var init_agent_env = __esm({
3593
3597
  "CommonProgramFiles"
3594
3598
  ]);
3595
3599
  ALLOW_PREFIX = [
3596
- // AI provider / CLI config (grok-build, claude-code, claude-code-minimax)
3600
+ // AI provider / CLI config (grok-build, claude-code)
3597
3601
  "GROK_",
3598
3602
  "XAI_",
3599
3603
  "ANTHROPIC_",
@@ -3900,8 +3904,10 @@ __export(dist_exports, {
3900
3904
  MOBILE_STEP_TYPES: () => MOBILE_STEP_TYPES,
3901
3905
  PLAN_DEFINITIONS: () => PLAN_DEFINITIONS,
3902
3906
  PLAN_ORDER: () => PLAN_ORDER,
3907
+ PLATFORM_ADMIN_EMAIL: () => PLATFORM_ADMIN_EMAIL,
3903
3908
  SELECTOR_PRIORITIES: () => SELECTOR_PRIORITIES,
3904
3909
  SHARED_PRICING_PLAN_MAP: () => SHARED_PRICING_PLAN_MAP,
3910
+ SUPPORT_EMAIL: () => SUPPORT_EMAIL,
3905
3911
  TRANSIENT_CONTROL_ROLES: () => TRANSIENT_CONTROL_ROLES,
3906
3912
  TRIAL_DURATION_DAYS: () => TRIAL_DURATION_DAYS,
3907
3913
  UI_VARIANTS: () => UI_VARIANTS,
@@ -298969,7 +298975,8 @@ var require_bootstrap_grok_auth = __commonJS({
298969
298975
  const home = process.env.HOME ?? "/home/appuser";
298970
298976
  const authPath = node_path_1.default.join(home, ".grok", "auth.json");
298971
298977
  const b64 = process.env.GROK_AUTH_JSON_B64;
298972
- if (node_fs_1.default.existsSync(authPath)) {
298978
+ const force = process.env.GROK_AUTH_FORCE_RESEED === "true" || process.env.GROK_AUTH_FORCE_RESEED === "1";
298979
+ if (!force && node_fs_1.default.existsSync(authPath)) {
298973
298980
  return;
298974
298981
  }
298975
298982
  if (!b64) {
@@ -298980,7 +298987,7 @@ var require_bootstrap_grok_auth = __commonJS({
298980
298987
  node_fs_1.default.mkdirSync(dir, { recursive: true, mode: 448 });
298981
298988
  node_fs_1.default.writeFileSync(authPath, Buffer.from(b64, "base64"));
298982
298989
  node_fs_1.default.chmodSync(authPath, 384);
298983
- console.log(`[grok-auth][runner] Seeded ${authPath} from GROK_AUTH_JSON_B64`);
298990
+ console.log(force ? `[grok-auth][runner] Force-reseeded ${authPath} from GROK_AUTH_JSON_B64` : `[grok-auth][runner] Seeded ${authPath} from GROK_AUTH_JSON_B64`);
298984
298991
  } catch (err) {
298985
298992
  const message = err instanceof Error ? err.message : String(err);
298986
298993
  console.warn(`[grok-auth][runner] Failed to seed auth.json: ${message}`);
@@ -299625,6 +299632,37 @@ var require_proven_actions_adapter = __commonJS({
299625
299632
  }
299626
299633
  });
299627
299634
 
299635
+ // ../runner-core/dist/services/agentic-cli-constants.js
299636
+ var require_agentic_cli_constants = __commonJS({
299637
+ "../runner-core/dist/services/agentic-cli-constants.js"(exports2) {
299638
+ "use strict";
299639
+ Object.defineProperty(exports2, "__esModule", { value: true });
299640
+ exports2.GROK_CLI_DEFAULT_REASONING_EFFORT = exports2.GROK_CLI_DEFAULT_MODEL = exports2.CLAUDE_CODE_DEFAULT_EFFORT = exports2.CLAUDE_CODE_DEFAULT_MODEL = exports2.MODEL_CLAUDE_CODE = exports2.MODEL_GROK_BUILD = void 0;
299641
+ exports2.isGrokBuildModel = isGrokBuildModel;
299642
+ exports2.isClaudeCodeModel = isClaudeCodeModel;
299643
+ exports2.getAgenticEngine = getAgenticEngine;
299644
+ exports2.MODEL_GROK_BUILD = "grok-build";
299645
+ function isGrokBuildModel(id) {
299646
+ return id === exports2.MODEL_GROK_BUILD;
299647
+ }
299648
+ exports2.MODEL_CLAUDE_CODE = "claude-code";
299649
+ function isClaudeCodeModel(id) {
299650
+ return id === exports2.MODEL_CLAUDE_CODE;
299651
+ }
299652
+ function getAgenticEngine(modelId) {
299653
+ if (isGrokBuildModel(modelId))
299654
+ return "grok-build";
299655
+ if (isClaudeCodeModel(modelId))
299656
+ return "claude-code";
299657
+ return "native";
299658
+ }
299659
+ exports2.CLAUDE_CODE_DEFAULT_MODEL = "claude-sonnet-5";
299660
+ exports2.CLAUDE_CODE_DEFAULT_EFFORT = "max";
299661
+ exports2.GROK_CLI_DEFAULT_MODEL = "grok-4.5";
299662
+ exports2.GROK_CLI_DEFAULT_REASONING_EFFORT = "high";
299663
+ }
299664
+ });
299665
+
299628
299666
  // ../runner-core/dist/services/grok-cli.js
299629
299667
  var require_grok_cli = __commonJS({
299630
299668
  "../runner-core/dist/services/grok-cli.js"(exports2) {
@@ -299635,6 +299673,7 @@ var require_grok_cli = __commonJS({
299635
299673
  exports2.runGrok = runGrok;
299636
299674
  var node_child_process_1 = require("child_process");
299637
299675
  var shared_1 = (init_dist(), __toCommonJS(dist_exports));
299676
+ var agentic_cli_constants_js_1 = require_agentic_cli_constants();
299638
299677
  function extractAssistantJson(stdout) {
299639
299678
  const tryParse = (s) => {
299640
299679
  const trimmed = s.trim();
@@ -299729,7 +299768,8 @@ var require_grok_cli = __commonJS({
299729
299768
  function runGrok(options) {
299730
299769
  const {
299731
299770
  prompt,
299732
- model = "grok-build",
299771
+ model = agentic_cli_constants_js_1.GROK_CLI_DEFAULT_MODEL,
299772
+ reasoningEffort = agentic_cli_constants_js_1.GROK_CLI_DEFAULT_REASONING_EFFORT,
299733
299773
  maxTurns,
299734
299774
  // undefined = let grok decide when to quit
299735
299775
  timeoutMs = 6e5,
@@ -299758,6 +299798,9 @@ var require_grok_cli = __commonJS({
299758
299798
  "--always-approve",
299759
299799
  "--no-alt-screen"
299760
299800
  ];
299801
+ if (reasoningEffort) {
299802
+ args.push("--reasoning-effort", reasoningEffort);
299803
+ }
299761
299804
  if (typeof maxTurns === "number" && maxTurns > 0) {
299762
299805
  args.push("--max-turns", String(maxTurns));
299763
299806
  }
@@ -299903,7 +299946,7 @@ var require_grok_per_test_healer = __commonJS({
299903
299946
  var HEAL_MCP_CAPABILITIES = ["core", "core-navigation", "core-input", "core-tabs", "testing"];
299904
299947
  var grok_cli_js_1 = require_grok_cli();
299905
299948
  var DEFAULT_MAX_ATTEMPTS = 3;
299906
- var DEFAULT_TIMEOUT_MS = 30 * 60 * 1e3;
299949
+ var DEFAULT_TIMEOUT_MS2 = 30 * 60 * 1e3;
299907
299950
  var IDLE_WATCHDOG_MS = 10 * 60 * 1e3;
299908
299951
  function getMaxAttempts() {
299909
299952
  const raw = process.env.GROK_PER_TEST_HEAL_MAX_ATTEMPTS;
@@ -299913,7 +299956,7 @@ var require_grok_per_test_healer = __commonJS({
299913
299956
  function getAttemptTimeoutMs() {
299914
299957
  const raw = process.env.GROK_PER_TEST_HEAL_TIMEOUT_MS;
299915
299958
  const parsed = raw ? parseInt(raw, 10) : NaN;
299916
- return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_TIMEOUT_MS;
299959
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_TIMEOUT_MS2;
299917
299960
  }
299918
299961
  async function executeGrokPerTestHeal2(playwrightCode, steps, baseUrl, options = {}) {
299919
299962
  const externalLogSink = options.onLog;
@@ -300326,7 +300369,7 @@ Output the JSON envelope exactly ONCE as your final message, then exit.`;
300326
300369
  "-p",
300327
300370
  'Read BRIEF.md in this directory. Heal TEST_UNDER_HEAL.spec.ts as instructed. Your FINAL assistant message MUST be ONLY a JSON object \u2014 no prose around it \u2014 with this shape: {"verdict":"fix|app_bug|config_issue|prereq_unmet|state_stale|test_invalid","playwrightCode":"<full file if verdict=fix>","changeDescription":"<one sentence>","reason":"<terse, when not fix>","confidence":"high|medium|low"}',
300328
300371
  "-m",
300329
- "grok-build",
300372
+ "grok-4.5",
300330
300373
  // streaming-json: per-event NDJSON so the UI's GrokSessionLog drawer can
300331
300374
  // show progress instead of a frozen "starting…" until the final envelope.
300332
300375
  "--output-format",
@@ -301546,7 +301589,7 @@ When done with all ${input.tests.length} tests in this chunk, exit.`;
301546
301589
  "-p",
301547
301590
  "Read BRIEF.md in this directory. Heal every test under tests/*.spec.ts as instructed and emit a verdict file per test under verdicts/<testCaseId>.json (write to .tmp then rename \u2014 the runner is polling). When done, exit.",
301548
301591
  "-m",
301549
- "grok-build",
301592
+ "grok-4.5",
301550
301593
  // streaming-json so per-token output reaches the UI for live progress.
301551
301594
  "--output-format",
301552
301595
  "streaming-json",
@@ -309035,47 +309078,6 @@ var require_sitemap_builder = __commonJS({
309035
309078
  }
309036
309079
  });
309037
309080
 
309038
- // ../runner-core/dist/services/agentic-cli-constants.js
309039
- var require_agentic_cli_constants = __commonJS({
309040
- "../runner-core/dist/services/agentic-cli-constants.js"(exports2) {
309041
- "use strict";
309042
- Object.defineProperty(exports2, "__esModule", { value: true });
309043
- exports2.CLAUDE_CODE_MINIMAX_FALLBACK_CHAIN = exports2.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL = exports2.CLAUDE_CODE_DEFAULT_MODEL = exports2.MODEL_CLAUDE_CODE_MINIMAX = exports2.MODEL_CLAUDE_CODE = exports2.MODEL_GROK_BUILD = void 0;
309044
- exports2.isGrokBuildModel = isGrokBuildModel;
309045
- exports2.isClaudeCodeModel = isClaudeCodeModel;
309046
- exports2.isClaudeCodeMinimaxModel = isClaudeCodeMinimaxModel;
309047
- exports2.getAgenticEngine = getAgenticEngine;
309048
- exports2.MODEL_GROK_BUILD = "grok-build";
309049
- function isGrokBuildModel(id) {
309050
- return id === exports2.MODEL_GROK_BUILD;
309051
- }
309052
- exports2.MODEL_CLAUDE_CODE = "claude-code";
309053
- function isClaudeCodeModel(id) {
309054
- return id === exports2.MODEL_CLAUDE_CODE;
309055
- }
309056
- exports2.MODEL_CLAUDE_CODE_MINIMAX = "claude-code-minimax";
309057
- function isClaudeCodeMinimaxModel(id) {
309058
- return id === exports2.MODEL_CLAUDE_CODE_MINIMAX;
309059
- }
309060
- function getAgenticEngine(modelId) {
309061
- if (isGrokBuildModel(modelId))
309062
- return "grok-build";
309063
- if (isClaudeCodeMinimaxModel(modelId))
309064
- return "claude-code-minimax";
309065
- if (isClaudeCodeModel(modelId))
309066
- return "claude-code";
309067
- return "native";
309068
- }
309069
- exports2.CLAUDE_CODE_DEFAULT_MODEL = "claude-sonnet-4-6";
309070
- exports2.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL = "MiniMax-M3";
309071
- exports2.CLAUDE_CODE_MINIMAX_FALLBACK_CHAIN = [
309072
- "MiniMax-M3",
309073
- "MiniMax-M2.7-highspeed",
309074
- "MiniMax-M2.7"
309075
- ];
309076
- }
309077
- });
309078
-
309079
309081
  // ../runner-core/dist/services/auth-capture-run.js
309080
309082
  var require_auth_capture_run = __commonJS({
309081
309083
  "../runner-core/dist/services/auth-capture-run.js"(exports2) {
@@ -309879,7 +309881,7 @@ var require_grok_survey_runner = __commonJS({
309879
309881
  var scrub_credentials_js_1 = require_scrub_credentials();
309880
309882
  var agentic_survey_prompts_js_1 = require_agentic_survey_prompts();
309881
309883
  var MCP_CAPABILITIES = ["core", "core-navigation", "core-input", "core-tabs", "testing"];
309882
- var DEFAULT_TIMEOUT_MS = 15 * 60 * 1e3;
309884
+ var DEFAULT_TIMEOUT_MS2 = 15 * 60 * 1e3;
309883
309885
  var RETRY_TIMEOUT_MS = 5 * 60 * 1e3;
309884
309886
  function extractCredentials(vars) {
309885
309887
  if (!vars)
@@ -310315,7 +310317,7 @@ var require_grok_survey_runner = __commonJS({
310315
310317
  }
310316
310318
  async function runGrokSurveyOnRunner(ctx, options = {}) {
310317
310319
  const maxTurns = options.maxTurns;
310318
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
310320
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
310319
310321
  const logs2 = [];
310320
310322
  const log2 = (line) => {
310321
310323
  logs2.push(line);
@@ -310449,7 +310451,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
310449
310451
  try {
310450
310452
  const result = await (0, grok_cli_js_1.runGrok)({
310451
310453
  prompt: kickoffPrompt,
310452
- model: "grok-build",
310454
+ model: "grok-4.5",
310453
310455
  maxTurns,
310454
310456
  timeoutMs,
310455
310457
  homeDir: grokHomeDir,
@@ -310496,7 +310498,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
310496
310498
  try {
310497
310499
  const retryResult = await (0, grok_cli_js_1.runGrok)({
310498
310500
  prompt: fixPrompt,
310499
- model: "grok-build",
310501
+ model: "grok-4.5",
310500
310502
  // Retry: also let grok decide turns; the shorter retry budget lives
310501
310503
  // in the wall-clock timeout below.
310502
310504
  timeoutMs: RETRY_TIMEOUT_MS,
@@ -310629,20 +310631,19 @@ var require_canvas_detector = __commonJS({
310629
310631
  return { kind: "override", canvasMode: false };
310630
310632
  if (opts.engine === "claude-code")
310631
310633
  return { kind: "canvas-mode", canvasMode: true };
310632
- if (opts.engine === "claude-code-minimax" || opts.engine === "native")
310634
+ if (opts.engine === "native")
310633
310635
  return { kind: "bail" };
310634
310636
  return { kind: "proceed", canvasMode: false };
310635
310637
  }
310636
310638
  function modelSupportsVision(modelId) {
310637
310639
  if (!modelId)
310638
310640
  return false;
310639
- if (modelId === "claude-code-minimax")
310640
- return false;
310641
310641
  if (modelId === "claude-code")
310642
310642
  return true;
310643
310643
  if (modelId === "grok-build")
310644
310644
  return false;
310645
310645
  const visionCapable = /* @__PURE__ */ new Set([
310646
+ "claude-sonnet-5",
310646
310647
  "claude-sonnet-4-6",
310647
310648
  "claude-opus-4-7",
310648
310649
  "claude-haiku-4-5",
@@ -311819,7 +311820,7 @@ var require_grok_discovery_runner = __commonJS({
311819
311820
  "core-tabs",
311820
311821
  "testing"
311821
311822
  ];
311822
- var DEFAULT_TIMEOUT_MS = 20 * 60 * 1e3;
311823
+ var DEFAULT_TIMEOUT_MS2 = 20 * 60 * 1e3;
311823
311824
  var RETRY_TIMEOUT_MS = 6 * 60 * 1e3;
311824
311825
  var DEFAULT_TARGET = { min: 6, max: 15 };
311825
311826
  var WATCHER_DEBOUNCE_MS = 500;
@@ -311983,7 +311984,7 @@ var require_grok_discovery_runner = __commonJS({
311983
311984
  const manifestFeatureRoutes = Array.isArray(manifestShape?.feature?.pages) ? manifestShape.feature.pages.filter((r) => typeof r === "string" && r.length > 0) : [];
311984
311985
  const featureRoutes = manifestFeatureRoutes.length > 0 ? manifestFeatureRoutes : ctx.featureContext?.pageIntel?.map((p) => p.route) ?? ctx.focusAreas ?? [];
311985
311986
  const targetTestCount = options.targetTestCount ?? DEFAULT_TARGET;
311986
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
311987
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
311987
311988
  const logs2 = [];
311988
311989
  const log2 = (line) => {
311989
311990
  logs2.push(line);
@@ -312588,7 +312589,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
312588
312589
  try {
312589
312590
  const result = await (0, grok_cli_js_1.runGrok)({
312590
312591
  prompt: kickoffPrompt,
312591
- model: "grok-build",
312592
+ model: "grok-4.5",
312592
312593
  timeoutMs,
312593
312594
  homeDir: grokHomeDir,
312594
312595
  cwd: runDir,
@@ -312668,7 +312669,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
312668
312669
  try {
312669
312670
  const retryResult = await (0, grok_cli_js_1.runGrok)({
312670
312671
  prompt: fixPrompt,
312671
- model: "grok-build",
312672
+ model: "grok-4.5",
312672
312673
  timeoutMs: RETRY_TIMEOUT_MS,
312673
312674
  homeDir: grokHomeDir,
312674
312675
  cwd: runDir,
@@ -312900,7 +312901,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
312900
312901
  const manifestFeatureRoutes = Array.isArray(manifestShape?.feature?.pages) ? manifestShape.feature.pages.filter((r) => typeof r === "string" && r.length > 0) : [];
312901
312902
  const featureRoutes = manifestFeatureRoutes.length > 0 ? manifestFeatureRoutes : ctx.featureContext?.pageIntel?.map((p) => p.route) ?? ctx.focusAreas ?? [];
312902
312903
  const targetTestCount = options.targetTestCount ?? DEFAULT_TARGET;
312903
- const callerTimeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
312904
+ const callerTimeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
312904
312905
  const call1TimeoutMs = Math.max(callerTimeoutMs, GROK_V2_CALL1_TIMEOUT_MS);
312905
312906
  const logs2 = [];
312906
312907
  const log2 = (line) => {
@@ -313417,24 +313418,12 @@ var require_claude_cli = __commonJS({
313417
313418
  return s.includes("authentication_failed") || s.includes("oauth_org_not_allowed") || s.includes("invalid_grant") || s.includes("401 unauthorized") || s.includes("invalid api key") || s.includes("invalid bearer token") || /\boauth token\b.*\b(expired|invalid)\b/.test(s) || /\b(token|credentials?)\b.*\bexpired\b/.test(s);
313418
313419
  }
313419
313420
  function runClaudeOnce(options) {
313420
- const { prompt, model = "claude-sonnet-4-6", provider = "anthropic", maxTurns, timeoutMs = 6e5, cwd, mcpConfigPath, addDirs, appendSystemPrompt, disallowedTools = ["Task"], onChunk, idleKillMs = 5 * 60 * 1e3, abortRef } = options;
313421
+ const { prompt, model = agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL, effort = agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_EFFORT, provider = "anthropic", maxTurns, timeoutMs = 6e5, cwd, mcpConfigPath, addDirs, appendSystemPrompt, disallowedTools = ["Task"], onChunk, idleKillMs = 5 * 60 * 1e3, abortRef } = options;
313421
313422
  return new Promise((resolve, reject) => {
313422
- let oauthToken;
313423
- let minimaxBaseUrl;
313424
- let minimaxApiKey;
313425
- if (provider === "minimax") {
313426
- minimaxBaseUrl = process.env.MINIMAX_ANTHROPIC_BASE_URL;
313427
- minimaxApiKey = process.env.MINIMAX_API_KEY;
313428
- if (!minimaxBaseUrl || !minimaxApiKey) {
313429
- reject(new ClaudeSpawnError("Claude Code (MiniMax) engine selected but MINIMAX_ANTHROPIC_BASE_URL and/or MINIMAX_API_KEY are not set. Set both as Railway env vars on the runner service.", -1, "", "", true));
313430
- return;
313431
- }
313432
- } else {
313433
- oauthToken = process.env.CLAUDE_CODE_OAUTH_TOKEN;
313434
- if (!oauthToken) {
313435
- reject(new ClaudeSpawnError("Claude Code engine selected but CLAUDE_CODE_OAUTH_TOKEN is not set. Set it as a Railway env var on the runner service.", -1, "", "", true));
313436
- return;
313437
- }
313423
+ const oauthToken = process.env.CLAUDE_CODE_OAUTH_TOKEN;
313424
+ if (!oauthToken) {
313425
+ reject(new ClaudeSpawnError("Claude Code engine selected but CLAUDE_CODE_OAUTH_TOKEN is not set. Set it as a Railway env var on the runner service.", -1, "", "", true));
313426
+ return;
313438
313427
  }
313439
313428
  const args = [
313440
313429
  "-p",
@@ -313456,8 +313445,8 @@ var require_claude_cli = __commonJS({
313456
313445
  // Stateless container — don't write session transcripts to disk.
313457
313446
  "--no-session-persistence"
313458
313447
  ];
313459
- if (provider === "minimax") {
313460
- args.push("--bare");
313448
+ if (effort && effort.trim().length > 0) {
313449
+ args.push("--effort", effort.trim());
313461
313450
  }
313462
313451
  if (typeof maxTurns === "number" && maxTurns > 0) {
313463
313452
  args.push("--max-turns", String(maxTurns));
@@ -313482,21 +313471,9 @@ var require_claude_cli = __commonJS({
313482
313471
  MCP_TIMEOUT: process.env.MCP_TIMEOUT ?? "120000"
313483
313472
  }
313484
313473
  });
313485
- if (provider === "minimax") {
313486
- spawnEnv.ANTHROPIC_BASE_URL = minimaxBaseUrl;
313487
- spawnEnv.ANTHROPIC_API_KEY = minimaxApiKey;
313488
- spawnEnv.ANTHROPIC_AUTH_TOKEN = minimaxApiKey;
313489
- delete spawnEnv.CLAUDE_CODE_OAUTH_TOKEN;
313490
- delete spawnEnv.ANTHROPIC_MODEL;
313491
- delete spawnEnv.ANTHROPIC_DEFAULT_SONNET_MODEL;
313492
- delete spawnEnv.ANTHROPIC_DEFAULT_OPUS_MODEL;
313493
- delete spawnEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL;
313494
- delete spawnEnv.ANTHROPIC_SMALL_FAST_MODEL;
313495
- } else {
313496
- spawnEnv.CLAUDE_CODE_OAUTH_TOKEN = oauthToken;
313497
- delete spawnEnv.ANTHROPIC_API_KEY;
313498
- delete spawnEnv.ANTHROPIC_AUTH_TOKEN;
313499
- }
313474
+ spawnEnv.CLAUDE_CODE_OAUTH_TOKEN = oauthToken;
313475
+ delete spawnEnv.ANTHROPIC_API_KEY;
313476
+ delete spawnEnv.ANTHROPIC_AUTH_TOKEN;
313500
313477
  const isWindows = process.platform === "win32";
313501
313478
  const proc = (0, node_child_process_1.spawn)("claude", args, {
313502
313479
  env: spawnEnv,
@@ -313608,7 +313585,7 @@ var require_claude_cli = __commonJS({
313608
313585
  }
313609
313586
  if (exitCode !== 0) {
313610
313587
  const authFailure = looksLikeAuthFailure(stdout + "\n" + stderr);
313611
- const msg = authFailure ? provider === "minimax" ? "claude --bare session failed to authenticate against MiniMax \u2014 MINIMAX_API_KEY is missing, expired, or rejected by MINIMAX_ANTHROPIC_BASE_URL. Verify both env vars on the runner service." : "claude session failed to authenticate \u2014 CLAUDE_CODE_OAUTH_TOKEN is missing, expired, or invalid. Regenerate it with `claude setup-token` and update the Railway env var on the runner service." : `claude exited with code ${exitCode}${signal ? ` (signal=${signal})` : ""}`;
313588
+ const msg = authFailure ? "claude session failed to authenticate \u2014 CLAUDE_CODE_OAUTH_TOKEN is missing, expired, or invalid. Regenerate it with `claude setup-token` and update the Railway env var on the runner service." : `claude exited with code ${exitCode}${signal ? ` (signal=${signal})` : ""}`;
313612
313589
  reject(new ClaudeSpawnError(msg, exitCode, stderr.trim(), stdout.trim(), authFailure));
313613
313590
  return;
313614
313591
  }
@@ -313621,39 +313598,8 @@ var require_claude_cli = __commonJS({
313621
313598
  });
313622
313599
  });
313623
313600
  }
313624
- function minimaxClaudeFallbackModels(requested) {
313625
- const chain = agentic_cli_constants_js_1.CLAUDE_CODE_MINIMAX_FALLBACK_CHAIN;
313626
- const idx = chain.indexOf(requested);
313627
- if (idx === -1)
313628
- return [requested];
313629
- return chain.slice(idx);
313630
- }
313631
313601
  async function runClaude(options) {
313632
- if (options.provider !== "minimax")
313633
- return runClaudeOnce(options);
313634
- const requested = options.model ?? agentic_cli_constants_js_1.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL;
313635
- const chain = minimaxClaudeFallbackModels(requested);
313636
- if (chain.length <= 1)
313637
- return runClaudeOnce({ ...options, model: requested });
313638
- let lastError;
313639
- for (let i = 0; i < chain.length; i++) {
313640
- const model = chain[i];
313641
- const isLast = i === chain.length - 1;
313642
- try {
313643
- const result = await runClaudeOnce({ ...options, model });
313644
- if (i > 0)
313645
- console.warn(`[claude-cli] MiniMax CLI failover succeeded on ${model} (requested ${requested})`);
313646
- return result;
313647
- } catch (err) {
313648
- lastError = err;
313649
- const spawnErr = err instanceof ClaudeSpawnError ? err : null;
313650
- if (isLast || spawnErr?.isAuthError || spawnErr?.isTimeout)
313651
- throw err;
313652
- const reason = err instanceof Error ? err.message : String(err);
313653
- console.warn(`[claude-cli] MiniMax CLI ${model} failed (${reason}) \u2014 failing over to ${chain[i + 1]}`);
313654
- }
313655
- }
313656
- throw lastError;
313602
+ return runClaudeOnce(options);
313657
313603
  }
313658
313604
  }
313659
313605
  });
@@ -314038,6 +313984,8 @@ var require_claude_pricing = __commonJS({
314038
313984
  Object.defineProperty(exports2, "__esModule", { value: true });
314039
313985
  exports2.computeClaudeCostUsd = computeClaudeCostUsd;
314040
313986
  var CLAUDE_PRICE_PER_M = {
313987
+ // Introductory pricing through 2026-08-31 ($2/$10); standard is $3/$15.
313988
+ "claude-sonnet-5": { input: 2, output: 10 },
314041
313989
  "claude-sonnet-4-6": { input: 3, output: 15 },
314042
313990
  "claude-haiku-4-5-20251001": { input: 1, output: 5 },
314043
313991
  "claude-opus-4-7": { input: 5, output: 25 }
@@ -314077,7 +314025,7 @@ var require_claude_survey_runner = __commonJS({
314077
314025
  var agentic_survey_prompts_js_1 = require_agentic_survey_prompts();
314078
314026
  var MCP_CAPABILITIES = ["core", "core-navigation", "core-input", "core-tabs", "testing"];
314079
314027
  var CANVAS_MODE_EXTRA_CAPABILITIES = ["vision"];
314080
- var DEFAULT_TIMEOUT_MS = 15 * 60 * 1e3;
314028
+ var DEFAULT_TIMEOUT_MS2 = 15 * 60 * 1e3;
314081
314029
  var RETRY_TIMEOUT_MS = 5 * 60 * 1e3;
314082
314030
  async function logResultFile(path, log2) {
314083
314031
  try {
@@ -314089,10 +314037,10 @@ ${preview}`);
314089
314037
  log2("[diagnostic] result file does not exist \u2014 Claude never wrote it");
314090
314038
  }
314091
314039
  }
314092
- async function runClaudeSurveyOnRunner(ctx, options = {}, provider = "anthropic") {
314040
+ async function runClaudeSurveyOnRunner(ctx, options = {}) {
314093
314041
  const maxTurns = options.maxTurns;
314094
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
314095
- const claudeDefaultModel = provider === "minimax" ? agentic_cli_constants_js_1.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL : agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
314042
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
314043
+ const claudeDefaultModel = agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
314096
314044
  const logs2 = [];
314097
314045
  const log2 = (line) => {
314098
314046
  logs2.push(line);
@@ -314236,7 +314184,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
314236
314184
  console.log(`[claude-survey] ${line}`);
314237
314185
  };
314238
314186
  const onAudit = options.onAudit;
314239
- const claudeProviderLabel = provider === "minimax" ? "minimax" : "anthropic";
314187
+ const claudeProviderLabel = "anthropic";
314240
314188
  const claudeModelLabel = claudeDefaultModel;
314241
314189
  const surveyExploreCallType = "surveyExplore";
314242
314190
  const sessionStartedAt = Date.now();
@@ -314272,7 +314220,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
314272
314220
  groupId: auditGroupId,
314273
314221
  callType: surveyExploreCallType,
314274
314222
  model: claudeModelLabel,
314275
- provider: claudeProviderLabel,
314223
+ provider: "anthropic",
314276
314224
  durationMs: turn.durationMs ?? 0,
314277
314225
  promptTokens,
314278
314226
  completionTokens,
@@ -314315,7 +314263,6 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
314315
314263
  const result = await (0, claude_cli_js_1.runClaude)({
314316
314264
  prompt: kickoffPrompt,
314317
314265
  model: claudeDefaultModel,
314318
- provider,
314319
314266
  maxTurns,
314320
314267
  timeoutMs,
314321
314268
  cwd: runDir,
@@ -314375,7 +314322,6 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
314375
314322
  const retryResult = await (0, claude_cli_js_1.runClaude)({
314376
314323
  prompt: fixPrompt,
314377
314324
  model: claudeDefaultModel,
314378
- provider,
314379
314325
  timeoutMs: RETRY_TIMEOUT_MS,
314380
314326
  cwd: runDir,
314381
314327
  mcpConfigPath,
@@ -314431,7 +314377,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
314431
314377
  groupId: auditGroupId,
314432
314378
  callType: surveyExploreCallType,
314433
314379
  model: claudeModelLabel,
314434
- provider: claudeProviderLabel,
314380
+ provider: "anthropic",
314435
314381
  durationMs: sessionDurationMs,
314436
314382
  promptTokens: sessionInputTokens,
314437
314383
  completionTokens: sessionOutputTokens,
@@ -314807,11 +314753,11 @@ var require_claude_discovery_adapter = __commonJS({
314807
314753
  var PER_TEST_IDLE_KILL_MS = 10 * 60 * 1e3;
314808
314754
  var PER_TEST_MAX_TURNS = 120;
314809
314755
  function createClaudeDiscoveryAdapter(args) {
314810
- const { provider, claudeDefaultModel } = args;
314756
+ const { claudeDefaultModel } = args;
314811
314757
  return {
314812
- engine: provider === "minimax" ? "claude-code-minimax" : "claude-code",
314758
+ engine: "claude-code",
314813
314759
  auditModel: claudeDefaultModel,
314814
- auditProvider: provider,
314760
+ auditProvider: "anthropic",
314815
314761
  computeSessionCostUsd(usage) {
314816
314762
  return (0, claude_pricing_js_1.computeClaudeCostUsd)(claudeDefaultModel, {
314817
314763
  inputTokens: usage.inputTokens,
@@ -314852,7 +314798,7 @@ var require_claude_discovery_adapter = __commonJS({
314852
314798
  prompt,
314853
314799
  appendSystemPrompt,
314854
314800
  model: claudeDefaultModel,
314855
- provider,
314801
+ provider: "anthropic",
314856
314802
  maxTurns: PER_TEST_MAX_TURNS,
314857
314803
  // A per-test session needs only browser MCP + the file tools — never a
314858
314804
  // shell. Disallow Bash to shrink the off-task surface (and Task, the
@@ -314924,17 +314870,17 @@ var require_claude_discovery_runner = __commonJS({
314924
314870
  ];
314925
314871
  var CALL1_TIMEOUT_MS = 38 * 60 * 1e3;
314926
314872
  var DISCOVERY_IDLE_KILL_MS = 15 * 60 * 1e3;
314927
- var DEFAULT_TIMEOUT_MS = 20 * 60 * 1e3;
314873
+ var DEFAULT_TIMEOUT_MS2 = 20 * 60 * 1e3;
314928
314874
  var DEFAULT_TARGET = { min: 6, max: 15 };
314929
- async function runClaudeDiscoveryOnRunner(ctx, callbackOptions, options = {}, provider = "anthropic") {
314930
- const claudeDefaultModel = provider === "minimax" ? agentic_cli_constants_js_1.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL : agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
314931
- const claudeProviderLabel = provider === "minimax" ? "minimax" : "anthropic";
314875
+ async function runClaudeDiscoveryOnRunner(ctx, callbackOptions, options = {}) {
314876
+ const claudeDefaultModel = agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
314877
+ const claudeProviderLabel = "anthropic";
314932
314878
  const featureName = ctx.featureName ?? "Untitled Feature";
314933
314879
  const manifestShape = (0, grok_discovery_runner_js_1.narrowManifest)(ctx.featureContextManifest);
314934
314880
  const manifestFeatureRoutes = Array.isArray(manifestShape?.feature?.pages) ? manifestShape.feature.pages.filter((r) => typeof r === "string" && r.length > 0) : [];
314935
314881
  const featureRoutes = manifestFeatureRoutes.length > 0 ? manifestFeatureRoutes : ctx.featureContext?.pageIntel?.map((p) => p.route) ?? ctx.focusAreas ?? [];
314936
314882
  const targetTestCount = options.targetTestCount ?? DEFAULT_TARGET;
314937
- const callerTimeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
314883
+ const callerTimeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
314938
314884
  const call1TimeoutMs = Math.max(callerTimeoutMs, CALL1_TIMEOUT_MS);
314939
314885
  const logs2 = [];
314940
314886
  const log2 = (line) => {
@@ -315181,7 +315127,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
315181
315127
  groupId: ctx.sessionId ?? featureName,
315182
315128
  callType: featureExploreCallType,
315183
315129
  model: claudeModelLabel,
315184
- provider: claudeProviderLabel,
315130
+ provider: "anthropic",
315185
315131
  durationMs: turn.durationMs ?? 0,
315186
315132
  promptTokens,
315187
315133
  completionTokens,
@@ -315292,7 +315238,6 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
315292
315238
  // they actually get put there.
315293
315239
  appendSystemPrompt: canvasMode ? (0, agentic_discovery_prompts_js_1.buildAuthoringRules)() + (0, canvas_detector_js_1.buildCanvasModeAuthoringAddendum)() : (0, agentic_discovery_prompts_js_1.buildAuthoringRules)(),
315294
315240
  model: claudeDefaultModel,
315295
- provider,
315296
315241
  timeoutMs: call1TimeoutMs,
315297
315242
  idleKillMs: DISCOVERY_IDLE_KILL_MS,
315298
315243
  cwd: runDir,
@@ -315402,7 +315347,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
315402
315347
  groupId: ctx.sessionId ?? featureName,
315403
315348
  callType: featureExploreCallType,
315404
315349
  model: claudeModelLabel,
315405
- provider: claudeProviderLabel,
315350
+ provider: "anthropic",
315406
315351
  durationMs: sessionDurationMs,
315407
315352
  promptTokens: sessionInputTokens,
315408
315353
  completionTokens: sessionOutputTokens,
@@ -315494,7 +315439,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
315494
315439
  },
315495
315440
  onAudit,
315496
315441
  auditGroupId: ctx.sessionId ?? featureName,
315497
- adapter: (0, claude_discovery_adapter_js_1.createClaudeDiscoveryAdapter)({ provider, claudeDefaultModel })
315442
+ adapter: (0, claude_discovery_adapter_js_1.createClaudeDiscoveryAdapter)({ claudeDefaultModel })
315498
315443
  });
315499
315444
  log2(`Verify + Call 2: complete \u2014 ${capturedTests.length} test(s) saved, ${localUnverified.length} unverified`);
315500
315445
  }
@@ -316420,7 +316365,7 @@ var require_discover_agent = __commonJS({
316420
316365
  } else if (cached === "standard") {
316421
316366
  return { renderType: "standard", canvasMode: false, probeRan: false };
316422
316367
  } else {
316423
- const bailEligible = engine === "native" || engine === "claude-code-minimax";
316368
+ const bailEligible = engine === "native";
316424
316369
  const cannotConfirm = (reason) => {
316425
316370
  const note = bailEligible ? ` \u26A0 engine=${engine} would have bailed on canvas \u2014 if discovery loops, set Settings \u2192 App renderer manually.` : "";
316426
316371
  log2(`[canvas] preflight could not run: ${reason} \u2014 proceeding as standard.${note}`);
@@ -316739,7 +316684,7 @@ Respond with ONLY valid JSON:
316739
316684
  // wiring is in place when it does.
316740
316685
  onAudit: onAICall
316741
316686
  };
316742
- const cliResult = surveyEngine === "claude-code-minimax" ? await (0, claude_survey_runner_js_1.runClaudeSurveyOnRunner)(ctx, surveyOpts, "minimax") : surveyEngine === "claude-code" ? await (0, claude_survey_runner_js_1.runClaudeSurveyOnRunner)(ctx, surveyOpts, "anthropic") : await (0, grok_survey_runner_js_1.runGrokSurveyOnRunner)(ctx, surveyOpts);
316687
+ const cliResult = surveyEngine === "claude-code" ? await (0, claude_survey_runner_js_1.runClaudeSurveyOnRunner)(ctx, surveyOpts) : await (0, grok_survey_runner_js_1.runGrokSurveyOnRunner)(ctx, surveyOpts);
316743
316688
  logs2.push(`${surveyEngine} survey runner finished cleanly.`);
316744
316689
  onLog?.("done", logs2.join("\n"));
316745
316690
  return {
@@ -317261,7 +317206,7 @@ Fatal error: ${msg}`);
317261
317206
  // through the existing DiscoveryAuditCallback (→ aiAuditBatch).
317262
317207
  onAudit: onAICall
317263
317208
  };
317264
- const cliResult = deepEngine === "claude-code-minimax" ? await (0, claude_discovery_runner_js_1.runClaudeDiscoveryOnRunner)(ctx, deepCallbacks, deepOpts, "minimax") : deepEngine === "claude-code" ? await (0, claude_discovery_runner_js_1.runClaudeDiscoveryOnRunner)(ctx, deepCallbacks, deepOpts, "anthropic") : await (0, grok_discovery_runner_js_1.runGrokDiscoveryOnRunner)(ctx, deepCallbacks, deepOpts);
317209
+ const cliResult = deepEngine === "claude-code" ? await (0, claude_discovery_runner_js_1.runClaudeDiscoveryOnRunner)(ctx, deepCallbacks, deepOpts) : await (0, grok_discovery_runner_js_1.runGrokDiscoveryOnRunner)(ctx, deepCallbacks, deepOpts);
317265
317210
  logs2.push(`${deepEngine} deep discovery finished cleanly. ${cliResult.testsEmitted} tests emitted, ${cliResult.unverified.length} unverified.`);
317266
317211
  onLog?.("done", logs2.join("\n"));
317267
317212
  return {
@@ -328141,9 +328086,8 @@ var require_framework_import_runner = __commonJS({
328141
328086
  const imp = ctx.frameworkImport;
328142
328087
  if (!imp)
328143
328088
  throw new Error("runFrameworkImportOnRunner: ctx.frameworkImport is required");
328144
- const engine = (0, agentic_cli_constants_js_1.getAgenticEngine)(ctx.exploreModel);
328145
- const provider = engine === "claude-code-minimax" ? "minimax" : "anthropic";
328146
- const model = provider === "minimax" ? agentic_cli_constants_js_1.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL : agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
328089
+ const provider = "anthropic";
328090
+ const model = agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
328147
328091
  log2("=== Framework Import Runner (Claude CLI, no browser) ===");
328148
328092
  log2(`Source: ${imp.source}${imp.source === "github" ? ` (${imp.repoOwner}/${imp.repoName}@${imp.branch ?? "default"})` : ""}`);
328149
328093
  const runDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "framework-import-"));
@@ -329273,8 +329217,8 @@ var require_repo_analysis_runner = __commonJS({
329273
329217
  const maxEndpointsPerFeature = intEnv("REPO_ANALYSIS_MAX_ENDPOINTS_PER_FEATURE", 80, 1, 400);
329274
329218
  const maxFacts = intEnv("REPO_ANALYSIS_MAX_FACTS", 40, 1, 120);
329275
329219
  const engine = (0, agentic_cli_constants_js_1.getAgenticEngine)(ctx.exploreModel);
329276
- const provider = engine === "claude-code-minimax" ? "minimax" : "anthropic";
329277
- const model = provider === "minimax" ? agentic_cli_constants_js_1.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL : agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
329220
+ const provider = "anthropic";
329221
+ const model = agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
329278
329222
  log2("=== Repo Analysis Runner (Claude CLI, no browser) ===");
329279
329223
  log2(`Source: ${imp.source}${imp.source === "github" ? ` (${imp.repoOwner}/${imp.repoName}@${imp.branch ?? "default"})` : ""}`);
329280
329224
  const runDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "repo-analysis-"));
@@ -329757,7 +329701,7 @@ var require_process_inventory = __commonJS({
329757
329701
  var node_util_1 = require("util");
329758
329702
  var execFileAsync3 = (0, node_util_1.promisify)(node_child_process_1.execFile);
329759
329703
  var DEFAULT_LIMIT = 60;
329760
- var DEFAULT_TIMEOUT_MS = 800;
329704
+ var DEFAULT_TIMEOUT_MS2 = 800;
329761
329705
  var MAX_COMMAND_LENGTH = 320;
329762
329706
  function roundOne(value) {
329763
329707
  return Math.round(value * 10) / 10;
@@ -329906,7 +329850,7 @@ var require_process_inventory = __commonJS({
329906
329850
  }
329907
329851
  async function getBrowserProcessInventory2(options = {}) {
329908
329852
  const limit = Math.max(1, Math.min(200, options.limit ?? DEFAULT_LIMIT));
329909
- const timeoutMs = Math.max(100, Math.min(5e3, options.timeoutMs ?? DEFAULT_TIMEOUT_MS));
329853
+ const timeoutMs = Math.max(100, Math.min(5e3, options.timeoutMs ?? DEFAULT_TIMEOUT_MS2));
329910
329854
  try {
329911
329855
  const rawProcesses = process.platform === "win32" ? await collectWindowsProcesses(timeoutMs) : await collectUnixProcesses(timeoutMs);
329912
329856
  const processes = [...rawProcesses].sort((a, b) => (b.cpuPct ?? 0) - (a.cpuPct ?? 0) || (b.rssMB ?? 0) - (a.rssMB ?? 0)).slice(0, limit);
@@ -330873,7 +330817,7 @@ var require_package4 = __commonJS({
330873
330817
  "package.json"(exports2, module2) {
330874
330818
  module2.exports = {
330875
330819
  name: "@validate.qa/runner",
330876
- version: "1.0.34",
330820
+ version: "1.0.35",
330877
330821
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
330878
330822
  bin: {
330879
330823
  "validate-runner": "dist/cli.js"
@@ -330881,6 +330825,7 @@ var require_package4 = __commonJS({
330881
330825
  scripts: {
330882
330826
  build: "tsup",
330883
330827
  dev: "tsx src/cli.ts",
330828
+ test: "node --import tsx --test src/version-check.test.ts",
330884
330829
  "test:mobile": "node --import tsx --test src/runner.mobile-ai-env.test.ts src/services/mobile/mobile-network-capture.smoke.test.ts src/services/mobile/mobile-host-proxy.test.ts",
330885
330830
  prepublishOnly: "npm run build"
330886
330831
  },
@@ -331009,6 +330954,136 @@ function shouldUseAuthState(tags, playwrightCode) {
331009
330954
  return !tags.includes(INLINE_LOGIN_TAG) && !hasLegacyInlineLogin;
331010
330955
  }
331011
330956
 
330957
+ // src/version-check.ts
330958
+ var RUNNER_NPM_PACKAGE = "@validate.qa/runner";
330959
+ var NPM_LATEST_URL = `https://registry.npmjs.org/${encodeURIComponent(RUNNER_NPM_PACKAGE)}/latest`;
330960
+ var DEFAULT_TIMEOUT_MS = 8e3;
330961
+ function parseSemver(raw) {
330962
+ const cleaned = raw.trim().replace(/^v/i, "");
330963
+ const match = cleaned.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
330964
+ if (!match) return null;
330965
+ return {
330966
+ major: Number(match[1]),
330967
+ minor: Number(match[2]),
330968
+ patch: Number(match[3]),
330969
+ prerelease: match[4] ?? null
330970
+ };
330971
+ }
330972
+ function compareSemver(a, b) {
330973
+ const pa = parseSemver(a);
330974
+ const pb = parseSemver(b);
330975
+ if (!pa || !pb) return null;
330976
+ if (pa.major !== pb.major) return pa.major < pb.major ? -1 : 1;
330977
+ if (pa.minor !== pb.minor) return pa.minor < pb.minor ? -1 : 1;
330978
+ if (pa.patch !== pb.patch) return pa.patch < pb.patch ? -1 : 1;
330979
+ if (pa.prerelease === pb.prerelease) return 0;
330980
+ if (pa.prerelease === null) return 1;
330981
+ if (pb.prerelease === null) return -1;
330982
+ return pa.prerelease < pb.prerelease ? -1 : pa.prerelease > pb.prerelease ? 1 : 0;
330983
+ }
330984
+ function isVersionOutdated(current, latest) {
330985
+ const cmp = compareSemver(current, latest);
330986
+ return cmp === -1;
330987
+ }
330988
+ function shouldSkipVersionCheck() {
330989
+ if (process.env.RUNNER_CLOUD === "true") {
330990
+ return "cloud runner (RUNNER_CLOUD=true)";
330991
+ }
330992
+ if (process.env.VALIDATE_RUNNER_ALLOW_OUTDATED === "1" || process.env.VALIDATE_RUNNER_ALLOW_OUTDATED === "true") {
330993
+ return "VALIDATE_RUNNER_ALLOW_OUTDATED is set";
330994
+ }
330995
+ return null;
330996
+ }
330997
+ async function fetchLatestRunnerVersion(timeoutMs = DEFAULT_TIMEOUT_MS, fetchImpl = fetch) {
330998
+ const controller = new AbortController();
330999
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
331000
+ try {
331001
+ const res = await fetchImpl(NPM_LATEST_URL, {
331002
+ headers: {
331003
+ Accept: "application/json",
331004
+ // Identify ourselves; helps npm operators + caching intermediaries.
331005
+ "User-Agent": `${RUNNER_NPM_PACKAGE}-version-check`
331006
+ },
331007
+ signal: controller.signal
331008
+ });
331009
+ if (!res.ok) return null;
331010
+ const body = await res.json();
331011
+ return typeof body.version === "string" && body.version.length > 0 ? body.version : null;
331012
+ } catch {
331013
+ return null;
331014
+ } finally {
331015
+ clearTimeout(timer);
331016
+ }
331017
+ }
331018
+ async function checkRunnerVersion(currentVersion, opts = {}) {
331019
+ const skip = shouldSkipVersionCheck();
331020
+ if (skip) {
331021
+ return { outdated: false, currentVersion, latestVersion: null, skippedReason: skip };
331022
+ }
331023
+ const latestVersion = await fetchLatestRunnerVersion(opts.timeoutMs, opts.fetchImpl);
331024
+ if (!latestVersion) {
331025
+ return {
331026
+ outdated: false,
331027
+ currentVersion,
331028
+ latestVersion: null,
331029
+ skippedReason: "could not reach npm registry (or response was invalid)"
331030
+ };
331031
+ }
331032
+ if (!parseSemver(currentVersion) || !parseSemver(latestVersion)) {
331033
+ return {
331034
+ outdated: false,
331035
+ currentVersion,
331036
+ latestVersion,
331037
+ skippedReason: "unparseable version string"
331038
+ };
331039
+ }
331040
+ return {
331041
+ outdated: isVersionOutdated(currentVersion, latestVersion),
331042
+ currentVersion,
331043
+ latestVersion
331044
+ };
331045
+ }
331046
+ function formatUpgradeInstructions(latestVersion) {
331047
+ const lines = [
331048
+ "",
331049
+ "\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557",
331050
+ "\u2551 VALIDATE.QA RUNNER UPDATE REQUIRED \u2551",
331051
+ "\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563",
331052
+ "\u2551 A newer runner is published on npm. Each runner release changes \u2551",
331053
+ "\u2551 the workflow, so this version can no longer run. \u2551",
331054
+ `\u2551 Latest: ${latestVersion.padEnd(54)}\u2551`,
331055
+ "\u2551 \u2551",
331056
+ "\u2551 Upgrade with: \u2551",
331057
+ `\u2551 npm install -g ${RUNNER_NPM_PACKAGE}@latest`.padEnd(69) + "\u2551",
331058
+ "\u2551 \u2551",
331059
+ "\u2551 Then restart: \u2551",
331060
+ "\u2551 validate-runner start \u2551",
331061
+ "\u2551 # or: npx @validate.qa/runner@latest start \u2551",
331062
+ "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D",
331063
+ ""
331064
+ ];
331065
+ return lines.join("\n");
331066
+ }
331067
+ async function enforceRunnerUpToDate(currentVersion, opts = {}) {
331068
+ const log2 = opts.log ?? ((msg) => console.error(msg));
331069
+ const result = await checkRunnerVersion(currentVersion, opts);
331070
+ if (result.skippedReason && !result.outdated) {
331071
+ if (result.skippedReason.startsWith("could not reach") || result.skippedReason.startsWith("unparseable")) {
331072
+ log2(`\u26A0 Runner version check skipped: ${result.skippedReason}`);
331073
+ }
331074
+ return result;
331075
+ }
331076
+ if (result.outdated && result.latestVersion) {
331077
+ log2(formatUpgradeInstructions(result.latestVersion));
331078
+ log2(` Installed: ${result.currentVersion}`);
331079
+ log2(` Required: ${result.latestVersion} (or newer)`);
331080
+ log2("");
331081
+ const exit = opts.exitFn ?? ((code) => process.exit(code));
331082
+ exit(1);
331083
+ }
331084
+ return result;
331085
+ }
331086
+
331012
331087
  // src/services/appium-executor.ts
331013
331088
  init_dist();
331014
331089
 
@@ -336042,13 +336117,31 @@ function buildHeaders(authToken, projectId) {
336042
336117
  return {
336043
336118
  "Content-Type": "application/json",
336044
336119
  Authorization: `Bearer ${authToken}`,
336045
- "X-Project-Id": projectId
336120
+ "X-Project-Id": projectId,
336121
+ // Lets the server force-upgrade outdated local installs on /pending too
336122
+ // (not only heartbeat), so they cannot claim work after a new npm publish.
336123
+ "X-Runner-Version": RUNNER_VERSION,
336124
+ "X-Runner-Name": RUNNER_NAME
336046
336125
  };
336047
336126
  }
336127
+ var RunnerUpgradeRequiredError = class extends Error {
336128
+ latestVersion;
336129
+ constructor(message, latestVersion) {
336130
+ super(message);
336131
+ this.name = "RunnerUpgradeRequiredError";
336132
+ this.latestVersion = latestVersion;
336133
+ }
336134
+ };
336048
336135
  async function fetchPendingRuns(serverUrl, headers) {
336049
336136
  const res = await fetch(`${serverUrl}/api/runner/pending`, { headers, signal: AbortSignal.timeout(3e4) });
336050
336137
  if (!res.ok) {
336051
336138
  if (res.status === 401) throw new Error("Runner token is invalid or expired. Run: validate.qa-runner login");
336139
+ if (res.status === 426) {
336140
+ const body = await res.json().catch(() => null);
336141
+ const latest = typeof body?.latestRunnerVersion === "string" ? body.latestRunnerVersion : null;
336142
+ const msg = typeof body?.error === "string" ? body.error : "A newer @validate.qa/runner is required. Run: npm install -g @validate.qa/runner@latest";
336143
+ throw new RunnerUpgradeRequiredError(msg, latest);
336144
+ }
336052
336145
  if (res.status === 429) {
336053
336146
  const retryAfter = res.headers.get("Retry-After");
336054
336147
  const waitSecs = retryAfter ? parseInt(retryAfter, 10) : 60;
@@ -338561,10 +338654,34 @@ async function startRunner(opts) {
338561
338654
  }
338562
338655
  console.log("");
338563
338656
  log.ok(`Runner started - waiting for test runs...${enableMobile ? " (web + mobile)" : ""}`);
338657
+ log.info(`Version: ${RUNNER_VERSION}`);
338564
338658
  log.dim("Press Ctrl+C to stop");
338565
338659
  console.log("");
338566
338660
  let runsCompleted = 0;
338567
338661
  let activeRuns = 0;
338662
+ const VERSION_RECHECK_MS = Math.max(
338663
+ 6e4,
338664
+ envInt("VALIDATE_RUNNER_VERSION_CHECK_MS", 15 * 6e4)
338665
+ );
338666
+ const exitForUpgrade = (latestVersion, installed) => {
338667
+ console.error(formatUpgradeInstructions(latestVersion));
338668
+ console.error(` Installed: ${installed}`);
338669
+ console.error(` Required: ${latestVersion} (or newer)`);
338670
+ console.error("");
338671
+ process.exit(1);
338672
+ };
338673
+ const recheckRunnerVersion = async () => {
338674
+ if (activeRuns > 0) return;
338675
+ const result = await checkRunnerVersion(RUNNER_VERSION);
338676
+ if (result.outdated && result.latestVersion) {
338677
+ log.warn("A newer runner was published on npm \u2014 shutting down so you can upgrade.");
338678
+ exitForUpgrade(result.latestVersion, RUNNER_VERSION);
338679
+ }
338680
+ };
338681
+ const versionRecheckTimer = setInterval(() => {
338682
+ void recheckRunnerVersion();
338683
+ }, VERSION_RECHECK_MS);
338684
+ versionRecheckTimer.unref?.();
338568
338685
  const MAX_CONCURRENT = Math.max(1, envInt("MAX_CONCURRENT", DEFAULT_MAX_CONCURRENT));
338569
338686
  const MAX_PROJECT_CONCURRENT = Math.max(1, envInt("MAX_PROJECT_CONCURRENT", DEFAULT_MAX_PROJECT_CONCURRENT));
338570
338687
  const TYPE_LIMITS = {
@@ -338790,6 +338907,22 @@ async function startRunner(opts) {
338790
338907
  if (body && Array.isArray(body.commands) && body.commands.length > 0) {
338791
338908
  void handleControlCommands(body.commands);
338792
338909
  }
338910
+ if (body && body.forceUpgrade === true && typeof body.latestRunnerVersion === "string" && isVersionOutdated(RUNNER_VERSION, body.latestRunnerVersion) && activeRuns === 0) {
338911
+ log.warn(
338912
+ typeof body.upgradeMessage === "string" && body.upgradeMessage ? body.upgradeMessage : "Server requires a newer runner version \u2014 shutting down."
338913
+ );
338914
+ exitForUpgrade(body.latestRunnerVersion, RUNNER_VERSION);
338915
+ }
338916
+ } else if (response.status === 426) {
338917
+ const body = await response.json().catch(() => null);
338918
+ const latest = typeof body?.latestRunnerVersion === "string" ? body.latestRunnerVersion : null;
338919
+ if (latest) {
338920
+ exitForUpgrade(latest, RUNNER_VERSION);
338921
+ }
338922
+ log.warn(
338923
+ typeof body?.error === "string" ? body.error : "Server rejected this runner version (HTTP 426). Upgrade @validate.qa/runner."
338924
+ );
338925
+ process.exit(1);
338793
338926
  }
338794
338927
  } catch {
338795
338928
  }
@@ -339030,6 +339163,10 @@ async function startRunner(opts) {
339030
339163
  consecutivePollErrors = 0;
339031
339164
  }
339032
339165
  } catch (err) {
339166
+ if (err instanceof RunnerUpgradeRequiredError) {
339167
+ log.warn(err.message);
339168
+ exitForUpgrade(err.latestVersion ?? "latest", RUNNER_VERSION);
339169
+ }
339033
339170
  const message = err instanceof Error ? err.message : String(err);
339034
339171
  consecutivePollErrors++;
339035
339172
  const backoffMs = Math.min(pollIntervalMs * Math.pow(2, consecutivePollErrors - 1), MAX_BACKOFF_MS);
@@ -339049,7 +339186,11 @@ async function startRunner(opts) {
339049
339186
  var pkg = require_package4();
339050
339187
  var program = new import_commander.Command();
339051
339188
  program.name("validate-runner").description("validate.qa local test runner - execute Playwright and Appium tests on your machine").version(pkg.version);
339189
+ async function requireLatestRunner() {
339190
+ await enforceRunnerUpToDate(pkg.version);
339191
+ }
339052
339192
  program.command("login").description("Save runner credentials for future use").requiredOption("--token <token>", "Runner token (urt_... from validate.qa dashboard)").requiredOption("--server <url>", "validate.qa server URL").option("--project <id>", "Project ID (from dashboard URL)").action(async (opts) => {
339193
+ await requireLatestRunner();
339053
339194
  const serverUrl = opts.server.replace(/\/+$/, "");
339054
339195
  if (!opts.token.startsWith("urt_") && !opts.token.startsWith("rt_") && !opts.token.startsWith("eyJ")) {
339055
339196
  console.error("\u26A0 Token should start with urt_ (from the dashboard Runner Token)");
@@ -339081,6 +339222,7 @@ program.command("login").description("Save runner credentials for future use").r
339081
339222
  console.log("Run: validate-runner start");
339082
339223
  });
339083
339224
  program.command("start").description("Start the local test runner").option("--token <token>", "Runner token (overrides saved credentials)").option("--server <url>", "Server URL (overrides saved credentials)").option("--project <id>", "Project ID (overrides saved credentials)").option("--mode <mode>", "Runner mode: playwright-native (default)", "playwright-native").option("--poll-interval <ms>", "Poll interval in milliseconds", "2000").option("--mobile", "Enable mobile testing (Appium + mobile bridge server)").option("--tunnel", "Enable ngrok tunnel for mobile bridge (allows HTTPS dashboard to connect)").action(async (opts) => {
339225
+ await requireLatestRunner();
339084
339226
  const saved = loadCredentials();
339085
339227
  const authToken = opts.token || process.env.AUTH_TOKEN || saved?.token;
339086
339228
  const serverUrl = (opts.server || process.env.SERVER_URL || saved?.serverUrl)?.replace(/\/+$/, "");
@@ -339133,6 +339275,7 @@ program.command("logout").description("Clear saved runner credentials").action((
339133
339275
  console.log("\u2713 Credentials cleared");
339134
339276
  });
339135
339277
  program.command("status").description("Check connection to validate.qa server").action(async () => {
339278
+ await requireLatestRunner();
339136
339279
  const saved = loadCredentials();
339137
339280
  if (!saved) {
339138
339281
  console.log("No saved credentials. Run: validate-runner login");