@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.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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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 :
|
|
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-
|
|
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-
|
|
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
|
|
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 ??
|
|
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-
|
|
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-
|
|
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 === "
|
|
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
|
|
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 ??
|
|
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-
|
|
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-
|
|
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 ??
|
|
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 =
|
|
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
|
-
|
|
313423
|
-
|
|
313424
|
-
|
|
313425
|
-
|
|
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 (
|
|
313460
|
-
args.push("--
|
|
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
|
-
|
|
313486
|
-
|
|
313487
|
-
|
|
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 ?
|
|
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
|
-
|
|
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
|
|
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 = {}
|
|
314040
|
+
async function runClaudeSurveyOnRunner(ctx, options = {}) {
|
|
314093
314041
|
const maxTurns = options.maxTurns;
|
|
314094
|
-
const timeoutMs = options.timeoutMs ??
|
|
314095
|
-
const claudeDefaultModel =
|
|
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 =
|
|
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:
|
|
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:
|
|
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 {
|
|
314756
|
+
const { claudeDefaultModel } = args;
|
|
314811
314757
|
return {
|
|
314812
|
-
engine:
|
|
314758
|
+
engine: "claude-code",
|
|
314813
314759
|
auditModel: claudeDefaultModel,
|
|
314814
|
-
auditProvider:
|
|
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
|
|
314873
|
+
var DEFAULT_TIMEOUT_MS2 = 20 * 60 * 1e3;
|
|
314928
314874
|
var DEFAULT_TARGET = { min: 6, max: 15 };
|
|
314929
|
-
async function runClaudeDiscoveryOnRunner(ctx, callbackOptions, options = {}
|
|
314930
|
-
const claudeDefaultModel =
|
|
314931
|
-
const claudeProviderLabel =
|
|
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 ??
|
|
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:
|
|
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:
|
|
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)({
|
|
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"
|
|
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
|
|
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
|
|
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
|
|
328145
|
-
const
|
|
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 =
|
|
329277
|
-
const 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
|
|
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 ??
|
|
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.
|
|
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");
|