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

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;
@@ -3254,7 +3272,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
3254
3272
  } else if ("errorText" in next) {
3255
3273
  delete next.errorText;
3256
3274
  }
3257
- writeJsonFile3(resolve9(resolveAuthorityRunDir(projectRoot, input.runId), "run.json"), next);
3275
+ writeJsonFile3(resolve10(resolveAuthorityRunDir(projectRoot, input.runId), "run.json"), next);
3258
3276
  return next;
3259
3277
  }
3260
3278
 
@@ -3375,10 +3393,10 @@ async function executeAgent(context, args) {
3375
3393
  status: "running",
3376
3394
  startedAt: createdAt,
3377
3395
  worktreePath: runtime.workspaceDir,
3378
- artifactRoot: resolve10(runtime.workspaceDir, "artifacts", taskId),
3396
+ artifactRoot: resolve11(runtime.workspaceDir, "artifacts", taskId),
3379
3397
  logRoot: runtime.logsDir,
3380
- sessionPath: resolve10(runtime.sessionDir, "session.json"),
3381
- sessionLogPath: resolve10(runtime.logsDir, "agent-stdout.log"),
3398
+ sessionPath: resolve11(runtime.sessionDir, "session.json"),
3399
+ sessionLogPath: resolve11(runtime.logsDir, "agent-stdout.log"),
3382
3400
  pid: process.pid
3383
3401
  });
3384
3402
  const result = await runInAgentRuntime({
@@ -3398,10 +3416,10 @@ async function executeAgent(context, args) {
3398
3416
  startedAt: createdAt,
3399
3417
  completedAt: failedAt,
3400
3418
  worktreePath: runtime.workspaceDir,
3401
- artifactRoot: resolve10(runtime.workspaceDir, "artifacts", taskId),
3419
+ artifactRoot: resolve11(runtime.workspaceDir, "artifacts", taskId),
3402
3420
  logRoot: runtime.logsDir,
3403
- sessionPath: resolve10(runtime.sessionDir, "session.json"),
3404
- sessionLogPath: resolve10(runtime.logsDir, "agent-stdout.log"),
3421
+ sessionPath: resolve11(runtime.sessionDir, "session.json"),
3422
+ sessionLogPath: resolve11(runtime.logsDir, "agent-stdout.log"),
3405
3423
  pid: process.pid,
3406
3424
  errorText: result.stderr ? result.stderr.trim() : `Agent runtime command failed (${result.exitCode})`
3407
3425
  });
@@ -3418,10 +3436,10 @@ ${result.stderr.trim()}` : ""}`, result.exitCode);
3418
3436
  startedAt: createdAt,
3419
3437
  completedAt,
3420
3438
  worktreePath: runtime.workspaceDir,
3421
- artifactRoot: resolve10(runtime.workspaceDir, "artifacts", taskId),
3439
+ artifactRoot: resolve11(runtime.workspaceDir, "artifacts", taskId),
3422
3440
  logRoot: runtime.logsDir,
3423
- sessionPath: resolve10(runtime.sessionDir, "session.json"),
3424
- sessionLogPath: resolve10(runtime.logsDir, "agent-stdout.log"),
3441
+ sessionPath: resolve11(runtime.sessionDir, "session.json"),
3442
+ sessionLogPath: resolve11(runtime.logsDir, "agent-stdout.log"),
3425
3443
  pid: process.pid
3426
3444
  });
3427
3445
  return {
@@ -3495,7 +3513,7 @@ ${result.stderr.trim()}` : ""}`, result.exitCode);
3495
3513
  import {
3496
3514
  chmodSync,
3497
3515
  copyFileSync as copyFileSync2,
3498
- existsSync as existsSync6,
3516
+ existsSync as existsSync7,
3499
3517
  mkdirSync as mkdirSync5,
3500
3518
  readdirSync,
3501
3519
  readlinkSync,
@@ -3505,7 +3523,7 @@ import {
3505
3523
  unlinkSync
3506
3524
  } from "fs";
3507
3525
  import { homedir as homedir4 } from "os";
3508
- import { resolve as resolve11 } from "path";
3526
+ import { resolve as resolve12 } from "path";
3509
3527
  import { buildBinary as buildBinary2 } from "@rig/runtime/control-plane/runtime/isolation";
3510
3528
  import {
3511
3529
  computeRuntimeImageFingerprint,
@@ -3524,13 +3542,13 @@ async function runQuietBinaryProbe(binaryPath, args, cwd) {
3524
3542
 
3525
3543
  // packages/cli/src/commands/dist.ts
3526
3544
  function collectRigValidatorBuildTargets(input) {
3527
- const validatorsRoot = resolve11(input.hostProjectRoot, "packages/runtime/src/control-plane/validators");
3528
- if (!existsSync6(validatorsRoot))
3545
+ const validatorsRoot = resolve12(input.hostProjectRoot, "packages/runtime/src/control-plane/validators");
3546
+ if (!existsSync7(validatorsRoot))
3529
3547
  return [];
3530
3548
  const targets = [];
3531
3549
  const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
3532
3550
  for (const category of categories) {
3533
- const categoryDir = resolve11(validatorsRoot, category.name);
3551
+ const categoryDir = resolve12(validatorsRoot, category.name);
3534
3552
  for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
3535
3553
  if (!entry.isFile() || !entry.name.endsWith(".ts"))
3536
3554
  continue;
@@ -3539,7 +3557,7 @@ function collectRigValidatorBuildTargets(input) {
3539
3557
  continue;
3540
3558
  targets.push({
3541
3559
  source: `packages/runtime/src/control-plane/validators/${category.name}/${entry.name}`,
3542
- dest: resolve11(input.imageDir, `bin/validators/${category.name}-${check}`),
3560
+ dest: resolve12(input.imageDir, `bin/validators/${category.name}-${check}`),
3543
3561
  cwd: input.hostProjectRoot
3544
3562
  });
3545
3563
  }
@@ -3548,16 +3566,16 @@ function collectRigValidatorBuildTargets(input) {
3548
3566
  }
3549
3567
  async function findLatestDistBinary(projectRoot) {
3550
3568
  const distRoot = resolveControlPlaneHostDistDir(projectRoot);
3551
- if (!existsSync6(distRoot)) {
3569
+ if (!existsSync7(distRoot)) {
3552
3570
  return null;
3553
3571
  }
3554
3572
  const entries = readdirSync(distRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith("rig-")).map((entry) => ({
3555
3573
  name: entry.name,
3556
- mtimeMs: statSync(resolve11(distRoot, entry.name)).mtimeMs
3574
+ mtimeMs: statSync(resolve12(distRoot, entry.name)).mtimeMs
3557
3575
  })).sort((a, b) => b.mtimeMs - a.mtimeMs || b.name.localeCompare(a.name));
3558
3576
  for (const { name } of entries) {
3559
- const candidate = resolve11(distRoot, name, "bin", "rig");
3560
- if (existsSync6(candidate) && await isRunnableRigBinary(candidate, projectRoot)) {
3577
+ const candidate = resolve12(distRoot, name, "bin", "rig");
3578
+ if (existsSync7(candidate) && await isRunnableRigBinary(candidate, projectRoot)) {
3561
3579
  return candidate;
3562
3580
  }
3563
3581
  }
@@ -3569,7 +3587,7 @@ async function isRunnableRigBinary(binaryPath, projectRoot) {
3569
3587
  async function runDistDoctor(projectRoot) {
3570
3588
  const bunPath = Bun.which("bun");
3571
3589
  const rigPath = Bun.which("rig");
3572
- const userBinDir = resolve11(homedir4(), ".local/bin");
3590
+ const userBinDir = resolve12(homedir4(), ".local/bin");
3573
3591
  const userBinInPath = (process.env.PATH || "").split(":").filter(Boolean).includes(userBinDir);
3574
3592
  let rigRunnable = false;
3575
3593
  if (rigPath) {
@@ -3617,15 +3635,15 @@ async function executeDist(context, args) {
3617
3635
  let source = await findLatestDistBinary(context.projectRoot);
3618
3636
  let buildDir = null;
3619
3637
  if (!source) {
3620
- buildDir = resolve11(resolveControlPlaneHostDistDir(context.projectRoot), `rig-install-${Date.now()}`);
3638
+ buildDir = resolve12(resolveControlPlaneHostDistDir(context.projectRoot), `rig-install-${Date.now()}`);
3621
3639
  await context.runCommand(["bun", "run", "packages/cli/bin/build-rig-binaries.ts", "--output-dir", buildDir]);
3622
- source = resolve11(buildDir, "bin", "rig");
3640
+ source = resolve12(buildDir, "bin", "rig");
3623
3641
  }
3624
- if (!existsSync6(source)) {
3642
+ if (!existsSync7(source)) {
3625
3643
  throw new CliError2(`Unable to locate rig binary at ${source}.`, 2);
3626
3644
  }
3627
- const installedPath = resolve11(installDir, "rig");
3628
- if (existsSync6(installedPath)) {
3645
+ const installedPath = resolve12(installDir, "rig");
3646
+ if (existsSync7(installedPath)) {
3629
3647
  unlinkSync(installedPath);
3630
3648
  }
3631
3649
  copyFileSync2(source, installedPath);
@@ -3667,22 +3685,22 @@ async function executeDist(context, args) {
3667
3685
  requireNoExtraArgs(rest, "bun run rig dist rebuild-agent");
3668
3686
  const fp = await computeRuntimeImageFingerprint(context.projectRoot);
3669
3687
  const currentId = computeRuntimeImageId(fp);
3670
- const imagesDir = resolve11(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
3688
+ const imagesDir = resolve12(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
3671
3689
  mkdirSync5(imagesDir, { recursive: true });
3672
3690
  let pruned = 0;
3673
3691
  for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
3674
3692
  if (entry.isDirectory() && entry.name !== currentId) {
3675
- rmSync4(resolve11(imagesDir, entry.name), { recursive: true, force: true });
3693
+ rmSync4(resolve12(imagesDir, entry.name), { recursive: true, force: true });
3676
3694
  pruned++;
3677
3695
  }
3678
3696
  }
3679
3697
  if (pruned > 0 && context.outputMode === "text") {
3680
3698
  console.log(`Pruned ${pruned} stale image(s).`);
3681
3699
  }
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 });
3700
+ const imageDir = resolve12(imagesDir, currentId);
3701
+ mkdirSync5(resolve12(imageDir, "bin/hooks"), { recursive: true });
3702
+ mkdirSync5(resolve12(imageDir, "bin/plugins"), { recursive: true });
3703
+ mkdirSync5(resolve12(imageDir, "bin/validators"), { recursive: true });
3686
3704
  const hookNames = [
3687
3705
  "scope-guard",
3688
3706
  "import-guard",
@@ -3696,25 +3714,25 @@ async function executeDist(context, args) {
3696
3714
  ];
3697
3715
  const targets = [];
3698
3716
  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 });
3717
+ targets.push({ source: "packages/runtime/bin/rig-agent.ts", dest: resolve12(imageDir, "bin/rig-agent"), cwd: hostProjectRoot });
3718
+ targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest: resolve12(resolveControlPlaneHostBinDir(context.projectRoot), "rig-agent"), cwd: hostProjectRoot });
3701
3719
  for (const hookName of hookNames) {
3702
3720
  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 });
3721
+ targets.push({ source: src, dest: resolve12(imageDir, `bin/hooks/${hookName}`), cwd: hostProjectRoot });
3722
+ targets.push({ source: src, dest: resolve12(resolveControlPlaneHostBinDir(context.projectRoot), `hooks/${hookName}`), cwd: hostProjectRoot });
3705
3723
  }
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");
3724
+ const pluginsDir = resolve12(context.projectRoot, "rig/plugins");
3725
+ const binPluginsDir = resolve12(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
3726
+ const validatorsRoot = resolve12(hostProjectRoot, "packages/runtime/src/control-plane/validators");
3727
+ const binValidatorsDir = resolve12(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
3710
3728
  mkdirSync5(binPluginsDir, { recursive: true });
3711
3729
  mkdirSync5(binValidatorsDir, { recursive: true });
3712
- if (existsSync6(pluginsDir)) {
3730
+ if (existsSync7(pluginsDir)) {
3713
3731
  for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
3714
3732
  const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
3715
3733
  if (!m)
3716
3734
  continue;
3717
- targets.push({ source: `rig/plugins/${entry.name}`, dest: resolve11(imageDir, `bin/plugins/${m[1]}`), cwd: context.projectRoot });
3735
+ targets.push({ source: `rig/plugins/${entry.name}`, dest: resolve12(imageDir, `bin/plugins/${m[1]}`), cwd: context.projectRoot });
3718
3736
  }
3719
3737
  }
3720
3738
  targets.push(...collectRigValidatorBuildTargets({ contextProjectRoot: context.projectRoot, hostProjectRoot, imageDir }));
@@ -3725,17 +3743,17 @@ async function executeDist(context, args) {
3725
3743
  const isValidator = dest.includes("/bin/validators/");
3726
3744
  await buildBinary2(source, dest, cwd, isValidator ? { AGENT_BUN_PATH: Bun.which("bun") || "bun" } : { AGENT_PROJECT_ROOT: context.projectRoot });
3727
3745
  }
3728
- if (existsSync6(pluginsDir)) {
3746
+ if (existsSync7(pluginsDir)) {
3729
3747
  for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
3730
3748
  const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
3731
3749
  if (!m)
3732
3750
  continue;
3733
3751
  const pluginName = m[1];
3734
- const imageBin = resolve11(imageDir, `bin/plugins/${pluginName}`);
3752
+ const imageBin = resolve12(imageDir, `bin/plugins/${pluginName}`);
3735
3753
  if (!pluginName)
3736
3754
  continue;
3737
- const symlinkPath = resolve11(binPluginsDir, pluginName);
3738
- if (existsSync6(imageBin)) {
3755
+ const symlinkPath = resolve12(binPluginsDir, pluginName);
3756
+ if (existsSync7(imageBin)) {
3739
3757
  try {
3740
3758
  unlinkSync(symlinkPath);
3741
3759
  } catch {}
@@ -3743,10 +3761,10 @@ async function executeDist(context, args) {
3743
3761
  }
3744
3762
  }
3745
3763
  }
3746
- if (existsSync6(validatorsRoot)) {
3764
+ if (existsSync7(validatorsRoot)) {
3747
3765
  const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
3748
3766
  for (const category of categories) {
3749
- const categoryDir = resolve11(validatorsRoot, category.name);
3767
+ const categoryDir = resolve12(validatorsRoot, category.name);
3750
3768
  for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
3751
3769
  if (!entry.isFile() || !entry.name.endsWith(".ts"))
3752
3770
  continue;
@@ -3754,9 +3772,9 @@ async function executeDist(context, args) {
3754
3772
  if (!check || check === "index" || check === "shared")
3755
3773
  continue;
3756
3774
  const validatorName = `${category.name}-${check}`;
3757
- const imageBin = resolve11(imageDir, `bin/validators/${validatorName}`);
3758
- const symlinkPath = resolve11(binValidatorsDir, validatorName);
3759
- if (existsSync6(imageBin)) {
3775
+ const imageBin = resolve12(imageDir, `bin/validators/${validatorName}`);
3776
+ const symlinkPath = resolve12(binValidatorsDir, validatorName);
3777
+ if (existsSync7(imageBin)) {
3760
3778
  try {
3761
3779
  unlinkSync(symlinkPath);
3762
3780
  } catch {}
@@ -3765,18 +3783,18 @@ async function executeDist(context, args) {
3765
3783
  }
3766
3784
  }
3767
3785
  }
3768
- const agentsDir = resolve11(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "agents");
3769
- if (existsSync6(agentsDir)) {
3786
+ const agentsDir = resolve12(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "agents");
3787
+ if (existsSync7(agentsDir)) {
3770
3788
  let relinkCount = 0;
3771
3789
  for (const agentEntry of readdirSync(agentsDir, { withFileTypes: true })) {
3772
3790
  if (!agentEntry.isDirectory())
3773
3791
  continue;
3774
- const agentBinDir = resolve11(agentsDir, agentEntry.name, "worktree", ".rig", "bin");
3775
- if (!existsSync6(agentBinDir))
3792
+ const agentBinDir = resolve12(agentsDir, agentEntry.name, "worktree", ".rig", "bin");
3793
+ if (!existsSync7(agentBinDir))
3776
3794
  continue;
3777
3795
  const walkDir = (dir) => {
3778
3796
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
3779
- const fullPath = resolve11(dir, entry.name);
3797
+ const fullPath = resolve12(dir, entry.name);
3780
3798
  if (entry.isDirectory()) {
3781
3799
  walkDir(fullPath);
3782
3800
  } else if (entry.isSymbolicLink()) {
@@ -3810,7 +3828,7 @@ async function executeDist(context, args) {
3810
3828
 
3811
3829
  // packages/cli/src/commands/inbox.ts
3812
3830
  import { writeFileSync as writeFileSync4 } from "fs";
3813
- import { resolve as resolve12 } from "path";
3831
+ import { resolve as resolve13 } from "path";
3814
3832
  import {
3815
3833
  listAuthorityRuns,
3816
3834
  readJsonlFile as readJsonlFile3,
@@ -3827,7 +3845,7 @@ async function executeInbox(context, args) {
3827
3845
  pending = task.rest;
3828
3846
  requireNoExtraArgs(pending, "bun run rig inbox approvals [--run <id>] [--task <id>]");
3829
3847
  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) => ({
3848
+ const approvals = runs.flatMap((entry) => readJsonlFile3(resolve13(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "approvals.jsonl")).map((record) => ({
3831
3849
  runId: entry.runId,
3832
3850
  record
3833
3851
  })));
@@ -3855,7 +3873,7 @@ async function executeInbox(context, args) {
3855
3873
  if (decision.value !== "approve" && decision.value !== "reject") {
3856
3874
  throw new CliError2("decision must be approve or reject.");
3857
3875
  }
3858
- const approvalsPath = resolve12(resolveAuthorityRunDir2(context.projectRoot, run.value), "approvals.jsonl");
3876
+ const approvalsPath = resolve13(resolveAuthorityRunDir2(context.projectRoot, run.value), "approvals.jsonl");
3859
3877
  const approvals = readJsonlFile3(approvalsPath);
3860
3878
  const resolvedAt = new Date().toISOString();
3861
3879
  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 +3890,7 @@ async function executeInbox(context, args) {
3872
3890
  pending = task.rest;
3873
3891
  requireNoExtraArgs(pending, "bun run rig inbox inputs [--run <id>] [--task <id>]");
3874
3892
  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) => ({
3893
+ const requests = runs.flatMap((entry) => readJsonlFile3(resolve13(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "user-input.jsonl")).map((record) => ({
3876
3894
  runId: entry.runId,
3877
3895
  record
3878
3896
  })));
@@ -3914,7 +3932,7 @@ async function executeInbox(context, args) {
3914
3932
  const [key, ...restValue] = entry.split("=");
3915
3933
  return [key, restValue.join("=")];
3916
3934
  }));
3917
- const requestsPath = resolve12(resolveAuthorityRunDir2(context.projectRoot, run.value), "user-input.jsonl");
3935
+ const requestsPath = resolve13(resolveAuthorityRunDir2(context.projectRoot, run.value), "user-input.jsonl");
3918
3936
  const requests = readJsonlFile3(requestsPath);
3919
3937
  const resolvedAt = new Date().toISOString();
3920
3938
  const next = requests.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", answers: parsedAnswers, respondedAt: resolvedAt, resolvedAt } : entry);
@@ -3929,14 +3947,14 @@ async function executeInbox(context, args) {
3929
3947
  }
3930
3948
 
3931
3949
  // 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";
3950
+ import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
3933
3951
  import { spawnSync as spawnSync2 } from "child_process";
3934
- import { resolve as resolve15 } from "path";
3952
+ import { resolve as resolve16 } from "path";
3935
3953
  import { buildRigInitConfigSource } from "@rig/core";
3936
3954
 
3937
3955
  // packages/cli/src/commands/_snapshot-upload.ts
3938
3956
  import { mkdir, readdir, readFile, writeFile } from "fs/promises";
3939
- import { dirname as dirname2, resolve as resolve13, relative, sep } from "path";
3957
+ import { dirname as dirname2, resolve as resolve14, relative, sep } from "path";
3940
3958
  var SNAPSHOT_ARCHIVE_VERSION = 1;
3941
3959
  var SNAPSHOT_ARCHIVE_CONTENT_TYPE = "application/vnd.rig.snapshot+json";
3942
3960
  var DEFAULT_EXCLUDED_DIRECTORIES = new Set([
@@ -3958,15 +3976,15 @@ function assertManifestPath(root, relativePath) {
3958
3976
  if (!relativePath || relativePath.startsWith("/") || relativePath.includes("\x00")) {
3959
3977
  throw new Error(`Invalid snapshot path: ${relativePath}`);
3960
3978
  }
3961
- const resolved = resolve13(root, relativePath);
3979
+ const resolved = resolve14(root, relativePath);
3962
3980
  const relativeToRoot = relative(root, resolved);
3963
- if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || resolve13(relativeToRoot) === resolved) {
3981
+ if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || resolve14(relativeToRoot) === resolved) {
3964
3982
  throw new Error(`Snapshot path escapes project root: ${relativePath}`);
3965
3983
  }
3966
3984
  return resolved;
3967
3985
  }
3968
3986
  async function buildSnapshotUploadManifest(projectRoot, options = {}) {
3969
- const root = resolve13(projectRoot);
3987
+ const root = resolve14(projectRoot);
3970
3988
  const excludedDirectories = [...new Set([
3971
3989
  ...DEFAULT_EXCLUDED_DIRECTORIES,
3972
3990
  ...options.excludedDirectories ?? []
@@ -3978,7 +3996,7 @@ async function buildSnapshotUploadManifest(projectRoot, options = {}) {
3978
3996
  for (const entry of entries) {
3979
3997
  if (entry.isDirectory() && excludedSet.has(entry.name))
3980
3998
  continue;
3981
- const fullPath = resolve13(dir, entry.name);
3999
+ const fullPath = resolve14(dir, entry.name);
3982
4000
  if (entry.isDirectory()) {
3983
4001
  await visit(fullPath);
3984
4002
  continue;
@@ -4026,8 +4044,8 @@ async function uploadSnapshotArchiveViaServer(context, input) {
4026
4044
  }
4027
4045
 
4028
4046
  // packages/cli/src/commands/_doctor-checks.ts
4029
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
4030
- import { resolve as resolve14 } from "path";
4047
+ import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
4048
+ import { resolve as resolve15 } from "path";
4031
4049
  import { isSupportedBunVersion, MIN_SUPPORTED_BUN_VERSION } from "@rig/runtime/control-plane/setup-version";
4032
4050
  function check(id, label, status, detail, remediation) {
4033
4051
  return {
@@ -4067,11 +4085,11 @@ function repoSlugFromConfig(config) {
4067
4085
  function loadFallbackConfig(projectRoot) {
4068
4086
  const candidates = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
4069
4087
  for (const name of candidates) {
4070
- const path = resolve14(projectRoot, name);
4071
- if (!existsSync7(path))
4088
+ const path = resolve15(projectRoot, name);
4089
+ if (!existsSync8(path))
4072
4090
  continue;
4073
4091
  try {
4074
- const source = readFileSync4(path, "utf8");
4092
+ const source = readFileSync5(path, "utf8");
4075
4093
  if (name.endsWith(".json"))
4076
4094
  return JSON.parse(source);
4077
4095
  const owner = source.match(/owner\s*:\s*["']([^"']+)["']/)?.[1];
@@ -4150,7 +4168,7 @@ async function runRigDoctorChecks(options) {
4150
4168
  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
4169
  const loadedConfig = await loadConfig(projectRoot).catch(() => null);
4152
4170
  const config = loadedConfig ?? loadFallbackConfig(projectRoot);
4153
- const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync7(resolve14(projectRoot, name)));
4171
+ const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync8(resolve15(projectRoot, name)));
4154
4172
  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
4173
  const taskSourceKind = config?.taskSource?.kind;
4156
4174
  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 +4263,10 @@ function countDoctorFailures(checks) {
4245
4263
  }
4246
4264
 
4247
4265
  // packages/cli/src/commands/init.ts
4248
- var RIG_CONFIG_PACKAGE_VERSION = "0.0.6-alpha.1";
4266
+ var RIG_CONFIG_PACKAGE_DIST_TAG = "latest";
4249
4267
  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}`
4268
+ "@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_DIST_TAG}`,
4269
+ "@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_DIST_TAG}`
4252
4270
  };
4253
4271
  function parseRepoSlugFromRemote(remoteUrl) {
4254
4272
  const trimmed = remoteUrl.trim();
@@ -4268,20 +4286,20 @@ function parseRepoSlug(value) {
4268
4286
  return { owner: match[1], repo: match[2], slug: `${match[1]}/${match[2]}` };
4269
4287
  }
4270
4288
  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))
4289
+ const rigDir = resolve16(projectRoot, ".rig");
4290
+ mkdirSync6(resolve16(rigDir, "state"), { recursive: true });
4291
+ mkdirSync6(resolve16(rigDir, "logs"), { recursive: true });
4292
+ mkdirSync6(resolve16(rigDir, "runs"), { recursive: true });
4293
+ mkdirSync6(resolve16(rigDir, "tmp"), { recursive: true });
4294
+ mkdirSync6(resolve16(projectRoot, "artifacts"), { recursive: true });
4295
+ const taskConfigPath = resolve16(rigDir, "task-config.json");
4296
+ if (!existsSync9(taskConfigPath))
4279
4297
  writeFileSync5(taskConfigPath, `{}
4280
4298
  `, "utf-8");
4281
4299
  }
4282
4300
  function ensureGitignoreEntries(projectRoot) {
4283
- const path = resolve15(projectRoot, ".gitignore");
4284
- const existing = existsSync8(path) ? readFileSync5(path, "utf8") : "";
4301
+ const path = resolve16(projectRoot, ".gitignore");
4302
+ const existing = existsSync9(path) ? readFileSync6(path, "utf8") : "";
4285
4303
  const entries = [".rig/state/", ".rig/logs/", ".rig/runs/", ".rig/tmp/"];
4286
4304
  const missing = entries.filter((entry) => !existing.split(/\r?\n/).includes(entry));
4287
4305
  if (missing.length === 0)
@@ -4294,14 +4312,14 @@ function ensureGitignoreEntries(projectRoot) {
4294
4312
  `, "utf8");
4295
4313
  }
4296
4314
  function ensureRigConfigPackageDependencies(projectRoot) {
4297
- const path = resolve15(projectRoot, "package.json");
4298
- const existing = existsSync8(path) ? JSON.parse(readFileSync5(path, "utf8")) : {};
4315
+ const path = resolve16(projectRoot, "package.json");
4316
+ const existing = existsSync9(path) ? JSON.parse(readFileSync6(path, "utf8")) : {};
4299
4317
  const devDependencies = existing.devDependencies && typeof existing.devDependencies === "object" && !Array.isArray(existing.devDependencies) ? { ...existing.devDependencies } : {};
4300
4318
  for (const [name, spec] of Object.entries(RIG_CONFIG_DEV_DEPENDENCIES)) {
4301
4319
  devDependencies[name] = spec;
4302
4320
  }
4303
4321
  const next = {
4304
- ...existsSync8(path) ? existing : { name: "rig-project", private: true },
4322
+ ...existsSync9(path) ? existing : { name: "rig-project", private: true },
4305
4323
  devDependencies
4306
4324
  };
4307
4325
  writeFileSync5(path, `${JSON.stringify(next, null, 2)}
@@ -4371,15 +4389,54 @@ async function promptSelect(prompts, options) {
4371
4389
  throw new CliError2("Init cancelled.", 1);
4372
4390
  return String(value);
4373
4391
  }
4374
- async function pollDeviceAuthOnce(context, pollId) {
4392
+ function sleep2(ms) {
4393
+ return new Promise((resolve17) => setTimeout(resolve17, ms));
4394
+ }
4395
+ function positiveIntFromEnv(name, fallback) {
4396
+ const value = Number.parseInt(process.env[name] ?? "", 10);
4397
+ return Number.isFinite(value) && value >= 0 ? value : fallback;
4398
+ }
4399
+ function apiSessionTokenFrom(payload) {
4400
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
4401
+ return null;
4402
+ const token = payload.apiSessionToken;
4403
+ return typeof token === "string" && token.trim() ? token.trim() : null;
4404
+ }
4405
+ function writeRemoteGitHubAuthState(projectRoot, input) {
4406
+ writeFileSync5(resolve16(projectRoot, ".rig", "state", "github-auth.json"), `${JSON.stringify({
4407
+ authenticated: true,
4408
+ source: input.source,
4409
+ storedOnServer: true,
4410
+ selectedRepo: input.selectedRepo,
4411
+ ...input.apiSessionToken ? { apiSessionToken: input.apiSessionToken } : {},
4412
+ updatedAt: new Date().toISOString()
4413
+ }, null, 2)}
4414
+ `, "utf8");
4415
+ }
4416
+ async function pollDeviceAuthUntilComplete(context, pollId, firstPayload) {
4375
4417
  if (typeof pollId !== "string" || !pollId.trim())
4376
4418
  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;
4419
+ const intervalSeconds = typeof firstPayload.interval === "number" && Number.isFinite(firstPayload.interval) && firstPayload.interval > 0 ? firstPayload.interval : 5;
4420
+ const timeoutMs = positiveIntFromEnv("RIG_DEVICE_AUTH_POLL_TIMEOUT_MS", 300000);
4421
+ const intervalMs = positiveIntFromEnv("RIG_DEVICE_AUTH_POLL_INTERVAL_MS", Math.max(1000, intervalSeconds * 1000));
4422
+ const deadline = Date.now() + timeoutMs;
4423
+ let last = null;
4424
+ do {
4425
+ const payload = await requestServerJson(context, "/api/github/auth/device/poll", {
4426
+ method: "POST",
4427
+ headers: { "content-type": "application/json" },
4428
+ body: JSON.stringify({ pollId })
4429
+ }).catch(() => null);
4430
+ last = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
4431
+ const status = typeof last?.status === "string" ? last.status : null;
4432
+ if (status === "signed-in" || status === "expired" || status === "cancelled" || status === "failed") {
4433
+ return last;
4434
+ }
4435
+ if (timeoutMs <= 0)
4436
+ return last;
4437
+ await sleep2(intervalMs);
4438
+ } while (Date.now() < deadline);
4439
+ return last;
4383
4440
  }
4384
4441
  async function runControlPlaneInit(context, options) {
4385
4442
  const projectRoot = context.projectRoot;
@@ -4402,9 +4459,9 @@ async function runControlPlaneInit(context, options) {
4402
4459
  });
4403
4460
  ensureRigPrivateDirs(projectRoot);
4404
4461
  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);
4462
+ const configTsPath = resolve16(projectRoot, "rig.config.ts");
4463
+ const configJsonPath = resolve16(projectRoot, "rig.config.json");
4464
+ const configExists = existsSync9(configTsPath) || existsSync9(configJsonPath);
4408
4465
  if (!options.privateStateOnly) {
4409
4466
  if (configExists && !options.repair) {
4410
4467
  if (context.outputMode !== "json")
@@ -4420,7 +4477,7 @@ async function runControlPlaneInit(context, options) {
4420
4477
  }
4421
4478
  ensureRigConfigPackageDependencies(projectRoot);
4422
4479
  }
4423
- writeFileSync5(resolve15(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
4480
+ writeFileSync5(resolve16(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
4424
4481
  `, "utf8");
4425
4482
  const checkout = checkoutForInit(projectRoot, serverKind, options.remoteCheckout);
4426
4483
  let uploadedSnapshot = null;
@@ -4442,10 +4499,14 @@ async function runControlPlaneInit(context, options) {
4442
4499
  const token = authMethod === "gh" && !options.githubToken ? readGhAuthToken() : options.githubToken?.trim();
4443
4500
  if (token) {
4444
4501
  githubAuth = await postGitHubTokenViaServer(context, token, { selectedRepo: repo.slug });
4445
- setGitHubBearerTokenForCurrentProcess(token);
4502
+ const apiSessionToken = apiSessionTokenFrom(githubAuth);
4503
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token);
4446
4504
  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");
4505
+ writeRemoteGitHubAuthState(projectRoot, {
4506
+ source: authMethod === "gh" ? "gh" : "init-token",
4507
+ selectedRepo: repo.slug,
4508
+ apiSessionToken
4509
+ });
4449
4510
  }
4450
4511
  } else if (authMethod === "device") {
4451
4512
  const payload = await requestServerJson(context, "/api/github/auth/device/start", {
@@ -4454,9 +4515,22 @@ async function runControlPlaneInit(context, options) {
4454
4515
  body: JSON.stringify({ repoSlug: repo.slug })
4455
4516
  });
4456
4517
  deviceAuth = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
4457
- const completed = await pollDeviceAuthOnce(context, deviceAuth.pollId);
4458
- if (completed)
4518
+ if (context.outputMode !== "json") {
4519
+ const verificationUri = String(deviceAuth.verificationUri ?? deviceAuth.verification_uri ?? deviceAuth.verification_uri_complete ?? "the verification URL returned by the server");
4520
+ const userCode = String(deviceAuth.userCode ?? deviceAuth.user_code ?? "the returned user code");
4521
+ console.log(`GitHub device flow: open ${verificationUri} and enter ${userCode}. Waiting for authorization...`);
4522
+ }
4523
+ const completed = await pollDeviceAuthUntilComplete(context, deviceAuth.pollId, deviceAuth);
4524
+ if (completed) {
4525
+ const apiSessionToken = apiSessionTokenFrom(completed);
4526
+ if (apiSessionToken) {
4527
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken);
4528
+ if (serverKind === "remote") {
4529
+ writeRemoteGitHubAuthState(projectRoot, { source: "device", selectedRepo: repo.slug, apiSessionToken });
4530
+ }
4531
+ }
4459
4532
  deviceAuth = { ...deviceAuth, poll: completed, completed: completed.status === "signed-in" };
4533
+ }
4460
4534
  }
4461
4535
  let remoteCheckoutPreparation = null;
4462
4536
  if (serverKind === "remote" && options.remoteCheckout?.kind !== "uploaded-snapshot") {
@@ -4476,6 +4550,12 @@ async function runControlPlaneInit(context, options) {
4476
4550
  });
4477
4551
  const checkoutPath = typeof checkout.path === "string" ? checkout.path : null;
4478
4552
  const serverRootSwitch = serverKind === "remote" && checkoutPath ? await switchServerProjectRootViaServer(context, checkoutPath) : null;
4553
+ if (serverRootSwitch && token) {
4554
+ githubAuth = await postGitHubTokenViaServer(context, token, { selectedRepo: repo.slug, projectRoot: checkoutPath ?? undefined });
4555
+ const apiSessionToken = apiSessionTokenFrom(githubAuth);
4556
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token);
4557
+ writeRemoteGitHubAuthState(projectRoot, { source: authMethod === "gh" ? "gh" : "init-token", selectedRepo: repo.slug, apiSessionToken });
4558
+ }
4479
4559
  const activeProjectRegistration = serverRootSwitch ? await registerProjectViaServer(context, { repoSlug: repo.slug, checkout }) : null;
4480
4560
  const pi = serverKind === "remote" ? await ensureRemotePiRigInstalled({ requestJson: (pathname, init) => requestServerJson(context, pathname, init) }).catch((error) => ({
4481
4561
  remote: true,
@@ -4585,7 +4665,7 @@ function parseInitOptions(args) {
4585
4665
  async function runInteractiveControlPlaneInit(context, prompts) {
4586
4666
  prompts.intro?.("Initialize a Rig control-plane project");
4587
4667
  const projectRoot = context.projectRoot;
4588
- const existingConfig = existsSync8(resolve15(projectRoot, "rig.config.ts")) || existsSync8(resolve15(projectRoot, "rig.config.json"));
4668
+ const existingConfig = existsSync9(resolve16(projectRoot, "rig.config.ts")) || existsSync9(resolve16(projectRoot, "rig.config.json"));
4589
4669
  let repair = false;
4590
4670
  let privateStateOnly = false;
4591
4671
  if (existingConfig) {
@@ -4685,7 +4765,7 @@ async function runInteractiveControlPlaneInit(context, prompts) {
4685
4765
  });
4686
4766
  const details = result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : {};
4687
4767
  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")}.` : "";
4768
+ 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
4769
  prompts.outro?.(`Rig project initialized.${deviceMessage} Next: rig doctor && rig task list`);
4690
4770
  return result;
4691
4771
  }
@@ -4847,8 +4927,8 @@ async function executeDoctor(context, args) {
4847
4927
  }
4848
4928
 
4849
4929
  // packages/cli/src/commands/_run-driver-helpers.ts
4850
- import { readFileSync as readFileSync6 } from "fs";
4851
- import { resolve as resolve16 } from "path";
4930
+ import { readFileSync as readFileSync7 } from "fs";
4931
+ import { resolve as resolve17 } from "path";
4852
4932
  import {
4853
4933
  appendJsonlRecord as appendJsonlRecord2,
4854
4934
  readAuthorityRun as readAuthorityRun2,
@@ -4868,7 +4948,7 @@ function patchAuthorityRun(projectRoot, runId, patch) {
4868
4948
  ...patch,
4869
4949
  updatedAt: new Date().toISOString()
4870
4950
  };
4871
- writeJsonFile4(resolve16(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), next);
4951
+ writeJsonFile4(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), next);
4872
4952
  return next;
4873
4953
  }
4874
4954
  function touchAuthorityRun(projectRoot, runId) {
@@ -4876,21 +4956,21 @@ function touchAuthorityRun(projectRoot, runId) {
4876
4956
  if (!current) {
4877
4957
  return;
4878
4958
  }
4879
- writeJsonFile4(resolve16(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), {
4959
+ writeJsonFile4(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), {
4880
4960
  ...current,
4881
4961
  updatedAt: new Date().toISOString()
4882
4962
  });
4883
4963
  }
4884
4964
  function appendRunTimeline(projectRoot, runId, value) {
4885
- appendJsonlRecord2(resolve16(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), value);
4965
+ appendJsonlRecord2(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), value);
4886
4966
  touchAuthorityRun(projectRoot, runId);
4887
4967
  }
4888
4968
  function appendRunLog(projectRoot, runId, value) {
4889
- appendJsonlRecord2(resolve16(resolveAuthorityRunDir3(projectRoot, runId), "logs.jsonl"), value);
4969
+ appendJsonlRecord2(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "logs.jsonl"), value);
4890
4970
  touchAuthorityRun(projectRoot, runId);
4891
4971
  }
4892
4972
  function appendRunAction(projectRoot, runId, value) {
4893
- appendJsonlRecord2(resolve16(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), {
4973
+ appendJsonlRecord2(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), {
4894
4974
  id: value.id,
4895
4975
  type: "action",
4896
4976
  actionType: value.actionType,
@@ -4961,7 +5041,7 @@ function buildRunPrompt(input) {
4961
5041
  })();
4962
5042
  const scopeText = (() => {
4963
5043
  try {
4964
- const parsed = JSON.parse(readFileSync6(resolveControlPlaneTaskConfigPath(input.projectRoot), "utf8"));
5044
+ const parsed = JSON.parse(readFileSync7(resolveControlPlaneTaskConfigPath(input.projectRoot), "utf8"));
4965
5045
  const entry = parsed[input.taskId] ?? {};
4966
5046
  const scope = Array.isArray(entry.scope) ? entry.scope.filter((item) => typeof item === "string") : [];
4967
5047
  const validation = Array.isArray(entry.validation) ? entry.validation.filter((item) => typeof item === "string") : [];
@@ -5074,8 +5154,8 @@ function renderSourceScopeValidation(task, validation) {
5074
5154
  }
5075
5155
 
5076
5156
  // packages/cli/src/commands/inspect.ts
5077
- import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
5078
- import { resolve as resolve17 } from "path";
5157
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
5158
+ import { resolve as resolve18 } from "path";
5079
5159
  import {
5080
5160
  listAuthorityRuns as listAuthorityRuns2,
5081
5161
  readAuthorityRun as readAuthorityRun3,
@@ -5096,8 +5176,8 @@ async function executeInspect(context, args) {
5096
5176
  if (!latestRun) {
5097
5177
  throw new CliError2(`No runs found for ${requiredTask}.`);
5098
5178
  }
5099
- const logsPath = resolve17(resolveAuthorityRunDir4(context.projectRoot, latestRun.runId), "logs.jsonl");
5100
- if (!existsSync9(logsPath)) {
5179
+ const logsPath = resolve18(resolveAuthorityRunDir4(context.projectRoot, latestRun.runId), "logs.jsonl");
5180
+ if (!existsSync10(logsPath)) {
5101
5181
  throw new CliError2(`No logs found for run ${latestRun.runId}.`);
5102
5182
  }
5103
5183
  await context.runCommand(["cat", logsPath]);
@@ -5107,7 +5187,7 @@ async function executeInspect(context, args) {
5107
5187
  const { value: task, rest: remaining } = takeOption(rest, "--task");
5108
5188
  requireNoExtraArgs(remaining, "bun run rig inspect artifacts --task <beads-id>");
5109
5189
  const requiredTask = requireTask(task, "bun run rig inspect artifacts --task <beads-id>");
5110
- const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) => existsSync9(path));
5190
+ const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) => existsSync10(path));
5111
5191
  if (!artifactRoot) {
5112
5192
  throw new CliError2(`No artifacts found for ${requiredTask}.`);
5113
5193
  }
@@ -5164,10 +5244,10 @@ async function executeInspect(context, args) {
5164
5244
  case "failures": {
5165
5245
  requireNoExtraArgs(rest, "bun run rig inspect failures");
5166
5246
  const failed = resolveHarnessPaths2(context.projectRoot).failedApproachesPath;
5167
- if (!existsSync9(failed)) {
5247
+ if (!existsSync10(failed)) {
5168
5248
  console.log("No failures recorded.");
5169
5249
  } else {
5170
- process.stdout.write(readFileSync7(failed, "utf-8"));
5250
+ process.stdout.write(readFileSync8(failed, "utf-8"));
5171
5251
  }
5172
5252
  return { ok: true, group: "inspect", command };
5173
5253
  }
@@ -5184,11 +5264,11 @@ async function executeInspect(context, args) {
5184
5264
  return { ok: true, group: "inspect", command };
5185
5265
  case "audit": {
5186
5266
  requireNoExtraArgs(rest, "bun run rig inspect audit");
5187
- const auditPath = resolve17(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
5188
- if (!existsSync9(auditPath)) {
5267
+ const auditPath = resolve18(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
5268
+ if (!existsSync10(auditPath)) {
5189
5269
  console.log("No audit log found.");
5190
5270
  } else {
5191
- const lines = readFileSync7(auditPath, "utf-8").split(/\r?\n/).filter(Boolean).slice(-20);
5271
+ const lines = readFileSync8(auditPath, "utf-8").split(/\r?\n/).filter(Boolean).slice(-20);
5192
5272
  for (const line of lines) {
5193
5273
  console.log(line);
5194
5274
  }
@@ -5817,8 +5897,8 @@ async function executeRemote(context, args) {
5817
5897
  }
5818
5898
 
5819
5899
  // packages/cli/src/commands/run.ts
5820
- import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
5821
- import { resolve as resolve18 } from "path";
5900
+ import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
5901
+ import { resolve as resolve19 } from "path";
5822
5902
  import { createInterface as createInterface2 } from "readline/promises";
5823
5903
  import {
5824
5904
  listAuthorityRuns as listAuthorityRuns3,
@@ -6097,7 +6177,7 @@ async function executeRun(context, args) {
6097
6177
  if (!run.value) {
6098
6178
  throw new CliError2("run timeline requires --run <id>.");
6099
6179
  }
6100
- const timelinePath = resolve18(resolveAuthorityRunDir5(context.projectRoot, run.value), "timeline.jsonl");
6180
+ const timelinePath = resolve19(resolveAuthorityRunDir5(context.projectRoot, run.value), "timeline.jsonl");
6101
6181
  const printEvents = () => {
6102
6182
  const events2 = readJsonlFile4(timelinePath);
6103
6183
  if (context.outputMode === "text") {
@@ -6109,12 +6189,12 @@ async function executeRun(context, args) {
6109
6189
  };
6110
6190
  const events = printEvents();
6111
6191
  if (follow.value && context.outputMode === "text") {
6112
- let lastLength = existsSync10(timelinePath) ? readFileSync8(timelinePath, "utf8").length : 0;
6192
+ let lastLength = existsSync11(timelinePath) ? readFileSync9(timelinePath, "utf8").length : 0;
6113
6193
  while (true) {
6114
6194
  await Bun.sleep(1000);
6115
- if (!existsSync10(timelinePath))
6195
+ if (!existsSync11(timelinePath))
6116
6196
  continue;
6117
- const next = readFileSync8(timelinePath, "utf8");
6197
+ const next = readFileSync9(timelinePath, "utf8");
6118
6198
  if (next.length <= lastLength)
6119
6199
  continue;
6120
6200
  const delta = next.slice(lastLength);
@@ -6400,10 +6480,10 @@ async function executeServer(context, args, options) {
6400
6480
  }
6401
6481
 
6402
6482
  // packages/cli/src/commands/task.ts
6403
- import { readFileSync as readFileSync9 } from "fs";
6483
+ import { readFileSync as readFileSync10 } from "fs";
6404
6484
  import { spawnSync as spawnSync4 } from "child_process";
6405
6485
  import { createInterface as createInterface4 } from "readline/promises";
6406
- import { resolve as resolve19 } from "path";
6486
+ import { resolve as resolve20 } from "path";
6407
6487
  import {
6408
6488
  taskArtifactDir,
6409
6489
  taskArtifacts,
@@ -6734,7 +6814,7 @@ async function executeTask(context, args, options) {
6734
6814
  const fileFlag = takeOption(rest.slice(1), "--file");
6735
6815
  let content;
6736
6816
  if (fileFlag.value) {
6737
- content = readFileSync9(resolve19(context.projectRoot, fileFlag.value), "utf-8");
6817
+ content = readFileSync10(resolve20(context.projectRoot, fileFlag.value), "utf-8");
6738
6818
  } else {
6739
6819
  content = await readStdin();
6740
6820
  }
@@ -6955,8 +7035,8 @@ async function executeTask(context, args, options) {
6955
7035
  }
6956
7036
 
6957
7037
  // 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";
7038
+ import { copyFileSync as copyFileSync3, existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync11, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
7039
+ import { resolve as resolve21 } from "path";
6960
7040
  import { spawn as spawn2, spawnSync as spawnSync5 } from "child_process";
6961
7041
  import { createInterface as createLineInterface } from "readline";
6962
7042
  import { loadConfig as loadConfig2 } from "@rig/core/load-config";
@@ -7022,12 +7102,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
7022
7102
  return 0;
7023
7103
  let copied = 0;
7024
7104
  for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
7025
- const sourcePath = resolve20(sourceRoot, relativePath);
7026
- const targetPath = resolve20(targetRoot, relativePath);
7105
+ const sourcePath = resolve21(sourceRoot, relativePath);
7106
+ const targetPath = resolve21(targetRoot, relativePath);
7027
7107
  try {
7028
7108
  if (!statSync2(sourcePath).isFile())
7029
7109
  continue;
7030
- mkdirSync7(resolve20(targetPath, ".."), { recursive: true });
7110
+ mkdirSync7(resolve21(targetPath, ".."), { recursive: true });
7031
7111
  copyFileSync3(sourcePath, targetPath);
7032
7112
  copied += 1;
7033
7113
  } catch {}
@@ -7061,6 +7141,14 @@ function buildTaskRunReviewEnv(config) {
7061
7141
  ...review?.provider ? { AI_REVIEW_PROVIDER: review.provider } : {}
7062
7142
  };
7063
7143
  }
7144
+ function buildDirtyBaselineHandshakeEnv(input) {
7145
+ if (input.baselineMode !== "dirty-snapshot")
7146
+ return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
7147
+ return {
7148
+ RIG_BASELINE_MODE: "dirty-snapshot",
7149
+ RIG_DIRTY_BASELINE_READY_FILE: resolve21(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
7150
+ };
7151
+ }
7064
7152
  function positiveInt(value, fallback) {
7065
7153
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
7066
7154
  }
@@ -7169,9 +7257,9 @@ function createCommandRunner(binary) {
7169
7257
  const stderrChunks = [];
7170
7258
  child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
7171
7259
  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({
7260
+ return await new Promise((resolve22) => {
7261
+ child.once("error", (error) => resolve22({ exitCode: 1, stderr: error.message }));
7262
+ child.once("close", (code) => resolve22({
7175
7263
  exitCode: code ?? 1,
7176
7264
  stdout: Buffer.concat(stdoutChunks).toString("utf8"),
7177
7265
  stderr: Buffer.concat(stderrChunks).toString("utf8")
@@ -7367,7 +7455,7 @@ function summarizeValidationFailure(projectRoot, taskId2) {
7367
7455
  return null;
7368
7456
  }
7369
7457
  for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId2)) {
7370
- const summary = readJsonFile3(resolve20(artifactDir, "validation-summary.json"), null);
7458
+ const summary = readJsonFile3(resolve21(artifactDir, "validation-summary.json"), null);
7371
7459
  if (!summary || summary.status !== "fail") {
7372
7460
  continue;
7373
7461
  }
@@ -7448,9 +7536,9 @@ function readTaskRunAcceptedArtifactState(input) {
7448
7536
  if (!input.taskId || !input.workspaceDir) {
7449
7537
  return { accepted: false, reason: null };
7450
7538
  }
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");
7539
+ const artifactDir = resolve21(input.workspaceDir, "artifacts", input.taskId);
7540
+ const reviewStatusPath = resolve21(artifactDir, "review-status.txt");
7541
+ const taskResultPath = resolve21(artifactDir, "task-result.json");
7454
7542
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
7455
7543
  if (reviewStatus !== "APPROVED") {
7456
7544
  return { accepted: false, reason: null };
@@ -7487,12 +7575,12 @@ function resolveTaskRunRetryContext(input) {
7487
7575
  if (!input.taskId || !input.workspaceDir) {
7488
7576
  return { shouldRetry: false, failureDetail: null, nextPrompt: null };
7489
7577
  }
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");
7578
+ const artifactDir = resolve21(input.workspaceDir, "artifacts", input.taskId);
7579
+ const reviewStatePath = resolve21(artifactDir, "review-state.json");
7580
+ const reviewFeedbackPath = resolve21(artifactDir, "review-feedback.md");
7581
+ const reviewStatusPath = resolve21(artifactDir, "review-status.txt");
7582
+ const failedApproachesPath = resolve21(input.workspaceDir, ".rig", "state", "failed_approaches.md");
7583
+ const validationSummaryPath = resolve21(artifactDir, "validation-summary.json");
7496
7584
  const reviewState = readJsonFile3(reviewStatePath, null);
7497
7585
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
7498
7586
  const reviewRejected = isTaskRunReviewRejected(reviewState);
@@ -7547,11 +7635,11 @@ function summarizeTaskRunReviewFailure(reviewState) {
7547
7635
  return "Completion verification rejected the task. Read review-feedback.md for required fixes.";
7548
7636
  }
7549
7637
  function readTaskRunReviewStatus(reviewStatusPath) {
7550
- if (!existsSync11(reviewStatusPath)) {
7638
+ if (!existsSync12(reviewStatusPath)) {
7551
7639
  return null;
7552
7640
  }
7553
7641
  try {
7554
- const status = readFileSync10(reviewStatusPath, "utf8").trim().toUpperCase();
7642
+ const status = readFileSync11(reviewStatusPath, "utf8").trim().toUpperCase();
7555
7643
  return status === "APPROVED" || status === "REJECTED" ? status : null;
7556
7644
  } catch {
7557
7645
  return null;
@@ -7635,7 +7723,7 @@ function stringArrayField(record, key) {
7635
7723
  async function executeRigOwnedTaskRun(context, input) {
7636
7724
  const runtimeTaskId = input.taskId?.trim() || `adhoc-${input.runId}`;
7637
7725
  const sourceTask = readRunSourceTaskContract(context.projectRoot, input.runId, input.taskId);
7638
- const prompt = buildRunPrompt({
7726
+ let prompt = buildRunPrompt({
7639
7727
  projectRoot: context.projectRoot,
7640
7728
  taskId: input.taskId,
7641
7729
  fallbackTitle: input.title,
@@ -7735,7 +7823,22 @@ async function executeRigOwnedTaskRun(context, input) {
7735
7823
  const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
7736
7824
  const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
7737
7825
  const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
7738
- patchAuthorityRun(context.projectRoot, input.runId, { planning: planningClassification });
7826
+ const planningArtifactPath = resolve21("artifacts", runtimeTaskId, "implementation-plan.md");
7827
+ const persistedPlanning = {
7828
+ ...planningClassification,
7829
+ classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
7830
+ artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
7831
+ classifiedAt: new Date().toISOString()
7832
+ };
7833
+ mkdirSync7(resolve21(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
7834
+ writeFileSync6(resolve21(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
7835
+ `, "utf8");
7836
+ patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
7837
+ prompt = `${prompt}
7838
+
7839
+ Rig planning classification:
7840
+ ${JSON.stringify(persistedPlanning, null, 2)}
7841
+ ${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
7842
  if (input.runtimeAdapter === "pi") {
7740
7843
  for (const stage of ["Connect", "GitHub/task sync", "Prepare workspace", "Launch Pi", "Plan", "Implement"]) {
7741
7844
  appendPiStageLog({
@@ -7802,6 +7905,7 @@ async function executeRigOwnedTaskRun(context, input) {
7802
7905
  ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {}
7803
7906
  };
7804
7907
  Object.assign(childEnv, buildTaskRunReviewEnv(automationConfig));
7908
+ Object.assign(childEnv, buildDirtyBaselineHandshakeEnv({ projectRoot: context.projectRoot, runId: input.runId, baselineMode: input.baselineMode }));
7805
7909
  const automationLimits = resolveTaskRunAutomationLimits(automationConfig);
7806
7910
  const maxAttempts = automationLimits.maxValidationAttempts;
7807
7911
  const promoteToValidating = (detail) => {
@@ -7856,22 +7960,29 @@ async function executeRigOwnedTaskRun(context, input) {
7856
7960
  patchAuthorityRun(context.projectRoot, input.runId, {
7857
7961
  status: "running",
7858
7962
  worktreePath: latestRuntimeWorkspace,
7859
- artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve20(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
7963
+ artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve21(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
7860
7964
  logRoot: latestLogsDir,
7861
- sessionPath: latestSessionDir ? resolve20(latestSessionDir, "session.json") : null,
7862
- sessionLogPath: latestLogsDir ? resolve20(latestLogsDir, "agent-stdout.log") : null,
7965
+ sessionPath: latestSessionDir ? resolve21(latestSessionDir, "session.json") : null,
7966
+ sessionLogPath: latestLogsDir ? resolve21(latestLogsDir, "agent-stdout.log") : null,
7863
7967
  branch: runtimeId
7864
7968
  });
7865
7969
  if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
7866
7970
  dirtyBaselineApplied = true;
7867
7971
  const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
7972
+ const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
7973
+ if (readyFile) {
7974
+ mkdirSync7(resolve21(readyFile, ".."), { recursive: true });
7975
+ writeFileSync6(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
7976
+ `, "utf8");
7977
+ }
7868
7978
  appendRunLog(context.projectRoot, input.runId, {
7869
7979
  id: `log:${input.runId}:dirty-baseline`,
7870
7980
  title: "Dirty baseline snapshot",
7871
7981
  detail: dirty.detail,
7872
7982
  tone: dirty.applied ? "tool" : "info",
7873
7983
  status: dirty.applied ? "completed" : "skipped",
7874
- createdAt: new Date().toISOString()
7984
+ createdAt: new Date().toISOString(),
7985
+ payload: readyFile ? { readyFile } : undefined
7875
7986
  });
7876
7987
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Dirty baseline snapshot" });
7877
7988
  }
@@ -8138,7 +8249,7 @@ async function executeRigOwnedTaskRun(context, input) {
8138
8249
  let acceptedArtifactObservedAt = null;
8139
8250
  let acceptedArtifactPollTimer = null;
8140
8251
  let acceptedArtifactKillTimer = null;
8141
- const attemptExit = await new Promise((resolve21) => {
8252
+ const attemptExit = await new Promise((resolve22) => {
8142
8253
  let settled = false;
8143
8254
  const settle = (result) => {
8144
8255
  if (settled)
@@ -8146,7 +8257,7 @@ async function executeRigOwnedTaskRun(context, input) {
8146
8257
  settled = true;
8147
8258
  if (acceptedArtifactPollTimer)
8148
8259
  clearInterval(acceptedArtifactPollTimer);
8149
- resolve21(result);
8260
+ resolve22(result);
8150
8261
  };
8151
8262
  const pollAcceptedArtifacts = () => {
8152
8263
  const artifactState = readTaskRunAcceptedArtifactState({
@@ -8343,6 +8454,29 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
8343
8454
  });
8344
8455
  throw new CliError2(terminalFailureDetail, exit.code ?? 1);
8345
8456
  }
8457
+ if (planningClassification.planningRequired) {
8458
+ const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
8459
+ const expectedPlanPath = resolve21(planWorkspace, planningArtifactPath);
8460
+ if (!existsSync12(expectedPlanPath)) {
8461
+ const failedAt = new Date().toISOString();
8462
+ const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
8463
+ patchAuthorityRun(context.projectRoot, input.runId, {
8464
+ status: "needs_attention",
8465
+ completedAt: failedAt,
8466
+ errorText: failureDetail
8467
+ });
8468
+ appendRunLog(context.projectRoot, input.runId, {
8469
+ id: `log:${input.runId}:plan-artifact-missing`,
8470
+ title: "Required plan artifact missing",
8471
+ detail: failureDetail,
8472
+ tone: "error",
8473
+ status: "needs_attention",
8474
+ createdAt: failedAt
8475
+ });
8476
+ emitServerRunEvent({ type: "failed", runId: input.runId, error: failureDetail });
8477
+ throw new CliError2(failureDetail, 1);
8478
+ }
8479
+ }
8346
8480
  const runPiPrFeedbackFix = async (message2) => {
8347
8481
  appendPiStageLog({
8348
8482
  projectRoot: context.projectRoot,
@@ -8400,9 +8534,9 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
8400
8534
  });
8401
8535
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
8402
8536
  });
8403
- const exitCode = await new Promise((resolve21) => {
8404
- child.once("error", () => resolve21(1));
8405
- child.once("close", (code) => resolve21(code ?? 1));
8537
+ const exitCode = await new Promise((resolve22) => {
8538
+ child.once("error", () => resolve22(1));
8539
+ child.once("close", (code) => resolve22(code ?? 1));
8406
8540
  });
8407
8541
  if (exitCode !== 0) {
8408
8542
  throw new Error(`Pi PR feedback fix failed with exit code ${exitCode}.`);
@@ -8521,8 +8655,8 @@ async function executeTest(context, args) {
8521
8655
  }
8522
8656
 
8523
8657
  // 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";
8658
+ import { existsSync as existsSync13, mkdirSync as mkdirSync8, readdirSync as readdirSync2, writeFileSync as writeFileSync7 } from "fs";
8659
+ import { resolve as resolve22 } from "path";
8526
8660
  import { createPluginHost } from "@rig/core";
8527
8661
  import {
8528
8662
  isSupportedBunVersion as isSupportedBunVersion2,
@@ -8585,9 +8719,9 @@ function runSetupInit(projectRoot) {
8585
8719
  mkdirSync8(stateDir, { recursive: true });
8586
8720
  mkdirSync8(logsDir, { recursive: true });
8587
8721
  mkdirSync8(artifactsDir, { recursive: true });
8588
- const failuresPath = resolve21(stateDir, "failed_approaches.md");
8589
- if (!existsSync12(failuresPath)) {
8590
- writeFileSync6(failuresPath, `# Failed Approaches
8722
+ const failuresPath = resolve22(stateDir, "failed_approaches.md");
8723
+ if (!existsSync13(failuresPath)) {
8724
+ writeFileSync7(failuresPath, `# Failed Approaches
8591
8725
 
8592
8726
  `, "utf-8");
8593
8727
  }
@@ -8604,18 +8738,18 @@ async function runSetupCheck(projectRoot) {
8604
8738
  }
8605
8739
  async function runSetupPreflight(projectRoot) {
8606
8740
  await runSetupCheck(projectRoot);
8607
- const validationRoot = resolve21(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
8608
- if (existsSync12(validationRoot)) {
8741
+ const validationRoot = resolve22(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
8742
+ if (existsSync13(validationRoot)) {
8609
8743
  const validators = readdirSync2(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
8610
8744
  for (const validator of validators) {
8611
- const script = resolve21(validationRoot, validator.name, "validate.sh");
8612
- if (existsSync12(script)) {
8745
+ const script = resolve22(validationRoot, validator.name, "validate.sh");
8746
+ if (existsSync13(script)) {
8613
8747
  console.log(`OK: validator script ${script}`);
8614
8748
  }
8615
8749
  }
8616
8750
  }
8617
- const hooksRoot = resolve21(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
8618
- if (existsSync12(hooksRoot)) {
8751
+ const hooksRoot = resolve22(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
8752
+ if (existsSync13(hooksRoot)) {
8619
8753
  const hooks = readdirSync2(hooksRoot).filter((name) => name.endsWith(".sh"));
8620
8754
  for (const hook of hooks) {
8621
8755
  console.log(`OK: hook ${hook}`);