@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.
- package/README.md +24 -1
- package/dist/cli.js +306 -163
- package/dist/cli.mjs +306 -163
- package/package.json +2 -1
package/dist/cli.mjs
CHANGED
|
@@ -1354,11 +1354,13 @@ function escapeEnvValue(value) {
|
|
|
1354
1354
|
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
1355
1355
|
return `"${escaped}"`;
|
|
1356
1356
|
}
|
|
1357
|
-
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;
|
|
1357
|
+
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;
|
|
1358
1358
|
var init_constants = __esm({
|
|
1359
1359
|
"../shared/dist/constants.js"() {
|
|
1360
1360
|
"use strict";
|
|
1361
1361
|
API_PREFIX = "/api";
|
|
1362
|
+
SUPPORT_EMAIL = "support@validate.qa";
|
|
1363
|
+
PLATFORM_ADMIN_EMAIL = "admin@validate.qa";
|
|
1362
1364
|
AUDIO_CHUNK_DURATION_MS = 3e4;
|
|
1363
1365
|
ACTION_BATCH_INTERVAL_MS = 2e3;
|
|
1364
1366
|
ACTION_BATCH_MAX_SIZE = 10;
|
|
@@ -2562,6 +2564,8 @@ var init_audit_pricing = __esm({
|
|
|
2562
2564
|
// Current defaults
|
|
2563
2565
|
"grok-build-0.1": { input: 1, output: 2 },
|
|
2564
2566
|
"claude-opus-4-7": { input: 5, output: 25 },
|
|
2567
|
+
// Introductory pricing through 2026-08-31 ($2/$10); standard is $3/$15.
|
|
2568
|
+
"claude-sonnet-5": { input: 2, output: 10 },
|
|
2565
2569
|
"claude-sonnet-4-6": { input: 3, output: 15 },
|
|
2566
2570
|
"claude-haiku-4-5-20251001": { input: 1, output: 5 },
|
|
2567
2571
|
"gpt-4o": { input: 2.5, output: 10 },
|
|
@@ -3598,7 +3602,7 @@ var init_agent_env = __esm({
|
|
|
3598
3602
|
"CommonProgramFiles"
|
|
3599
3603
|
]);
|
|
3600
3604
|
ALLOW_PREFIX = [
|
|
3601
|
-
// AI provider / CLI config (grok-build, claude-code
|
|
3605
|
+
// AI provider / CLI config (grok-build, claude-code)
|
|
3602
3606
|
"GROK_",
|
|
3603
3607
|
"XAI_",
|
|
3604
3608
|
"ANTHROPIC_",
|
|
@@ -3905,8 +3909,10 @@ __export(dist_exports, {
|
|
|
3905
3909
|
MOBILE_STEP_TYPES: () => MOBILE_STEP_TYPES,
|
|
3906
3910
|
PLAN_DEFINITIONS: () => PLAN_DEFINITIONS,
|
|
3907
3911
|
PLAN_ORDER: () => PLAN_ORDER,
|
|
3912
|
+
PLATFORM_ADMIN_EMAIL: () => PLATFORM_ADMIN_EMAIL,
|
|
3908
3913
|
SELECTOR_PRIORITIES: () => SELECTOR_PRIORITIES,
|
|
3909
3914
|
SHARED_PRICING_PLAN_MAP: () => SHARED_PRICING_PLAN_MAP,
|
|
3915
|
+
SUPPORT_EMAIL: () => SUPPORT_EMAIL,
|
|
3910
3916
|
TRANSIENT_CONTROL_ROLES: () => TRANSIENT_CONTROL_ROLES,
|
|
3911
3917
|
TRIAL_DURATION_DAYS: () => TRIAL_DURATION_DAYS,
|
|
3912
3918
|
UI_VARIANTS: () => UI_VARIANTS,
|
|
@@ -298974,7 +298980,8 @@ var require_bootstrap_grok_auth = __commonJS({
|
|
|
298974
298980
|
const home = process.env.HOME ?? "/home/appuser";
|
|
298975
298981
|
const authPath = node_path_1.default.join(home, ".grok", "auth.json");
|
|
298976
298982
|
const b64 = process.env.GROK_AUTH_JSON_B64;
|
|
298977
|
-
|
|
298983
|
+
const force = process.env.GROK_AUTH_FORCE_RESEED === "true" || process.env.GROK_AUTH_FORCE_RESEED === "1";
|
|
298984
|
+
if (!force && node_fs_1.default.existsSync(authPath)) {
|
|
298978
298985
|
return;
|
|
298979
298986
|
}
|
|
298980
298987
|
if (!b64) {
|
|
@@ -298985,7 +298992,7 @@ var require_bootstrap_grok_auth = __commonJS({
|
|
|
298985
298992
|
node_fs_1.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
298986
298993
|
node_fs_1.default.writeFileSync(authPath, Buffer.from(b64, "base64"));
|
|
298987
298994
|
node_fs_1.default.chmodSync(authPath, 384);
|
|
298988
|
-
console.log(`[grok-auth][runner] Seeded ${authPath} from GROK_AUTH_JSON_B64`);
|
|
298995
|
+
console.log(force ? `[grok-auth][runner] Force-reseeded ${authPath} from GROK_AUTH_JSON_B64` : `[grok-auth][runner] Seeded ${authPath} from GROK_AUTH_JSON_B64`);
|
|
298989
298996
|
} catch (err) {
|
|
298990
298997
|
const message = err instanceof Error ? err.message : String(err);
|
|
298991
298998
|
console.warn(`[grok-auth][runner] Failed to seed auth.json: ${message}`);
|
|
@@ -299630,6 +299637,37 @@ var require_proven_actions_adapter = __commonJS({
|
|
|
299630
299637
|
}
|
|
299631
299638
|
});
|
|
299632
299639
|
|
|
299640
|
+
// ../runner-core/dist/services/agentic-cli-constants.js
|
|
299641
|
+
var require_agentic_cli_constants = __commonJS({
|
|
299642
|
+
"../runner-core/dist/services/agentic-cli-constants.js"(exports) {
|
|
299643
|
+
"use strict";
|
|
299644
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
299645
|
+
exports.GROK_CLI_DEFAULT_REASONING_EFFORT = exports.GROK_CLI_DEFAULT_MODEL = exports.CLAUDE_CODE_DEFAULT_EFFORT = exports.CLAUDE_CODE_DEFAULT_MODEL = exports.MODEL_CLAUDE_CODE = exports.MODEL_GROK_BUILD = void 0;
|
|
299646
|
+
exports.isGrokBuildModel = isGrokBuildModel;
|
|
299647
|
+
exports.isClaudeCodeModel = isClaudeCodeModel;
|
|
299648
|
+
exports.getAgenticEngine = getAgenticEngine;
|
|
299649
|
+
exports.MODEL_GROK_BUILD = "grok-build";
|
|
299650
|
+
function isGrokBuildModel(id) {
|
|
299651
|
+
return id === exports.MODEL_GROK_BUILD;
|
|
299652
|
+
}
|
|
299653
|
+
exports.MODEL_CLAUDE_CODE = "claude-code";
|
|
299654
|
+
function isClaudeCodeModel(id) {
|
|
299655
|
+
return id === exports.MODEL_CLAUDE_CODE;
|
|
299656
|
+
}
|
|
299657
|
+
function getAgenticEngine(modelId) {
|
|
299658
|
+
if (isGrokBuildModel(modelId))
|
|
299659
|
+
return "grok-build";
|
|
299660
|
+
if (isClaudeCodeModel(modelId))
|
|
299661
|
+
return "claude-code";
|
|
299662
|
+
return "native";
|
|
299663
|
+
}
|
|
299664
|
+
exports.CLAUDE_CODE_DEFAULT_MODEL = "claude-sonnet-5";
|
|
299665
|
+
exports.CLAUDE_CODE_DEFAULT_EFFORT = "max";
|
|
299666
|
+
exports.GROK_CLI_DEFAULT_MODEL = "grok-4.5";
|
|
299667
|
+
exports.GROK_CLI_DEFAULT_REASONING_EFFORT = "high";
|
|
299668
|
+
}
|
|
299669
|
+
});
|
|
299670
|
+
|
|
299633
299671
|
// ../runner-core/dist/services/grok-cli.js
|
|
299634
299672
|
var require_grok_cli = __commonJS({
|
|
299635
299673
|
"../runner-core/dist/services/grok-cli.js"(exports) {
|
|
@@ -299640,6 +299678,7 @@ var require_grok_cli = __commonJS({
|
|
|
299640
299678
|
exports.runGrok = runGrok;
|
|
299641
299679
|
var node_child_process_1 = __require("child_process");
|
|
299642
299680
|
var shared_1 = (init_dist(), __toCommonJS(dist_exports));
|
|
299681
|
+
var agentic_cli_constants_js_1 = require_agentic_cli_constants();
|
|
299643
299682
|
function extractAssistantJson(stdout) {
|
|
299644
299683
|
const tryParse = (s) => {
|
|
299645
299684
|
const trimmed = s.trim();
|
|
@@ -299734,7 +299773,8 @@ var require_grok_cli = __commonJS({
|
|
|
299734
299773
|
function runGrok(options) {
|
|
299735
299774
|
const {
|
|
299736
299775
|
prompt,
|
|
299737
|
-
model =
|
|
299776
|
+
model = agentic_cli_constants_js_1.GROK_CLI_DEFAULT_MODEL,
|
|
299777
|
+
reasoningEffort = agentic_cli_constants_js_1.GROK_CLI_DEFAULT_REASONING_EFFORT,
|
|
299738
299778
|
maxTurns,
|
|
299739
299779
|
// undefined = let grok decide when to quit
|
|
299740
299780
|
timeoutMs = 6e5,
|
|
@@ -299763,6 +299803,9 @@ var require_grok_cli = __commonJS({
|
|
|
299763
299803
|
"--always-approve",
|
|
299764
299804
|
"--no-alt-screen"
|
|
299765
299805
|
];
|
|
299806
|
+
if (reasoningEffort) {
|
|
299807
|
+
args.push("--reasoning-effort", reasoningEffort);
|
|
299808
|
+
}
|
|
299766
299809
|
if (typeof maxTurns === "number" && maxTurns > 0) {
|
|
299767
299810
|
args.push("--max-turns", String(maxTurns));
|
|
299768
299811
|
}
|
|
@@ -299908,7 +299951,7 @@ var require_grok_per_test_healer = __commonJS({
|
|
|
299908
299951
|
var HEAL_MCP_CAPABILITIES = ["core", "core-navigation", "core-input", "core-tabs", "testing"];
|
|
299909
299952
|
var grok_cli_js_1 = require_grok_cli();
|
|
299910
299953
|
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
299911
|
-
var
|
|
299954
|
+
var DEFAULT_TIMEOUT_MS2 = 30 * 60 * 1e3;
|
|
299912
299955
|
var IDLE_WATCHDOG_MS = 10 * 60 * 1e3;
|
|
299913
299956
|
function getMaxAttempts() {
|
|
299914
299957
|
const raw = process.env.GROK_PER_TEST_HEAL_MAX_ATTEMPTS;
|
|
@@ -299918,7 +299961,7 @@ var require_grok_per_test_healer = __commonJS({
|
|
|
299918
299961
|
function getAttemptTimeoutMs() {
|
|
299919
299962
|
const raw = process.env.GROK_PER_TEST_HEAL_TIMEOUT_MS;
|
|
299920
299963
|
const parsed = raw ? parseInt(raw, 10) : NaN;
|
|
299921
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed :
|
|
299964
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_TIMEOUT_MS2;
|
|
299922
299965
|
}
|
|
299923
299966
|
async function executeGrokPerTestHeal2(playwrightCode, steps, baseUrl, options = {}) {
|
|
299924
299967
|
const externalLogSink = options.onLog;
|
|
@@ -300331,7 +300374,7 @@ Output the JSON envelope exactly ONCE as your final message, then exit.`;
|
|
|
300331
300374
|
"-p",
|
|
300332
300375
|
'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"}',
|
|
300333
300376
|
"-m",
|
|
300334
|
-
"grok-
|
|
300377
|
+
"grok-4.5",
|
|
300335
300378
|
// streaming-json: per-event NDJSON so the UI's GrokSessionLog drawer can
|
|
300336
300379
|
// show progress instead of a frozen "starting…" until the final envelope.
|
|
300337
300380
|
"--output-format",
|
|
@@ -301551,7 +301594,7 @@ When done with all ${input.tests.length} tests in this chunk, exit.`;
|
|
|
301551
301594
|
"-p",
|
|
301552
301595
|
"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.",
|
|
301553
301596
|
"-m",
|
|
301554
|
-
"grok-
|
|
301597
|
+
"grok-4.5",
|
|
301555
301598
|
// streaming-json so per-token output reaches the UI for live progress.
|
|
301556
301599
|
"--output-format",
|
|
301557
301600
|
"streaming-json",
|
|
@@ -309040,47 +309083,6 @@ var require_sitemap_builder = __commonJS({
|
|
|
309040
309083
|
}
|
|
309041
309084
|
});
|
|
309042
309085
|
|
|
309043
|
-
// ../runner-core/dist/services/agentic-cli-constants.js
|
|
309044
|
-
var require_agentic_cli_constants = __commonJS({
|
|
309045
|
-
"../runner-core/dist/services/agentic-cli-constants.js"(exports) {
|
|
309046
|
-
"use strict";
|
|
309047
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
309048
|
-
exports.CLAUDE_CODE_MINIMAX_FALLBACK_CHAIN = exports.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL = exports.CLAUDE_CODE_DEFAULT_MODEL = exports.MODEL_CLAUDE_CODE_MINIMAX = exports.MODEL_CLAUDE_CODE = exports.MODEL_GROK_BUILD = void 0;
|
|
309049
|
-
exports.isGrokBuildModel = isGrokBuildModel;
|
|
309050
|
-
exports.isClaudeCodeModel = isClaudeCodeModel;
|
|
309051
|
-
exports.isClaudeCodeMinimaxModel = isClaudeCodeMinimaxModel;
|
|
309052
|
-
exports.getAgenticEngine = getAgenticEngine;
|
|
309053
|
-
exports.MODEL_GROK_BUILD = "grok-build";
|
|
309054
|
-
function isGrokBuildModel(id) {
|
|
309055
|
-
return id === exports.MODEL_GROK_BUILD;
|
|
309056
|
-
}
|
|
309057
|
-
exports.MODEL_CLAUDE_CODE = "claude-code";
|
|
309058
|
-
function isClaudeCodeModel(id) {
|
|
309059
|
-
return id === exports.MODEL_CLAUDE_CODE;
|
|
309060
|
-
}
|
|
309061
|
-
exports.MODEL_CLAUDE_CODE_MINIMAX = "claude-code-minimax";
|
|
309062
|
-
function isClaudeCodeMinimaxModel(id) {
|
|
309063
|
-
return id === exports.MODEL_CLAUDE_CODE_MINIMAX;
|
|
309064
|
-
}
|
|
309065
|
-
function getAgenticEngine(modelId) {
|
|
309066
|
-
if (isGrokBuildModel(modelId))
|
|
309067
|
-
return "grok-build";
|
|
309068
|
-
if (isClaudeCodeMinimaxModel(modelId))
|
|
309069
|
-
return "claude-code-minimax";
|
|
309070
|
-
if (isClaudeCodeModel(modelId))
|
|
309071
|
-
return "claude-code";
|
|
309072
|
-
return "native";
|
|
309073
|
-
}
|
|
309074
|
-
exports.CLAUDE_CODE_DEFAULT_MODEL = "claude-sonnet-4-6";
|
|
309075
|
-
exports.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL = "MiniMax-M3";
|
|
309076
|
-
exports.CLAUDE_CODE_MINIMAX_FALLBACK_CHAIN = [
|
|
309077
|
-
"MiniMax-M3",
|
|
309078
|
-
"MiniMax-M2.7-highspeed",
|
|
309079
|
-
"MiniMax-M2.7"
|
|
309080
|
-
];
|
|
309081
|
-
}
|
|
309082
|
-
});
|
|
309083
|
-
|
|
309084
309086
|
// ../runner-core/dist/services/auth-capture-run.js
|
|
309085
309087
|
var require_auth_capture_run = __commonJS({
|
|
309086
309088
|
"../runner-core/dist/services/auth-capture-run.js"(exports) {
|
|
@@ -309884,7 +309886,7 @@ var require_grok_survey_runner = __commonJS({
|
|
|
309884
309886
|
var scrub_credentials_js_1 = require_scrub_credentials();
|
|
309885
309887
|
var agentic_survey_prompts_js_1 = require_agentic_survey_prompts();
|
|
309886
309888
|
var MCP_CAPABILITIES = ["core", "core-navigation", "core-input", "core-tabs", "testing"];
|
|
309887
|
-
var
|
|
309889
|
+
var DEFAULT_TIMEOUT_MS2 = 15 * 60 * 1e3;
|
|
309888
309890
|
var RETRY_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
309889
309891
|
function extractCredentials(vars) {
|
|
309890
309892
|
if (!vars)
|
|
@@ -310320,7 +310322,7 @@ var require_grok_survey_runner = __commonJS({
|
|
|
310320
310322
|
}
|
|
310321
310323
|
async function runGrokSurveyOnRunner(ctx, options = {}) {
|
|
310322
310324
|
const maxTurns = options.maxTurns;
|
|
310323
|
-
const timeoutMs = options.timeoutMs ??
|
|
310325
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
310324
310326
|
const logs2 = [];
|
|
310325
310327
|
const log2 = (line) => {
|
|
310326
310328
|
logs2.push(line);
|
|
@@ -310454,7 +310456,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
310454
310456
|
try {
|
|
310455
310457
|
const result = await (0, grok_cli_js_1.runGrok)({
|
|
310456
310458
|
prompt: kickoffPrompt,
|
|
310457
|
-
model: "grok-
|
|
310459
|
+
model: "grok-4.5",
|
|
310458
310460
|
maxTurns,
|
|
310459
310461
|
timeoutMs,
|
|
310460
310462
|
homeDir: grokHomeDir,
|
|
@@ -310501,7 +310503,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
310501
310503
|
try {
|
|
310502
310504
|
const retryResult = await (0, grok_cli_js_1.runGrok)({
|
|
310503
310505
|
prompt: fixPrompt,
|
|
310504
|
-
model: "grok-
|
|
310506
|
+
model: "grok-4.5",
|
|
310505
310507
|
// Retry: also let grok decide turns; the shorter retry budget lives
|
|
310506
310508
|
// in the wall-clock timeout below.
|
|
310507
310509
|
timeoutMs: RETRY_TIMEOUT_MS,
|
|
@@ -310634,20 +310636,19 @@ var require_canvas_detector = __commonJS({
|
|
|
310634
310636
|
return { kind: "override", canvasMode: false };
|
|
310635
310637
|
if (opts.engine === "claude-code")
|
|
310636
310638
|
return { kind: "canvas-mode", canvasMode: true };
|
|
310637
|
-
if (opts.engine === "
|
|
310639
|
+
if (opts.engine === "native")
|
|
310638
310640
|
return { kind: "bail" };
|
|
310639
310641
|
return { kind: "proceed", canvasMode: false };
|
|
310640
310642
|
}
|
|
310641
310643
|
function modelSupportsVision(modelId) {
|
|
310642
310644
|
if (!modelId)
|
|
310643
310645
|
return false;
|
|
310644
|
-
if (modelId === "claude-code-minimax")
|
|
310645
|
-
return false;
|
|
310646
310646
|
if (modelId === "claude-code")
|
|
310647
310647
|
return true;
|
|
310648
310648
|
if (modelId === "grok-build")
|
|
310649
310649
|
return false;
|
|
310650
310650
|
const visionCapable = /* @__PURE__ */ new Set([
|
|
310651
|
+
"claude-sonnet-5",
|
|
310651
310652
|
"claude-sonnet-4-6",
|
|
310652
310653
|
"claude-opus-4-7",
|
|
310653
310654
|
"claude-haiku-4-5",
|
|
@@ -311824,7 +311825,7 @@ var require_grok_discovery_runner = __commonJS({
|
|
|
311824
311825
|
"core-tabs",
|
|
311825
311826
|
"testing"
|
|
311826
311827
|
];
|
|
311827
|
-
var
|
|
311828
|
+
var DEFAULT_TIMEOUT_MS2 = 20 * 60 * 1e3;
|
|
311828
311829
|
var RETRY_TIMEOUT_MS = 6 * 60 * 1e3;
|
|
311829
311830
|
var DEFAULT_TARGET = { min: 6, max: 15 };
|
|
311830
311831
|
var WATCHER_DEBOUNCE_MS = 500;
|
|
@@ -311988,7 +311989,7 @@ var require_grok_discovery_runner = __commonJS({
|
|
|
311988
311989
|
const manifestFeatureRoutes = Array.isArray(manifestShape?.feature?.pages) ? manifestShape.feature.pages.filter((r) => typeof r === "string" && r.length > 0) : [];
|
|
311989
311990
|
const featureRoutes = manifestFeatureRoutes.length > 0 ? manifestFeatureRoutes : ctx.featureContext?.pageIntel?.map((p) => p.route) ?? ctx.focusAreas ?? [];
|
|
311990
311991
|
const targetTestCount = options.targetTestCount ?? DEFAULT_TARGET;
|
|
311991
|
-
const timeoutMs = options.timeoutMs ??
|
|
311992
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
311992
311993
|
const logs2 = [];
|
|
311993
311994
|
const log2 = (line) => {
|
|
311994
311995
|
logs2.push(line);
|
|
@@ -312593,7 +312594,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
312593
312594
|
try {
|
|
312594
312595
|
const result = await (0, grok_cli_js_1.runGrok)({
|
|
312595
312596
|
prompt: kickoffPrompt,
|
|
312596
|
-
model: "grok-
|
|
312597
|
+
model: "grok-4.5",
|
|
312597
312598
|
timeoutMs,
|
|
312598
312599
|
homeDir: grokHomeDir,
|
|
312599
312600
|
cwd: runDir,
|
|
@@ -312673,7 +312674,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
312673
312674
|
try {
|
|
312674
312675
|
const retryResult = await (0, grok_cli_js_1.runGrok)({
|
|
312675
312676
|
prompt: fixPrompt,
|
|
312676
|
-
model: "grok-
|
|
312677
|
+
model: "grok-4.5",
|
|
312677
312678
|
timeoutMs: RETRY_TIMEOUT_MS,
|
|
312678
312679
|
homeDir: grokHomeDir,
|
|
312679
312680
|
cwd: runDir,
|
|
@@ -312905,7 +312906,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
312905
312906
|
const manifestFeatureRoutes = Array.isArray(manifestShape?.feature?.pages) ? manifestShape.feature.pages.filter((r) => typeof r === "string" && r.length > 0) : [];
|
|
312906
312907
|
const featureRoutes = manifestFeatureRoutes.length > 0 ? manifestFeatureRoutes : ctx.featureContext?.pageIntel?.map((p) => p.route) ?? ctx.focusAreas ?? [];
|
|
312907
312908
|
const targetTestCount = options.targetTestCount ?? DEFAULT_TARGET;
|
|
312908
|
-
const callerTimeoutMs = options.timeoutMs ??
|
|
312909
|
+
const callerTimeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
312909
312910
|
const call1TimeoutMs = Math.max(callerTimeoutMs, GROK_V2_CALL1_TIMEOUT_MS);
|
|
312910
312911
|
const logs2 = [];
|
|
312911
312912
|
const log2 = (line) => {
|
|
@@ -313422,24 +313423,12 @@ var require_claude_cli = __commonJS({
|
|
|
313422
313423
|
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);
|
|
313423
313424
|
}
|
|
313424
313425
|
function runClaudeOnce(options) {
|
|
313425
|
-
const { prompt, model =
|
|
313426
|
+
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;
|
|
313426
313427
|
return new Promise((resolve, reject) => {
|
|
313427
|
-
|
|
313428
|
-
|
|
313429
|
-
|
|
313430
|
-
|
|
313431
|
-
minimaxBaseUrl = process.env.MINIMAX_ANTHROPIC_BASE_URL;
|
|
313432
|
-
minimaxApiKey = process.env.MINIMAX_API_KEY;
|
|
313433
|
-
if (!minimaxBaseUrl || !minimaxApiKey) {
|
|
313434
|
-
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));
|
|
313435
|
-
return;
|
|
313436
|
-
}
|
|
313437
|
-
} else {
|
|
313438
|
-
oauthToken = process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
313439
|
-
if (!oauthToken) {
|
|
313440
|
-
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));
|
|
313441
|
-
return;
|
|
313442
|
-
}
|
|
313428
|
+
const oauthToken = process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
313429
|
+
if (!oauthToken) {
|
|
313430
|
+
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));
|
|
313431
|
+
return;
|
|
313443
313432
|
}
|
|
313444
313433
|
const args = [
|
|
313445
313434
|
"-p",
|
|
@@ -313461,8 +313450,8 @@ var require_claude_cli = __commonJS({
|
|
|
313461
313450
|
// Stateless container — don't write session transcripts to disk.
|
|
313462
313451
|
"--no-session-persistence"
|
|
313463
313452
|
];
|
|
313464
|
-
if (
|
|
313465
|
-
args.push("--
|
|
313453
|
+
if (effort && effort.trim().length > 0) {
|
|
313454
|
+
args.push("--effort", effort.trim());
|
|
313466
313455
|
}
|
|
313467
313456
|
if (typeof maxTurns === "number" && maxTurns > 0) {
|
|
313468
313457
|
args.push("--max-turns", String(maxTurns));
|
|
@@ -313487,21 +313476,9 @@ var require_claude_cli = __commonJS({
|
|
|
313487
313476
|
MCP_TIMEOUT: process.env.MCP_TIMEOUT ?? "120000"
|
|
313488
313477
|
}
|
|
313489
313478
|
});
|
|
313490
|
-
|
|
313491
|
-
|
|
313492
|
-
|
|
313493
|
-
spawnEnv.ANTHROPIC_AUTH_TOKEN = minimaxApiKey;
|
|
313494
|
-
delete spawnEnv.CLAUDE_CODE_OAUTH_TOKEN;
|
|
313495
|
-
delete spawnEnv.ANTHROPIC_MODEL;
|
|
313496
|
-
delete spawnEnv.ANTHROPIC_DEFAULT_SONNET_MODEL;
|
|
313497
|
-
delete spawnEnv.ANTHROPIC_DEFAULT_OPUS_MODEL;
|
|
313498
|
-
delete spawnEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL;
|
|
313499
|
-
delete spawnEnv.ANTHROPIC_SMALL_FAST_MODEL;
|
|
313500
|
-
} else {
|
|
313501
|
-
spawnEnv.CLAUDE_CODE_OAUTH_TOKEN = oauthToken;
|
|
313502
|
-
delete spawnEnv.ANTHROPIC_API_KEY;
|
|
313503
|
-
delete spawnEnv.ANTHROPIC_AUTH_TOKEN;
|
|
313504
|
-
}
|
|
313479
|
+
spawnEnv.CLAUDE_CODE_OAUTH_TOKEN = oauthToken;
|
|
313480
|
+
delete spawnEnv.ANTHROPIC_API_KEY;
|
|
313481
|
+
delete spawnEnv.ANTHROPIC_AUTH_TOKEN;
|
|
313505
313482
|
const isWindows = process.platform === "win32";
|
|
313506
313483
|
const proc = (0, node_child_process_1.spawn)("claude", args, {
|
|
313507
313484
|
env: spawnEnv,
|
|
@@ -313613,7 +313590,7 @@ var require_claude_cli = __commonJS({
|
|
|
313613
313590
|
}
|
|
313614
313591
|
if (exitCode !== 0) {
|
|
313615
313592
|
const authFailure = looksLikeAuthFailure(stdout + "\n" + stderr);
|
|
313616
|
-
const msg = authFailure ?
|
|
313593
|
+
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})` : ""}`;
|
|
313617
313594
|
reject(new ClaudeSpawnError(msg, exitCode, stderr.trim(), stdout.trim(), authFailure));
|
|
313618
313595
|
return;
|
|
313619
313596
|
}
|
|
@@ -313626,39 +313603,8 @@ var require_claude_cli = __commonJS({
|
|
|
313626
313603
|
});
|
|
313627
313604
|
});
|
|
313628
313605
|
}
|
|
313629
|
-
function minimaxClaudeFallbackModels(requested) {
|
|
313630
|
-
const chain = agentic_cli_constants_js_1.CLAUDE_CODE_MINIMAX_FALLBACK_CHAIN;
|
|
313631
|
-
const idx = chain.indexOf(requested);
|
|
313632
|
-
if (idx === -1)
|
|
313633
|
-
return [requested];
|
|
313634
|
-
return chain.slice(idx);
|
|
313635
|
-
}
|
|
313636
313606
|
async function runClaude(options) {
|
|
313637
|
-
|
|
313638
|
-
return runClaudeOnce(options);
|
|
313639
|
-
const requested = options.model ?? agentic_cli_constants_js_1.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL;
|
|
313640
|
-
const chain = minimaxClaudeFallbackModels(requested);
|
|
313641
|
-
if (chain.length <= 1)
|
|
313642
|
-
return runClaudeOnce({ ...options, model: requested });
|
|
313643
|
-
let lastError;
|
|
313644
|
-
for (let i = 0; i < chain.length; i++) {
|
|
313645
|
-
const model = chain[i];
|
|
313646
|
-
const isLast = i === chain.length - 1;
|
|
313647
|
-
try {
|
|
313648
|
-
const result = await runClaudeOnce({ ...options, model });
|
|
313649
|
-
if (i > 0)
|
|
313650
|
-
console.warn(`[claude-cli] MiniMax CLI failover succeeded on ${model} (requested ${requested})`);
|
|
313651
|
-
return result;
|
|
313652
|
-
} catch (err) {
|
|
313653
|
-
lastError = err;
|
|
313654
|
-
const spawnErr = err instanceof ClaudeSpawnError ? err : null;
|
|
313655
|
-
if (isLast || spawnErr?.isAuthError || spawnErr?.isTimeout)
|
|
313656
|
-
throw err;
|
|
313657
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
313658
|
-
console.warn(`[claude-cli] MiniMax CLI ${model} failed (${reason}) \u2014 failing over to ${chain[i + 1]}`);
|
|
313659
|
-
}
|
|
313660
|
-
}
|
|
313661
|
-
throw lastError;
|
|
313607
|
+
return runClaudeOnce(options);
|
|
313662
313608
|
}
|
|
313663
313609
|
}
|
|
313664
313610
|
});
|
|
@@ -314043,6 +313989,8 @@ var require_claude_pricing = __commonJS({
|
|
|
314043
313989
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
314044
313990
|
exports.computeClaudeCostUsd = computeClaudeCostUsd;
|
|
314045
313991
|
var CLAUDE_PRICE_PER_M = {
|
|
313992
|
+
// Introductory pricing through 2026-08-31 ($2/$10); standard is $3/$15.
|
|
313993
|
+
"claude-sonnet-5": { input: 2, output: 10 },
|
|
314046
313994
|
"claude-sonnet-4-6": { input: 3, output: 15 },
|
|
314047
313995
|
"claude-haiku-4-5-20251001": { input: 1, output: 5 },
|
|
314048
313996
|
"claude-opus-4-7": { input: 5, output: 25 }
|
|
@@ -314082,7 +314030,7 @@ var require_claude_survey_runner = __commonJS({
|
|
|
314082
314030
|
var agentic_survey_prompts_js_1 = require_agentic_survey_prompts();
|
|
314083
314031
|
var MCP_CAPABILITIES = ["core", "core-navigation", "core-input", "core-tabs", "testing"];
|
|
314084
314032
|
var CANVAS_MODE_EXTRA_CAPABILITIES = ["vision"];
|
|
314085
|
-
var
|
|
314033
|
+
var DEFAULT_TIMEOUT_MS2 = 15 * 60 * 1e3;
|
|
314086
314034
|
var RETRY_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
314087
314035
|
async function logResultFile(path, log2) {
|
|
314088
314036
|
try {
|
|
@@ -314094,10 +314042,10 @@ ${preview}`);
|
|
|
314094
314042
|
log2("[diagnostic] result file does not exist \u2014 Claude never wrote it");
|
|
314095
314043
|
}
|
|
314096
314044
|
}
|
|
314097
|
-
async function runClaudeSurveyOnRunner(ctx, options = {}
|
|
314045
|
+
async function runClaudeSurveyOnRunner(ctx, options = {}) {
|
|
314098
314046
|
const maxTurns = options.maxTurns;
|
|
314099
|
-
const timeoutMs = options.timeoutMs ??
|
|
314100
|
-
const claudeDefaultModel =
|
|
314047
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
314048
|
+
const claudeDefaultModel = agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
|
|
314101
314049
|
const logs2 = [];
|
|
314102
314050
|
const log2 = (line) => {
|
|
314103
314051
|
logs2.push(line);
|
|
@@ -314241,7 +314189,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
314241
314189
|
console.log(`[claude-survey] ${line}`);
|
|
314242
314190
|
};
|
|
314243
314191
|
const onAudit = options.onAudit;
|
|
314244
|
-
const claudeProviderLabel =
|
|
314192
|
+
const claudeProviderLabel = "anthropic";
|
|
314245
314193
|
const claudeModelLabel = claudeDefaultModel;
|
|
314246
314194
|
const surveyExploreCallType = "surveyExplore";
|
|
314247
314195
|
const sessionStartedAt = Date.now();
|
|
@@ -314277,7 +314225,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
314277
314225
|
groupId: auditGroupId,
|
|
314278
314226
|
callType: surveyExploreCallType,
|
|
314279
314227
|
model: claudeModelLabel,
|
|
314280
|
-
provider:
|
|
314228
|
+
provider: "anthropic",
|
|
314281
314229
|
durationMs: turn.durationMs ?? 0,
|
|
314282
314230
|
promptTokens,
|
|
314283
314231
|
completionTokens,
|
|
@@ -314320,7 +314268,6 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
314320
314268
|
const result = await (0, claude_cli_js_1.runClaude)({
|
|
314321
314269
|
prompt: kickoffPrompt,
|
|
314322
314270
|
model: claudeDefaultModel,
|
|
314323
|
-
provider,
|
|
314324
314271
|
maxTurns,
|
|
314325
314272
|
timeoutMs,
|
|
314326
314273
|
cwd: runDir,
|
|
@@ -314380,7 +314327,6 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
314380
314327
|
const retryResult = await (0, claude_cli_js_1.runClaude)({
|
|
314381
314328
|
prompt: fixPrompt,
|
|
314382
314329
|
model: claudeDefaultModel,
|
|
314383
|
-
provider,
|
|
314384
314330
|
timeoutMs: RETRY_TIMEOUT_MS,
|
|
314385
314331
|
cwd: runDir,
|
|
314386
314332
|
mcpConfigPath,
|
|
@@ -314436,7 +314382,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
314436
314382
|
groupId: auditGroupId,
|
|
314437
314383
|
callType: surveyExploreCallType,
|
|
314438
314384
|
model: claudeModelLabel,
|
|
314439
|
-
provider:
|
|
314385
|
+
provider: "anthropic",
|
|
314440
314386
|
durationMs: sessionDurationMs,
|
|
314441
314387
|
promptTokens: sessionInputTokens,
|
|
314442
314388
|
completionTokens: sessionOutputTokens,
|
|
@@ -314812,11 +314758,11 @@ var require_claude_discovery_adapter = __commonJS({
|
|
|
314812
314758
|
var PER_TEST_IDLE_KILL_MS = 10 * 60 * 1e3;
|
|
314813
314759
|
var PER_TEST_MAX_TURNS = 120;
|
|
314814
314760
|
function createClaudeDiscoveryAdapter(args) {
|
|
314815
|
-
const {
|
|
314761
|
+
const { claudeDefaultModel } = args;
|
|
314816
314762
|
return {
|
|
314817
|
-
engine:
|
|
314763
|
+
engine: "claude-code",
|
|
314818
314764
|
auditModel: claudeDefaultModel,
|
|
314819
|
-
auditProvider:
|
|
314765
|
+
auditProvider: "anthropic",
|
|
314820
314766
|
computeSessionCostUsd(usage) {
|
|
314821
314767
|
return (0, claude_pricing_js_1.computeClaudeCostUsd)(claudeDefaultModel, {
|
|
314822
314768
|
inputTokens: usage.inputTokens,
|
|
@@ -314857,7 +314803,7 @@ var require_claude_discovery_adapter = __commonJS({
|
|
|
314857
314803
|
prompt,
|
|
314858
314804
|
appendSystemPrompt,
|
|
314859
314805
|
model: claudeDefaultModel,
|
|
314860
|
-
provider,
|
|
314806
|
+
provider: "anthropic",
|
|
314861
314807
|
maxTurns: PER_TEST_MAX_TURNS,
|
|
314862
314808
|
// A per-test session needs only browser MCP + the file tools — never a
|
|
314863
314809
|
// shell. Disallow Bash to shrink the off-task surface (and Task, the
|
|
@@ -314929,17 +314875,17 @@ var require_claude_discovery_runner = __commonJS({
|
|
|
314929
314875
|
];
|
|
314930
314876
|
var CALL1_TIMEOUT_MS = 38 * 60 * 1e3;
|
|
314931
314877
|
var DISCOVERY_IDLE_KILL_MS = 15 * 60 * 1e3;
|
|
314932
|
-
var
|
|
314878
|
+
var DEFAULT_TIMEOUT_MS2 = 20 * 60 * 1e3;
|
|
314933
314879
|
var DEFAULT_TARGET = { min: 6, max: 15 };
|
|
314934
|
-
async function runClaudeDiscoveryOnRunner(ctx, callbackOptions, options = {}
|
|
314935
|
-
const claudeDefaultModel =
|
|
314936
|
-
const claudeProviderLabel =
|
|
314880
|
+
async function runClaudeDiscoveryOnRunner(ctx, callbackOptions, options = {}) {
|
|
314881
|
+
const claudeDefaultModel = agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
|
|
314882
|
+
const claudeProviderLabel = "anthropic";
|
|
314937
314883
|
const featureName = ctx.featureName ?? "Untitled Feature";
|
|
314938
314884
|
const manifestShape = (0, grok_discovery_runner_js_1.narrowManifest)(ctx.featureContextManifest);
|
|
314939
314885
|
const manifestFeatureRoutes = Array.isArray(manifestShape?.feature?.pages) ? manifestShape.feature.pages.filter((r) => typeof r === "string" && r.length > 0) : [];
|
|
314940
314886
|
const featureRoutes = manifestFeatureRoutes.length > 0 ? manifestFeatureRoutes : ctx.featureContext?.pageIntel?.map((p) => p.route) ?? ctx.focusAreas ?? [];
|
|
314941
314887
|
const targetTestCount = options.targetTestCount ?? DEFAULT_TARGET;
|
|
314942
|
-
const callerTimeoutMs = options.timeoutMs ??
|
|
314888
|
+
const callerTimeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
314943
314889
|
const call1TimeoutMs = Math.max(callerTimeoutMs, CALL1_TIMEOUT_MS);
|
|
314944
314890
|
const logs2 = [];
|
|
314945
314891
|
const log2 = (line) => {
|
|
@@ -315186,7 +315132,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
315186
315132
|
groupId: ctx.sessionId ?? featureName,
|
|
315187
315133
|
callType: featureExploreCallType,
|
|
315188
315134
|
model: claudeModelLabel,
|
|
315189
|
-
provider:
|
|
315135
|
+
provider: "anthropic",
|
|
315190
315136
|
durationMs: turn.durationMs ?? 0,
|
|
315191
315137
|
promptTokens,
|
|
315192
315138
|
completionTokens,
|
|
@@ -315297,7 +315243,6 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
315297
315243
|
// they actually get put there.
|
|
315298
315244
|
appendSystemPrompt: canvasMode ? (0, agentic_discovery_prompts_js_1.buildAuthoringRules)() + (0, canvas_detector_js_1.buildCanvasModeAuthoringAddendum)() : (0, agentic_discovery_prompts_js_1.buildAuthoringRules)(),
|
|
315299
315245
|
model: claudeDefaultModel,
|
|
315300
|
-
provider,
|
|
315301
315246
|
timeoutMs: call1TimeoutMs,
|
|
315302
315247
|
idleKillMs: DISCOVERY_IDLE_KILL_MS,
|
|
315303
315248
|
cwd: runDir,
|
|
@@ -315407,7 +315352,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
315407
315352
|
groupId: ctx.sessionId ?? featureName,
|
|
315408
315353
|
callType: featureExploreCallType,
|
|
315409
315354
|
model: claudeModelLabel,
|
|
315410
|
-
provider:
|
|
315355
|
+
provider: "anthropic",
|
|
315411
315356
|
durationMs: sessionDurationMs,
|
|
315412
315357
|
promptTokens: sessionInputTokens,
|
|
315413
315358
|
completionTokens: sessionOutputTokens,
|
|
@@ -315499,7 +315444,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
|
|
|
315499
315444
|
},
|
|
315500
315445
|
onAudit,
|
|
315501
315446
|
auditGroupId: ctx.sessionId ?? featureName,
|
|
315502
|
-
adapter: (0, claude_discovery_adapter_js_1.createClaudeDiscoveryAdapter)({
|
|
315447
|
+
adapter: (0, claude_discovery_adapter_js_1.createClaudeDiscoveryAdapter)({ claudeDefaultModel })
|
|
315503
315448
|
});
|
|
315504
315449
|
log2(`Verify + Call 2: complete \u2014 ${capturedTests.length} test(s) saved, ${localUnverified.length} unverified`);
|
|
315505
315450
|
}
|
|
@@ -316425,7 +316370,7 @@ var require_discover_agent = __commonJS({
|
|
|
316425
316370
|
} else if (cached === "standard") {
|
|
316426
316371
|
return { renderType: "standard", canvasMode: false, probeRan: false };
|
|
316427
316372
|
} else {
|
|
316428
|
-
const bailEligible = engine === "native"
|
|
316373
|
+
const bailEligible = engine === "native";
|
|
316429
316374
|
const cannotConfirm = (reason) => {
|
|
316430
316375
|
const note = bailEligible ? ` \u26A0 engine=${engine} would have bailed on canvas \u2014 if discovery loops, set Settings \u2192 App renderer manually.` : "";
|
|
316431
316376
|
log2(`[canvas] preflight could not run: ${reason} \u2014 proceeding as standard.${note}`);
|
|
@@ -316744,7 +316689,7 @@ Respond with ONLY valid JSON:
|
|
|
316744
316689
|
// wiring is in place when it does.
|
|
316745
316690
|
onAudit: onAICall
|
|
316746
316691
|
};
|
|
316747
|
-
const cliResult = surveyEngine === "claude-code
|
|
316692
|
+
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);
|
|
316748
316693
|
logs2.push(`${surveyEngine} survey runner finished cleanly.`);
|
|
316749
316694
|
onLog?.("done", logs2.join("\n"));
|
|
316750
316695
|
return {
|
|
@@ -317266,7 +317211,7 @@ Fatal error: ${msg}`);
|
|
|
317266
317211
|
// through the existing DiscoveryAuditCallback (→ aiAuditBatch).
|
|
317267
317212
|
onAudit: onAICall
|
|
317268
317213
|
};
|
|
317269
|
-
const cliResult = deepEngine === "claude-code
|
|
317214
|
+
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);
|
|
317270
317215
|
logs2.push(`${deepEngine} deep discovery finished cleanly. ${cliResult.testsEmitted} tests emitted, ${cliResult.unverified.length} unverified.`);
|
|
317271
317216
|
onLog?.("done", logs2.join("\n"));
|
|
317272
317217
|
return {
|
|
@@ -328146,9 +328091,8 @@ var require_framework_import_runner = __commonJS({
|
|
|
328146
328091
|
const imp = ctx.frameworkImport;
|
|
328147
328092
|
if (!imp)
|
|
328148
328093
|
throw new Error("runFrameworkImportOnRunner: ctx.frameworkImport is required");
|
|
328149
|
-
const
|
|
328150
|
-
const
|
|
328151
|
-
const model = provider === "minimax" ? agentic_cli_constants_js_1.CLAUDE_CODE_MINIMAX_DEFAULT_MODEL : agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
|
|
328094
|
+
const provider = "anthropic";
|
|
328095
|
+
const model = agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
|
|
328152
328096
|
log2("=== Framework Import Runner (Claude CLI, no browser) ===");
|
|
328153
328097
|
log2(`Source: ${imp.source}${imp.source === "github" ? ` (${imp.repoOwner}/${imp.repoName}@${imp.branch ?? "default"})` : ""}`);
|
|
328154
328098
|
const runDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "framework-import-"));
|
|
@@ -329278,8 +329222,8 @@ var require_repo_analysis_runner = __commonJS({
|
|
|
329278
329222
|
const maxEndpointsPerFeature = intEnv("REPO_ANALYSIS_MAX_ENDPOINTS_PER_FEATURE", 80, 1, 400);
|
|
329279
329223
|
const maxFacts = intEnv("REPO_ANALYSIS_MAX_FACTS", 40, 1, 120);
|
|
329280
329224
|
const engine = (0, agentic_cli_constants_js_1.getAgenticEngine)(ctx.exploreModel);
|
|
329281
|
-
const provider =
|
|
329282
|
-
const model =
|
|
329225
|
+
const provider = "anthropic";
|
|
329226
|
+
const model = agentic_cli_constants_js_1.CLAUDE_CODE_DEFAULT_MODEL;
|
|
329283
329227
|
log2("=== Repo Analysis Runner (Claude CLI, no browser) ===");
|
|
329284
329228
|
log2(`Source: ${imp.source}${imp.source === "github" ? ` (${imp.repoOwner}/${imp.repoName}@${imp.branch ?? "default"})` : ""}`);
|
|
329285
329229
|
const runDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "repo-analysis-"));
|
|
@@ -329762,7 +329706,7 @@ var require_process_inventory = __commonJS({
|
|
|
329762
329706
|
var node_util_1 = __require("util");
|
|
329763
329707
|
var execFileAsync3 = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
329764
329708
|
var DEFAULT_LIMIT = 60;
|
|
329765
|
-
var
|
|
329709
|
+
var DEFAULT_TIMEOUT_MS2 = 800;
|
|
329766
329710
|
var MAX_COMMAND_LENGTH = 320;
|
|
329767
329711
|
function roundOne(value) {
|
|
329768
329712
|
return Math.round(value * 10) / 10;
|
|
@@ -329911,7 +329855,7 @@ var require_process_inventory = __commonJS({
|
|
|
329911
329855
|
}
|
|
329912
329856
|
async function getBrowserProcessInventory2(options = {}) {
|
|
329913
329857
|
const limit = Math.max(1, Math.min(200, options.limit ?? DEFAULT_LIMIT));
|
|
329914
|
-
const timeoutMs = Math.max(100, Math.min(5e3, options.timeoutMs ??
|
|
329858
|
+
const timeoutMs = Math.max(100, Math.min(5e3, options.timeoutMs ?? DEFAULT_TIMEOUT_MS2));
|
|
329915
329859
|
try {
|
|
329916
329860
|
const rawProcesses = process.platform === "win32" ? await collectWindowsProcesses(timeoutMs) : await collectUnixProcesses(timeoutMs);
|
|
329917
329861
|
const processes = [...rawProcesses].sort((a, b) => (b.cpuPct ?? 0) - (a.cpuPct ?? 0) || (b.rssMB ?? 0) - (a.rssMB ?? 0)).slice(0, limit);
|
|
@@ -330878,7 +330822,7 @@ var require_package4 = __commonJS({
|
|
|
330878
330822
|
"package.json"(exports, module) {
|
|
330879
330823
|
module.exports = {
|
|
330880
330824
|
name: "@validate.qa/runner",
|
|
330881
|
-
version: "1.0.
|
|
330825
|
+
version: "1.0.35",
|
|
330882
330826
|
description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
|
|
330883
330827
|
bin: {
|
|
330884
330828
|
"validate-runner": "dist/cli.js"
|
|
@@ -330886,6 +330830,7 @@ var require_package4 = __commonJS({
|
|
|
330886
330830
|
scripts: {
|
|
330887
330831
|
build: "tsup",
|
|
330888
330832
|
dev: "tsx src/cli.ts",
|
|
330833
|
+
test: "node --import tsx --test src/version-check.test.ts",
|
|
330889
330834
|
"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",
|
|
330890
330835
|
prepublishOnly: "npm run build"
|
|
330891
330836
|
},
|
|
@@ -331014,6 +330959,136 @@ function shouldUseAuthState(tags, playwrightCode) {
|
|
|
331014
330959
|
return !tags.includes(INLINE_LOGIN_TAG) && !hasLegacyInlineLogin;
|
|
331015
330960
|
}
|
|
331016
330961
|
|
|
330962
|
+
// src/version-check.ts
|
|
330963
|
+
var RUNNER_NPM_PACKAGE = "@validate.qa/runner";
|
|
330964
|
+
var NPM_LATEST_URL = `https://registry.npmjs.org/${encodeURIComponent(RUNNER_NPM_PACKAGE)}/latest`;
|
|
330965
|
+
var DEFAULT_TIMEOUT_MS = 8e3;
|
|
330966
|
+
function parseSemver(raw) {
|
|
330967
|
+
const cleaned = raw.trim().replace(/^v/i, "");
|
|
330968
|
+
const match = cleaned.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
|
|
330969
|
+
if (!match) return null;
|
|
330970
|
+
return {
|
|
330971
|
+
major: Number(match[1]),
|
|
330972
|
+
minor: Number(match[2]),
|
|
330973
|
+
patch: Number(match[3]),
|
|
330974
|
+
prerelease: match[4] ?? null
|
|
330975
|
+
};
|
|
330976
|
+
}
|
|
330977
|
+
function compareSemver(a, b) {
|
|
330978
|
+
const pa = parseSemver(a);
|
|
330979
|
+
const pb = parseSemver(b);
|
|
330980
|
+
if (!pa || !pb) return null;
|
|
330981
|
+
if (pa.major !== pb.major) return pa.major < pb.major ? -1 : 1;
|
|
330982
|
+
if (pa.minor !== pb.minor) return pa.minor < pb.minor ? -1 : 1;
|
|
330983
|
+
if (pa.patch !== pb.patch) return pa.patch < pb.patch ? -1 : 1;
|
|
330984
|
+
if (pa.prerelease === pb.prerelease) return 0;
|
|
330985
|
+
if (pa.prerelease === null) return 1;
|
|
330986
|
+
if (pb.prerelease === null) return -1;
|
|
330987
|
+
return pa.prerelease < pb.prerelease ? -1 : pa.prerelease > pb.prerelease ? 1 : 0;
|
|
330988
|
+
}
|
|
330989
|
+
function isVersionOutdated(current, latest) {
|
|
330990
|
+
const cmp = compareSemver(current, latest);
|
|
330991
|
+
return cmp === -1;
|
|
330992
|
+
}
|
|
330993
|
+
function shouldSkipVersionCheck() {
|
|
330994
|
+
if (process.env.RUNNER_CLOUD === "true") {
|
|
330995
|
+
return "cloud runner (RUNNER_CLOUD=true)";
|
|
330996
|
+
}
|
|
330997
|
+
if (process.env.VALIDATE_RUNNER_ALLOW_OUTDATED === "1" || process.env.VALIDATE_RUNNER_ALLOW_OUTDATED === "true") {
|
|
330998
|
+
return "VALIDATE_RUNNER_ALLOW_OUTDATED is set";
|
|
330999
|
+
}
|
|
331000
|
+
return null;
|
|
331001
|
+
}
|
|
331002
|
+
async function fetchLatestRunnerVersion(timeoutMs = DEFAULT_TIMEOUT_MS, fetchImpl = fetch) {
|
|
331003
|
+
const controller = new AbortController();
|
|
331004
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
331005
|
+
try {
|
|
331006
|
+
const res = await fetchImpl(NPM_LATEST_URL, {
|
|
331007
|
+
headers: {
|
|
331008
|
+
Accept: "application/json",
|
|
331009
|
+
// Identify ourselves; helps npm operators + caching intermediaries.
|
|
331010
|
+
"User-Agent": `${RUNNER_NPM_PACKAGE}-version-check`
|
|
331011
|
+
},
|
|
331012
|
+
signal: controller.signal
|
|
331013
|
+
});
|
|
331014
|
+
if (!res.ok) return null;
|
|
331015
|
+
const body = await res.json();
|
|
331016
|
+
return typeof body.version === "string" && body.version.length > 0 ? body.version : null;
|
|
331017
|
+
} catch {
|
|
331018
|
+
return null;
|
|
331019
|
+
} finally {
|
|
331020
|
+
clearTimeout(timer);
|
|
331021
|
+
}
|
|
331022
|
+
}
|
|
331023
|
+
async function checkRunnerVersion(currentVersion, opts = {}) {
|
|
331024
|
+
const skip = shouldSkipVersionCheck();
|
|
331025
|
+
if (skip) {
|
|
331026
|
+
return { outdated: false, currentVersion, latestVersion: null, skippedReason: skip };
|
|
331027
|
+
}
|
|
331028
|
+
const latestVersion = await fetchLatestRunnerVersion(opts.timeoutMs, opts.fetchImpl);
|
|
331029
|
+
if (!latestVersion) {
|
|
331030
|
+
return {
|
|
331031
|
+
outdated: false,
|
|
331032
|
+
currentVersion,
|
|
331033
|
+
latestVersion: null,
|
|
331034
|
+
skippedReason: "could not reach npm registry (or response was invalid)"
|
|
331035
|
+
};
|
|
331036
|
+
}
|
|
331037
|
+
if (!parseSemver(currentVersion) || !parseSemver(latestVersion)) {
|
|
331038
|
+
return {
|
|
331039
|
+
outdated: false,
|
|
331040
|
+
currentVersion,
|
|
331041
|
+
latestVersion,
|
|
331042
|
+
skippedReason: "unparseable version string"
|
|
331043
|
+
};
|
|
331044
|
+
}
|
|
331045
|
+
return {
|
|
331046
|
+
outdated: isVersionOutdated(currentVersion, latestVersion),
|
|
331047
|
+
currentVersion,
|
|
331048
|
+
latestVersion
|
|
331049
|
+
};
|
|
331050
|
+
}
|
|
331051
|
+
function formatUpgradeInstructions(latestVersion) {
|
|
331052
|
+
const lines = [
|
|
331053
|
+
"",
|
|
331054
|
+
"\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",
|
|
331055
|
+
"\u2551 VALIDATE.QA RUNNER UPDATE REQUIRED \u2551",
|
|
331056
|
+
"\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",
|
|
331057
|
+
"\u2551 A newer runner is published on npm. Each runner release changes \u2551",
|
|
331058
|
+
"\u2551 the workflow, so this version can no longer run. \u2551",
|
|
331059
|
+
`\u2551 Latest: ${latestVersion.padEnd(54)}\u2551`,
|
|
331060
|
+
"\u2551 \u2551",
|
|
331061
|
+
"\u2551 Upgrade with: \u2551",
|
|
331062
|
+
`\u2551 npm install -g ${RUNNER_NPM_PACKAGE}@latest`.padEnd(69) + "\u2551",
|
|
331063
|
+
"\u2551 \u2551",
|
|
331064
|
+
"\u2551 Then restart: \u2551",
|
|
331065
|
+
"\u2551 validate-runner start \u2551",
|
|
331066
|
+
"\u2551 # or: npx @validate.qa/runner@latest start \u2551",
|
|
331067
|
+
"\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",
|
|
331068
|
+
""
|
|
331069
|
+
];
|
|
331070
|
+
return lines.join("\n");
|
|
331071
|
+
}
|
|
331072
|
+
async function enforceRunnerUpToDate(currentVersion, opts = {}) {
|
|
331073
|
+
const log2 = opts.log ?? ((msg) => console.error(msg));
|
|
331074
|
+
const result = await checkRunnerVersion(currentVersion, opts);
|
|
331075
|
+
if (result.skippedReason && !result.outdated) {
|
|
331076
|
+
if (result.skippedReason.startsWith("could not reach") || result.skippedReason.startsWith("unparseable")) {
|
|
331077
|
+
log2(`\u26A0 Runner version check skipped: ${result.skippedReason}`);
|
|
331078
|
+
}
|
|
331079
|
+
return result;
|
|
331080
|
+
}
|
|
331081
|
+
if (result.outdated && result.latestVersion) {
|
|
331082
|
+
log2(formatUpgradeInstructions(result.latestVersion));
|
|
331083
|
+
log2(` Installed: ${result.currentVersion}`);
|
|
331084
|
+
log2(` Required: ${result.latestVersion} (or newer)`);
|
|
331085
|
+
log2("");
|
|
331086
|
+
const exit = opts.exitFn ?? ((code) => process.exit(code));
|
|
331087
|
+
exit(1);
|
|
331088
|
+
}
|
|
331089
|
+
return result;
|
|
331090
|
+
}
|
|
331091
|
+
|
|
331017
331092
|
// src/services/appium-executor.ts
|
|
331018
331093
|
init_dist();
|
|
331019
331094
|
|
|
@@ -336050,13 +336125,31 @@ function buildHeaders(authToken, projectId) {
|
|
|
336050
336125
|
return {
|
|
336051
336126
|
"Content-Type": "application/json",
|
|
336052
336127
|
Authorization: `Bearer ${authToken}`,
|
|
336053
|
-
"X-Project-Id": projectId
|
|
336128
|
+
"X-Project-Id": projectId,
|
|
336129
|
+
// Lets the server force-upgrade outdated local installs on /pending too
|
|
336130
|
+
// (not only heartbeat), so they cannot claim work after a new npm publish.
|
|
336131
|
+
"X-Runner-Version": RUNNER_VERSION,
|
|
336132
|
+
"X-Runner-Name": RUNNER_NAME
|
|
336054
336133
|
};
|
|
336055
336134
|
}
|
|
336135
|
+
var RunnerUpgradeRequiredError = class extends Error {
|
|
336136
|
+
latestVersion;
|
|
336137
|
+
constructor(message, latestVersion) {
|
|
336138
|
+
super(message);
|
|
336139
|
+
this.name = "RunnerUpgradeRequiredError";
|
|
336140
|
+
this.latestVersion = latestVersion;
|
|
336141
|
+
}
|
|
336142
|
+
};
|
|
336056
336143
|
async function fetchPendingRuns(serverUrl, headers) {
|
|
336057
336144
|
const res = await fetch(`${serverUrl}/api/runner/pending`, { headers, signal: AbortSignal.timeout(3e4) });
|
|
336058
336145
|
if (!res.ok) {
|
|
336059
336146
|
if (res.status === 401) throw new Error("Runner token is invalid or expired. Run: validate.qa-runner login");
|
|
336147
|
+
if (res.status === 426) {
|
|
336148
|
+
const body = await res.json().catch(() => null);
|
|
336149
|
+
const latest = typeof body?.latestRunnerVersion === "string" ? body.latestRunnerVersion : null;
|
|
336150
|
+
const msg = typeof body?.error === "string" ? body.error : "A newer @validate.qa/runner is required. Run: npm install -g @validate.qa/runner@latest";
|
|
336151
|
+
throw new RunnerUpgradeRequiredError(msg, latest);
|
|
336152
|
+
}
|
|
336060
336153
|
if (res.status === 429) {
|
|
336061
336154
|
const retryAfter = res.headers.get("Retry-After");
|
|
336062
336155
|
const waitSecs = retryAfter ? parseInt(retryAfter, 10) : 60;
|
|
@@ -338569,10 +338662,34 @@ async function startRunner(opts) {
|
|
|
338569
338662
|
}
|
|
338570
338663
|
console.log("");
|
|
338571
338664
|
log.ok(`Runner started - waiting for test runs...${enableMobile ? " (web + mobile)" : ""}`);
|
|
338665
|
+
log.info(`Version: ${RUNNER_VERSION}`);
|
|
338572
338666
|
log.dim("Press Ctrl+C to stop");
|
|
338573
338667
|
console.log("");
|
|
338574
338668
|
let runsCompleted = 0;
|
|
338575
338669
|
let activeRuns = 0;
|
|
338670
|
+
const VERSION_RECHECK_MS = Math.max(
|
|
338671
|
+
6e4,
|
|
338672
|
+
envInt("VALIDATE_RUNNER_VERSION_CHECK_MS", 15 * 6e4)
|
|
338673
|
+
);
|
|
338674
|
+
const exitForUpgrade = (latestVersion, installed) => {
|
|
338675
|
+
console.error(formatUpgradeInstructions(latestVersion));
|
|
338676
|
+
console.error(` Installed: ${installed}`);
|
|
338677
|
+
console.error(` Required: ${latestVersion} (or newer)`);
|
|
338678
|
+
console.error("");
|
|
338679
|
+
process.exit(1);
|
|
338680
|
+
};
|
|
338681
|
+
const recheckRunnerVersion = async () => {
|
|
338682
|
+
if (activeRuns > 0) return;
|
|
338683
|
+
const result = await checkRunnerVersion(RUNNER_VERSION);
|
|
338684
|
+
if (result.outdated && result.latestVersion) {
|
|
338685
|
+
log.warn("A newer runner was published on npm \u2014 shutting down so you can upgrade.");
|
|
338686
|
+
exitForUpgrade(result.latestVersion, RUNNER_VERSION);
|
|
338687
|
+
}
|
|
338688
|
+
};
|
|
338689
|
+
const versionRecheckTimer = setInterval(() => {
|
|
338690
|
+
void recheckRunnerVersion();
|
|
338691
|
+
}, VERSION_RECHECK_MS);
|
|
338692
|
+
versionRecheckTimer.unref?.();
|
|
338576
338693
|
const MAX_CONCURRENT = Math.max(1, envInt("MAX_CONCURRENT", DEFAULT_MAX_CONCURRENT));
|
|
338577
338694
|
const MAX_PROJECT_CONCURRENT = Math.max(1, envInt("MAX_PROJECT_CONCURRENT", DEFAULT_MAX_PROJECT_CONCURRENT));
|
|
338578
338695
|
const TYPE_LIMITS = {
|
|
@@ -338798,6 +338915,22 @@ async function startRunner(opts) {
|
|
|
338798
338915
|
if (body && Array.isArray(body.commands) && body.commands.length > 0) {
|
|
338799
338916
|
void handleControlCommands(body.commands);
|
|
338800
338917
|
}
|
|
338918
|
+
if (body && body.forceUpgrade === true && typeof body.latestRunnerVersion === "string" && isVersionOutdated(RUNNER_VERSION, body.latestRunnerVersion) && activeRuns === 0) {
|
|
338919
|
+
log.warn(
|
|
338920
|
+
typeof body.upgradeMessage === "string" && body.upgradeMessage ? body.upgradeMessage : "Server requires a newer runner version \u2014 shutting down."
|
|
338921
|
+
);
|
|
338922
|
+
exitForUpgrade(body.latestRunnerVersion, RUNNER_VERSION);
|
|
338923
|
+
}
|
|
338924
|
+
} else if (response.status === 426) {
|
|
338925
|
+
const body = await response.json().catch(() => null);
|
|
338926
|
+
const latest = typeof body?.latestRunnerVersion === "string" ? body.latestRunnerVersion : null;
|
|
338927
|
+
if (latest) {
|
|
338928
|
+
exitForUpgrade(latest, RUNNER_VERSION);
|
|
338929
|
+
}
|
|
338930
|
+
log.warn(
|
|
338931
|
+
typeof body?.error === "string" ? body.error : "Server rejected this runner version (HTTP 426). Upgrade @validate.qa/runner."
|
|
338932
|
+
);
|
|
338933
|
+
process.exit(1);
|
|
338801
338934
|
}
|
|
338802
338935
|
} catch {
|
|
338803
338936
|
}
|
|
@@ -339038,6 +339171,10 @@ async function startRunner(opts) {
|
|
|
339038
339171
|
consecutivePollErrors = 0;
|
|
339039
339172
|
}
|
|
339040
339173
|
} catch (err) {
|
|
339174
|
+
if (err instanceof RunnerUpgradeRequiredError) {
|
|
339175
|
+
log.warn(err.message);
|
|
339176
|
+
exitForUpgrade(err.latestVersion ?? "latest", RUNNER_VERSION);
|
|
339177
|
+
}
|
|
339041
339178
|
const message = err instanceof Error ? err.message : String(err);
|
|
339042
339179
|
consecutivePollErrors++;
|
|
339043
339180
|
const backoffMs = Math.min(pollIntervalMs * Math.pow(2, consecutivePollErrors - 1), MAX_BACKOFF_MS);
|
|
@@ -339057,7 +339194,11 @@ async function startRunner(opts) {
|
|
|
339057
339194
|
var pkg = require_package4();
|
|
339058
339195
|
var program = new Command();
|
|
339059
339196
|
program.name("validate-runner").description("validate.qa local test runner - execute Playwright and Appium tests on your machine").version(pkg.version);
|
|
339197
|
+
async function requireLatestRunner() {
|
|
339198
|
+
await enforceRunnerUpToDate(pkg.version);
|
|
339199
|
+
}
|
|
339060
339200
|
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) => {
|
|
339201
|
+
await requireLatestRunner();
|
|
339061
339202
|
const serverUrl = opts.server.replace(/\/+$/, "");
|
|
339062
339203
|
if (!opts.token.startsWith("urt_") && !opts.token.startsWith("rt_") && !opts.token.startsWith("eyJ")) {
|
|
339063
339204
|
console.error("\u26A0 Token should start with urt_ (from the dashboard Runner Token)");
|
|
@@ -339089,6 +339230,7 @@ program.command("login").description("Save runner credentials for future use").r
|
|
|
339089
339230
|
console.log("Run: validate-runner start");
|
|
339090
339231
|
});
|
|
339091
339232
|
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) => {
|
|
339233
|
+
await requireLatestRunner();
|
|
339092
339234
|
const saved = loadCredentials();
|
|
339093
339235
|
const authToken = opts.token || process.env.AUTH_TOKEN || saved?.token;
|
|
339094
339236
|
const serverUrl = (opts.server || process.env.SERVER_URL || saved?.serverUrl)?.replace(/\/+$/, "");
|
|
@@ -339141,6 +339283,7 @@ program.command("logout").description("Clear saved runner credentials").action((
|
|
|
339141
339283
|
console.log("\u2713 Credentials cleared");
|
|
339142
339284
|
});
|
|
339143
339285
|
program.command("status").description("Check connection to validate.qa server").action(async () => {
|
|
339286
|
+
await requireLatestRunner();
|
|
339144
339287
|
const saved = loadCredentials();
|
|
339145
339288
|
if (!saved) {
|
|
339146
339289
|
console.log("No saved credentials. Run: validate-runner login");
|