@h-rig/cli 0.0.6-alpha.1 → 0.0.6-alpha.10

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.
@@ -2465,6 +2465,8 @@ function resolveSelectedConnection(projectRoot, options = {}) {
2465
2465
 
2466
2466
  // packages/cli/src/commands/_server-client.ts
2467
2467
  import { spawnSync } from "child_process";
2468
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
2469
+ import { resolve as resolve8 } from "path";
2468
2470
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
2469
2471
  var cachedGitHubBearerToken;
2470
2472
  function cleanToken(value) {
@@ -2474,9 +2476,25 @@ function cleanToken(value) {
2474
2476
  function setGitHubBearerTokenForCurrentProcess(token) {
2475
2477
  cachedGitHubBearerToken = cleanToken(token ?? undefined);
2476
2478
  }
2477
- function readGitHubBearerTokenForRemote() {
2479
+ function readPrivateRemoteSessionToken(projectRoot) {
2480
+ const path = resolve8(projectRoot, ".rig", "state", "github-auth.json");
2481
+ if (!existsSync4(path))
2482
+ return null;
2483
+ try {
2484
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
2485
+ return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
2486
+ } catch {
2487
+ return null;
2488
+ }
2489
+ }
2490
+ function readGitHubBearerTokenForRemote(projectRoot) {
2478
2491
  if (cachedGitHubBearerToken !== undefined)
2479
2492
  return cachedGitHubBearerToken;
2493
+ const privateSession = readPrivateRemoteSessionToken(projectRoot);
2494
+ if (privateSession) {
2495
+ cachedGitHubBearerToken = privateSession;
2496
+ return cachedGitHubBearerToken;
2497
+ }
2480
2498
  const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
2481
2499
  if (envToken) {
2482
2500
  cachedGitHubBearerToken = envToken;
@@ -2496,7 +2514,7 @@ async function ensureServerForCli(projectRoot) {
2496
2514
  if (selected?.connection.kind === "remote") {
2497
2515
  return {
2498
2516
  baseUrl: selected.connection.baseUrl,
2499
- authToken: readGitHubBearerTokenForRemote(),
2517
+ authToken: readGitHubBearerTokenForRemote(projectRoot),
2500
2518
  connectionKind: "remote"
2501
2519
  };
2502
2520
  }
@@ -2603,7 +2621,7 @@ async function postGitHubTokenViaServer(context, token, options = {}) {
2603
2621
  const payload = await requestServerJson(context, "/api/github/auth/token", {
2604
2622
  method: "POST",
2605
2623
  headers: { "content-type": "application/json" },
2606
- body: JSON.stringify({ token, selectedRepo: options.selectedRepo })
2624
+ body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot })
2607
2625
  });
2608
2626
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
2609
2627
  }
@@ -2624,7 +2642,7 @@ async function registerProjectViaServer(context, input) {
2624
2642
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
2625
2643
  }
2626
2644
  function sleep(ms) {
2627
- return new Promise((resolve8) => setTimeout(resolve8, ms));
2645
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
2628
2646
  }
2629
2647
  async function switchServerProjectRootViaServer(context, projectRoot, options = {}) {
2630
2648
  const switched = await requestServerJson(context, "/api/server/project-root", {
@@ -2715,9 +2733,9 @@ async function submitTaskRunViaServer(context, input) {
2715
2733
  }
2716
2734
 
2717
2735
  // packages/cli/src/commands/_pi-install.ts
2718
- import { existsSync as existsSync4, readFileSync as readFileSync3, rmSync as rmSync3 } from "fs";
2736
+ import { existsSync as existsSync5, readFileSync as readFileSync4, rmSync as rmSync3 } from "fs";
2719
2737
  import { homedir as homedir3 } from "os";
2720
- import { resolve as resolve8 } from "path";
2738
+ import { resolve as resolve9 } from "path";
2721
2739
  var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
2722
2740
  var LEGACY_PI_RIG_MARKER = `// Managed by Rig. Source package: @rig/pi-rig.
2723
2741
  export { default } from '@rig/pi-rig';
@@ -2732,11 +2750,11 @@ async function defaultCommandRunner(command, options = {}) {
2732
2750
  return { exitCode, stdout, stderr };
2733
2751
  }
2734
2752
  function resolvePiRigExtensionPath(homeDir) {
2735
- return resolve8(homeDir, ".pi", "agent", "extensions", "pi-rig");
2753
+ return resolve9(homeDir, ".pi", "agent", "extensions", "pi-rig");
2736
2754
  }
2737
- function resolvePiRigPackageSource(projectRoot, exists = existsSync4) {
2738
- const localPackage = resolve8(projectRoot, "packages", "pi-rig");
2739
- if (exists(resolve8(localPackage, "package.json")))
2755
+ function resolvePiRigPackageSource(projectRoot, exists = existsSync5) {
2756
+ const localPackage = resolve9(projectRoot, "packages", "pi-rig");
2757
+ if (exists(resolve9(localPackage, "package.json")))
2740
2758
  return localPackage;
2741
2759
  return `npm:${PI_RIG_PACKAGE_NAME}`;
2742
2760
  }
@@ -2787,13 +2805,13 @@ async function ensurePiBinaryAvailable(input) {
2787
2805
  ...next.exitCode === 0 ? {} : { error: (next.stderr || next.stdout).trim() || "pi --version failed after install" }
2788
2806
  };
2789
2807
  }
2790
- function removeManagedLegacyPiRigBridge(homeDir, exists = existsSync4) {
2808
+ function removeManagedLegacyPiRigBridge(homeDir, exists = existsSync5) {
2791
2809
  const extensionPath = resolvePiRigExtensionPath(homeDir);
2792
- const indexPath = resolve8(extensionPath, "index.ts");
2810
+ const indexPath = resolve9(extensionPath, "index.ts");
2793
2811
  if (!exists(indexPath))
2794
2812
  return;
2795
2813
  try {
2796
- const content = readFileSync3(indexPath, "utf8");
2814
+ const content = readFileSync4(indexPath, "utf8");
2797
2815
  if (content === LEGACY_PI_RIG_MARKER || content.includes("Managed by Rig. Source package: @rig/pi-rig")) {
2798
2816
  rmSync3(extensionPath, { recursive: true, force: true });
2799
2817
  }
@@ -2809,13 +2827,13 @@ async function checkPiRigInstall(input = {}) {
2809
2827
  piRig: { ok: true, label: "pi-rig global extension", detail: extensionPath }
2810
2828
  };
2811
2829
  }
2812
- const exists = input.exists ?? existsSync4;
2830
+ const exists = input.exists ?? existsSync5;
2813
2831
  const runner = input.commandRunner ?? defaultCommandRunner;
2814
2832
  const piResult = await safeRun(runner, ["pi", "--version"]);
2815
2833
  const piListResult = piResult.exitCode === 0 ? await safeRun(runner, ["pi", "list"]) : { exitCode: 1, stdout: "", stderr: "" };
2816
2834
  const listedPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
2817
2835
  ${piListResult.stderr}`);
2818
- const legacyBridge = exists(resolve8(extensionPath, "index.ts"));
2836
+ const legacyBridge = exists(resolve9(extensionPath, "index.ts"));
2819
2837
  const hasPiRig = listedPiRig;
2820
2838
  return {
2821
2839
  extensionPath,
@@ -3153,7 +3171,7 @@ async function executeQueue(context, args) {
3153
3171
  }
3154
3172
 
3155
3173
  // packages/cli/src/commands/agent.ts
3156
- import { resolve as resolve10 } from "path";
3174
+ import { resolve as resolve11 } from "path";
3157
3175
  import {
3158
3176
  agentId,
3159
3177
  cleanupAgentRuntime,
@@ -3163,8 +3181,8 @@ import {
3163
3181
  } from "@rig/runtime/control-plane/runtime/isolation";
3164
3182
 
3165
3183
  // packages/cli/src/commands/_authority-runs.ts
3166
- import { existsSync as existsSync5 } from "fs";
3167
- import { resolve as resolve9 } from "path";
3184
+ import { existsSync as existsSync6 } from "fs";
3185
+ import { resolve as resolve10 } from "path";
3168
3186
  import {
3169
3187
  readAuthorityRun,
3170
3188
  readJsonlFile as readJsonlFile2,
@@ -3186,8 +3204,8 @@ function normalizeRuntimeAdapter(value) {
3186
3204
  return "claude-code";
3187
3205
  }
3188
3206
  function readLatestBeadRecord(projectRoot, taskId) {
3189
- const issuesPath = resolve9(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
3190
- if (!existsSync5(issuesPath)) {
3207
+ const issuesPath = resolve10(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
3208
+ if (!existsSync6(issuesPath)) {
3191
3209
  return null;
3192
3210
  }
3193
3211
  let latest = null;
@@ -3222,6 +3240,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
3222
3240
  const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
3223
3241
  const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
3224
3242
  const next = {
3243
+ ...existing ?? {},
3225
3244
  runId: input.runId,
3226
3245
  projectRoot,
3227
3246
  workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
@@ -3254,7 +3273,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
3254
3273
  } else if ("errorText" in next) {
3255
3274
  delete next.errorText;
3256
3275
  }
3257
- writeJsonFile3(resolve9(resolveAuthorityRunDir(projectRoot, input.runId), "run.json"), next);
3276
+ writeJsonFile3(resolve10(resolveAuthorityRunDir(projectRoot, input.runId), "run.json"), next);
3258
3277
  return next;
3259
3278
  }
3260
3279
 
@@ -3375,10 +3394,10 @@ async function executeAgent(context, args) {
3375
3394
  status: "running",
3376
3395
  startedAt: createdAt,
3377
3396
  worktreePath: runtime.workspaceDir,
3378
- artifactRoot: resolve10(runtime.workspaceDir, "artifacts", taskId),
3397
+ artifactRoot: resolve11(runtime.workspaceDir, "artifacts", taskId),
3379
3398
  logRoot: runtime.logsDir,
3380
- sessionPath: resolve10(runtime.sessionDir, "session.json"),
3381
- sessionLogPath: resolve10(runtime.logsDir, "agent-stdout.log"),
3399
+ sessionPath: resolve11(runtime.sessionDir, "session.json"),
3400
+ sessionLogPath: resolve11(runtime.logsDir, "agent-stdout.log"),
3382
3401
  pid: process.pid
3383
3402
  });
3384
3403
  const result = await runInAgentRuntime({
@@ -3398,10 +3417,10 @@ async function executeAgent(context, args) {
3398
3417
  startedAt: createdAt,
3399
3418
  completedAt: failedAt,
3400
3419
  worktreePath: runtime.workspaceDir,
3401
- artifactRoot: resolve10(runtime.workspaceDir, "artifacts", taskId),
3420
+ artifactRoot: resolve11(runtime.workspaceDir, "artifacts", taskId),
3402
3421
  logRoot: runtime.logsDir,
3403
- sessionPath: resolve10(runtime.sessionDir, "session.json"),
3404
- sessionLogPath: resolve10(runtime.logsDir, "agent-stdout.log"),
3422
+ sessionPath: resolve11(runtime.sessionDir, "session.json"),
3423
+ sessionLogPath: resolve11(runtime.logsDir, "agent-stdout.log"),
3405
3424
  pid: process.pid,
3406
3425
  errorText: result.stderr ? result.stderr.trim() : `Agent runtime command failed (${result.exitCode})`
3407
3426
  });
@@ -3418,10 +3437,10 @@ ${result.stderr.trim()}` : ""}`, result.exitCode);
3418
3437
  startedAt: createdAt,
3419
3438
  completedAt,
3420
3439
  worktreePath: runtime.workspaceDir,
3421
- artifactRoot: resolve10(runtime.workspaceDir, "artifacts", taskId),
3440
+ artifactRoot: resolve11(runtime.workspaceDir, "artifacts", taskId),
3422
3441
  logRoot: runtime.logsDir,
3423
- sessionPath: resolve10(runtime.sessionDir, "session.json"),
3424
- sessionLogPath: resolve10(runtime.logsDir, "agent-stdout.log"),
3442
+ sessionPath: resolve11(runtime.sessionDir, "session.json"),
3443
+ sessionLogPath: resolve11(runtime.logsDir, "agent-stdout.log"),
3425
3444
  pid: process.pid
3426
3445
  });
3427
3446
  return {
@@ -3495,7 +3514,7 @@ ${result.stderr.trim()}` : ""}`, result.exitCode);
3495
3514
  import {
3496
3515
  chmodSync,
3497
3516
  copyFileSync as copyFileSync2,
3498
- existsSync as existsSync6,
3517
+ existsSync as existsSync7,
3499
3518
  mkdirSync as mkdirSync5,
3500
3519
  readdirSync,
3501
3520
  readlinkSync,
@@ -3505,7 +3524,7 @@ import {
3505
3524
  unlinkSync
3506
3525
  } from "fs";
3507
3526
  import { homedir as homedir4 } from "os";
3508
- import { resolve as resolve11 } from "path";
3527
+ import { resolve as resolve12 } from "path";
3509
3528
  import { buildBinary as buildBinary2 } from "@rig/runtime/control-plane/runtime/isolation";
3510
3529
  import {
3511
3530
  computeRuntimeImageFingerprint,
@@ -3524,13 +3543,13 @@ async function runQuietBinaryProbe(binaryPath, args, cwd) {
3524
3543
 
3525
3544
  // packages/cli/src/commands/dist.ts
3526
3545
  function collectRigValidatorBuildTargets(input) {
3527
- const validatorsRoot = resolve11(input.hostProjectRoot, "packages/runtime/src/control-plane/validators");
3528
- if (!existsSync6(validatorsRoot))
3546
+ const validatorsRoot = resolve12(input.hostProjectRoot, "packages/runtime/src/control-plane/validators");
3547
+ if (!existsSync7(validatorsRoot))
3529
3548
  return [];
3530
3549
  const targets = [];
3531
3550
  const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
3532
3551
  for (const category of categories) {
3533
- const categoryDir = resolve11(validatorsRoot, category.name);
3552
+ const categoryDir = resolve12(validatorsRoot, category.name);
3534
3553
  for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
3535
3554
  if (!entry.isFile() || !entry.name.endsWith(".ts"))
3536
3555
  continue;
@@ -3539,7 +3558,7 @@ function collectRigValidatorBuildTargets(input) {
3539
3558
  continue;
3540
3559
  targets.push({
3541
3560
  source: `packages/runtime/src/control-plane/validators/${category.name}/${entry.name}`,
3542
- dest: resolve11(input.imageDir, `bin/validators/${category.name}-${check}`),
3561
+ dest: resolve12(input.imageDir, `bin/validators/${category.name}-${check}`),
3543
3562
  cwd: input.hostProjectRoot
3544
3563
  });
3545
3564
  }
@@ -3548,16 +3567,16 @@ function collectRigValidatorBuildTargets(input) {
3548
3567
  }
3549
3568
  async function findLatestDistBinary(projectRoot) {
3550
3569
  const distRoot = resolveControlPlaneHostDistDir(projectRoot);
3551
- if (!existsSync6(distRoot)) {
3570
+ if (!existsSync7(distRoot)) {
3552
3571
  return null;
3553
3572
  }
3554
3573
  const entries = readdirSync(distRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith("rig-")).map((entry) => ({
3555
3574
  name: entry.name,
3556
- mtimeMs: statSync(resolve11(distRoot, entry.name)).mtimeMs
3575
+ mtimeMs: statSync(resolve12(distRoot, entry.name)).mtimeMs
3557
3576
  })).sort((a, b) => b.mtimeMs - a.mtimeMs || b.name.localeCompare(a.name));
3558
3577
  for (const { name } of entries) {
3559
- const candidate = resolve11(distRoot, name, "bin", "rig");
3560
- if (existsSync6(candidate) && await isRunnableRigBinary(candidate, projectRoot)) {
3578
+ const candidate = resolve12(distRoot, name, "bin", "rig");
3579
+ if (existsSync7(candidate) && await isRunnableRigBinary(candidate, projectRoot)) {
3561
3580
  return candidate;
3562
3581
  }
3563
3582
  }
@@ -3569,7 +3588,7 @@ async function isRunnableRigBinary(binaryPath, projectRoot) {
3569
3588
  async function runDistDoctor(projectRoot) {
3570
3589
  const bunPath = Bun.which("bun");
3571
3590
  const rigPath = Bun.which("rig");
3572
- const userBinDir = resolve11(homedir4(), ".local/bin");
3591
+ const userBinDir = resolve12(homedir4(), ".local/bin");
3573
3592
  const userBinInPath = (process.env.PATH || "").split(":").filter(Boolean).includes(userBinDir);
3574
3593
  let rigRunnable = false;
3575
3594
  if (rigPath) {
@@ -3617,15 +3636,15 @@ async function executeDist(context, args) {
3617
3636
  let source = await findLatestDistBinary(context.projectRoot);
3618
3637
  let buildDir = null;
3619
3638
  if (!source) {
3620
- buildDir = resolve11(resolveControlPlaneHostDistDir(context.projectRoot), `rig-install-${Date.now()}`);
3639
+ buildDir = resolve12(resolveControlPlaneHostDistDir(context.projectRoot), `rig-install-${Date.now()}`);
3621
3640
  await context.runCommand(["bun", "run", "packages/cli/bin/build-rig-binaries.ts", "--output-dir", buildDir]);
3622
- source = resolve11(buildDir, "bin", "rig");
3641
+ source = resolve12(buildDir, "bin", "rig");
3623
3642
  }
3624
- if (!existsSync6(source)) {
3643
+ if (!existsSync7(source)) {
3625
3644
  throw new CliError2(`Unable to locate rig binary at ${source}.`, 2);
3626
3645
  }
3627
- const installedPath = resolve11(installDir, "rig");
3628
- if (existsSync6(installedPath)) {
3646
+ const installedPath = resolve12(installDir, "rig");
3647
+ if (existsSync7(installedPath)) {
3629
3648
  unlinkSync(installedPath);
3630
3649
  }
3631
3650
  copyFileSync2(source, installedPath);
@@ -3667,22 +3686,22 @@ async function executeDist(context, args) {
3667
3686
  requireNoExtraArgs(rest, "bun run rig dist rebuild-agent");
3668
3687
  const fp = await computeRuntimeImageFingerprint(context.projectRoot);
3669
3688
  const currentId = computeRuntimeImageId(fp);
3670
- const imagesDir = resolve11(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
3689
+ const imagesDir = resolve12(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
3671
3690
  mkdirSync5(imagesDir, { recursive: true });
3672
3691
  let pruned = 0;
3673
3692
  for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
3674
3693
  if (entry.isDirectory() && entry.name !== currentId) {
3675
- rmSync4(resolve11(imagesDir, entry.name), { recursive: true, force: true });
3694
+ rmSync4(resolve12(imagesDir, entry.name), { recursive: true, force: true });
3676
3695
  pruned++;
3677
3696
  }
3678
3697
  }
3679
3698
  if (pruned > 0 && context.outputMode === "text") {
3680
3699
  console.log(`Pruned ${pruned} stale image(s).`);
3681
3700
  }
3682
- const imageDir = resolve11(imagesDir, currentId);
3683
- mkdirSync5(resolve11(imageDir, "bin/hooks"), { recursive: true });
3684
- mkdirSync5(resolve11(imageDir, "bin/plugins"), { recursive: true });
3685
- mkdirSync5(resolve11(imageDir, "bin/validators"), { recursive: true });
3701
+ const imageDir = resolve12(imagesDir, currentId);
3702
+ mkdirSync5(resolve12(imageDir, "bin/hooks"), { recursive: true });
3703
+ mkdirSync5(resolve12(imageDir, "bin/plugins"), { recursive: true });
3704
+ mkdirSync5(resolve12(imageDir, "bin/validators"), { recursive: true });
3686
3705
  const hookNames = [
3687
3706
  "scope-guard",
3688
3707
  "import-guard",
@@ -3696,25 +3715,25 @@ async function executeDist(context, args) {
3696
3715
  ];
3697
3716
  const targets = [];
3698
3717
  const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || context.projectRoot;
3699
- targets.push({ source: "packages/runtime/bin/rig-agent.ts", dest: resolve11(imageDir, "bin/rig-agent"), cwd: hostProjectRoot });
3700
- targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest: resolve11(resolveControlPlaneHostBinDir(context.projectRoot), "rig-agent"), cwd: hostProjectRoot });
3718
+ targets.push({ source: "packages/runtime/bin/rig-agent.ts", dest: resolve12(imageDir, "bin/rig-agent"), cwd: hostProjectRoot });
3719
+ targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest: resolve12(resolveControlPlaneHostBinDir(context.projectRoot), "rig-agent"), cwd: hostProjectRoot });
3701
3720
  for (const hookName of hookNames) {
3702
3721
  const src = `packages/runtime/src/control-plane/hooks/${hookName}.ts`;
3703
- targets.push({ source: src, dest: resolve11(imageDir, `bin/hooks/${hookName}`), cwd: hostProjectRoot });
3704
- targets.push({ source: src, dest: resolve11(resolveControlPlaneHostBinDir(context.projectRoot), `hooks/${hookName}`), cwd: hostProjectRoot });
3722
+ targets.push({ source: src, dest: resolve12(imageDir, `bin/hooks/${hookName}`), cwd: hostProjectRoot });
3723
+ targets.push({ source: src, dest: resolve12(resolveControlPlaneHostBinDir(context.projectRoot), `hooks/${hookName}`), cwd: hostProjectRoot });
3705
3724
  }
3706
- const pluginsDir = resolve11(context.projectRoot, "rig/plugins");
3707
- const binPluginsDir = resolve11(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
3708
- const validatorsRoot = resolve11(hostProjectRoot, "packages/runtime/src/control-plane/validators");
3709
- const binValidatorsDir = resolve11(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
3725
+ const pluginsDir = resolve12(context.projectRoot, "rig/plugins");
3726
+ const binPluginsDir = resolve12(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
3727
+ const validatorsRoot = resolve12(hostProjectRoot, "packages/runtime/src/control-plane/validators");
3728
+ const binValidatorsDir = resolve12(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
3710
3729
  mkdirSync5(binPluginsDir, { recursive: true });
3711
3730
  mkdirSync5(binValidatorsDir, { recursive: true });
3712
- if (existsSync6(pluginsDir)) {
3731
+ if (existsSync7(pluginsDir)) {
3713
3732
  for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
3714
3733
  const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
3715
3734
  if (!m)
3716
3735
  continue;
3717
- targets.push({ source: `rig/plugins/${entry.name}`, dest: resolve11(imageDir, `bin/plugins/${m[1]}`), cwd: context.projectRoot });
3736
+ targets.push({ source: `rig/plugins/${entry.name}`, dest: resolve12(imageDir, `bin/plugins/${m[1]}`), cwd: context.projectRoot });
3718
3737
  }
3719
3738
  }
3720
3739
  targets.push(...collectRigValidatorBuildTargets({ contextProjectRoot: context.projectRoot, hostProjectRoot, imageDir }));
@@ -3725,17 +3744,17 @@ async function executeDist(context, args) {
3725
3744
  const isValidator = dest.includes("/bin/validators/");
3726
3745
  await buildBinary2(source, dest, cwd, isValidator ? { AGENT_BUN_PATH: Bun.which("bun") || "bun" } : { AGENT_PROJECT_ROOT: context.projectRoot });
3727
3746
  }
3728
- if (existsSync6(pluginsDir)) {
3747
+ if (existsSync7(pluginsDir)) {
3729
3748
  for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
3730
3749
  const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
3731
3750
  if (!m)
3732
3751
  continue;
3733
3752
  const pluginName = m[1];
3734
- const imageBin = resolve11(imageDir, `bin/plugins/${pluginName}`);
3753
+ const imageBin = resolve12(imageDir, `bin/plugins/${pluginName}`);
3735
3754
  if (!pluginName)
3736
3755
  continue;
3737
- const symlinkPath = resolve11(binPluginsDir, pluginName);
3738
- if (existsSync6(imageBin)) {
3756
+ const symlinkPath = resolve12(binPluginsDir, pluginName);
3757
+ if (existsSync7(imageBin)) {
3739
3758
  try {
3740
3759
  unlinkSync(symlinkPath);
3741
3760
  } catch {}
@@ -3743,10 +3762,10 @@ async function executeDist(context, args) {
3743
3762
  }
3744
3763
  }
3745
3764
  }
3746
- if (existsSync6(validatorsRoot)) {
3765
+ if (existsSync7(validatorsRoot)) {
3747
3766
  const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
3748
3767
  for (const category of categories) {
3749
- const categoryDir = resolve11(validatorsRoot, category.name);
3768
+ const categoryDir = resolve12(validatorsRoot, category.name);
3750
3769
  for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
3751
3770
  if (!entry.isFile() || !entry.name.endsWith(".ts"))
3752
3771
  continue;
@@ -3754,9 +3773,9 @@ async function executeDist(context, args) {
3754
3773
  if (!check || check === "index" || check === "shared")
3755
3774
  continue;
3756
3775
  const validatorName = `${category.name}-${check}`;
3757
- const imageBin = resolve11(imageDir, `bin/validators/${validatorName}`);
3758
- const symlinkPath = resolve11(binValidatorsDir, validatorName);
3759
- if (existsSync6(imageBin)) {
3776
+ const imageBin = resolve12(imageDir, `bin/validators/${validatorName}`);
3777
+ const symlinkPath = resolve12(binValidatorsDir, validatorName);
3778
+ if (existsSync7(imageBin)) {
3760
3779
  try {
3761
3780
  unlinkSync(symlinkPath);
3762
3781
  } catch {}
@@ -3765,18 +3784,18 @@ async function executeDist(context, args) {
3765
3784
  }
3766
3785
  }
3767
3786
  }
3768
- const agentsDir = resolve11(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "agents");
3769
- if (existsSync6(agentsDir)) {
3787
+ const agentsDir = resolve12(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "agents");
3788
+ if (existsSync7(agentsDir)) {
3770
3789
  let relinkCount = 0;
3771
3790
  for (const agentEntry of readdirSync(agentsDir, { withFileTypes: true })) {
3772
3791
  if (!agentEntry.isDirectory())
3773
3792
  continue;
3774
- const agentBinDir = resolve11(agentsDir, agentEntry.name, "worktree", ".rig", "bin");
3775
- if (!existsSync6(agentBinDir))
3793
+ const agentBinDir = resolve12(agentsDir, agentEntry.name, "worktree", ".rig", "bin");
3794
+ if (!existsSync7(agentBinDir))
3776
3795
  continue;
3777
3796
  const walkDir = (dir) => {
3778
3797
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
3779
- const fullPath = resolve11(dir, entry.name);
3798
+ const fullPath = resolve12(dir, entry.name);
3780
3799
  if (entry.isDirectory()) {
3781
3800
  walkDir(fullPath);
3782
3801
  } else if (entry.isSymbolicLink()) {
@@ -3810,7 +3829,7 @@ async function executeDist(context, args) {
3810
3829
 
3811
3830
  // packages/cli/src/commands/inbox.ts
3812
3831
  import { writeFileSync as writeFileSync4 } from "fs";
3813
- import { resolve as resolve12 } from "path";
3832
+ import { resolve as resolve13 } from "path";
3814
3833
  import {
3815
3834
  listAuthorityRuns,
3816
3835
  readJsonlFile as readJsonlFile3,
@@ -3827,7 +3846,7 @@ async function executeInbox(context, args) {
3827
3846
  pending = task.rest;
3828
3847
  requireNoExtraArgs(pending, "bun run rig inbox approvals [--run <id>] [--task <id>]");
3829
3848
  const runs = listAuthorityRuns(context.projectRoot).filter((entry) => (!run.value || entry.runId === run.value) && (!task.value || entry.taskId === task.value));
3830
- const approvals = runs.flatMap((entry) => readJsonlFile3(resolve12(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "approvals.jsonl")).map((record) => ({
3849
+ const approvals = runs.flatMap((entry) => readJsonlFile3(resolve13(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "approvals.jsonl")).map((record) => ({
3831
3850
  runId: entry.runId,
3832
3851
  record
3833
3852
  })));
@@ -3855,7 +3874,7 @@ async function executeInbox(context, args) {
3855
3874
  if (decision.value !== "approve" && decision.value !== "reject") {
3856
3875
  throw new CliError2("decision must be approve or reject.");
3857
3876
  }
3858
- const approvalsPath = resolve12(resolveAuthorityRunDir2(context.projectRoot, run.value), "approvals.jsonl");
3877
+ const approvalsPath = resolve13(resolveAuthorityRunDir2(context.projectRoot, run.value), "approvals.jsonl");
3859
3878
  const approvals = readJsonlFile3(approvalsPath);
3860
3879
  const resolvedAt = new Date().toISOString();
3861
3880
  const next = approvals.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", decision: decision.value, note: note3.value ?? null, resolvedAt } : entry);
@@ -3872,7 +3891,7 @@ async function executeInbox(context, args) {
3872
3891
  pending = task.rest;
3873
3892
  requireNoExtraArgs(pending, "bun run rig inbox inputs [--run <id>] [--task <id>]");
3874
3893
  const runs = listAuthorityRuns(context.projectRoot).filter((entry) => (!run.value || entry.runId === run.value) && (!task.value || entry.taskId === task.value));
3875
- const requests = runs.flatMap((entry) => readJsonlFile3(resolve12(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "user-input.jsonl")).map((record) => ({
3894
+ const requests = runs.flatMap((entry) => readJsonlFile3(resolve13(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "user-input.jsonl")).map((record) => ({
3876
3895
  runId: entry.runId,
3877
3896
  record
3878
3897
  })));
@@ -3914,7 +3933,7 @@ async function executeInbox(context, args) {
3914
3933
  const [key, ...restValue] = entry.split("=");
3915
3934
  return [key, restValue.join("=")];
3916
3935
  }));
3917
- const requestsPath = resolve12(resolveAuthorityRunDir2(context.projectRoot, run.value), "user-input.jsonl");
3936
+ const requestsPath = resolve13(resolveAuthorityRunDir2(context.projectRoot, run.value), "user-input.jsonl");
3918
3937
  const requests = readJsonlFile3(requestsPath);
3919
3938
  const resolvedAt = new Date().toISOString();
3920
3939
  const next = requests.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", answers: parsedAnswers, respondedAt: resolvedAt, resolvedAt } : entry);
@@ -3929,14 +3948,14 @@ async function executeInbox(context, args) {
3929
3948
  }
3930
3949
 
3931
3950
  // packages/cli/src/commands/init.ts
3932
- import { appendFileSync as appendFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
3951
+ import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
3933
3952
  import { spawnSync as spawnSync2 } from "child_process";
3934
- import { resolve as resolve15 } from "path";
3953
+ import { resolve as resolve16 } from "path";
3935
3954
  import { buildRigInitConfigSource } from "@rig/core";
3936
3955
 
3937
3956
  // packages/cli/src/commands/_snapshot-upload.ts
3938
3957
  import { mkdir, readdir, readFile, writeFile } from "fs/promises";
3939
- import { dirname as dirname2, resolve as resolve13, relative, sep } from "path";
3958
+ import { dirname as dirname2, resolve as resolve14, relative, sep } from "path";
3940
3959
  var SNAPSHOT_ARCHIVE_VERSION = 1;
3941
3960
  var SNAPSHOT_ARCHIVE_CONTENT_TYPE = "application/vnd.rig.snapshot+json";
3942
3961
  var DEFAULT_EXCLUDED_DIRECTORIES = new Set([
@@ -3958,15 +3977,15 @@ function assertManifestPath(root, relativePath) {
3958
3977
  if (!relativePath || relativePath.startsWith("/") || relativePath.includes("\x00")) {
3959
3978
  throw new Error(`Invalid snapshot path: ${relativePath}`);
3960
3979
  }
3961
- const resolved = resolve13(root, relativePath);
3980
+ const resolved = resolve14(root, relativePath);
3962
3981
  const relativeToRoot = relative(root, resolved);
3963
- if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || resolve13(relativeToRoot) === resolved) {
3982
+ if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || resolve14(relativeToRoot) === resolved) {
3964
3983
  throw new Error(`Snapshot path escapes project root: ${relativePath}`);
3965
3984
  }
3966
3985
  return resolved;
3967
3986
  }
3968
3987
  async function buildSnapshotUploadManifest(projectRoot, options = {}) {
3969
- const root = resolve13(projectRoot);
3988
+ const root = resolve14(projectRoot);
3970
3989
  const excludedDirectories = [...new Set([
3971
3990
  ...DEFAULT_EXCLUDED_DIRECTORIES,
3972
3991
  ...options.excludedDirectories ?? []
@@ -3978,7 +3997,7 @@ async function buildSnapshotUploadManifest(projectRoot, options = {}) {
3978
3997
  for (const entry of entries) {
3979
3998
  if (entry.isDirectory() && excludedSet.has(entry.name))
3980
3999
  continue;
3981
- const fullPath = resolve13(dir, entry.name);
4000
+ const fullPath = resolve14(dir, entry.name);
3982
4001
  if (entry.isDirectory()) {
3983
4002
  await visit(fullPath);
3984
4003
  continue;
@@ -4026,8 +4045,8 @@ async function uploadSnapshotArchiveViaServer(context, input) {
4026
4045
  }
4027
4046
 
4028
4047
  // packages/cli/src/commands/_doctor-checks.ts
4029
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
4030
- import { resolve as resolve14 } from "path";
4048
+ import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
4049
+ import { resolve as resolve15 } from "path";
4031
4050
  import { isSupportedBunVersion, MIN_SUPPORTED_BUN_VERSION } from "@rig/runtime/control-plane/setup-version";
4032
4051
  function check(id, label, status, detail, remediation) {
4033
4052
  return {
@@ -4067,11 +4086,11 @@ function repoSlugFromConfig(config) {
4067
4086
  function loadFallbackConfig(projectRoot) {
4068
4087
  const candidates = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
4069
4088
  for (const name of candidates) {
4070
- const path = resolve14(projectRoot, name);
4071
- if (!existsSync7(path))
4089
+ const path = resolve15(projectRoot, name);
4090
+ if (!existsSync8(path))
4072
4091
  continue;
4073
4092
  try {
4074
- const source = readFileSync4(path, "utf8");
4093
+ const source = readFileSync5(path, "utf8");
4075
4094
  if (name.endsWith(".json"))
4076
4095
  return JSON.parse(source);
4077
4096
  const owner = source.match(/owner\s*:\s*["']([^"']+)["']/)?.[1];
@@ -4150,7 +4169,7 @@ async function runRigDoctorChecks(options) {
4150
4169
  checks.push(check("bun", `bun >= ${MIN_SUPPORTED_BUN_VERSION}`, isSupportedBunVersion(bunVersion) ? "pass" : "fail", `found ${bunVersion}`, `Install Bun ${MIN_SUPPORTED_BUN_VERSION} or newer.`), check("git", "git", which("git") ? "pass" : "fail", which("git") ?? undefined, "Install git and ensure it is on PATH."), check("jq", "jq", which("jq") ? "pass" : "warn", which("jq") ?? undefined, "Install jq (for example `brew install jq`)."));
4151
4170
  const loadedConfig = await loadConfig(projectRoot).catch(() => null);
4152
4171
  const config = loadedConfig ?? loadFallbackConfig(projectRoot);
4153
- const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync7(resolve14(projectRoot, name)));
4172
+ const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync8(resolve15(projectRoot, name)));
4154
4173
  checks.push(config ? check("config", "rig.config loadable", "pass") : check("config", "rig.config loadable", hasConfigFile ? "fail" : "fail", hasConfigFile ? "config file exists but failed to load" : "missing rig.config.ts/json", "Run `rig init` or fix the config error."));
4155
4174
  const taskSourceKind = config?.taskSource?.kind;
4156
4175
  checks.push(taskSourceKind ? check("task-source", "task source configured", "pass", taskSourceKind) : check("task-source", "task source configured", "fail", "missing taskSource", "Configure taskSource in rig.config.ts."));
@@ -4245,10 +4264,10 @@ function countDoctorFailures(checks) {
4245
4264
  }
4246
4265
 
4247
4266
  // packages/cli/src/commands/init.ts
4248
- var RIG_CONFIG_PACKAGE_VERSION = "0.0.6-alpha.1";
4267
+ var RIG_CONFIG_PACKAGE_DIST_TAG = "latest";
4249
4268
  var RIG_CONFIG_DEV_DEPENDENCIES = {
4250
- "@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_VERSION}`,
4251
- "@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_VERSION}`
4269
+ "@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_DIST_TAG}`,
4270
+ "@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_DIST_TAG}`
4252
4271
  };
4253
4272
  function parseRepoSlugFromRemote(remoteUrl) {
4254
4273
  const trimmed = remoteUrl.trim();
@@ -4268,20 +4287,20 @@ function parseRepoSlug(value) {
4268
4287
  return { owner: match[1], repo: match[2], slug: `${match[1]}/${match[2]}` };
4269
4288
  }
4270
4289
  function ensureRigPrivateDirs(projectRoot) {
4271
- const rigDir = resolve15(projectRoot, ".rig");
4272
- mkdirSync6(resolve15(rigDir, "state"), { recursive: true });
4273
- mkdirSync6(resolve15(rigDir, "logs"), { recursive: true });
4274
- mkdirSync6(resolve15(rigDir, "runs"), { recursive: true });
4275
- mkdirSync6(resolve15(rigDir, "tmp"), { recursive: true });
4276
- mkdirSync6(resolve15(projectRoot, "artifacts"), { recursive: true });
4277
- const taskConfigPath = resolve15(rigDir, "task-config.json");
4278
- if (!existsSync8(taskConfigPath))
4290
+ const rigDir = resolve16(projectRoot, ".rig");
4291
+ mkdirSync6(resolve16(rigDir, "state"), { recursive: true });
4292
+ mkdirSync6(resolve16(rigDir, "logs"), { recursive: true });
4293
+ mkdirSync6(resolve16(rigDir, "runs"), { recursive: true });
4294
+ mkdirSync6(resolve16(rigDir, "tmp"), { recursive: true });
4295
+ mkdirSync6(resolve16(projectRoot, "artifacts"), { recursive: true });
4296
+ const taskConfigPath = resolve16(rigDir, "task-config.json");
4297
+ if (!existsSync9(taskConfigPath))
4279
4298
  writeFileSync5(taskConfigPath, `{}
4280
4299
  `, "utf-8");
4281
4300
  }
4282
4301
  function ensureGitignoreEntries(projectRoot) {
4283
- const path = resolve15(projectRoot, ".gitignore");
4284
- const existing = existsSync8(path) ? readFileSync5(path, "utf8") : "";
4302
+ const path = resolve16(projectRoot, ".gitignore");
4303
+ const existing = existsSync9(path) ? readFileSync6(path, "utf8") : "";
4285
4304
  const entries = [".rig/state/", ".rig/logs/", ".rig/runs/", ".rig/tmp/"];
4286
4305
  const missing = entries.filter((entry) => !existing.split(/\r?\n/).includes(entry));
4287
4306
  if (missing.length === 0)
@@ -4294,14 +4313,14 @@ function ensureGitignoreEntries(projectRoot) {
4294
4313
  `, "utf8");
4295
4314
  }
4296
4315
  function ensureRigConfigPackageDependencies(projectRoot) {
4297
- const path = resolve15(projectRoot, "package.json");
4298
- const existing = existsSync8(path) ? JSON.parse(readFileSync5(path, "utf8")) : {};
4316
+ const path = resolve16(projectRoot, "package.json");
4317
+ const existing = existsSync9(path) ? JSON.parse(readFileSync6(path, "utf8")) : {};
4299
4318
  const devDependencies = existing.devDependencies && typeof existing.devDependencies === "object" && !Array.isArray(existing.devDependencies) ? { ...existing.devDependencies } : {};
4300
4319
  for (const [name, spec] of Object.entries(RIG_CONFIG_DEV_DEPENDENCIES)) {
4301
4320
  devDependencies[name] = spec;
4302
4321
  }
4303
4322
  const next = {
4304
- ...existsSync8(path) ? existing : { name: "rig-project", private: true },
4323
+ ...existsSync9(path) ? existing : { name: "rig-project", private: true },
4305
4324
  devDependencies
4306
4325
  };
4307
4326
  writeFileSync5(path, `${JSON.stringify(next, null, 2)}
@@ -4371,15 +4390,54 @@ async function promptSelect(prompts, options) {
4371
4390
  throw new CliError2("Init cancelled.", 1);
4372
4391
  return String(value);
4373
4392
  }
4374
- async function pollDeviceAuthOnce(context, pollId) {
4393
+ function sleep2(ms) {
4394
+ return new Promise((resolve17) => setTimeout(resolve17, ms));
4395
+ }
4396
+ function positiveIntFromEnv(name, fallback) {
4397
+ const value = Number.parseInt(process.env[name] ?? "", 10);
4398
+ return Number.isFinite(value) && value >= 0 ? value : fallback;
4399
+ }
4400
+ function apiSessionTokenFrom(payload) {
4401
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
4402
+ return null;
4403
+ const token = payload.apiSessionToken;
4404
+ return typeof token === "string" && token.trim() ? token.trim() : null;
4405
+ }
4406
+ function writeRemoteGitHubAuthState(projectRoot, input) {
4407
+ writeFileSync5(resolve16(projectRoot, ".rig", "state", "github-auth.json"), `${JSON.stringify({
4408
+ authenticated: true,
4409
+ source: input.source,
4410
+ storedOnServer: true,
4411
+ selectedRepo: input.selectedRepo,
4412
+ ...input.apiSessionToken ? { apiSessionToken: input.apiSessionToken } : {},
4413
+ updatedAt: new Date().toISOString()
4414
+ }, null, 2)}
4415
+ `, "utf8");
4416
+ }
4417
+ async function pollDeviceAuthUntilComplete(context, pollId, firstPayload) {
4375
4418
  if (typeof pollId !== "string" || !pollId.trim())
4376
4419
  return null;
4377
- const payload = await requestServerJson(context, "/api/github/auth/device/poll", {
4378
- method: "POST",
4379
- headers: { "content-type": "application/json" },
4380
- body: JSON.stringify({ pollId })
4381
- }).catch(() => null);
4382
- return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
4420
+ const intervalSeconds = typeof firstPayload.interval === "number" && Number.isFinite(firstPayload.interval) && firstPayload.interval > 0 ? firstPayload.interval : 5;
4421
+ const timeoutMs = positiveIntFromEnv("RIG_DEVICE_AUTH_POLL_TIMEOUT_MS", 300000);
4422
+ const intervalMs = positiveIntFromEnv("RIG_DEVICE_AUTH_POLL_INTERVAL_MS", Math.max(1000, intervalSeconds * 1000));
4423
+ const deadline = Date.now() + timeoutMs;
4424
+ let last = null;
4425
+ do {
4426
+ const payload = await requestServerJson(context, "/api/github/auth/device/poll", {
4427
+ method: "POST",
4428
+ headers: { "content-type": "application/json" },
4429
+ body: JSON.stringify({ pollId })
4430
+ }).catch(() => null);
4431
+ last = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
4432
+ const status = typeof last?.status === "string" ? last.status : null;
4433
+ if (status === "signed-in" || status === "expired" || status === "cancelled" || status === "failed") {
4434
+ return last;
4435
+ }
4436
+ if (timeoutMs <= 0)
4437
+ return last;
4438
+ await sleep2(intervalMs);
4439
+ } while (Date.now() < deadline);
4440
+ return last;
4383
4441
  }
4384
4442
  async function runControlPlaneInit(context, options) {
4385
4443
  const projectRoot = context.projectRoot;
@@ -4402,9 +4460,9 @@ async function runControlPlaneInit(context, options) {
4402
4460
  });
4403
4461
  ensureRigPrivateDirs(projectRoot);
4404
4462
  ensureGitignoreEntries(projectRoot);
4405
- const configTsPath = resolve15(projectRoot, "rig.config.ts");
4406
- const configJsonPath = resolve15(projectRoot, "rig.config.json");
4407
- const configExists = existsSync8(configTsPath) || existsSync8(configJsonPath);
4463
+ const configTsPath = resolve16(projectRoot, "rig.config.ts");
4464
+ const configJsonPath = resolve16(projectRoot, "rig.config.json");
4465
+ const configExists = existsSync9(configTsPath) || existsSync9(configJsonPath);
4408
4466
  if (!options.privateStateOnly) {
4409
4467
  if (configExists && !options.repair) {
4410
4468
  if (context.outputMode !== "json")
@@ -4420,7 +4478,7 @@ async function runControlPlaneInit(context, options) {
4420
4478
  }
4421
4479
  ensureRigConfigPackageDependencies(projectRoot);
4422
4480
  }
4423
- writeFileSync5(resolve15(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
4481
+ writeFileSync5(resolve16(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
4424
4482
  `, "utf8");
4425
4483
  const checkout = checkoutForInit(projectRoot, serverKind, options.remoteCheckout);
4426
4484
  let uploadedSnapshot = null;
@@ -4442,10 +4500,14 @@ async function runControlPlaneInit(context, options) {
4442
4500
  const token = authMethod === "gh" && !options.githubToken ? readGhAuthToken() : options.githubToken?.trim();
4443
4501
  if (token) {
4444
4502
  githubAuth = await postGitHubTokenViaServer(context, token, { selectedRepo: repo.slug });
4445
- setGitHubBearerTokenForCurrentProcess(token);
4503
+ const apiSessionToken = apiSessionTokenFrom(githubAuth);
4504
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token);
4446
4505
  if (serverKind === "remote") {
4447
- writeFileSync5(resolve15(projectRoot, ".rig", "state", "github-auth.json"), `${JSON.stringify({ authenticated: true, source: authMethod === "gh" ? "gh" : "init-token", storedOnServer: true, selectedRepo: repo.slug, updatedAt: new Date().toISOString() }, null, 2)}
4448
- `, "utf8");
4506
+ writeRemoteGitHubAuthState(projectRoot, {
4507
+ source: authMethod === "gh" ? "gh" : "init-token",
4508
+ selectedRepo: repo.slug,
4509
+ apiSessionToken
4510
+ });
4449
4511
  }
4450
4512
  } else if (authMethod === "device") {
4451
4513
  const payload = await requestServerJson(context, "/api/github/auth/device/start", {
@@ -4454,9 +4516,22 @@ async function runControlPlaneInit(context, options) {
4454
4516
  body: JSON.stringify({ repoSlug: repo.slug })
4455
4517
  });
4456
4518
  deviceAuth = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
4457
- const completed = await pollDeviceAuthOnce(context, deviceAuth.pollId);
4458
- if (completed)
4519
+ if (context.outputMode !== "json") {
4520
+ const verificationUri = String(deviceAuth.verificationUri ?? deviceAuth.verification_uri ?? deviceAuth.verification_uri_complete ?? "the verification URL returned by the server");
4521
+ const userCode = String(deviceAuth.userCode ?? deviceAuth.user_code ?? "the returned user code");
4522
+ console.log(`GitHub device flow: open ${verificationUri} and enter ${userCode}. Waiting for authorization...`);
4523
+ }
4524
+ const completed = await pollDeviceAuthUntilComplete(context, deviceAuth.pollId, deviceAuth);
4525
+ if (completed) {
4526
+ const apiSessionToken = apiSessionTokenFrom(completed);
4527
+ if (apiSessionToken) {
4528
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken);
4529
+ if (serverKind === "remote") {
4530
+ writeRemoteGitHubAuthState(projectRoot, { source: "device", selectedRepo: repo.slug, apiSessionToken });
4531
+ }
4532
+ }
4459
4533
  deviceAuth = { ...deviceAuth, poll: completed, completed: completed.status === "signed-in" };
4534
+ }
4460
4535
  }
4461
4536
  let remoteCheckoutPreparation = null;
4462
4537
  if (serverKind === "remote" && options.remoteCheckout?.kind !== "uploaded-snapshot") {
@@ -4476,6 +4551,12 @@ async function runControlPlaneInit(context, options) {
4476
4551
  });
4477
4552
  const checkoutPath = typeof checkout.path === "string" ? checkout.path : null;
4478
4553
  const serverRootSwitch = serverKind === "remote" && checkoutPath ? await switchServerProjectRootViaServer(context, checkoutPath) : null;
4554
+ if (serverRootSwitch && token) {
4555
+ githubAuth = await postGitHubTokenViaServer(context, token, { selectedRepo: repo.slug, projectRoot: checkoutPath ?? undefined });
4556
+ const apiSessionToken = apiSessionTokenFrom(githubAuth);
4557
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token);
4558
+ writeRemoteGitHubAuthState(projectRoot, { source: authMethod === "gh" ? "gh" : "init-token", selectedRepo: repo.slug, apiSessionToken });
4559
+ }
4479
4560
  const activeProjectRegistration = serverRootSwitch ? await registerProjectViaServer(context, { repoSlug: repo.slug, checkout }) : null;
4480
4561
  const pi = serverKind === "remote" ? await ensureRemotePiRigInstalled({ requestJson: (pathname, init) => requestServerJson(context, pathname, init) }).catch((error) => ({
4481
4562
  remote: true,
@@ -4585,7 +4666,7 @@ function parseInitOptions(args) {
4585
4666
  async function runInteractiveControlPlaneInit(context, prompts) {
4586
4667
  prompts.intro?.("Initialize a Rig control-plane project");
4587
4668
  const projectRoot = context.projectRoot;
4588
- const existingConfig = existsSync8(resolve15(projectRoot, "rig.config.ts")) || existsSync8(resolve15(projectRoot, "rig.config.json"));
4669
+ const existingConfig = existsSync9(resolve16(projectRoot, "rig.config.ts")) || existsSync9(resolve16(projectRoot, "rig.config.json"));
4589
4670
  let repair = false;
4590
4671
  let privateStateOnly = false;
4591
4672
  if (existingConfig) {
@@ -4685,7 +4766,7 @@ async function runInteractiveControlPlaneInit(context, prompts) {
4685
4766
  });
4686
4767
  const details = result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : {};
4687
4768
  const deviceAuth = details.deviceAuth && typeof details.deviceAuth === "object" && !Array.isArray(details.deviceAuth) ? details.deviceAuth : null;
4688
- const deviceMessage = deviceAuth ? ` GitHub device flow: open ${String(deviceAuth.verification_uri ?? deviceAuth.verification_uri_complete ?? "the verification URL returned by the server")} and enter ${String(deviceAuth.user_code ?? "the returned user code")}.` : "";
4769
+ const deviceMessage = deviceAuth ? ` GitHub device flow: open ${String(deviceAuth.verificationUri ?? deviceAuth.verification_uri ?? deviceAuth.verification_uri_complete ?? "the verification URL returned by the server")} and enter ${String(deviceAuth.userCode ?? deviceAuth.user_code ?? "the returned user code")}.` : "";
4689
4770
  prompts.outro?.(`Rig project initialized.${deviceMessage} Next: rig doctor && rig task list`);
4690
4771
  return result;
4691
4772
  }
@@ -4847,8 +4928,8 @@ async function executeDoctor(context, args) {
4847
4928
  }
4848
4929
 
4849
4930
  // packages/cli/src/commands/_run-driver-helpers.ts
4850
- import { readFileSync as readFileSync6 } from "fs";
4851
- import { resolve as resolve16 } from "path";
4931
+ import { readFileSync as readFileSync7 } from "fs";
4932
+ import { resolve as resolve17 } from "path";
4852
4933
  import {
4853
4934
  appendJsonlRecord as appendJsonlRecord2,
4854
4935
  readAuthorityRun as readAuthorityRun2,
@@ -4868,7 +4949,7 @@ function patchAuthorityRun(projectRoot, runId, patch) {
4868
4949
  ...patch,
4869
4950
  updatedAt: new Date().toISOString()
4870
4951
  };
4871
- writeJsonFile4(resolve16(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), next);
4952
+ writeJsonFile4(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), next);
4872
4953
  return next;
4873
4954
  }
4874
4955
  function touchAuthorityRun(projectRoot, runId) {
@@ -4876,21 +4957,21 @@ function touchAuthorityRun(projectRoot, runId) {
4876
4957
  if (!current) {
4877
4958
  return;
4878
4959
  }
4879
- writeJsonFile4(resolve16(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), {
4960
+ writeJsonFile4(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), {
4880
4961
  ...current,
4881
4962
  updatedAt: new Date().toISOString()
4882
4963
  });
4883
4964
  }
4884
4965
  function appendRunTimeline(projectRoot, runId, value) {
4885
- appendJsonlRecord2(resolve16(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), value);
4966
+ appendJsonlRecord2(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), value);
4886
4967
  touchAuthorityRun(projectRoot, runId);
4887
4968
  }
4888
4969
  function appendRunLog(projectRoot, runId, value) {
4889
- appendJsonlRecord2(resolve16(resolveAuthorityRunDir3(projectRoot, runId), "logs.jsonl"), value);
4970
+ appendJsonlRecord2(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "logs.jsonl"), value);
4890
4971
  touchAuthorityRun(projectRoot, runId);
4891
4972
  }
4892
4973
  function appendRunAction(projectRoot, runId, value) {
4893
- appendJsonlRecord2(resolve16(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), {
4974
+ appendJsonlRecord2(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), {
4894
4975
  id: value.id,
4895
4976
  type: "action",
4896
4977
  actionType: value.actionType,
@@ -4961,7 +5042,7 @@ function buildRunPrompt(input) {
4961
5042
  })();
4962
5043
  const scopeText = (() => {
4963
5044
  try {
4964
- const parsed = JSON.parse(readFileSync6(resolveControlPlaneTaskConfigPath(input.projectRoot), "utf8"));
5045
+ const parsed = JSON.parse(readFileSync7(resolveControlPlaneTaskConfigPath(input.projectRoot), "utf8"));
4965
5046
  const entry = parsed[input.taskId] ?? {};
4966
5047
  const scope = Array.isArray(entry.scope) ? entry.scope.filter((item) => typeof item === "string") : [];
4967
5048
  const validation = Array.isArray(entry.validation) ? entry.validation.filter((item) => typeof item === "string") : [];
@@ -5074,8 +5155,8 @@ function renderSourceScopeValidation(task, validation) {
5074
5155
  }
5075
5156
 
5076
5157
  // packages/cli/src/commands/inspect.ts
5077
- import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
5078
- import { resolve as resolve17 } from "path";
5158
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
5159
+ import { resolve as resolve18 } from "path";
5079
5160
  import {
5080
5161
  listAuthorityRuns as listAuthorityRuns2,
5081
5162
  readAuthorityRun as readAuthorityRun3,
@@ -5096,8 +5177,8 @@ async function executeInspect(context, args) {
5096
5177
  if (!latestRun) {
5097
5178
  throw new CliError2(`No runs found for ${requiredTask}.`);
5098
5179
  }
5099
- const logsPath = resolve17(resolveAuthorityRunDir4(context.projectRoot, latestRun.runId), "logs.jsonl");
5100
- if (!existsSync9(logsPath)) {
5180
+ const logsPath = resolve18(resolveAuthorityRunDir4(context.projectRoot, latestRun.runId), "logs.jsonl");
5181
+ if (!existsSync10(logsPath)) {
5101
5182
  throw new CliError2(`No logs found for run ${latestRun.runId}.`);
5102
5183
  }
5103
5184
  await context.runCommand(["cat", logsPath]);
@@ -5107,7 +5188,7 @@ async function executeInspect(context, args) {
5107
5188
  const { value: task, rest: remaining } = takeOption(rest, "--task");
5108
5189
  requireNoExtraArgs(remaining, "bun run rig inspect artifacts --task <beads-id>");
5109
5190
  const requiredTask = requireTask(task, "bun run rig inspect artifacts --task <beads-id>");
5110
- const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) => existsSync9(path));
5191
+ const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) => existsSync10(path));
5111
5192
  if (!artifactRoot) {
5112
5193
  throw new CliError2(`No artifacts found for ${requiredTask}.`);
5113
5194
  }
@@ -5164,10 +5245,10 @@ async function executeInspect(context, args) {
5164
5245
  case "failures": {
5165
5246
  requireNoExtraArgs(rest, "bun run rig inspect failures");
5166
5247
  const failed = resolveHarnessPaths2(context.projectRoot).failedApproachesPath;
5167
- if (!existsSync9(failed)) {
5248
+ if (!existsSync10(failed)) {
5168
5249
  console.log("No failures recorded.");
5169
5250
  } else {
5170
- process.stdout.write(readFileSync7(failed, "utf-8"));
5251
+ process.stdout.write(readFileSync8(failed, "utf-8"));
5171
5252
  }
5172
5253
  return { ok: true, group: "inspect", command };
5173
5254
  }
@@ -5184,11 +5265,11 @@ async function executeInspect(context, args) {
5184
5265
  return { ok: true, group: "inspect", command };
5185
5266
  case "audit": {
5186
5267
  requireNoExtraArgs(rest, "bun run rig inspect audit");
5187
- const auditPath = resolve17(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
5188
- if (!existsSync9(auditPath)) {
5268
+ const auditPath = resolve18(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
5269
+ if (!existsSync10(auditPath)) {
5189
5270
  console.log("No audit log found.");
5190
5271
  } else {
5191
- const lines = readFileSync7(auditPath, "utf-8").split(/\r?\n/).filter(Boolean).slice(-20);
5272
+ const lines = readFileSync8(auditPath, "utf-8").split(/\r?\n/).filter(Boolean).slice(-20);
5192
5273
  for (const line of lines) {
5193
5274
  console.log(line);
5194
5275
  }
@@ -5817,8 +5898,8 @@ async function executeRemote(context, args) {
5817
5898
  }
5818
5899
 
5819
5900
  // packages/cli/src/commands/run.ts
5820
- import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
5821
- import { resolve as resolve18 } from "path";
5901
+ import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
5902
+ import { resolve as resolve19 } from "path";
5822
5903
  import { createInterface as createInterface2 } from "readline/promises";
5823
5904
  import {
5824
5905
  listAuthorityRuns as listAuthorityRuns3,
@@ -5832,6 +5913,7 @@ import {
5832
5913
  listOpenEpics,
5833
5914
  resolveDefaultEpic,
5834
5915
  runResume,
5916
+ runRestart,
5835
5917
  runStatus,
5836
5918
  runStop,
5837
5919
  startRun,
@@ -5940,6 +6022,17 @@ async function attachRunOperatorView(context, input) {
5940
6022
  }
5941
6023
 
5942
6024
  // packages/cli/src/commands/run.ts
6025
+ function normalizeRemoteRunDetails(payload) {
6026
+ const run = payload.run;
6027
+ if (!run || typeof run !== "object" || Array.isArray(run))
6028
+ return null;
6029
+ return {
6030
+ ...run,
6031
+ ...Array.isArray(payload.timeline) ? { timeline: payload.timeline } : {},
6032
+ ...Array.isArray(payload.approvals) ? { approvals: payload.approvals } : {},
6033
+ ...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
6034
+ };
6035
+ }
5943
6036
  function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
5944
6037
  if (noEpicPrompt) {
5945
6038
  return false;
@@ -6078,7 +6171,7 @@ async function executeRun(context, args) {
6078
6171
  if (!run.value) {
6079
6172
  throw new CliError2("run show requires --run <id>.");
6080
6173
  }
6081
- const record = readAuthorityRun4(context.projectRoot, run.value);
6174
+ const record = readAuthorityRun4(context.projectRoot, run.value) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, run.value).catch(() => ({})));
6082
6175
  if (!record) {
6083
6176
  throw new CliError2(`Run not found: ${run.value}`, 2);
6084
6177
  }
@@ -6097,7 +6190,7 @@ async function executeRun(context, args) {
6097
6190
  if (!run.value) {
6098
6191
  throw new CliError2("run timeline requires --run <id>.");
6099
6192
  }
6100
- const timelinePath = resolve18(resolveAuthorityRunDir5(context.projectRoot, run.value), "timeline.jsonl");
6193
+ const timelinePath = resolve19(resolveAuthorityRunDir5(context.projectRoot, run.value), "timeline.jsonl");
6101
6194
  const printEvents = () => {
6102
6195
  const events2 = readJsonlFile4(timelinePath);
6103
6196
  if (context.outputMode === "text") {
@@ -6109,12 +6202,12 @@ async function executeRun(context, args) {
6109
6202
  };
6110
6203
  const events = printEvents();
6111
6204
  if (follow.value && context.outputMode === "text") {
6112
- let lastLength = existsSync10(timelinePath) ? readFileSync8(timelinePath, "utf8").length : 0;
6205
+ let lastLength = existsSync11(timelinePath) ? readFileSync9(timelinePath, "utf8").length : 0;
6113
6206
  while (true) {
6114
6207
  await Bun.sleep(1000);
6115
- if (!existsSync10(timelinePath))
6208
+ if (!existsSync11(timelinePath))
6116
6209
  continue;
6117
- const next = readFileSync8(timelinePath, "utf8");
6210
+ const next = readFileSync9(timelinePath, "utf8");
6118
6211
  if (next.length <= lastLength)
6119
6212
  continue;
6120
6213
  const delta = next.slice(lastLength);
@@ -6259,6 +6352,20 @@ async function executeRun(context, args) {
6259
6352
  }
6260
6353
  return { ok: true, group: "run", command, details: resumed };
6261
6354
  }
6355
+ case "restart": {
6356
+ requireNoExtraArgs(rest, "bun run rig run restart");
6357
+ if (context.dryRun) {
6358
+ if (context.outputMode === "text") {
6359
+ console.log("[dry-run] rig run restart");
6360
+ }
6361
+ return { ok: true, group: "run", command };
6362
+ }
6363
+ const restarted = await runRestart(context.projectRoot, runtimeContext);
6364
+ if (context.outputMode === "text") {
6365
+ console.log(`Restarted run: ${restarted.runId}`);
6366
+ }
6367
+ return { ok: true, group: "run", command, details: restarted };
6368
+ }
6262
6369
  case "stop": {
6263
6370
  const runOption = takeOption(rest, "--run");
6264
6371
  const positionalRunId = runOption.rest.length > 0 ? runOption.rest[0] : undefined;
@@ -6316,7 +6423,7 @@ async function executeServer(context, args, options) {
6316
6423
  const authTokenResult = takeOption(pending, "--auth-token");
6317
6424
  pending = authTokenResult.rest;
6318
6425
  requireNoExtraArgs(pending, "bun run rig server start [--host <host>] [--port <n>] [--poll-ms <n>] [--auth-token <token>]");
6319
- const commandParts = ["bun", "run", "packages/server/src/server.ts", "start"];
6426
+ const commandParts = ["rig-server", "start"];
6320
6427
  if (hostResult.value) {
6321
6428
  commandParts.push("--host", hostResult.value);
6322
6429
  }
@@ -6339,7 +6446,7 @@ async function executeServer(context, args, options) {
6339
6446
  const eventResult = takeOption(pending, "--event");
6340
6447
  pending = eventResult.rest;
6341
6448
  requireNoExtraArgs(pending, "bun run rig server notify-test [--event <type>]");
6342
- const commandParts = ["bun", "run", "packages/server/src/server.ts", "notify-test"];
6449
+ const commandParts = ["rig-server", "notify-test"];
6343
6450
  if (eventResult.value) {
6344
6451
  commandParts.push("--event", eventResult.value);
6345
6452
  }
@@ -6400,10 +6507,10 @@ async function executeServer(context, args, options) {
6400
6507
  }
6401
6508
 
6402
6509
  // packages/cli/src/commands/task.ts
6403
- import { readFileSync as readFileSync9 } from "fs";
6510
+ import { readFileSync as readFileSync10 } from "fs";
6404
6511
  import { spawnSync as spawnSync4 } from "child_process";
6405
6512
  import { createInterface as createInterface4 } from "readline/promises";
6406
- import { resolve as resolve19 } from "path";
6513
+ import { resolve as resolve20 } from "path";
6407
6514
  import {
6408
6515
  taskArtifactDir,
6409
6516
  taskArtifacts,
@@ -6734,7 +6841,7 @@ async function executeTask(context, args, options) {
6734
6841
  const fileFlag = takeOption(rest.slice(1), "--file");
6735
6842
  let content;
6736
6843
  if (fileFlag.value) {
6737
- content = readFileSync9(resolve19(context.projectRoot, fileFlag.value), "utf-8");
6844
+ content = readFileSync10(resolve20(context.projectRoot, fileFlag.value), "utf-8");
6738
6845
  } else {
6739
6846
  content = await readStdin();
6740
6847
  }
@@ -6955,8 +7062,8 @@ async function executeTask(context, args, options) {
6955
7062
  }
6956
7063
 
6957
7064
  // packages/cli/src/commands/task-run-driver.ts
6958
- import { copyFileSync as copyFileSync3, existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync10, statSync as statSync2 } from "fs";
6959
- import { resolve as resolve20 } from "path";
7065
+ import { copyFileSync as copyFileSync3, existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync11, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
7066
+ import { resolve as resolve21 } from "path";
6960
7067
  import { spawn as spawn2, spawnSync as spawnSync5 } from "child_process";
6961
7068
  import { createInterface as createLineInterface } from "readline";
6962
7069
  import { loadConfig as loadConfig2 } from "@rig/core/load-config";
@@ -6990,7 +7097,24 @@ import {
6990
7097
  commitRunChanges,
6991
7098
  runPrAutomation
6992
7099
  } from "@rig/runtime/control-plane/native/pr-automation";
7100
+ function looksLikeGitHubToken(value) {
7101
+ const token = value?.trim();
7102
+ if (!token)
7103
+ return false;
7104
+ return /^(gh[opusr]_|github_pat_)/.test(token);
7105
+ }
7106
+ function githubBridgeEnv(token) {
7107
+ const clean = token?.trim();
7108
+ if (!clean)
7109
+ return {};
7110
+ return {
7111
+ RIG_GITHUB_TOKEN: clean,
7112
+ GITHUB_TOKEN: clean,
7113
+ GH_TOKEN: clean
7114
+ };
7115
+ }
6993
7116
  function buildPiRigBridgeEnv(input) {
7117
+ const githubToken = input.githubToken?.trim() || (looksLikeGitHubToken(input.authToken) ? input.authToken.trim() : "");
6994
7118
  return {
6995
7119
  RIG_PROJECT_ROOT: input.projectRoot,
6996
7120
  PROJECT_RIG_ROOT: input.projectRoot,
@@ -7000,7 +7124,7 @@ function buildPiRigBridgeEnv(input) {
7000
7124
  RIG_RUNTIME_ADAPTER: "pi",
7001
7125
  ...input.serverUrl ? { RIG_SERVER_URL: input.serverUrl } : {},
7002
7126
  ...input.authToken ? { RIG_AUTH_TOKEN: input.authToken } : {},
7003
- ...input.githubToken ? { RIG_GITHUB_TOKEN: input.githubToken } : {}
7127
+ ...githubBridgeEnv(githubToken)
7004
7128
  };
7005
7129
  }
7006
7130
  function runGitSync(cwd, args, input) {
@@ -7022,12 +7146,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
7022
7146
  return 0;
7023
7147
  let copied = 0;
7024
7148
  for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
7025
- const sourcePath = resolve20(sourceRoot, relativePath);
7026
- const targetPath = resolve20(targetRoot, relativePath);
7149
+ const sourcePath = resolve21(sourceRoot, relativePath);
7150
+ const targetPath = resolve21(targetRoot, relativePath);
7027
7151
  try {
7028
7152
  if (!statSync2(sourcePath).isFile())
7029
7153
  continue;
7030
- mkdirSync7(resolve20(targetPath, ".."), { recursive: true });
7154
+ mkdirSync7(resolve21(targetPath, ".."), { recursive: true });
7031
7155
  copyFileSync3(sourcePath, targetPath);
7032
7156
  copied += 1;
7033
7157
  } catch {}
@@ -7061,6 +7185,14 @@ function buildTaskRunReviewEnv(config) {
7061
7185
  ...review?.provider ? { AI_REVIEW_PROVIDER: review.provider } : {}
7062
7186
  };
7063
7187
  }
7188
+ function buildDirtyBaselineHandshakeEnv(input) {
7189
+ if (input.baselineMode !== "dirty-snapshot")
7190
+ return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
7191
+ return {
7192
+ RIG_BASELINE_MODE: "dirty-snapshot",
7193
+ RIG_DIRTY_BASELINE_READY_FILE: resolve21(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
7194
+ };
7195
+ }
7064
7196
  function positiveInt(value, fallback) {
7065
7197
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
7066
7198
  }
@@ -7169,9 +7301,9 @@ function createCommandRunner(binary) {
7169
7301
  const stderrChunks = [];
7170
7302
  child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
7171
7303
  child.stderr.on("data", (chunk) => stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
7172
- return await new Promise((resolve21) => {
7173
- child.once("error", (error) => resolve21({ exitCode: 1, stderr: error.message }));
7174
- child.once("close", (code) => resolve21({
7304
+ return await new Promise((resolve22) => {
7305
+ child.once("error", (error) => resolve22({ exitCode: 1, stderr: error.message }));
7306
+ child.once("close", (code) => resolve22({
7175
7307
  exitCode: code ?? 1,
7176
7308
  stdout: Buffer.concat(stdoutChunks).toString("utf8"),
7177
7309
  stderr: Buffer.concat(stderrChunks).toString("utf8")
@@ -7367,7 +7499,7 @@ function summarizeValidationFailure(projectRoot, taskId2) {
7367
7499
  return null;
7368
7500
  }
7369
7501
  for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId2)) {
7370
- const summary = readJsonFile3(resolve20(artifactDir, "validation-summary.json"), null);
7502
+ const summary = readJsonFile3(resolve21(artifactDir, "validation-summary.json"), null);
7371
7503
  if (!summary || summary.status !== "fail") {
7372
7504
  continue;
7373
7505
  }
@@ -7448,9 +7580,9 @@ function readTaskRunAcceptedArtifactState(input) {
7448
7580
  if (!input.taskId || !input.workspaceDir) {
7449
7581
  return { accepted: false, reason: null };
7450
7582
  }
7451
- const artifactDir = resolve20(input.workspaceDir, "artifacts", input.taskId);
7452
- const reviewStatusPath = resolve20(artifactDir, "review-status.txt");
7453
- const taskResultPath = resolve20(artifactDir, "task-result.json");
7583
+ const artifactDir = resolve21(input.workspaceDir, "artifacts", input.taskId);
7584
+ const reviewStatusPath = resolve21(artifactDir, "review-status.txt");
7585
+ const taskResultPath = resolve21(artifactDir, "task-result.json");
7454
7586
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
7455
7587
  if (reviewStatus !== "APPROVED") {
7456
7588
  return { accepted: false, reason: null };
@@ -7487,12 +7619,12 @@ function resolveTaskRunRetryContext(input) {
7487
7619
  if (!input.taskId || !input.workspaceDir) {
7488
7620
  return { shouldRetry: false, failureDetail: null, nextPrompt: null };
7489
7621
  }
7490
- const artifactDir = resolve20(input.workspaceDir, "artifacts", input.taskId);
7491
- const reviewStatePath = resolve20(artifactDir, "review-state.json");
7492
- const reviewFeedbackPath = resolve20(artifactDir, "review-feedback.md");
7493
- const reviewStatusPath = resolve20(artifactDir, "review-status.txt");
7494
- const failedApproachesPath = resolve20(input.workspaceDir, ".rig", "state", "failed_approaches.md");
7495
- const validationSummaryPath = resolve20(artifactDir, "validation-summary.json");
7622
+ const artifactDir = resolve21(input.workspaceDir, "artifacts", input.taskId);
7623
+ const reviewStatePath = resolve21(artifactDir, "review-state.json");
7624
+ const reviewFeedbackPath = resolve21(artifactDir, "review-feedback.md");
7625
+ const reviewStatusPath = resolve21(artifactDir, "review-status.txt");
7626
+ const failedApproachesPath = resolve21(input.workspaceDir, ".rig", "state", "failed_approaches.md");
7627
+ const validationSummaryPath = resolve21(artifactDir, "validation-summary.json");
7496
7628
  const reviewState = readJsonFile3(reviewStatePath, null);
7497
7629
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
7498
7630
  const reviewRejected = isTaskRunReviewRejected(reviewState);
@@ -7547,11 +7679,11 @@ function summarizeTaskRunReviewFailure(reviewState) {
7547
7679
  return "Completion verification rejected the task. Read review-feedback.md for required fixes.";
7548
7680
  }
7549
7681
  function readTaskRunReviewStatus(reviewStatusPath) {
7550
- if (!existsSync11(reviewStatusPath)) {
7682
+ if (!existsSync12(reviewStatusPath)) {
7551
7683
  return null;
7552
7684
  }
7553
7685
  try {
7554
- const status = readFileSync10(reviewStatusPath, "utf8").trim().toUpperCase();
7686
+ const status = readFileSync11(reviewStatusPath, "utf8").trim().toUpperCase();
7555
7687
  return status === "APPROVED" || status === "REJECTED" ? status : null;
7556
7688
  } catch {
7557
7689
  return null;
@@ -7634,8 +7766,11 @@ function stringArrayField(record, key) {
7634
7766
  }
7635
7767
  async function executeRigOwnedTaskRun(context, input) {
7636
7768
  const runtimeTaskId = input.taskId?.trim() || `adhoc-${input.runId}`;
7769
+ const existingRunRecord = readAuthorityRun5(context.projectRoot, input.runId);
7770
+ const resumeMode = process.env.RIG_RUN_RESUME === "1";
7771
+ const resumePreviousStatus = String(existingRunRecord?.status ?? "").toLowerCase();
7637
7772
  const sourceTask = readRunSourceTaskContract(context.projectRoot, input.runId, input.taskId);
7638
- const prompt = buildRunPrompt({
7773
+ let prompt = buildRunPrompt({
7639
7774
  projectRoot: context.projectRoot,
7640
7775
  taskId: input.taskId,
7641
7776
  fallbackTitle: input.title,
@@ -7689,14 +7824,14 @@ async function executeRigOwnedTaskRun(context, input) {
7689
7824
  taskId: runtimeTaskId,
7690
7825
  createdAt: startedAt,
7691
7826
  runtimeAdapter: input.runtimeAdapter,
7692
- status: "created"
7827
+ status: resumeMode ? "preparing" : "created"
7693
7828
  });
7694
7829
  patchAuthorityRun(context.projectRoot, input.runId, {
7695
7830
  status: "preparing",
7696
7831
  startedAt,
7697
7832
  completedAt: null,
7698
7833
  errorText: null,
7699
- artifactRoot: null,
7834
+ artifactRoot: resumeMode ? existingRunRecord?.artifactRoot ?? null : null,
7700
7835
  runtimeAdapter: input.runtimeAdapter,
7701
7836
  runtimeMode: input.runtimeMode,
7702
7837
  interactionMode: input.interactionMode,
@@ -7712,9 +7847,9 @@ async function executeRigOwnedTaskRun(context, input) {
7712
7847
  detail: input.taskId ?? input.title ?? runtimeTaskId
7713
7848
  });
7714
7849
  appendRunLog(context.projectRoot, input.runId, {
7715
- id: `log:${input.runId}:start`,
7716
- title: "Rig task run started",
7717
- detail: input.taskId ?? input.title ?? runtimeTaskId,
7850
+ id: `log:${input.runId}:${resumeMode ? "resume" : "start"}`,
7851
+ title: resumeMode ? "Rig task run resumed" : "Rig task run started",
7852
+ detail: resumeMode ? `Continuing the same run lifecycle for ${input.taskId ?? input.title ?? runtimeTaskId}.` : input.taskId ?? input.title ?? runtimeTaskId,
7718
7853
  tone: "info",
7719
7854
  status: "preparing",
7720
7855
  createdAt: startedAt
@@ -7735,7 +7870,22 @@ async function executeRigOwnedTaskRun(context, input) {
7735
7870
  const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
7736
7871
  const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
7737
7872
  const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
7738
- patchAuthorityRun(context.projectRoot, input.runId, { planning: planningClassification });
7873
+ const planningArtifactPath = resolve21("artifacts", runtimeTaskId, "implementation-plan.md");
7874
+ const persistedPlanning = {
7875
+ ...planningClassification,
7876
+ classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
7877
+ artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
7878
+ classifiedAt: new Date().toISOString()
7879
+ };
7880
+ mkdirSync7(resolve21(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
7881
+ writeFileSync6(resolve21(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
7882
+ `, "utf8");
7883
+ patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
7884
+ prompt = `${prompt}
7885
+
7886
+ Rig planning classification:
7887
+ ${JSON.stringify(persistedPlanning, null, 2)}
7888
+ ${planningClassification.planningRequired ? `Before implementing, write a concise implementation plan to ${planningArtifactPath}. Treat that plan artifact as required acceptance evidence for the Plan stage.` : "Planning is not required for this run; briefly state why before implementation."}`;
7739
7889
  if (input.runtimeAdapter === "pi") {
7740
7890
  for (const stage of ["Connect", "GitHub/task sync", "Prepare workspace", "Launch Pi", "Plan", "Implement"]) {
7741
7891
  appendPiStageLog({
@@ -7777,11 +7927,11 @@ async function executeRigOwnedTaskRun(context, input) {
7777
7927
  let reviewAction;
7778
7928
  let verificationStarted = false;
7779
7929
  let reviewStarted = false;
7780
- let latestRuntimeWorkspace = null;
7781
- let latestSessionDir = null;
7782
- let latestLogsDir = null;
7930
+ let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
7931
+ let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve21(existingRunRecord.sessionPath, "..") : null;
7932
+ let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
7783
7933
  let latestProviderCommand = null;
7784
- let latestRuntimeBranch = null;
7934
+ let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
7785
7935
  let snapshotSidecarPromise = null;
7786
7936
  let dirtyBaselineApplied = false;
7787
7937
  const childEnv = {
@@ -7799,9 +7949,14 @@ async function executeRigOwnedTaskRun(context, input) {
7799
7949
  RIG_RUNTIME_ADAPTER: input.runtimeAdapter,
7800
7950
  RIG_SERVER_RUN_ID: input.runId
7801
7951
  },
7802
- ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {}
7952
+ ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {},
7953
+ ...resumeMode ? {
7954
+ RIG_RUN_RESUME: "1",
7955
+ RIG_RUNTIME_ARTIFACT_CLEANUP: "preserve"
7956
+ } : {}
7803
7957
  };
7804
7958
  Object.assign(childEnv, buildTaskRunReviewEnv(automationConfig));
7959
+ Object.assign(childEnv, buildDirtyBaselineHandshakeEnv({ projectRoot: context.projectRoot, runId: input.runId, baselineMode: input.baselineMode }));
7805
7960
  const automationLimits = resolveTaskRunAutomationLimits(automationConfig);
7806
7961
  const maxAttempts = automationLimits.maxValidationAttempts;
7807
7962
  const promoteToValidating = (detail) => {
@@ -7856,22 +8011,29 @@ async function executeRigOwnedTaskRun(context, input) {
7856
8011
  patchAuthorityRun(context.projectRoot, input.runId, {
7857
8012
  status: "running",
7858
8013
  worktreePath: latestRuntimeWorkspace,
7859
- artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve20(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
8014
+ artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve21(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
7860
8015
  logRoot: latestLogsDir,
7861
- sessionPath: latestSessionDir ? resolve20(latestSessionDir, "session.json") : null,
7862
- sessionLogPath: latestLogsDir ? resolve20(latestLogsDir, "agent-stdout.log") : null,
8016
+ sessionPath: latestSessionDir ? resolve21(latestSessionDir, "session.json") : null,
8017
+ sessionLogPath: latestLogsDir ? resolve21(latestLogsDir, "agent-stdout.log") : null,
7863
8018
  branch: runtimeId
7864
8019
  });
7865
8020
  if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
7866
8021
  dirtyBaselineApplied = true;
7867
8022
  const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
8023
+ const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
8024
+ if (readyFile) {
8025
+ mkdirSync7(resolve21(readyFile, ".."), { recursive: true });
8026
+ writeFileSync6(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
8027
+ `, "utf8");
8028
+ }
7868
8029
  appendRunLog(context.projectRoot, input.runId, {
7869
8030
  id: `log:${input.runId}:dirty-baseline`,
7870
8031
  title: "Dirty baseline snapshot",
7871
8032
  detail: dirty.detail,
7872
8033
  tone: dirty.applied ? "tool" : "info",
7873
8034
  status: dirty.applied ? "completed" : "skipped",
7874
- createdAt: new Date().toISOString()
8035
+ createdAt: new Date().toISOString(),
8036
+ payload: readyFile ? { readyFile } : undefined
7875
8037
  });
7876
8038
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Dirty baseline snapshot" });
7877
8039
  }
@@ -8097,7 +8259,36 @@ async function executeRigOwnedTaskRun(context, input) {
8097
8259
  let reviewFailureDetail = null;
8098
8260
  const stderrLines = [];
8099
8261
  const piAcceptedArtifactExitGraceMs = resolvePiAcceptedArtifactExitGraceMs(childEnv);
8100
- for (let attempt = 1;attempt <= maxAttempts; attempt += 1) {
8262
+ if (resumeMode && ["validating", "reviewing"].includes(resumePreviousStatus)) {
8263
+ appendRunLog(context.projectRoot, input.runId, {
8264
+ id: `log:${input.runId}:resume-closeout-phase`,
8265
+ title: "Resume continuing from closeout phase",
8266
+ detail: `Previous run status was ${resumePreviousStatus}; skipping agent relaunch and continuing validation/PR/merge closeout for the same run.`,
8267
+ tone: "info",
8268
+ status: resumePreviousStatus,
8269
+ createdAt: new Date().toISOString()
8270
+ });
8271
+ emitServerRunEvent({ type: "log", runId: input.runId, title: "Resume continuing from closeout phase" });
8272
+ exit = { code: 0, signal: null };
8273
+ } else if (resumeMode && latestRuntimeWorkspace) {
8274
+ const acceptedArtifactState = readTaskRunAcceptedArtifactState({
8275
+ taskId: input.taskId ?? runtimeTaskId,
8276
+ workspaceDir: latestRuntimeWorkspace
8277
+ });
8278
+ if (acceptedArtifactState.accepted) {
8279
+ appendRunLog(context.projectRoot, input.runId, {
8280
+ id: `log:${input.runId}:resume-accepted-artifacts`,
8281
+ title: "Resume found accepted artifacts; continuing closeout",
8282
+ detail: acceptedArtifactState.reason ?? "Accepted task artifacts are present from the previous run process.",
8283
+ tone: "info",
8284
+ status: "validating",
8285
+ createdAt: new Date().toISOString()
8286
+ });
8287
+ emitServerRunEvent({ type: "log", runId: input.runId, title: "Resume found accepted artifacts; continuing closeout" });
8288
+ exit = { code: 0, signal: null };
8289
+ }
8290
+ }
8291
+ for (let attempt = 1;!exit && attempt <= maxAttempts; attempt += 1) {
8101
8292
  const attemptHostAgentCommand = buildHostAgentCommand(currentPrompt);
8102
8293
  const child = spawn2(attemptHostAgentCommand[0], attemptHostAgentCommand.slice(1), {
8103
8294
  cwd: context.projectRoot,
@@ -8138,7 +8329,7 @@ async function executeRigOwnedTaskRun(context, input) {
8138
8329
  let acceptedArtifactObservedAt = null;
8139
8330
  let acceptedArtifactPollTimer = null;
8140
8331
  let acceptedArtifactKillTimer = null;
8141
- const attemptExit = await new Promise((resolve21) => {
8332
+ const attemptExit = await new Promise((resolve22) => {
8142
8333
  let settled = false;
8143
8334
  const settle = (result) => {
8144
8335
  if (settled)
@@ -8146,7 +8337,7 @@ async function executeRigOwnedTaskRun(context, input) {
8146
8337
  settled = true;
8147
8338
  if (acceptedArtifactPollTimer)
8148
8339
  clearInterval(acceptedArtifactPollTimer);
8149
- resolve21(result);
8340
+ resolve22(result);
8150
8341
  };
8151
8342
  const pollAcceptedArtifacts = () => {
8152
8343
  const artifactState = readTaskRunAcceptedArtifactState({
@@ -8343,6 +8534,29 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
8343
8534
  });
8344
8535
  throw new CliError2(terminalFailureDetail, exit.code ?? 1);
8345
8536
  }
8537
+ if (planningClassification.planningRequired) {
8538
+ const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
8539
+ const expectedPlanPath = resolve21(planWorkspace, planningArtifactPath);
8540
+ if (!existsSync12(expectedPlanPath)) {
8541
+ const failedAt = new Date().toISOString();
8542
+ const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
8543
+ patchAuthorityRun(context.projectRoot, input.runId, {
8544
+ status: "needs_attention",
8545
+ completedAt: failedAt,
8546
+ errorText: failureDetail
8547
+ });
8548
+ appendRunLog(context.projectRoot, input.runId, {
8549
+ id: `log:${input.runId}:plan-artifact-missing`,
8550
+ title: "Required plan artifact missing",
8551
+ detail: failureDetail,
8552
+ tone: "error",
8553
+ status: "needs_attention",
8554
+ createdAt: failedAt
8555
+ });
8556
+ emitServerRunEvent({ type: "failed", runId: input.runId, error: failureDetail });
8557
+ throw new CliError2(failureDetail, 1);
8558
+ }
8559
+ }
8346
8560
  const runPiPrFeedbackFix = async (message2) => {
8347
8561
  appendPiStageLog({
8348
8562
  projectRoot: context.projectRoot,
@@ -8400,9 +8614,9 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
8400
8614
  });
8401
8615
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
8402
8616
  });
8403
- const exitCode = await new Promise((resolve21) => {
8404
- child.once("error", () => resolve21(1));
8405
- child.once("close", (code) => resolve21(code ?? 1));
8617
+ const exitCode = await new Promise((resolve22) => {
8618
+ child.once("error", () => resolve22(1));
8619
+ child.once("close", (code) => resolve22(code ?? 1));
8406
8620
  });
8407
8621
  if (exitCode !== 0) {
8408
8622
  throw new Error(`Pi PR feedback fix failed with exit code ${exitCode}.`);
@@ -8521,8 +8735,8 @@ async function executeTest(context, args) {
8521
8735
  }
8522
8736
 
8523
8737
  // packages/cli/src/commands/setup.ts
8524
- import { existsSync as existsSync12, mkdirSync as mkdirSync8, readdirSync as readdirSync2, writeFileSync as writeFileSync6 } from "fs";
8525
- import { resolve as resolve21 } from "path";
8738
+ import { existsSync as existsSync13, mkdirSync as mkdirSync8, readdirSync as readdirSync2, writeFileSync as writeFileSync7 } from "fs";
8739
+ import { resolve as resolve22 } from "path";
8526
8740
  import { createPluginHost } from "@rig/core";
8527
8741
  import {
8528
8742
  isSupportedBunVersion as isSupportedBunVersion2,
@@ -8585,9 +8799,9 @@ function runSetupInit(projectRoot) {
8585
8799
  mkdirSync8(stateDir, { recursive: true });
8586
8800
  mkdirSync8(logsDir, { recursive: true });
8587
8801
  mkdirSync8(artifactsDir, { recursive: true });
8588
- const failuresPath = resolve21(stateDir, "failed_approaches.md");
8589
- if (!existsSync12(failuresPath)) {
8590
- writeFileSync6(failuresPath, `# Failed Approaches
8802
+ const failuresPath = resolve22(stateDir, "failed_approaches.md");
8803
+ if (!existsSync13(failuresPath)) {
8804
+ writeFileSync7(failuresPath, `# Failed Approaches
8591
8805
 
8592
8806
  `, "utf-8");
8593
8807
  }
@@ -8604,18 +8818,18 @@ async function runSetupCheck(projectRoot) {
8604
8818
  }
8605
8819
  async function runSetupPreflight(projectRoot) {
8606
8820
  await runSetupCheck(projectRoot);
8607
- const validationRoot = resolve21(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
8608
- if (existsSync12(validationRoot)) {
8821
+ const validationRoot = resolve22(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
8822
+ if (existsSync13(validationRoot)) {
8609
8823
  const validators = readdirSync2(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
8610
8824
  for (const validator of validators) {
8611
- const script = resolve21(validationRoot, validator.name, "validate.sh");
8612
- if (existsSync12(script)) {
8825
+ const script = resolve22(validationRoot, validator.name, "validate.sh");
8826
+ if (existsSync13(script)) {
8613
8827
  console.log(`OK: validator script ${script}`);
8614
8828
  }
8615
8829
  }
8616
8830
  }
8617
- const hooksRoot = resolve21(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
8618
- if (existsSync12(hooksRoot)) {
8831
+ const hooksRoot = resolve22(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
8832
+ if (existsSync13(hooksRoot)) {
8619
8833
  const hooks = readdirSync2(hooksRoot).filter((name) => name.endsWith(".sh"));
8620
8834
  for (const hook of hooks) {
8621
8835
  console.log(`OK: hook ${hook}`);