agent-gauntlet 0.15.4 → 1.0.0
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/dist/index.js +67 -460
- package/dist/index.js.map +15 -15
- package/package.json +2 -3
- package/skills/gauntlet-help/SKILL.md +0 -1
- package/skills/gauntlet-help/references/stop-hook-troubleshooting.md +0 -9
- package/skills/gauntlet-run/SKILL.md +9 -3
- package/skills/gauntlet-skip/SKILL.md +17 -0
- package/skills/gauntlet-fix-pr/SKILL.md +0 -14
- package/skills/gauntlet-help/references/ci-pr-troubleshooting.md +0 -104
- package/skills/gauntlet-push-pr/SKILL.md +0 -11
package/dist/index.js
CHANGED
|
@@ -299,7 +299,7 @@ import { Command } from "commander";
|
|
|
299
299
|
// package.json
|
|
300
300
|
var package_default = {
|
|
301
301
|
name: "agent-gauntlet",
|
|
302
|
-
version: "0.
|
|
302
|
+
version: "1.0.0",
|
|
303
303
|
description: "A CLI tool for testing AI coding agents",
|
|
304
304
|
license: "MIT",
|
|
305
305
|
author: "Paul Caplan",
|
|
@@ -349,8 +349,7 @@ var package_default = {
|
|
|
349
349
|
detect: "bun src/index.ts detect",
|
|
350
350
|
list: "bun src/index.ts list",
|
|
351
351
|
health: "bun src/index.ts health",
|
|
352
|
-
validate: "bun src/index.ts validate"
|
|
353
|
-
"wait-ci": "bun src/index.ts wait-ci"
|
|
352
|
+
validate: "bun src/index.ts validate"
|
|
354
353
|
},
|
|
355
354
|
devDependencies: {
|
|
356
355
|
"@biomejs/biome": "^2.4.3",
|
|
@@ -391,23 +390,17 @@ var debugLogConfigSchema = z.object({
|
|
|
391
390
|
var globalConfigSchema = z.object({
|
|
392
391
|
stop_hook: z.object({
|
|
393
392
|
enabled: z.boolean().default(false),
|
|
394
|
-
run_interval_minutes: z.number().default(5)
|
|
395
|
-
auto_push_pr: z.boolean().default(false),
|
|
396
|
-
auto_fix_pr: z.boolean().default(false)
|
|
393
|
+
run_interval_minutes: z.number().default(5)
|
|
397
394
|
}).default({
|
|
398
395
|
enabled: false,
|
|
399
|
-
run_interval_minutes: 5
|
|
400
|
-
auto_push_pr: false,
|
|
401
|
-
auto_fix_pr: false
|
|
396
|
+
run_interval_minutes: 5
|
|
402
397
|
}),
|
|
403
398
|
debug_log: debugLogConfigSchema.default({ enabled: false, max_size_mb: 10 })
|
|
404
399
|
});
|
|
405
400
|
var DEFAULT_GLOBAL_CONFIG = {
|
|
406
401
|
stop_hook: {
|
|
407
402
|
enabled: false,
|
|
408
|
-
run_interval_minutes: 5
|
|
409
|
-
auto_push_pr: false,
|
|
410
|
-
auto_fix_pr: false
|
|
403
|
+
run_interval_minutes: 5
|
|
411
404
|
},
|
|
412
405
|
debug_log: {
|
|
413
406
|
enabled: false,
|
|
@@ -625,9 +618,7 @@ var loggingConfigSchema = z2.object({
|
|
|
625
618
|
});
|
|
626
619
|
var stopHookConfigSchema = z2.object({
|
|
627
620
|
enabled: z2.boolean().optional(),
|
|
628
|
-
run_interval_minutes: z2.number().int().min(0).optional()
|
|
629
|
-
auto_push_pr: z2.boolean().optional(),
|
|
630
|
-
auto_fix_pr: z2.boolean().optional()
|
|
621
|
+
run_interval_minutes: z2.number().int().min(0).optional()
|
|
631
622
|
});
|
|
632
623
|
var gauntletConfigSchema = z2.object({
|
|
633
624
|
base_branch: z2.string().min(1).default("origin/main"),
|
|
@@ -1371,7 +1362,7 @@ import { exec as exec3 } from "node:child_process";
|
|
|
1371
1362
|
import fs12 from "node:fs/promises";
|
|
1372
1363
|
import os2 from "node:os";
|
|
1373
1364
|
import path11 from "node:path";
|
|
1374
|
-
import { promisify as
|
|
1365
|
+
import { promisify as promisify3 } from "node:util";
|
|
1375
1366
|
|
|
1376
1367
|
// src/commands/stop-hook.ts
|
|
1377
1368
|
import fsSync from "node:fs";
|
|
@@ -1469,17 +1460,13 @@ class CursorStopHookAdapter {
|
|
|
1469
1460
|
}
|
|
1470
1461
|
|
|
1471
1462
|
// src/hooks/stop-hook-handler.ts
|
|
1472
|
-
import { execFile } from "node:child_process";
|
|
1473
1463
|
import fs10 from "node:fs/promises";
|
|
1474
1464
|
import path9 from "node:path";
|
|
1475
|
-
import { promisify as promisify3 } from "node:util";
|
|
1476
1465
|
import YAML3 from "yaml";
|
|
1477
1466
|
|
|
1478
1467
|
// src/config/stop-hook-config.ts
|
|
1479
1468
|
var GAUNTLET_STOP_HOOK_ENABLED = "GAUNTLET_STOP_HOOK_ENABLED";
|
|
1480
1469
|
var GAUNTLET_STOP_HOOK_INTERVAL_MINUTES = "GAUNTLET_STOP_HOOK_INTERVAL_MINUTES";
|
|
1481
|
-
var GAUNTLET_AUTO_PUSH_PR = "GAUNTLET_AUTO_PUSH_PR";
|
|
1482
|
-
var GAUNTLET_AUTO_FIX_PR = "GAUNTLET_AUTO_FIX_PR";
|
|
1483
1470
|
function parseBooleanEnv(envVar) {
|
|
1484
1471
|
if (envVar === undefined)
|
|
1485
1472
|
return;
|
|
@@ -1503,9 +1490,7 @@ function parseIntegerEnv(envVar) {
|
|
|
1503
1490
|
function parseStopHookEnvVars() {
|
|
1504
1491
|
return {
|
|
1505
1492
|
enabled: parseBooleanEnv(process.env[GAUNTLET_STOP_HOOK_ENABLED]),
|
|
1506
|
-
run_interval_minutes: parseIntegerEnv(process.env[GAUNTLET_STOP_HOOK_INTERVAL_MINUTES])
|
|
1507
|
-
auto_push_pr: parseBooleanEnv(process.env[GAUNTLET_AUTO_PUSH_PR]),
|
|
1508
|
-
auto_fix_pr: parseBooleanEnv(process.env[GAUNTLET_AUTO_FIX_PR])
|
|
1493
|
+
run_interval_minutes: parseIntegerEnv(process.env[GAUNTLET_STOP_HOOK_INTERVAL_MINUTES])
|
|
1509
1494
|
};
|
|
1510
1495
|
}
|
|
1511
1496
|
function resolveField(envValue, projectValue, globalValue) {
|
|
@@ -1520,13 +1505,7 @@ function resolveStopHookConfig(projectConfig, globalConfig) {
|
|
|
1520
1505
|
const globalStop = globalConfig.stop_hook;
|
|
1521
1506
|
const enabled = resolveField(envVars.enabled, projectConfig?.enabled, globalStop.enabled);
|
|
1522
1507
|
const run_interval_minutes = resolveField(envVars.run_interval_minutes, projectConfig?.run_interval_minutes, globalStop.run_interval_minutes);
|
|
1523
|
-
|
|
1524
|
-
let auto_fix_pr = resolveField(envVars.auto_fix_pr, projectConfig?.auto_fix_pr, globalStop.auto_fix_pr);
|
|
1525
|
-
if (auto_fix_pr && !auto_push_pr) {
|
|
1526
|
-
console.error("[gauntlet] Warning: auto_fix_pr=true requires auto_push_pr=true. Treating auto_fix_pr as false.");
|
|
1527
|
-
auto_fix_pr = false;
|
|
1528
|
-
}
|
|
1529
|
-
return { enabled, run_interval_minutes, auto_push_pr, auto_fix_pr };
|
|
1508
|
+
return { enabled, run_interval_minutes };
|
|
1530
1509
|
}
|
|
1531
1510
|
|
|
1532
1511
|
// src/output/app-logger.ts
|
|
@@ -2214,12 +2193,6 @@ async function hasChangesVsBaseBranch(cwd, baseBranch) {
|
|
|
2214
2193
|
return true;
|
|
2215
2194
|
}
|
|
2216
2195
|
}
|
|
2217
|
-
async function getLastRunStatus(logDir) {
|
|
2218
|
-
const state = await readExecutionState(logDir);
|
|
2219
|
-
if (!state)
|
|
2220
|
-
return null;
|
|
2221
|
-
return null;
|
|
2222
|
-
}
|
|
2223
2196
|
async function readBlockTimestamps(logDir) {
|
|
2224
2197
|
try {
|
|
2225
2198
|
const filePath = path8.join(logDir, BLOCK_TIMESTAMPS_FILE);
|
|
@@ -2254,14 +2227,9 @@ async function resetBlockTimestamps(logDir) {
|
|
|
2254
2227
|
}
|
|
2255
2228
|
|
|
2256
2229
|
// src/hooks/stop-hook-handler.ts
|
|
2257
|
-
var execFileAsync = promisify3(execFile);
|
|
2258
2230
|
var DEFAULT_LOG_DIR = "gauntlet_logs";
|
|
2259
2231
|
var SKILL_INSTRUCTIONS = {
|
|
2260
|
-
validation_required: "Changes detected, you must use the `gauntlet-run` skill to validate them now."
|
|
2261
|
-
pr_push_required: "Gauntlet passed. You must use the `gauntlet-push-pr` skill to create or update your pull request.",
|
|
2262
|
-
pr_push_required_with_warnings: "Gauntlet passed with warnings (some issues were skipped). You must use the `gauntlet-push-pr` skill to create or update your pull request. Include a summary of skipped issues in the PR description.",
|
|
2263
|
-
ci_pending: "PR is up to date but CI checks are still running. You must use the `gauntlet-fix-pr` skill to poll CI status until checks complete, then fix any failures.",
|
|
2264
|
-
ci_failed: "PR is up to date but CI checks have failed. You must use the `gauntlet-fix-pr` skill to check which CI checks failed, fix the issues, and push."
|
|
2232
|
+
validation_required: "Changes detected, you must use the `gauntlet-run` skill to validate them now."
|
|
2265
2233
|
};
|
|
2266
2234
|
async function readProjectConfig(projectCwd) {
|
|
2267
2235
|
try {
|
|
@@ -2283,10 +2251,6 @@ var STATUS_MESSAGES = {
|
|
|
2283
2251
|
retry_limit_exceeded: "⚠ Gauntlet terminated — retry limit exceeded. Run `agent-gauntlet clean` to archive and continue.",
|
|
2284
2252
|
lock_conflict: "⏭ Gauntlet skipped — another gauntlet run is already in progress.",
|
|
2285
2253
|
failed: "✗ Gauntlet failed — issues must be fixed before stopping.",
|
|
2286
|
-
pr_push_required: "✓ Gauntlet passed — PR needs to be created or updated before stopping.",
|
|
2287
|
-
ci_pending: "⏳ CI checks still running — waiting for completion.",
|
|
2288
|
-
ci_failed: "✗ CI failed or review changes requested — fix issues and push.",
|
|
2289
|
-
ci_passed: "✓ CI passed — all checks completed and no blocking reviews.",
|
|
2290
2254
|
validation_required: "✗ Validation required — changes detected that need validation before stopping.",
|
|
2291
2255
|
no_config: "○ Not a gauntlet project — no .gauntlet/config.yml found.",
|
|
2292
2256
|
stop_hook_active: "↺ Stop hook cycle detected — allowing stop to prevent infinite loop.",
|
|
@@ -2323,71 +2287,6 @@ async function getResolvedStopHookConfig(projectCwd) {
|
|
|
2323
2287
|
return null;
|
|
2324
2288
|
}
|
|
2325
2289
|
}
|
|
2326
|
-
async function checkPRStatus(cwd) {
|
|
2327
|
-
try {
|
|
2328
|
-
try {
|
|
2329
|
-
await execFileAsync("gh", ["--version"], { cwd });
|
|
2330
|
-
} catch {
|
|
2331
|
-
return {
|
|
2332
|
-
prExists: false,
|
|
2333
|
-
upToDate: false,
|
|
2334
|
-
error: "gh CLI not installed"
|
|
2335
|
-
};
|
|
2336
|
-
}
|
|
2337
|
-
let prInfo;
|
|
2338
|
-
try {
|
|
2339
|
-
const { stdout } = await execFileAsync("gh", ["pr", "view", "--json", "number,state,headRefOid"], { cwd });
|
|
2340
|
-
prInfo = JSON.parse(stdout.trim());
|
|
2341
|
-
} catch (e) {
|
|
2342
|
-
const errMsg = e.message ?? "unknown";
|
|
2343
|
-
if (errMsg.includes("no pull requests found") || errMsg.includes("Could not resolve")) {
|
|
2344
|
-
return { prExists: false, upToDate: false };
|
|
2345
|
-
}
|
|
2346
|
-
return {
|
|
2347
|
-
prExists: false,
|
|
2348
|
-
upToDate: false,
|
|
2349
|
-
error: `gh pr view failed: ${errMsg}`
|
|
2350
|
-
};
|
|
2351
|
-
}
|
|
2352
|
-
if (prInfo.state !== "OPEN") {
|
|
2353
|
-
return { prExists: false, upToDate: false };
|
|
2354
|
-
}
|
|
2355
|
-
const { stdout: localHead } = await execFileAsync("git", ["rev-parse", "HEAD"], { cwd });
|
|
2356
|
-
const localSha = localHead.trim();
|
|
2357
|
-
const upToDate = prInfo.headRefOid === localSha;
|
|
2358
|
-
return {
|
|
2359
|
-
prExists: true,
|
|
2360
|
-
upToDate,
|
|
2361
|
-
prNumber: prInfo.number
|
|
2362
|
-
};
|
|
2363
|
-
} catch (error) {
|
|
2364
|
-
const errMsg = error.message ?? "unknown";
|
|
2365
|
-
return {
|
|
2366
|
-
prExists: false,
|
|
2367
|
-
upToDate: false,
|
|
2368
|
-
error: `PR status check failed: ${errMsg}`
|
|
2369
|
-
};
|
|
2370
|
-
}
|
|
2371
|
-
}
|
|
2372
|
-
async function checkCIStatus(cwd) {
|
|
2373
|
-
try {
|
|
2374
|
-
const { stdout } = await execFileAsync("gh", ["pr", "checks", "--json", "name,state"], { cwd });
|
|
2375
|
-
const checks = JSON.parse(stdout.trim());
|
|
2376
|
-
if (checks.length === 0) {
|
|
2377
|
-
return { status: "passed" };
|
|
2378
|
-
}
|
|
2379
|
-
const hasFailed = checks.some((c) => c.state === "FAILURE" || c.state === "ERROR");
|
|
2380
|
-
if (hasFailed)
|
|
2381
|
-
return { status: "failed" };
|
|
2382
|
-
const hasPending = checks.some((c) => c.state === "PENDING" || c.state === "EXPECTED");
|
|
2383
|
-
if (hasPending)
|
|
2384
|
-
return { status: "pending" };
|
|
2385
|
-
return { status: "passed" };
|
|
2386
|
-
} catch (e) {
|
|
2387
|
-
const errMsg = e.message ?? "unknown";
|
|
2388
|
-
return { status: "error", error: errMsg };
|
|
2389
|
-
}
|
|
2390
|
-
}
|
|
2391
2290
|
|
|
2392
2291
|
class StopHookHandler {
|
|
2393
2292
|
debugLogger;
|
|
@@ -2425,9 +2324,6 @@ class StopHookHandler {
|
|
|
2425
2324
|
const changesResult = await this.checkForChanges(hctx);
|
|
2426
2325
|
if (changesResult)
|
|
2427
2326
|
return changesResult;
|
|
2428
|
-
const prCiResult = await this.checkPRAndCI(hctx, config);
|
|
2429
|
-
if (prCiResult)
|
|
2430
|
-
return prCiResult;
|
|
2431
2327
|
hctx.log.info("All checks passed — allowing stop");
|
|
2432
2328
|
return this.allow("passed");
|
|
2433
2329
|
}
|
|
@@ -2463,44 +2359,6 @@ class StopHookHandler {
|
|
|
2463
2359
|
}
|
|
2464
2360
|
return null;
|
|
2465
2361
|
}
|
|
2466
|
-
async checkPRAndCI(hctx, config) {
|
|
2467
|
-
if (!config?.auto_push_pr)
|
|
2468
|
-
return null;
|
|
2469
|
-
const prStatus = await checkPRStatus(hctx.cwd);
|
|
2470
|
-
if (prStatus.error) {
|
|
2471
|
-
hctx.log.warn(`PR status check failed: ${prStatus.error} — allowing stop`);
|
|
2472
|
-
return null;
|
|
2473
|
-
}
|
|
2474
|
-
if (!(prStatus.prExists && prStatus.upToDate)) {
|
|
2475
|
-
hctx.log.info("PR missing or outdated — blocking with pr_push_required");
|
|
2476
|
-
return this.blockForPR(hctx);
|
|
2477
|
-
}
|
|
2478
|
-
if (!config?.auto_fix_pr)
|
|
2479
|
-
return null;
|
|
2480
|
-
return this.checkCI(hctx);
|
|
2481
|
-
}
|
|
2482
|
-
async blockForPR(hctx) {
|
|
2483
|
-
const lastStatus = await getLastRunStatus(hctx.logDir);
|
|
2484
|
-
const instruction = lastStatus === "passed_with_warnings" ? SKILL_INSTRUCTIONS.pr_push_required_with_warnings : SKILL_INSTRUCTIONS.pr_push_required;
|
|
2485
|
-
return this.block("pr_push_required", instruction);
|
|
2486
|
-
}
|
|
2487
|
-
async checkCI(hctx) {
|
|
2488
|
-
const ciResult = await checkCIStatus(hctx.cwd);
|
|
2489
|
-
if (ciResult.status === "error") {
|
|
2490
|
-
hctx.log.warn(`CI status check failed: ${ciResult.error} — allowing stop`);
|
|
2491
|
-
return null;
|
|
2492
|
-
}
|
|
2493
|
-
if (ciResult.status === "pending") {
|
|
2494
|
-
hctx.log.info("CI pending — blocking");
|
|
2495
|
-
return this.block("ci_pending", SKILL_INSTRUCTIONS.ci_pending);
|
|
2496
|
-
}
|
|
2497
|
-
if (ciResult.status === "failed") {
|
|
2498
|
-
hctx.log.info("CI failed — blocking");
|
|
2499
|
-
return this.block("ci_failed", SKILL_INSTRUCTIONS.ci_failed);
|
|
2500
|
-
}
|
|
2501
|
-
hctx.log.info("CI passed — allowing stop");
|
|
2502
|
-
return this.allow("ci_passed");
|
|
2503
|
-
}
|
|
2504
2362
|
async block(status, reason) {
|
|
2505
2363
|
await this.debugLogger?.logStopHook("block", status);
|
|
2506
2364
|
return {
|
|
@@ -2523,7 +2381,7 @@ class StopHookHandler {
|
|
|
2523
2381
|
|
|
2524
2382
|
// src/types/gauntlet-status.ts
|
|
2525
2383
|
function isSuccessStatus(status) {
|
|
2526
|
-
return status === "passed" || status === "passed_with_warnings" || status === "no_applicable_gates" || status === "no_changes"
|
|
2384
|
+
return status === "passed" || status === "passed_with_warnings" || status === "no_applicable_gates" || status === "no_changes";
|
|
2527
2385
|
}
|
|
2528
2386
|
|
|
2529
2387
|
// src/commands/stop-hook.ts
|
|
@@ -2839,7 +2697,7 @@ var GEMINI_THINKING_BUDGET = {
|
|
|
2839
2697
|
};
|
|
2840
2698
|
|
|
2841
2699
|
// src/cli-adapters/claude.ts
|
|
2842
|
-
var execAsync3 =
|
|
2700
|
+
var execAsync3 = promisify3(exec3);
|
|
2843
2701
|
function countBraceChange(line) {
|
|
2844
2702
|
const stripped = line.replace(/\\./g, "").replace(/"[^"]*"/g, "").replace(/'[^']*'/g, "");
|
|
2845
2703
|
let depth = 0;
|
|
@@ -3154,8 +3012,8 @@ import { exec as exec4 } from "node:child_process";
|
|
|
3154
3012
|
import fs13 from "node:fs/promises";
|
|
3155
3013
|
import os3 from "node:os";
|
|
3156
3014
|
import path12 from "node:path";
|
|
3157
|
-
import { promisify as
|
|
3158
|
-
var execAsync4 =
|
|
3015
|
+
import { promisify as promisify4 } from "node:util";
|
|
3016
|
+
var execAsync4 = promisify4(exec4);
|
|
3159
3017
|
function parseJsonlLine(line) {
|
|
3160
3018
|
try {
|
|
3161
3019
|
const obj = JSON.parse(line);
|
|
@@ -3356,7 +3214,7 @@ import { exec as exec5 } from "node:child_process";
|
|
|
3356
3214
|
import fs14 from "node:fs/promises";
|
|
3357
3215
|
import os4 from "node:os";
|
|
3358
3216
|
import path13 from "node:path";
|
|
3359
|
-
import { promisify as
|
|
3217
|
+
import { promisify as promisify5 } from "node:util";
|
|
3360
3218
|
|
|
3361
3219
|
// src/cli-adapters/model-resolution.ts
|
|
3362
3220
|
var TIER_SUFFIXES = ["-low", "-high", "-xhigh", "-fast"];
|
|
@@ -3395,7 +3253,7 @@ function resolveModelFromList(allModels, opts) {
|
|
|
3395
3253
|
}
|
|
3396
3254
|
|
|
3397
3255
|
// src/cli-adapters/cursor.ts
|
|
3398
|
-
var execAsync5 =
|
|
3256
|
+
var execAsync5 = promisify5(exec5);
|
|
3399
3257
|
var log = getCategoryLogger("cursor");
|
|
3400
3258
|
function parseModelList(output) {
|
|
3401
3259
|
return output.split(`
|
|
@@ -3526,8 +3384,8 @@ import { exec as exec6 } from "node:child_process";
|
|
|
3526
3384
|
import fs15 from "node:fs/promises";
|
|
3527
3385
|
import os5 from "node:os";
|
|
3528
3386
|
import path14 from "node:path";
|
|
3529
|
-
import { promisify as
|
|
3530
|
-
var execAsync6 =
|
|
3387
|
+
import { promisify as promisify6 } from "node:util";
|
|
3388
|
+
var execAsync6 = promisify6(exec6);
|
|
3531
3389
|
var TOKEN_TYPE_MAP = {
|
|
3532
3390
|
input: "inputTokens",
|
|
3533
3391
|
output: "outputTokens",
|
|
@@ -3887,8 +3745,8 @@ import { exec as exec7 } from "node:child_process";
|
|
|
3887
3745
|
import fs16 from "node:fs/promises";
|
|
3888
3746
|
import os6 from "node:os";
|
|
3889
3747
|
import path15 from "node:path";
|
|
3890
|
-
import { promisify as
|
|
3891
|
-
var execAsync7 =
|
|
3748
|
+
import { promisify as promisify7 } from "node:util";
|
|
3749
|
+
var execAsync7 = promisify7(exec7);
|
|
3892
3750
|
var log2 = getCategoryLogger("github-copilot");
|
|
3893
3751
|
function parseCopilotModels(helpOutput) {
|
|
3894
3752
|
const match = helpOutput.match(/choices:\s*(.+?)\)/);
|
|
@@ -4210,9 +4068,9 @@ async function handleCriticalError(error, jobId, startTime, logPaths, mainLogger
|
|
|
4210
4068
|
|
|
4211
4069
|
// src/gates/review-diff.ts
|
|
4212
4070
|
import { exec as exec8 } from "node:child_process";
|
|
4213
|
-
import { promisify as
|
|
4071
|
+
import { promisify as promisify8 } from "node:util";
|
|
4214
4072
|
var log4 = getCategoryLogger("gate", "review");
|
|
4215
|
-
var execAsync8 =
|
|
4073
|
+
var execAsync8 = promisify8(exec8);
|
|
4216
4074
|
function parseLines(stdout) {
|
|
4217
4075
|
return stdout.split(`
|
|
4218
4076
|
`).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
@@ -6156,7 +6014,6 @@ ${chalk2.bold(SEPARATOR)}`);
|
|
|
6156
6014
|
}
|
|
6157
6015
|
const { overallStatus, statusColor } = computeOverallStatus(results, statusOverride);
|
|
6158
6016
|
console.error(statusColor(`Status: ${overallStatus}`));
|
|
6159
|
-
console.log(`Status: ${overallStatus}`);
|
|
6160
6017
|
console.error(chalk2.bold(`${SEPARATOR}
|
|
6161
6018
|
`));
|
|
6162
6019
|
}
|
|
@@ -8170,20 +8027,10 @@ var SKILLS_SOURCE_DIR = (() => {
|
|
|
8170
8027
|
throw err;
|
|
8171
8028
|
}
|
|
8172
8029
|
})();
|
|
8173
|
-
var SKILL_ACTIONS = [
|
|
8174
|
-
"run",
|
|
8175
|
-
"check",
|
|
8176
|
-
"push-pr",
|
|
8177
|
-
"fix-pr",
|
|
8178
|
-
"status",
|
|
8179
|
-
"help",
|
|
8180
|
-
"setup"
|
|
8181
|
-
];
|
|
8030
|
+
var SKILL_ACTIONS = ["run", "check", "status", "help", "setup"];
|
|
8182
8031
|
var SKILL_DESCRIPTIONS = {
|
|
8183
8032
|
run: "Run the verification suite",
|
|
8184
8033
|
check: "Run checks only (no reviews)",
|
|
8185
|
-
"push-pr": "Commit, push, and create a PR",
|
|
8186
|
-
"fix-pr": "Fix PR review comments and CI failures",
|
|
8187
8034
|
status: "Show gauntlet status",
|
|
8188
8035
|
help: "Diagnose and explain gauntlet behavior",
|
|
8189
8036
|
setup: "Configure checks and reviews interactively"
|
|
@@ -8366,13 +8213,10 @@ entry_points: []
|
|
|
8366
8213
|
|
|
8367
8214
|
# Stop hook — auto-run gauntlet when the agent stops
|
|
8368
8215
|
# Precedence: env vars > project config > global config (~/.config/agent-gauntlet/config.yml)
|
|
8369
|
-
# Env overrides: GAUNTLET_STOP_HOOK_ENABLED, GAUNTLET_STOP_HOOK_INTERVAL_MINUTES
|
|
8370
|
-
# GAUNTLET_AUTO_PUSH_PR, GAUNTLET_AUTO_FIX_PR
|
|
8216
|
+
# Env overrides: GAUNTLET_STOP_HOOK_ENABLED, GAUNTLET_STOP_HOOK_INTERVAL_MINUTES
|
|
8371
8217
|
# stop_hook:
|
|
8372
8218
|
# enabled: false
|
|
8373
8219
|
# run_interval_minutes: 5 # Minimum minutes between runs (0 = always run)
|
|
8374
|
-
# auto_push_pr: false # Check/create PR after gates pass
|
|
8375
|
-
# auto_fix_pr: false # Wait for CI checks after PR (requires auto_push_pr)
|
|
8376
8220
|
|
|
8377
8221
|
# Debug log — persistent debug logging to .debug.log
|
|
8378
8222
|
# debug_log:
|
|
@@ -8502,12 +8346,12 @@ function registerReviewCommand(program) {
|
|
|
8502
8346
|
program.command("review").description("Run only applicable reviews for detected changes").option("-b, --base-branch <branch>", "Override base branch for change detection").option("-g, --gate <name>", "Run specific review gate only").option("-c, --commit <sha>", "Use diff for a specific commit").option("-u, --uncommitted", "Use diff for current uncommitted changes (staged and unstaged)").action((options) => executeGateCommand("review", options));
|
|
8503
8347
|
}
|
|
8504
8348
|
// src/core/diff-stats.ts
|
|
8505
|
-
import { execFile
|
|
8506
|
-
import { promisify as
|
|
8507
|
-
var execFileAsyncOriginal =
|
|
8508
|
-
var
|
|
8349
|
+
import { execFile } from "node:child_process";
|
|
8350
|
+
import { promisify as promisify9 } from "node:util";
|
|
8351
|
+
var execFileAsyncOriginal = promisify9(execFile);
|
|
8352
|
+
var execFileAsync = execFileAsyncOriginal;
|
|
8509
8353
|
async function gitExec(args) {
|
|
8510
|
-
const { stdout } = await
|
|
8354
|
+
const { stdout } = await execFileAsync("git", args);
|
|
8511
8355
|
return stdout;
|
|
8512
8356
|
}
|
|
8513
8357
|
async function computeDiffStats(baseBranch, options = {}) {
|
|
@@ -8891,10 +8735,6 @@ var statusMessages = {
|
|
|
8891
8735
|
interval_not_elapsed: "Run interval not elapsed.",
|
|
8892
8736
|
invalid_input: "Invalid input.",
|
|
8893
8737
|
stop_hook_disabled: "",
|
|
8894
|
-
pr_push_required: "Gates passed -- PR needs to be created/updated.",
|
|
8895
|
-
ci_pending: "CI checks still running.",
|
|
8896
|
-
ci_failed: "CI checks failed or review changes requested.",
|
|
8897
|
-
ci_passed: "CI checks passed, no blocking reviews.",
|
|
8898
8738
|
validation_required: "Changes need validation or previous run has unresolved failures."
|
|
8899
8739
|
};
|
|
8900
8740
|
function getStatusMessage2(status) {
|
|
@@ -9238,7 +9078,39 @@ function registerRunCommand(program) {
|
|
|
9238
9078
|
commit: options.commit,
|
|
9239
9079
|
uncommitted: options.uncommitted
|
|
9240
9080
|
});
|
|
9241
|
-
|
|
9081
|
+
const code = isSuccessStatus(result.status) ? 0 : 1;
|
|
9082
|
+
process.exit(code);
|
|
9083
|
+
});
|
|
9084
|
+
}
|
|
9085
|
+
// src/commands/skip.ts
|
|
9086
|
+
import chalk13 from "chalk";
|
|
9087
|
+
function registerSkipCommand(program) {
|
|
9088
|
+
program.command("skip").description("Advance execution state baseline without running gates").action(async () => {
|
|
9089
|
+
let config;
|
|
9090
|
+
let lockAcquired = false;
|
|
9091
|
+
try {
|
|
9092
|
+
config = await loadConfig();
|
|
9093
|
+
const globalConfig = await loadGlobalConfig();
|
|
9094
|
+
const debugLogConfig = mergeDebugLogConfig(config.project.debug_log, globalConfig.debug_log);
|
|
9095
|
+
initDebugLogger(config.project.log_dir, debugLogConfig);
|
|
9096
|
+
await acquireLock(config.project.log_dir);
|
|
9097
|
+
lockAcquired = true;
|
|
9098
|
+
const debugLogger = getDebugLogger();
|
|
9099
|
+
await debugLogger?.logCommand("skip", []);
|
|
9100
|
+
await cleanLogs(config.project.log_dir, config.project.max_previous_logs);
|
|
9101
|
+
await writeExecutionState(config.project.log_dir);
|
|
9102
|
+
const commit = await getCurrentCommit();
|
|
9103
|
+
const shortSha = commit.slice(0, 7);
|
|
9104
|
+
await releaseLock(config.project.log_dir);
|
|
9105
|
+
console.log(chalk13.green(`Baseline advanced to ${shortSha}. Next run will diff from here.`));
|
|
9106
|
+
} catch (error) {
|
|
9107
|
+
if (config && lockAcquired) {
|
|
9108
|
+
await releaseLock(config.project.log_dir);
|
|
9109
|
+
}
|
|
9110
|
+
const err = error;
|
|
9111
|
+
console.error(chalk13.red("Error:"), err.message);
|
|
9112
|
+
process.exit(1);
|
|
9113
|
+
}
|
|
9242
9114
|
});
|
|
9243
9115
|
}
|
|
9244
9116
|
// src/commands/start-hook.ts
|
|
@@ -9321,285 +9193,20 @@ function registerStatusCommand(program) {
|
|
|
9321
9193
|
});
|
|
9322
9194
|
}
|
|
9323
9195
|
// src/commands/validate.ts
|
|
9324
|
-
import
|
|
9196
|
+
import chalk14 from "chalk";
|
|
9325
9197
|
function registerValidateCommand(program) {
|
|
9326
9198
|
program.command("validate").description("Validate .gauntlet/ config files against schemas").action(async () => {
|
|
9327
9199
|
try {
|
|
9328
9200
|
await loadConfig();
|
|
9329
|
-
console.log(
|
|
9201
|
+
console.log(chalk14.green("All config files are valid."));
|
|
9330
9202
|
process.exitCode = 0;
|
|
9331
9203
|
} catch (error) {
|
|
9332
9204
|
const message = error instanceof Error ? error.message : String(error);
|
|
9333
|
-
console.error(
|
|
9205
|
+
console.error(chalk14.red("Validation failed:"), message);
|
|
9334
9206
|
process.exitCode = 1;
|
|
9335
9207
|
}
|
|
9336
9208
|
});
|
|
9337
9209
|
}
|
|
9338
|
-
// src/commands/wait-ci.ts
|
|
9339
|
-
import { spawn as spawn3 } from "node:child_process";
|
|
9340
|
-
async function isGhAvailable() {
|
|
9341
|
-
return new Promise((resolve) => {
|
|
9342
|
-
const proc = spawn3("gh", ["--version"], { stdio: "pipe" });
|
|
9343
|
-
proc.on("close", (code) => resolve(code === 0));
|
|
9344
|
-
proc.on("error", () => resolve(false));
|
|
9345
|
-
});
|
|
9346
|
-
}
|
|
9347
|
-
async function runGh(args, cwd) {
|
|
9348
|
-
return new Promise((resolve) => {
|
|
9349
|
-
const proc = spawn3("gh", args, { stdio: "pipe", cwd });
|
|
9350
|
-
let stdout = "";
|
|
9351
|
-
let stderr = "";
|
|
9352
|
-
proc.stdout.on("data", (data) => {
|
|
9353
|
-
stdout += data.toString();
|
|
9354
|
-
});
|
|
9355
|
-
proc.stderr.on("data", (data) => {
|
|
9356
|
-
stderr += data.toString();
|
|
9357
|
-
});
|
|
9358
|
-
proc.on("close", (code) => {
|
|
9359
|
-
resolve({ code: code ?? 1, stdout, stderr });
|
|
9360
|
-
});
|
|
9361
|
-
proc.on("error", (err) => {
|
|
9362
|
-
resolve({ code: 1, stdout: "", stderr: err.message });
|
|
9363
|
-
});
|
|
9364
|
-
});
|
|
9365
|
-
}
|
|
9366
|
-
async function getPRInfo(cwd) {
|
|
9367
|
-
const result = await runGh(["pr", "view", "--json", "number,url,headRefName"], cwd);
|
|
9368
|
-
if (result.code !== 0) {
|
|
9369
|
-
return null;
|
|
9370
|
-
}
|
|
9371
|
-
try {
|
|
9372
|
-
return JSON.parse(result.stdout.trim());
|
|
9373
|
-
} catch {
|
|
9374
|
-
return null;
|
|
9375
|
-
}
|
|
9376
|
-
}
|
|
9377
|
-
async function getChecks(cwd) {
|
|
9378
|
-
const result = await runGh(["pr", "checks", "--json", "name,state,link"], cwd);
|
|
9379
|
-
const output = result.stdout.trim();
|
|
9380
|
-
if (!output) {
|
|
9381
|
-
return result.code === 0 ? [] : null;
|
|
9382
|
-
}
|
|
9383
|
-
try {
|
|
9384
|
-
return JSON.parse(output) || [];
|
|
9385
|
-
} catch {
|
|
9386
|
-
return result.code === 0 ? [] : null;
|
|
9387
|
-
}
|
|
9388
|
-
}
|
|
9389
|
-
async function getReviews(prNumber, cwd) {
|
|
9390
|
-
const repoResult = await runGh(["repo", "view", "--json", "owner,name"], cwd);
|
|
9391
|
-
if (repoResult.code !== 0) {
|
|
9392
|
-
return null;
|
|
9393
|
-
}
|
|
9394
|
-
let owner;
|
|
9395
|
-
let repo;
|
|
9396
|
-
try {
|
|
9397
|
-
const repoInfo = JSON.parse(repoResult.stdout.trim());
|
|
9398
|
-
owner = repoInfo.owner.login;
|
|
9399
|
-
repo = repoInfo.name;
|
|
9400
|
-
} catch {
|
|
9401
|
-
return null;
|
|
9402
|
-
}
|
|
9403
|
-
const result = await runGh([
|
|
9404
|
-
"api",
|
|
9405
|
-
"--paginate",
|
|
9406
|
-
`repos/${owner}/${repo}/pulls/${prNumber}/reviews?per_page=100`
|
|
9407
|
-
], cwd);
|
|
9408
|
-
if (result.code !== 0) {
|
|
9409
|
-
return null;
|
|
9410
|
-
}
|
|
9411
|
-
try {
|
|
9412
|
-
const rawReviews = JSON.parse(result.stdout.trim()) || [];
|
|
9413
|
-
return rawReviews.filter((r) => r.user?.login).map((r) => ({
|
|
9414
|
-
author: { login: r.user.login },
|
|
9415
|
-
state: r.state,
|
|
9416
|
-
body: r.body || ""
|
|
9417
|
-
}));
|
|
9418
|
-
} catch {
|
|
9419
|
-
return null;
|
|
9420
|
-
}
|
|
9421
|
-
}
|
|
9422
|
-
function getLatestReviewsByAuthor(reviews) {
|
|
9423
|
-
const latestByAuthor = new Map;
|
|
9424
|
-
for (const review of reviews) {
|
|
9425
|
-
latestByAuthor.set(review.author.login, review);
|
|
9426
|
-
}
|
|
9427
|
-
return Array.from(latestByAuthor.values());
|
|
9428
|
-
}
|
|
9429
|
-
function sleep(ms) {
|
|
9430
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
9431
|
-
}
|
|
9432
|
-
function extractRunId(link) {
|
|
9433
|
-
const match = link.match(/\/actions\/runs\/(\d+)/);
|
|
9434
|
-
return match?.[1] ?? null;
|
|
9435
|
-
}
|
|
9436
|
-
async function getFailedRunLogs(runId, cwd) {
|
|
9437
|
-
const result = await runGh(["run", "view", runId, "--log-failed"], cwd);
|
|
9438
|
-
if (result.code !== 0 || !result.stdout.trim()) {
|
|
9439
|
-
return null;
|
|
9440
|
-
}
|
|
9441
|
-
const lines = result.stdout.trim().split(`
|
|
9442
|
-
`);
|
|
9443
|
-
const maxLines = 100;
|
|
9444
|
-
if (lines.length > maxLines) {
|
|
9445
|
-
return `... (${lines.length - maxLines} lines truncated)
|
|
9446
|
-
${lines.slice(-maxLines).join(`
|
|
9447
|
-
`)}`;
|
|
9448
|
-
}
|
|
9449
|
-
return result.stdout.trim();
|
|
9450
|
-
}
|
|
9451
|
-
function groupChecksByRunId(failedChecks) {
|
|
9452
|
-
const runIdToChecks = new Map;
|
|
9453
|
-
for (const check of failedChecks) {
|
|
9454
|
-
const runId = extractRunId(check.link);
|
|
9455
|
-
const key = runId ?? "";
|
|
9456
|
-
const existing = runIdToChecks.get(key) ?? [];
|
|
9457
|
-
existing.push(check);
|
|
9458
|
-
runIdToChecks.set(key, existing);
|
|
9459
|
-
}
|
|
9460
|
-
return runIdToChecks;
|
|
9461
|
-
}
|
|
9462
|
-
async function enrichFailedChecksWithLogs(failedChecks, cwd) {
|
|
9463
|
-
const runIdToChecks = groupChecksByRunId(failedChecks);
|
|
9464
|
-
const entries = Array.from(runIdToChecks.entries());
|
|
9465
|
-
const logResults = await Promise.all(entries.map(([runId]) => runId ? getFailedRunLogs(runId, cwd) : Promise.resolve(null)));
|
|
9466
|
-
const results = [];
|
|
9467
|
-
for (let i = 0;i < entries.length; i++) {
|
|
9468
|
-
const [, checks] = entries[i];
|
|
9469
|
-
const logs = logResults[i];
|
|
9470
|
-
for (const check of checks) {
|
|
9471
|
-
results.push({ ...check, log_output: logs ?? undefined });
|
|
9472
|
-
}
|
|
9473
|
-
}
|
|
9474
|
-
return results;
|
|
9475
|
-
}
|
|
9476
|
-
function createResult(opts) {
|
|
9477
|
-
const elapsed = Math.round((Date.now() - opts.startTime) / 1000);
|
|
9478
|
-
return {
|
|
9479
|
-
ci_status: opts.status,
|
|
9480
|
-
pr_number: opts.prInfo?.number,
|
|
9481
|
-
pr_url: opts.prInfo?.url,
|
|
9482
|
-
failed_checks: opts.failedChecks?.map((c) => ({
|
|
9483
|
-
name: c.name,
|
|
9484
|
-
conclusion: c.state.toLowerCase(),
|
|
9485
|
-
details_url: c.link,
|
|
9486
|
-
log_output: c.log_output
|
|
9487
|
-
})) || [],
|
|
9488
|
-
review_comments: opts.reviewComments || [],
|
|
9489
|
-
elapsed_seconds: elapsed,
|
|
9490
|
-
error_message: opts.errorMessage
|
|
9491
|
-
};
|
|
9492
|
-
}
|
|
9493
|
-
async function pollCIStatus(cwd, prNumber, isFirstPoll) {
|
|
9494
|
-
const checks = await getChecks(cwd);
|
|
9495
|
-
const reviews = await getReviews(prNumber, cwd);
|
|
9496
|
-
if (checks === null || reviews === null) {
|
|
9497
|
-
return { error: "Failed to fetch CI status or reviews from GitHub" };
|
|
9498
|
-
}
|
|
9499
|
-
if (checks.length === 0) {
|
|
9500
|
-
return isFirstPoll ? { noChecksYet: true } : { noChecksConfigured: true };
|
|
9501
|
-
}
|
|
9502
|
-
const latestReviews = getLatestReviewsByAuthor(reviews);
|
|
9503
|
-
const failedChecks = checks.filter((c) => c.state === "FAILURE");
|
|
9504
|
-
const blockingReviews = latestReviews.filter((r) => r.state === "CHANGES_REQUESTED");
|
|
9505
|
-
const reviewComments = blockingReviews.map((r) => ({
|
|
9506
|
-
author: r.author.login,
|
|
9507
|
-
body: r.body || ""
|
|
9508
|
-
}));
|
|
9509
|
-
const pendingChecks = checks.filter((c) => c.state === "PENDING" || c.state === "QUEUED" || c.state === "IN_PROGRESS");
|
|
9510
|
-
const shouldFail = failedChecks.length > 0 || blockingReviews.length > 0;
|
|
9511
|
-
const shouldPass = pendingChecks.length === 0;
|
|
9512
|
-
return { shouldFail, shouldPass, failedChecks, reviewComments };
|
|
9513
|
-
}
|
|
9514
|
-
async function waitForCI(timeoutSeconds, pollIntervalSeconds, cwd) {
|
|
9515
|
-
const startTime = Date.now();
|
|
9516
|
-
let isFirstPoll = true;
|
|
9517
|
-
if (!await isGhAvailable()) {
|
|
9518
|
-
return createResult({
|
|
9519
|
-
status: "error",
|
|
9520
|
-
startTime,
|
|
9521
|
-
errorMessage: "gh CLI is not installed or not authenticated"
|
|
9522
|
-
});
|
|
9523
|
-
}
|
|
9524
|
-
const prInfo = await getPRInfo(cwd);
|
|
9525
|
-
if (!prInfo) {
|
|
9526
|
-
return createResult({
|
|
9527
|
-
status: "error",
|
|
9528
|
-
startTime,
|
|
9529
|
-
errorMessage: "No PR found for current branch"
|
|
9530
|
-
});
|
|
9531
|
-
}
|
|
9532
|
-
const timeoutMs = timeoutSeconds * 1000;
|
|
9533
|
-
while (Date.now() - startTime < timeoutMs) {
|
|
9534
|
-
const pollOutcome = await pollCIStatus(cwd, prInfo.number, isFirstPoll);
|
|
9535
|
-
isFirstPoll = false;
|
|
9536
|
-
if (pollOutcome.error) {
|
|
9537
|
-
return createResult({
|
|
9538
|
-
status: "error",
|
|
9539
|
-
startTime,
|
|
9540
|
-
prInfo,
|
|
9541
|
-
errorMessage: pollOutcome.error
|
|
9542
|
-
});
|
|
9543
|
-
}
|
|
9544
|
-
if (pollOutcome.noChecksYet) {
|
|
9545
|
-
await sleep(pollIntervalSeconds * 1000);
|
|
9546
|
-
continue;
|
|
9547
|
-
}
|
|
9548
|
-
if (pollOutcome.noChecksConfigured) {
|
|
9549
|
-
return createResult({ status: "passed", startTime, prInfo });
|
|
9550
|
-
}
|
|
9551
|
-
if (pollOutcome.shouldFail && pollOutcome.failedChecks) {
|
|
9552
|
-
const enrichedChecks = await enrichFailedChecksWithLogs(pollOutcome.failedChecks, cwd);
|
|
9553
|
-
return createResult({
|
|
9554
|
-
status: "failed",
|
|
9555
|
-
startTime,
|
|
9556
|
-
prInfo,
|
|
9557
|
-
failedChecks: enrichedChecks,
|
|
9558
|
-
reviewComments: pollOutcome.reviewComments
|
|
9559
|
-
});
|
|
9560
|
-
}
|
|
9561
|
-
if (pollOutcome.shouldPass) {
|
|
9562
|
-
return createResult({ status: "passed", startTime, prInfo });
|
|
9563
|
-
}
|
|
9564
|
-
await sleep(pollIntervalSeconds * 1000);
|
|
9565
|
-
}
|
|
9566
|
-
return createResult({ status: "pending", startTime, prInfo });
|
|
9567
|
-
}
|
|
9568
|
-
function registerWaitCICommand(program) {
|
|
9569
|
-
program.command("wait-ci").description("Wait for CI checks to complete and check for blocking reviews").option("--timeout <seconds>", "Maximum time to wait for CI (default: 270)", "270").option("--poll-interval <seconds>", "Time between CI status checks (default: 15)", "15").action(async (options) => {
|
|
9570
|
-
const timeout = Number.parseInt(options.timeout, 10);
|
|
9571
|
-
const pollInterval = Number.parseInt(options.pollInterval, 10);
|
|
9572
|
-
if (Number.isNaN(timeout) || timeout <= 0) {
|
|
9573
|
-
console.log(JSON.stringify({
|
|
9574
|
-
ci_status: "error",
|
|
9575
|
-
failed_checks: [],
|
|
9576
|
-
review_comments: [],
|
|
9577
|
-
elapsed_seconds: 0,
|
|
9578
|
-
error_message: "Invalid timeout value"
|
|
9579
|
-
}));
|
|
9580
|
-
process.exit(1);
|
|
9581
|
-
}
|
|
9582
|
-
if (Number.isNaN(pollInterval) || pollInterval <= 0) {
|
|
9583
|
-
console.log(JSON.stringify({
|
|
9584
|
-
ci_status: "error",
|
|
9585
|
-
failed_checks: [],
|
|
9586
|
-
review_comments: [],
|
|
9587
|
-
elapsed_seconds: 0,
|
|
9588
|
-
error_message: "Invalid poll-interval value"
|
|
9589
|
-
}));
|
|
9590
|
-
process.exit(1);
|
|
9591
|
-
}
|
|
9592
|
-
const result = await waitForCI(timeout, pollInterval);
|
|
9593
|
-
console.log(JSON.stringify(result));
|
|
9594
|
-
if (result.ci_status === "passed") {
|
|
9595
|
-
process.exit(0);
|
|
9596
|
-
} else if (result.ci_status === "pending") {
|
|
9597
|
-
process.exit(2);
|
|
9598
|
-
} else {
|
|
9599
|
-
process.exit(1);
|
|
9600
|
-
}
|
|
9601
|
-
});
|
|
9602
|
-
}
|
|
9603
9210
|
// src/index.ts
|
|
9604
9211
|
var program = new Command;
|
|
9605
9212
|
program.name("agent-gauntlet").description("AI-assisted quality gates").version(package_default.version);
|
|
@@ -9613,14 +9220,14 @@ registerListCommand(program);
|
|
|
9613
9220
|
registerHealthCommand(program);
|
|
9614
9221
|
registerInitCommand(program);
|
|
9615
9222
|
registerValidateCommand(program);
|
|
9223
|
+
registerSkipCommand(program);
|
|
9616
9224
|
registerStartHookCommand(program);
|
|
9617
9225
|
registerStatusCommand(program);
|
|
9618
9226
|
registerStopHookCommand(program);
|
|
9619
|
-
registerWaitCICommand(program);
|
|
9620
9227
|
registerHelpCommand(program);
|
|
9621
9228
|
if (process.argv.length < 3) {
|
|
9622
9229
|
process.argv.push("help");
|
|
9623
9230
|
}
|
|
9624
9231
|
program.parse(process.argv);
|
|
9625
9232
|
|
|
9626
|
-
//# debugId=
|
|
9233
|
+
//# debugId=E93D541AB16DB2CC64756E2164756E21
|